PERFORCE change 112887 for review
Roman Divacky
rdivacky at FreeBSD.org
Sun Jan 14 09:47:48 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=112887
Change 112887 by rdivacky at rdivacky_witten on 2007/01/14 09:47:43
Implement linux_openat(). This includes linux_at function that is
common to all *at syscalls. This seems to pass my mangled LTP
test. The LTP test is wrong I think (it tries to open nonexistant
file and complains when it cant). The race seen in open() is present
in this implementation too.
If this implementation proves wrong implementing the rest of the *at
syscalls will be easy.
Affected files ...
.. //depot/projects/linuxolator/src/sys/amd64/linux32/linux.h#12 edit
.. //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_dummy.c#8 edit
.. //depot/projects/linuxolator/src/sys/compat/linux/linux_file.c#9 edit
.. //depot/projects/linuxolator/src/sys/compat/linux/linux_util.h#2 edit
.. //depot/projects/linuxolator/src/sys/i386/linux/linux.h#10 edit
.. //depot/projects/linuxolator/src/sys/i386/linux/linux_dummy.c#8 edit
.. //depot/projects/linuxolator/src/sys/kern/vfs_lookup.c#4 edit
Differences ...
==== //depot/projects/linuxolator/src/sys/amd64/linux32/linux.h#12 (text+ko) ====
@@ -556,6 +556,8 @@
#define LINUX_F_WRLCK 1
#define LINUX_F_UNLCK 2
+#define LINUX_AT_FDCWD -100
+
/*
* mount flags
*/
==== //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_dummy.c#8 (text+ko) ====
@@ -96,7 +96,6 @@
DUMMY(inotify_add_watch);
DUMMY(inotify_rm_watch);
DUMMY(migrate_pages);
-DUMMY(openat);
DUMMY(mkdirat);
DUMMY(mknodat);
DUMMY(fchownat);
==== //depot/projects/linuxolator/src/sys/compat/linux/linux_file.c#9 (text+ko) ====
@@ -43,6 +43,7 @@
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/mutex.h>
+#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/stat.h>
#include <sys/syscallsubr.h>
@@ -84,52 +85,42 @@
return (error);
}
-int
-linux_open(struct thread *td, struct linux_open_args *args)
+
+static int
+linux_common_open(struct thread *td, char *path, int l_flags, int mode, int openat)
{
struct proc *p = td->td_proc;
- char *path;
int bsd_flags, error;
- if (args->flags & LINUX_O_CREAT)
- LCONVPATHCREAT(td, args->path, &path);
- else
- LCONVPATHEXIST(td, args->path, &path);
-
-#ifdef DEBUG
- if (ldebug(open))
- printf(ARGS(open, "%s, 0x%x, 0x%x"),
- path, args->flags, args->mode);
-#endif
bsd_flags = 0;
- if (args->flags & LINUX_O_RDONLY)
+ if (l_flags & LINUX_O_RDONLY)
bsd_flags |= O_RDONLY;
- if (args->flags & LINUX_O_WRONLY)
+ if (l_flags & LINUX_O_WRONLY)
bsd_flags |= O_WRONLY;
- if (args->flags & LINUX_O_RDWR)
+ if (l_flags & LINUX_O_RDWR)
bsd_flags |= O_RDWR;
- if (args->flags & LINUX_O_NDELAY)
+ if (l_flags & LINUX_O_NDELAY)
bsd_flags |= O_NONBLOCK;
- if (args->flags & LINUX_O_APPEND)
+ if (l_flags & LINUX_O_APPEND)
bsd_flags |= O_APPEND;
- if (args->flags & LINUX_O_SYNC)
+ if (l_flags & LINUX_O_SYNC)
bsd_flags |= O_FSYNC;
- if (args->flags & LINUX_O_NONBLOCK)
+ if (l_flags & LINUX_O_NONBLOCK)
bsd_flags |= O_NONBLOCK;
- if (args->flags & LINUX_FASYNC)
+ if (l_flags & LINUX_FASYNC)
bsd_flags |= O_ASYNC;
- if (args->flags & LINUX_O_CREAT)
+ if (l_flags & LINUX_O_CREAT)
bsd_flags |= O_CREAT;
- if (args->flags & LINUX_O_TRUNC)
+ if (l_flags & LINUX_O_TRUNC)
bsd_flags |= O_TRUNC;
- if (args->flags & LINUX_O_EXCL)
+ if (l_flags & LINUX_O_EXCL)
bsd_flags |= O_EXCL;
- if (args->flags & LINUX_O_NOCTTY)
+ if (l_flags & LINUX_O_NOCTTY)
bsd_flags |= O_NOCTTY;
- if (args->flags & LINUX_O_DIRECT)
+ if (l_flags & LINUX_O_DIRECT)
bsd_flags |= O_DIRECT;
- error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, args->mode);
+ error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode);
PROC_LOCK(p);
if (!error && !(bsd_flags & O_NOCTTY) &&
SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
@@ -150,10 +141,121 @@
printf(LMSG("open returns error %d"), error);
#endif
}
- LFREEPATH(path);
+ if (!openat)
+ LFREEPATH(path);
return error;
}
+/*
+ * common code for linux *at set of syscalls
+ *
+ * works like this:
+ * if filename is absolute
+ * ignore dirfd
+ * else
+ * if dirfd == AT_FDCWD
+ * return CWD/filename
+ * else
+ * return DIRFD/filename
+ */
+static int
+linux_at(struct thread *td, int dirfd, char *filename, char **newpath, char **freebuf)
+{
+ struct file *fp;
+ int error = 0;
+ struct vnode *dvp;
+ struct filedesc *fdp = td->td_proc->p_fd;
+ char *fullpath = "unknown";
+ char *freepath = NULL;
+
+ /* dont do anything if the pathname is absolute */
+ if (*filename == '/') {
+ *newpath= filename;
+ return (0);
+ }
+
+ /* check for AT_FDWCD */
+ if (dirfd == LINUX_AT_FDCWD) {
+ FILEDESC_LOCK(fdp);
+ dvp = fdp->fd_cdir;
+ FILEDESC_UNLOCK(fdp);
+ } else {
+ error = fget(td, dirfd, &fp);
+ if (error)
+ return (error);
+ dvp = fp->f_vnode;
+ /* only a dir can be dfd */
+ if (dvp->v_type != VDIR) {
+ fdrop(fp, td);
+ return (ENOTDIR);
+ }
+ fdrop(fp, td);
+ }
+
+ error = vn_fullpath(td, dvp, &fullpath, &freepath);
+ if (!error) {
+ *newpath = malloc(strlen(fullpath) + strlen(filename) + 2, M_TEMP, M_WAITOK | M_ZERO);
+ *freebuf = freepath;
+ sprintf(*newpath, "%s/%s", fullpath, filename);
+ }
+
+ return (error);
+}
+
+int
+linux_openat(struct thread *td, struct linux_openat_args *args)
+{
+ char *newpath, *oldpath, *freebuf = NULL, *path;
+ int error, len;
+
+ oldpath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ error = copyinstr(args->filename, oldpath, MAXPATHLEN, &len);
+
+#ifdef DEBUG
+ if (ldebug(openat))
+ printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
+ oldpath, args->flags, args->mode);
+#endif
+
+ error = linux_at(td, args->dfd, oldpath, &newpath, &freebuf);
+ if (error)
+ return (error);
+#ifdef DEBUG
+ printf(LMSG("newpath: %s"), newpath);
+#endif
+ if (args->flags & LINUX_O_CREAT)
+ LCONVPATH_SEG(td, newpath, &path, 1, UIO_SYSSPACE);
+ else
+ LCONVPATH_SEG(td, newpath, &path, 0, UIO_SYSSPACE);
+ if (freebuf)
+ free(freebuf, M_TEMP);
+ if (*oldpath != '/')
+ free(newpath, M_TEMP);
+
+ error = linux_common_open(td, path, args->flags, args->mode, 1);
+ free(oldpath, M_TEMP);
+ return (error);
+}
+
+int
+linux_open(struct thread *td, struct linux_open_args *args)
+{
+ char *path;
+
+ if (args->flags & LINUX_O_CREAT)
+ LCONVPATHCREAT(td, args->path, &path);
+ else
+ LCONVPATHEXIST(td, args->path, &path);
+
+#ifdef DEBUG
+ if (ldebug(open))
+ printf(ARGS(open, "%s, 0x%x, 0x%x"),
+ path, args->flags, args->mode);
+#endif
+
+ return linux_common_open(td, path, args->flags, args->mode, 0);
+}
+
int
linux_lseek(struct thread *td, struct linux_lseek_args *args)
{
==== //depot/projects/linuxolator/src/sys/compat/linux/linux_util.h#2 (text+ko) ====
@@ -53,16 +53,19 @@
int linux_emul_convpath(struct thread *, char *, enum uio_seg, char **, int);
-#define LCONVPATH(td, upath, pathp, i) \
+#define LCONVPATH_SEG(td, upath, pathp, i, seg) \
do { \
int _error; \
\
- _error = linux_emul_convpath(td, upath, UIO_USERSPACE, \
+ _error = linux_emul_convpath(td, upath, seg, \
pathp, i); \
if (*(pathp) == NULL) \
return (_error); \
} while (0)
+#define LCONVPATH(td, upath, pathp, i) \
+ LCONVPATH_SEG(td, upath, pathp, i, UIO_USERSPACE)
+
#define LCONVPATHEXIST(td, upath, pathp) LCONVPATH(td, upath, pathp, 0)
#define LCONVPATHCREAT(td, upath, pathp) LCONVPATH(td, upath, pathp, 1)
#define LFREEPATH(path) free(path, M_TEMP)
==== //depot/projects/linuxolator/src/sys/i386/linux/linux.h#10 (text+ko) ====
@@ -527,6 +527,8 @@
#define LINUX_F_WRLCK 1
#define LINUX_F_UNLCK 2
+#define LINUX_AT_FDCWD -100
+
/*
* mount flags
*/
==== //depot/projects/linuxolator/src/sys/i386/linux/linux_dummy.c#8 (text+ko) ====
@@ -86,7 +86,6 @@
DUMMY(inotify_add_watch);
DUMMY(inotify_rm_watch);
DUMMY(migrate_pages);
-DUMMY(openat);
DUMMY(mkdirat);
DUMMY(mknodat);
DUMMY(fchownat);
==== //depot/projects/linuxolator/src/sys/kern/vfs_lookup.c#4 (text+ko) ====
More information about the p4-projects
mailing list