PERFORCE change 118086 for review

Roman Divacky rdivacky at FreeBSD.org
Sat Apr 14 11:18:14 UTC 2007


http://perforce.freebsd.org/chv.cgi?CH=118086

Change 118086 by rdivacky at rdivacky_witten on 2007/04/14 11:17:28

	Implement linux_openat(), linux_fstatat64() and linux_faccessat():
	
		o	extend struct nameidata to incorporate vdir param
		o	add NDINIT_AT that fills in vdir, NDINIT always fills in NULL
		o	change namei to use vdir as its starting dir if its non-NULL
		o	create kern_openat and kern_accessat
		o	add AT_FDCWD define that specifies CWD as dfd
	
	The names will probably change and the place for AT_FDCWD might change as well.
	Note that I saw a panic when starting X with this patch but I cannot reproduce it
	so its hard to say whether its related but I don't think so.
	
	Suggested by: rwatson

Affected files ...

.. //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_dummy.c#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_proto.h#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_syscall.h#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_sysent.c#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/syscalls.master#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/compat/linux/linux_file.c#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/compat/linux/linux_stats.c#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_dummy.c#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_proto.h#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_syscall.h#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_sysent.c#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/syscalls.master#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_lookup.c#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_syscalls.c#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/sys/fcntl.h#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/sys/namei.h#2 edit
.. //depot/projects/soc2007/rdivacky/linux_at/sys/sys/syscallsubr.h#2 edit

Differences ...

==== //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_dummy.c#2 (text+ko) ====

@@ -101,14 +101,12 @@
 DUMMY(mknodat);
 DUMMY(fchownat);
 DUMMY(futimesat);
-DUMMY(fstatat64);
 DUMMY(unlinkat);
 DUMMY(renameat);
 DUMMY(linkat);
 DUMMY(symlinkat);
 DUMMY(readlinkat);
 DUMMY(fchmodat);
-DUMMY(faccessat);
 DUMMY(pselect6);
 DUMMY(ppoll);
 DUMMY(unshare);

==== //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_proto.h#2 (text+ko) ====

@@ -2,7 +2,7 @@
  * System call prototypes.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/amd64/linux32/linux32_proto.h,v 1.31 2007/03/30 00:08:21 jkim Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/amd64/linux32/syscalls.master,v 1.28 2007/03/30 00:06:21 jkim Exp 
  */
 
@@ -892,7 +892,10 @@
 	register_t dummy;
 };
 struct linux_fstatat64_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char pathname_l_[PADL_(char *)]; char * pathname; char pathname_r_[PADR_(char *)];
+	char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)];
+	char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_unlinkat_args {
 	register_t dummy;
@@ -913,7 +916,9 @@
 	register_t dummy;
 };
 struct linux_faccessat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(char *)]; char * filename; char filename_r_[PADR_(char *)];
+	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_pselect6_args {
 	register_t dummy;

==== //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_syscall.h#2 (text+ko) ====

@@ -2,7 +2,7 @@
  * System call numbers.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/amd64/linux32/linux32_syscall.h,v 1.31 2007/03/30 00:08:21 jkim Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/amd64/linux32/syscalls.master,v 1.28 2007/03/30 00:06:21 jkim Exp 
  */
 

==== //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_sysent.c#2 (text+ko) ====

@@ -2,7 +2,7 @@
  * System call switch table.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/amd64/linux32/linux32_sysent.c,v 1.31 2007/03/30 00:08:21 jkim Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/amd64/linux32/syscalls.master,v 1.28 2007/03/30 00:06:21 jkim Exp 
  */
 
@@ -320,14 +320,14 @@
 	{ 0, (sy_call_t *)linux_mknodat, AUE_NULL, NULL, 0, 0 },	/* 297 = linux_mknodat */
 	{ 0, (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 },	/* 298 = linux_fchownat */
 	{ 0, (sy_call_t *)linux_futimesat, AUE_NULL, NULL, 0, 0 },	/* 299 = linux_futimesat */
-	{ 0, (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 },	/* 300 = linux_fstatat64 */
+	{ AS(linux_fstatat64_args), (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 },	/* 300 = linux_fstatat64 */
 	{ 0, (sy_call_t *)linux_unlinkat, AUE_NULL, NULL, 0, 0 },	/* 301 = linux_unlinkat */
 	{ 0, (sy_call_t *)linux_renameat, AUE_NULL, NULL, 0, 0 },	/* 302 = linux_renameat */
 	{ 0, (sy_call_t *)linux_linkat, AUE_NULL, NULL, 0, 0 },	/* 303 = linux_linkat */
 	{ 0, (sy_call_t *)linux_symlinkat, AUE_NULL, NULL, 0, 0 },	/* 304 = linux_symlinkat */
 	{ 0, (sy_call_t *)linux_readlinkat, AUE_NULL, NULL, 0, 0 },	/* 305 = linux_readlinkat */
 	{ 0, (sy_call_t *)linux_fchmodat, AUE_NULL, NULL, 0, 0 },	/* 306 = linux_fchmodat */
-	{ 0, (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 },	/* 307 = linux_faccessat */
+	{ AS(linux_faccessat_args), (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 },	/* 307 = linux_faccessat */
 	{ 0, (sy_call_t *)linux_pselect6, AUE_NULL, NULL, 0, 0 },	/* 308 = linux_pselect6 */
 	{ 0, (sy_call_t *)linux_ppoll, AUE_NULL, NULL, 0, 0 },	/* 309 = linux_ppoll */
 	{ 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0 },	/* 310 = linux_unshare */

==== //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/syscalls.master#2 (text+ko) ====

@@ -469,14 +469,15 @@
 297	AUE_NULL	STD	{ int linux_mknodat(void); }
 298	AUE_NULL	STD	{ int linux_fchownat(void); }
 299	AUE_NULL	STD	{ int linux_futimesat(void); }
-300	AUE_NULL	STD	{ int linux_fstatat64(void); }
+300	AUE_NULL	STD	{ int linux_fstatat64(l_int dfd, char *pathname, \
+					struct l_stat64 *statbuf, l_int flag); }
 301	AUE_NULL	STD	{ int linux_unlinkat(void); }
 302	AUE_NULL	STD	{ int linux_renameat(void); }
 303	AUE_NULL	STD	{ int linux_linkat(void); }
 304	AUE_NULL	STD	{ int linux_symlinkat(void); }
 305	AUE_NULL	STD	{ int linux_readlinkat(void); }
 306	AUE_NULL	STD	{ int linux_fchmodat(void); }
-307	AUE_NULL	STD	{ int linux_faccessat(void); }
+307	AUE_NULL	STD	{ int linux_faccessat(l_int dfd, char *filename, l_int mode); }
 308	AUE_NULL	STD	{ int linux_pselect6(void); }
 309	AUE_NULL	STD	{ int linux_ppoll(void); }
 310	AUE_NULL	STD	{ int linux_unshare(void); }

==== //depot/projects/soc2007/rdivacky/linux_at/sys/compat/linux/linux_file.c#2 (text+ko) ====

@@ -88,7 +88,7 @@
 
 
 static int
-linux_common_open(struct thread *td, char *path, int l_flags, int mode, int openat)
+linux_common_open(struct thread *td, char *path, int l_flags, int mode, int dirfd)
 {
     struct proc *p = td->td_proc;
     struct file *fp;
@@ -130,7 +130,10 @@
 	bsd_flags |= O_NOFOLLOW;
     /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
 
-    error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode);
+    if (dirfd != -1)
+	error = kern_openat(td, path, UIO_SYSSPACE, bsd_flags, mode, dirfd);
+    else
+	error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode);
     if (!error) {
 	    fd = td->td_retval[0];
 	    /*
@@ -172,113 +175,36 @@
     if (ldebug(open))
 	    printf(LMSG("open returns error %d"), error);
 #endif
-    if (!openat)
-	LFREEPATH(path);
+    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, vfslocked;
-	struct vnode *dvp;
-	struct filedesc *fdp = td->td_proc->p_fd;
-	char *fullpath = "unknown";
-	char *freepath = NULL;
-
-	/* don't do anything if the pathname is absolute */
-	if (*filename == '/') {
-	   	*newpath= filename;
-	   	return (0);
-	}
-
-	/* check for AT_FDWCD */
-	if (dirfd == LINUX_AT_FDCWD) {
-	   	FILEDESC_SLOCK(fdp);
-		dvp = fdp->fd_cdir;
-		vref(dvp);
-	   	FILEDESC_SUNLOCK(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);
-		}
-		vref(dvp);
-		fdrop(fp, td);
-	}
-
-	/*
-	 * XXXRW: This is bogus, as vn_fullpath() returns only an advisory
-	 * file path, and may fail in several common situations, including
-	 * for file systmes that don't use the name cache, and if the entry
-	 * for the file falls out of the name cache.  We should implement
-	 * openat() in the FreeBSD native system call layer properly (using a
-	 * requested starting directory), and have Linux and other ABIs wrap
-	 * the native implementation.
-	 */
-	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);
-	}
-	vfslocked = VFS_LOCK_GIANT(dvp->v_mount);
-	vrele(dvp);
-	VFS_UNLOCK_GIANT(vfslocked);
-	return (error);
-}
-
 int
 linux_openat(struct thread *td, struct linux_openat_args *args)
 {
-   	char *newpath, *oldpath, *freebuf = NULL, *path;
-	int error;
+   	char *newpath, *path;
+	int error, dirfd;
+
+	path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+	error = copyinstr(args->filename, path, MAXPATHLEN, NULL);
 
-	oldpath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
-	error = copyinstr(args->filename, oldpath, MAXPATHLEN, NULL);
+    	if (args->flags & LINUX_O_CREAT)
+		LCONVPATH_SEG(td, path, &newpath, 1, UIO_SYSSPACE);
+    	else
+		LCONVPATH_SEG(td, path, &newpath, 0, UIO_SYSSPACE);
+	free(path, M_TEMP);
 
 #ifdef DEBUG
 	if (ldebug(openat))
 		printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
-		    oldpath, args->flags, args->mode);
+		    newpath, args->flags, args->mode);
 #endif
+	if (args->dfd == LINUX_AT_FDCWD)
+		dirfd = AT_FDCWD;
+	else
+		dirfd = args->dfd;
 
-	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);
+	return linux_common_open(td, path, args->flags, args->mode, dirfd);
 }
 
 int
@@ -297,7 +223,7 @@
 		    path, args->flags, args->mode);
 #endif
 
-    return linux_common_open(td, path, args->flags, args->mode, 0);
+    return linux_common_open(td, path, args->flags, args->mode, -1);
 }
 
 int
@@ -647,6 +573,34 @@
 }
 
 int
+linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
+{
+	char *path;
+	int error, dfd;
+
+	/* linux convention */
+	if (args->mode & ~(F_OK | X_OK | W_OK | R_OK))
+		return (EINVAL);
+
+	LCONVPATHEXIST(td, args->filename, &path);
+
+#ifdef DEBUG
+	if (ldebug(access))
+		printf(ARGS(access, "%s, %d"), path, args->mode);
+#endif
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = -1;
+	else
+		dfd = args->dfd;
+
+	error = kern_accessat(td, path, UIO_SYSSPACE, args->mode, dfd);
+	LFREEPATH(path);
+
+	return (error);
+}
+
+int
 linux_unlink(struct thread *td, struct linux_unlink_args *args)
 {
 	char *path;

==== //depot/projects/soc2007/rdivacky/linux_at/sys/compat/linux/linux_stats.c#2 (text+ko) ====

@@ -578,4 +578,56 @@
 	return (error);
 }
 
+/* XXX: racy? */
+int
+linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
+{
+	int error;
+	char *path, *newpath;
+	int fd, dfd;
+	struct stat buf;
+
+	/* open the file */
+	path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+	error = copyinstr(args->pathname, path, MAXPATHLEN, NULL);
+	if (error) {
+		free(path, M_TEMP);
+		return (EFAULT);
+	}
+
+	LCONVPATH_SEG(td, path, &newpath, 0, UIO_SYSSPACE);
+	free(path, M_TEMP);
+
+#ifdef DEBUG
+	if (ldebug(fstatat64))
+		printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, newpath, args->flag);
+#endif
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	error = kern_openat(td, newpath, UIO_SYSSPACE, O_RDONLY, 0, dfd);
+	if (error) {
+		LFREEPATH(newpath);
+		return (error);
+	}
+	/* file opened */
+	fd = td->td_retval[0];
+	td->td_retval[0] = 0;
+
+	/* do the actual fstat */
+
+	error = kern_fstat(td, fd, &buf);
+	translate_fd_major_minor(td, fd, &buf);
+	if (!error)
+		error = stat64_copyout(&buf, args->statbuf);
+	
+	/* close the opened file */
+	kern_close(td, fd);
+	LFREEPATH(newpath);
+	return (0);
+}
+
 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */

==== //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_dummy.c#2 (text+ko) ====

@@ -91,14 +91,12 @@
 DUMMY(mknodat);
 DUMMY(fchownat);
 DUMMY(futimesat);
-DUMMY(fstatat64);
 DUMMY(unlinkat);
 DUMMY(renameat);
 DUMMY(linkat);
 DUMMY(symlinkat);
 DUMMY(readlinkat);
 DUMMY(fchmodat);
-DUMMY(faccessat);
 DUMMY(pselect6);
 DUMMY(ppoll);
 DUMMY(unshare);

==== //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_proto.h#2 (text+ko) ====

@@ -2,8 +2,8 @@
  * System call prototypes.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/i386/linux/linux_proto.h,v 1.92 2007/03/29 02:11:46 julian Exp $
- * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.86 2007/02/15 00:54:40 jkim Exp 
+ * $FreeBSD$
+ * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.87 2007/03/29 02:11:46 julian Exp 
  */
 
 #ifndef _LINUX_SYSPROTO_H_
@@ -911,7 +911,10 @@
 	register_t dummy;
 };
 struct linux_fstatat64_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char pathname_l_[PADL_(char *)]; char * pathname; char pathname_r_[PADR_(char *)];
+	char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)];
+	char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_unlinkat_args {
 	register_t dummy;
@@ -932,7 +935,9 @@
 	register_t dummy;
 };
 struct linux_faccessat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char filename_l_[PADL_(char *)]; char * filename; char filename_r_[PADR_(char *)];
+	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_pselect6_args {
 	register_t dummy;

==== //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_syscall.h#2 (text+ko) ====

@@ -2,8 +2,8 @@
  * System call numbers.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/i386/linux/linux_syscall.h,v 1.85 2007/03/29 02:11:46 julian Exp $
- * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.86 2007/02/15 00:54:40 jkim Exp 
+ * $FreeBSD$
+ * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.87 2007/03/29 02:11:46 julian Exp 
  */
 
 #define	LINUX_SYS_exit	1

==== //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_sysent.c#2 (text+ko) ====

@@ -2,8 +2,8 @@
  * System call switch table.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/i386/linux/linux_sysent.c,v 1.92 2007/03/29 02:11:46 julian Exp $
- * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.86 2007/02/15 00:54:40 jkim Exp 
+ * $FreeBSD$
+ * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.87 2007/03/29 02:11:46 julian Exp 
  */
 
 #include <bsm/audit_kevents.h>
@@ -319,14 +319,14 @@
 	{ 0, (sy_call_t *)linux_mknodat, AUE_NULL, NULL, 0, 0 },	/* 297 = linux_mknodat */
 	{ 0, (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 },	/* 298 = linux_fchownat */
 	{ 0, (sy_call_t *)linux_futimesat, AUE_NULL, NULL, 0, 0 },	/* 299 = linux_futimesat */
-	{ 0, (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 },	/* 300 = linux_fstatat64 */
+	{ AS(linux_fstatat64_args), (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 },	/* 300 = linux_fstatat64 */
 	{ 0, (sy_call_t *)linux_unlinkat, AUE_NULL, NULL, 0, 0 },	/* 301 = linux_unlinkat */
 	{ 0, (sy_call_t *)linux_renameat, AUE_NULL, NULL, 0, 0 },	/* 302 = linux_renameat */
 	{ 0, (sy_call_t *)linux_linkat, AUE_NULL, NULL, 0, 0 },	/* 303 = linux_linkat */
 	{ 0, (sy_call_t *)linux_symlinkat, AUE_NULL, NULL, 0, 0 },	/* 304 = linux_symlinkat */
 	{ 0, (sy_call_t *)linux_readlinkat, AUE_NULL, NULL, 0, 0 },	/* 305 = linux_readlinkat */
 	{ 0, (sy_call_t *)linux_fchmodat, AUE_NULL, NULL, 0, 0 },	/* 306 = linux_fchmodat */
-	{ 0, (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 },	/* 307 = linux_faccessat */
+	{ AS(linux_faccessat_args), (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 },	/* 307 = linux_faccessat */
 	{ 0, (sy_call_t *)linux_pselect6, AUE_NULL, NULL, 0, 0 },	/* 308 = linux_pselect6 */
 	{ 0, (sy_call_t *)linux_ppoll, AUE_NULL, NULL, 0, 0 },	/* 309 = linux_ppoll */
 	{ 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0 },	/* 310 = linux_unshare */

==== //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/syscalls.master#2 (text+ko) ====

@@ -479,14 +479,15 @@
 297	AUE_NULL	STD	{ int linux_mknodat(void); }
 298	AUE_NULL	STD	{ int linux_fchownat(void); }
 299	AUE_NULL	STD	{ int linux_futimesat(void); }
-300	AUE_NULL	STD	{ int linux_fstatat64(void); }
+300	AUE_NULL	STD	{ int linux_fstatat64(l_int dfd, char *pathname, \
+					struct l_stat64 *statbuf, l_int flag); }
 301	AUE_NULL	STD	{ int linux_unlinkat(void); }
 302	AUE_NULL	STD	{ int linux_renameat(void); }
 303	AUE_NULL	STD	{ int linux_linkat(void); }
 304	AUE_NULL	STD	{ int linux_symlinkat(void); }
 305	AUE_NULL	STD	{ int linux_readlinkat(void); }
 306	AUE_NULL	STD	{ int linux_fchmodat(void); }
-307	AUE_NULL	STD	{ int linux_faccessat(void); }
+307	AUE_NULL	STD	{ int linux_faccessat(l_int dfd, char *filename, l_int mode); }
 308	AUE_NULL	STD	{ int linux_pselect6(void); }
 309	AUE_NULL	STD	{ int linux_ppoll(void); }
 310	AUE_NULL	STD	{ int linux_unshare(void); }

==== //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_lookup.c#2 (text+ko) ====

@@ -192,7 +192,10 @@
 	ndp->ni_rootdir = fdp->fd_rdir;
 	ndp->ni_topdir = fdp->fd_jdir;
 
-	dp = fdp->fd_cdir;
+	if (ndp->ni_vdir)
+		dp = ndp->ni_vdir;
+	else
+		dp = fdp->fd_cdir;
 	vfslocked = VFS_LOCK_GIANT(dp->v_mount);
 	VREF(dp);
 	FILEDESC_SUNLOCK(fdp);

==== //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_syscalls.c#2 (text+ko) ====

@@ -87,6 +87,10 @@
     const struct timespec *, int, int);
 static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
     struct thread *td);
+static int kern_common_open(struct thread *td, char *path, enum uio_seg pathseg, 
+	int flags, int mode, struct nameidata *nd);
+static int kern_common_access(struct thread *td, char *path, enum uio_seg pathseg, 
+	int flags, struct nameidata *nd);
 
 /*
  * The module initialization routine for POSIX asynchronous I/O will
@@ -958,6 +962,47 @@
 kern_open(struct thread *td, char *path, enum uio_seg pathseg, int flags,
     int mode)
 {
+	struct nameidata nd;
+
+	AUDIT_ARG(fflags, flags);
+	AUDIT_ARG(mode, mode);
+	NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td);
+
+	return kern_common_open(td, path, pathseg, flags, mode, &nd);
+}
+
+int
+kern_openat(struct thread *td, char *path, enum uio_seg pathseg, int flags,
+    int mode, int dirfd)
+{
+	int error;
+	struct nameidata nd;
+	struct vnode *dir_vn;
+
+	AUDIT_ARG(fflags, flags);
+	AUDIT_ARG(mode, mode);
+	/* XXX: audit dirfd */
+
+	if (dirfd == AT_FDCWD)
+		dir_vn = NULL;
+	else {
+		error = fgetvp(td, dirfd, &dir_vn);
+		if (error)
+			return (error);
+	}
+
+	NDINIT_AT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td, dir_vn);
+
+	error = kern_common_open(td, path, pathseg, flags, mode, &nd);
+	if (dirfd != AT_FDCWD)
+		vrele(dir_vn);
+	return (error);
+}
+
+static int
+kern_common_open(struct thread *td, char *path, enum uio_seg pathseg, int flags,
+    int mode, struct nameidata *nd)
+{
 	struct proc *p = td->td_proc;
 	struct filedesc *fdp = p->p_fd;
 	struct file *fp;
@@ -968,23 +1013,20 @@
 	struct file *nfp;
 	int type, indx, error;
 	struct flock lf;
-	struct nameidata nd;
 	int vfslocked;
 
-	AUDIT_ARG(fflags, flags);
-	AUDIT_ARG(mode, mode);
 	if ((flags & O_ACCMODE) == O_ACCMODE)
 		return (EINVAL);
 	flags = FFLAGS(flags);
+
 	error = falloc(td, &nfp, &indx);
 	if (error)
 		return (error);
 	/* An extra reference on `nfp' has been held for us by falloc(). */
 	fp = nfp;
 	cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
-	NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td);
 	td->td_dupfd = -1;		/* XXX check for fdopen */
-	error = vn_open(&nd, &flags, cmode, indx);
+	error = vn_open(nd, &flags, cmode, indx);
 	if (error) {
 		/*
 		 * If the vn_open replaced the method vector, something
@@ -1022,9 +1064,9 @@
 		return (error);
 	}
 	td->td_dupfd = 0;
-	vfslocked = NDHASGIANT(&nd);
-	NDFREE(&nd, NDF_ONLY_PNBUF);
-	vp = nd.ni_vp;
+	vfslocked = NDHASGIANT(nd);
+	NDFREE(nd, NDF_ONLY_PNBUF);
+	vp = nd->ni_vp;
 
 	FILE_LOCK(fp);
 	fp->f_vnode = vp;
@@ -1855,9 +1897,44 @@
 int
 kern_access(struct thread *td, char *path, enum uio_seg pathseg, int flags)
 {
+	struct nameidata nd;
+
+	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
+	    pathseg, path, td);
+
+	return kern_common_access(td, path, pathseg, flags, &nd);
+}
+
+int
+kern_accessat(struct thread *td, char *path, enum uio_seg pathseg, int flags, int dirfd)
+{
+	int error;
+	struct nameidata nd;
+	struct vnode *dir_vn;
+
+	if (dirfd == AT_FDCWD)
+		dir_vn = NULL;
+	else {
+		error = fgetvp(td, dirfd, &dir_vn);
+		if (error)
+			return (error);
+	}
+
+	NDINIT_AT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
+	    pathseg, path, td, dir_vn);
+
+	error = kern_common_access(td, path, pathseg, flags, &nd);
+	if (dirfd != AT_FDCWD)
+		vrele(dir_vn);
+	return (error);
+}
+
+static int
+kern_common_access(struct thread *td, char *path, enum uio_seg pathseg, int flags,
+	struct nameidata *nd)
+{
 	struct ucred *cred, *tmpcred;
-	register struct vnode *vp;
-	struct nameidata nd;
+	struct vnode *vp;
 	int vfslocked;
 	int error;
 
@@ -1871,15 +1948,13 @@
 	tmpcred->cr_uid = cred->cr_ruid;
 	tmpcred->cr_groups[0] = cred->cr_rgid;
 	td->td_ucred = tmpcred;
-	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
-	if ((error = namei(&nd)) != 0)
+	if ((error = namei(nd)) != 0)
 		goto out1;
-	vfslocked = NDHASGIANT(&nd);
-	vp = nd.ni_vp;
+	vfslocked = NDHASGIANT(nd);
+	vp = nd->ni_vp;
 
 	error = vn_access(vp, flags, tmpcred, td);
-	NDFREE(&nd, NDF_ONLY_PNBUF);
+	NDFREE(nd, NDF_ONLY_PNBUF);
 	vput(vp);
 	VFS_UNLOCK_GIANT(vfslocked);
 out1:

==== //depot/projects/soc2007/rdivacky/linux_at/sys/sys/fcntl.h#2 (text+ko) ====

@@ -105,6 +105,9 @@
 #ifdef _KERNEL
 #define	FHASLOCK	0x4000		/* descriptor holds advisory lock */
 #endif
+#ifdef __BSD_VISIBLE
+#define	AT_FDCWD	-100		/* just like Linux */
+#endif
 
 /* Defined by POSIX 1003.1; BSD default, but must be distinct from O_RDONLY. */
 #define	O_NOCTTY	0x8000		/* don't assign controlling terminal */

==== //depot/projects/soc2007/rdivacky/linux_at/sys/sys/namei.h#2 (text+ko) ====

@@ -63,6 +63,7 @@
 	 */
 	const	char *ni_dirp;		/* pathname pointer */
 	enum	uio_seg ni_segflg;	/* location of pathname */
+	struct	vnode *ni_vdir;		/* relative directory */
 	/*
 	 * Arguments to lookup.
 	 */
@@ -148,8 +149,6 @@
 /*
  * Initialization of a nameidata structure.
  */
-static void NDINIT(struct nameidata *, u_long, u_long, enum uio_seg,
-	    const char *, struct thread *);
 static __inline void
 NDINIT(struct nameidata *ndp,
 	u_long op, u_long flags,
@@ -162,6 +161,23 @@
 	ndp->ni_segflg = segflg;
 	ndp->ni_dirp = namep;
 	ndp->ni_cnd.cn_thread = td;
+	ndp->ni_vdir = NULL;
+}
+
+static __inline void
+NDINIT_AT(struct nameidata *ndp,
+	u_long op, u_long flags,
+	enum uio_seg segflg,
+	const char *namep,
+	struct thread *td,
+	struct vnode *dvp)
+{
+	ndp->ni_cnd.cn_nameiop = op;
+	ndp->ni_cnd.cn_flags = flags;
+	ndp->ni_segflg = segflg;
+	ndp->ni_dirp = namep;
+	ndp->ni_cnd.cn_thread = td;
+	ndp->ni_vdir = dvp;
 }
 
 #define NDF_NO_DVP_RELE		0x00000001

==== //depot/projects/soc2007/rdivacky/linux_at/sys/sys/syscallsubr.h#2 (text+ko) ====

@@ -55,6 +55,8 @@
 	    socklen_t *namelen, struct file **fp);
 int	kern_access(struct thread *td, char *path, enum uio_seg pathseg,
 	    int flags);
+int	kern_accessat(struct thread *td, char *path, enum uio_seg pathseg,
+	    int flags, int dirfd);
 int	kern_adjtime(struct thread *td, struct timeval *delta,
 	    struct timeval *olddelta);
 int	kern_alternate_path(struct thread *td, const char *prefix, char *path,
@@ -120,6 +122,8 @@
 	    struct timespec *rmt);
 int	kern_open(struct thread *td, char *path, enum uio_seg pathseg,
 	    int flags, int mode);
+int	kern_openat(struct thread *td, char *path, enum uio_seg pathseg,
+	    int flags, int mode, int dirfd);
 int	kern_pathconf(struct thread *td, char *path, enum uio_seg pathseg,
 	    int name);
 int	kern_preadv(struct thread *td, int fd, struct uio *auio, off_t offset);


More information about the p4-projects mailing list