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