---  amd64/linux32/linux.h.orig
+++  amd64/linux32/linux.h
@@ -566,8 +566,6 @@
 #define	LINUX_F_WRLCK		1
 #define	LINUX_F_UNLCK		2
 
-#define	LINUX_AT_FDCWD		-100
-
 /*
  * mount flags
  */
---  amd64/linux32/linux32_dummy.c.orig
+++  amd64/linux32/linux32_dummy.c
@@ -96,18 +96,6 @@
 DUMMY(inotify_add_watch);
 DUMMY(inotify_rm_watch);
 DUMMY(migrate_pages);
-DUMMY(mkdirat);
-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);
---  amd64/linux32/linux32_proto.h.orig
+++  amd64/linux32/linux32_proto.h
@@ -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 
  */
 
@@ -880,40 +880,72 @@
 	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_mkdirat_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 mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_mknodat_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)];
+	char dev_l_[PADL_(l_uint)]; l_uint dev; char dev_r_[PADR_(l_uint)];
 };
 struct linux_fchownat_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 uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)];
+	char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)];
+	char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_futimesat_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 utimes_l_[PADL_(struct l_timeval *)]; struct l_timeval * utimes; char utimes_r_[PADR_(struct l_timeval *)];
 };
 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;
+	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 flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_renameat_args {
-	register_t dummy;
+	char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)];
+	char oldname_l_[PADL_(char *)]; char * oldname; char oldname_r_[PADR_(char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(char *)]; char * newname; char newname_r_[PADR_(char *)];
 };
 struct linux_linkat_args {
-	register_t dummy;
+	char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)];
+	char oldname_l_[PADL_(char *)]; char * oldname; char oldname_r_[PADR_(char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(char *)]; char * newname; char newname_r_[PADR_(char *)];
+	char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
 };
 struct linux_symlinkat_args {
-	register_t dummy;
+	char oldname_l_[PADL_(char *)]; char * oldname; char oldname_r_[PADR_(char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(char *)]; char * newname; char newname_r_[PADR_(char *)];
 };
 struct linux_readlinkat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)];
+	char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)];
+	char bufsiz_l_[PADL_(l_int)]; l_int bufsiz; char bufsiz_r_[PADR_(l_int)];
 };
 struct linux_fchmodat_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_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)];
 };
 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;
---  amd64/linux32/linux32_syscall.h.orig
+++  amd64/linux32/linux32_syscall.h
@@ -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 
  */
 
---  amd64/linux32/linux32_sysent.c.orig
+++  amd64/linux32/linux32_sysent.c
@@ -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 
  */
 
@@ -316,18 +316,18 @@
 	{ 0, (sy_call_t *)linux_inotify_rm_watch, AUE_NULL, NULL, 0, 0 },	/* 293 = linux_inotify_rm_watch */
 	{ 0, (sy_call_t *)linux_migrate_pages, AUE_NULL, NULL, 0, 0 },	/* 294 = linux_migrate_pages */
 	{ AS(linux_openat_args), (sy_call_t *)linux_openat, AUE_OPEN_RWTC, NULL, 0, 0 },	/* 295 = linux_openat */
-	{ 0, (sy_call_t *)linux_mkdirat, AUE_NULL, NULL, 0, 0 },	/* 296 = linux_mkdirat */
-	{ 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 */
-	{ 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_mkdirat_args), (sy_call_t *)linux_mkdirat, AUE_NULL, NULL, 0, 0 },	/* 296 = linux_mkdirat */
+	{ AS(linux_mknodat_args), (sy_call_t *)linux_mknodat, AUE_NULL, NULL, 0, 0 },	/* 297 = linux_mknodat */
+	{ AS(linux_fchownat_args), (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 },	/* 298 = linux_fchownat */
+	{ AS(linux_futimesat_args), (sy_call_t *)linux_futimesat, AUE_NULL, NULL, 0, 0 },	/* 299 = linux_futimesat */
+	{ AS(linux_fstatat64_args), (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 },	/* 300 = linux_fstatat64 */
+	{ AS(linux_unlinkat_args), (sy_call_t *)linux_unlinkat, AUE_NULL, NULL, 0, 0 },	/* 301 = linux_unlinkat */
+	{ AS(linux_renameat_args), (sy_call_t *)linux_renameat, AUE_NULL, NULL, 0, 0 },	/* 302 = linux_renameat */
+	{ AS(linux_linkat_args), (sy_call_t *)linux_linkat, AUE_NULL, NULL, 0, 0 },	/* 303 = linux_linkat */
+	{ AS(linux_symlinkat_args), (sy_call_t *)linux_symlinkat, AUE_NULL, NULL, 0, 0 },	/* 304 = linux_symlinkat */
+	{ AS(linux_readlinkat_args), (sy_call_t *)linux_readlinkat, AUE_NULL, NULL, 0, 0 },	/* 305 = linux_readlinkat */
+	{ AS(linux_fchmodat_args), (sy_call_t *)linux_fchmodat, AUE_NULL, NULL, 0, 0 },	/* 306 = linux_fchmodat */
+	{ 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 */
---  amd64/linux32/linux32_sysvec.c.orig
+++  amd64/linux32/linux32_sysvec.c
@@ -43,6 +43,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/exec.h>
+#include <sys/fcntl.h>
 #include <sys/imgact.h>
 #include <sys/imgact_elf.h>
 #include <sys/kernel.h>
@@ -787,7 +788,7 @@
 	     */
 	    if ((error = exec_shell_imgact(imgp)) == 0) {
 		    linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
-			imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0);
+			imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, AT_FDCWD);
 		    if (rpath != NULL) {
 			    len = strlen(rpath) + 1;
 
---  amd64/linux32/syscalls.master.orig
+++  amd64/linux32/syscalls.master
@@ -465,18 +465,24 @@
 294	AUE_NULL	STD	{ int linux_migrate_pages(void); }
 295	AUE_OPEN_RWTC	STD	{ int linux_openat(l_int dfd, char *filename, \
 					l_int flags, l_int mode); }
-296	AUE_NULL	STD	{ int linux_mkdirat(void); }
-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); }
-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); }
+296	AUE_NULL	STD	{ int linux_mkdirat(l_int dfd, char *pathname, l_int mode); }
+297	AUE_NULL	STD	{ int linux_mknodat(l_int dfd, char *filename, l_int mode, l_uint dev); }
+298	AUE_NULL	STD	{ int linux_fchownat(l_int dfd, char *filename, \
+					l_uid16_t uid, l_gid16_t gid, l_int flag); }
+299	AUE_NULL	STD	{ int linux_futimesat(l_int dfd, char *filename, struct l_timeval *utimes); }
+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(l_int dfd, char *pathname, l_int flag); }
+302	AUE_NULL	STD	{ int linux_renameat(l_int olddfd, char *oldname, l_int newdfd, \
+					char *newname); }
+303	AUE_NULL	STD	{ int linux_linkat(l_int olddfd, char *oldname, \
+					l_int newdfd, char *newname, l_int flags); }
+304	AUE_NULL	STD	{ int linux_symlinkat(char *oldname, l_int newdfd, char *newname); }
+305	AUE_NULL	STD	{ int linux_readlinkat(l_int dfd, char *path, \
+					char *buf, l_int bufsiz); }
+306	AUE_NULL	STD	{ int linux_fchmodat(l_int dfd, char *filename, \
+					l_mode_t mode); }
+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); }
---  compat/linux/linux_file.c.orig
+++  compat/linux/linux_file.c
@@ -67,6 +67,7 @@
 #include <machine/../linux/linux_proto.h>
 #endif
 #include <compat/linux/linux_util.h>
+#include <compat/linux/linux_file.h>
 
 int
 linux_creat(struct thread *td, struct linux_creat_args *args)
@@ -88,7 +89,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 +131,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,115 +176,33 @@
     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);
-	} else {
-		*newpath = NULL;
-	}
-	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 *path;
+	int dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
 
-	oldpath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
-	error = copyinstr(args->filename, oldpath, MAXPATHLEN, NULL);
+    	if (args->flags & LINUX_O_CREAT)
+		LCONVPATH_AT(td, args->filename, &path, 1, dfd);
+    	else
+		LCONVPATH_AT(td, args->filename, &path, 0, dfd);
 
 #ifdef DEBUG
 	if (ldebug(openat))
+#endif
 		printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
-		    oldpath, args->flags, args->mode);
-#endif
+		    path, args->flags, args->mode);
 
-	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, dfd);
 }
 
 int
@@ -299,7 +221,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
@@ -649,6 +571,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);
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = -1;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(access))
+		printf(ARGS(access, "%s, %d"), path, args->mode);
+#endif
+
+	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;
@@ -673,6 +623,40 @@
 }
 
 int
+linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
+{
+	char *path;
+	int error, dfd;
+	struct stat st;
+
+	if (args->flag & ~LINUX_AT_REMOVEDIR)
+		return (EINVAL);
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(unlinkat))
+		printf(ARGS(unlinkat, "%s"), path);
+#endif
+
+	if (args->flag & LINUX_AT_REMOVEDIR)
+		error = kern_rmdirat(td, path, UIO_SYSSPACE, dfd);
+	else
+		error = kern_unlinkat(td, path, UIO_SYSSPACE, dfd);
+	if (error == EPERM)
+		/* Introduce POSIX noncompliant behaviour of Linux */
+		if (kern_statat(td, path, UIO_SYSSPACE, &st, dfd) == 0)
+			if (S_ISDIR(st.st_mode))
+				error = EISDIR;
+	LFREEPATH(path);
+	return (error);
+}
+int
 linux_chdir(struct thread *td, struct linux_chdir_args *args)
 {
 	char *path;
@@ -707,6 +691,29 @@
 }
 
 int
+linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
+{
+	char *path;
+	int error, dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(fchmodat))
+		printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
+#endif
+
+	error = kern_chmodat(td, path, UIO_SYSSPACE, args->mode, dfd);
+	LFREEPATH(path);
+	return (error);
+}
+
+int
 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
 {
 	char *path;
@@ -724,6 +731,28 @@
 }
 
 int
+linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
+{
+	char *path;
+	int error, dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(mkdirat))
+		printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
+#endif
+	error = kern_mkdirat(td, path, UIO_SYSSPACE, args->mode, dfd);
+	LFREEPATH(path);
+	return (error);
+}
+
+int
 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
 {
 	char *path;
@@ -748,7 +777,7 @@
 
 	LCONVPATHEXIST(td, args->from, &from);
 	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
-	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
+	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
 	if (to == NULL) {
 		LFREEPATH(from);
 		return (error);
@@ -765,6 +794,40 @@
 }
 
 int
+linux_renameat(struct thread *td, struct linux_renameat_args *args)
+{
+	char *from, *to;
+	int error, olddfd, newdfd;
+
+	if (args->olddfd == LINUX_AT_FDCWD)
+		olddfd = AT_FDCWD;
+	else
+		olddfd = args->olddfd;
+
+	if (args->newdfd == LINUX_AT_FDCWD)
+		newdfd = AT_FDCWD;
+	else
+		newdfd = args->newdfd;
+
+	LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
+	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
+	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
+	if (to == NULL) {
+		LFREEPATH(from);
+		return (error);
+	}
+
+#ifdef DEBUG
+	if (ldebug(renameat))
+		printf(ARGS(renameat, "%s, %s"), from, to);
+#endif
+	error = kern_renameat(td, from, to, UIO_SYSSPACE, olddfd, newdfd);
+	LFREEPATH(from);
+	LFREEPATH(to);
+	return (error);
+}
+
+int
 linux_symlink(struct thread *td, struct linux_symlink_args *args)
 {
 	char *path, *to;
@@ -772,7 +835,7 @@
 
 	LCONVPATHEXIST(td, args->path, &path);
 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
-	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
+	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
 	if (to == NULL) {
 		LFREEPATH(path);
 		return (error);
@@ -789,6 +852,36 @@
 }
 
 int
+linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
+{
+	char *path, *to;
+	int error, dfd;
+
+	if (args->newdfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->newdfd;
+
+	LCONVPATHEXIST_AT(td, args->oldname, &path, dfd);
+	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
+	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
+	if (to == NULL) {
+		LFREEPATH(path);
+		return (error);
+	}
+
+#ifdef DEBUG
+	if (ldebug(symlinkat))
+		printf(ARGS(symlinkat, "%s, %s"), path, to);
+#endif
+
+	error = kern_symlinkat(td, path, to, UIO_SYSSPACE, dfd);
+	LFREEPATH(path);
+	LFREEPATH(to);
+	return (error);
+}
+
+int
 linux_readlink(struct thread *td, struct linux_readlink_args *args)
 {
 	char *name;
@@ -808,6 +901,30 @@
 }
 
 int
+linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
+{
+	char *name;
+	int error, dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
+
+#ifdef DEBUG
+	if (ldebug(readlinkat))
+		printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
+		    args->bufsiz);
+#endif
+
+	error = kern_readlinkat(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
+	    args->bufsiz, dfd);
+	LFREEPATH(name);
+	return (error);
+}
+int
 linux_truncate(struct thread *td, struct linux_truncate_args *args)
 {
 	char *path;
@@ -848,7 +965,7 @@
 
 	LCONVPATHEXIST(td, args->path, &path);
 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
-	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
+	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
 	if (to == NULL) {
 		LFREEPATH(path);
 		return (error);
@@ -865,6 +982,49 @@
 }
 
 int
+linux_linkat(struct thread *td, struct linux_linkat_args *args)
+{
+	char *path, *to;
+	int error, olddfd, newdfd;
+
+	/* 
+	 * don't laugh they really introduced flags argument
+	 * which is forbidden to use ;)
+	 */
+	if (args->flags != 0)
+		return (EINVAL);
+
+	if (args->olddfd == LINUX_AT_FDCWD)
+		olddfd = AT_FDCWD;
+	else
+		olddfd = args->olddfd;
+
+	if (args->newdfd == LINUX_AT_FDCWD)
+		newdfd = AT_FDCWD;
+	else
+		newdfd = args->newdfd;
+
+	LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
+	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
+	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
+	if (to == NULL) {
+		LFREEPATH(path);
+		return (error);
+	}
+
+#ifdef DEBUG
+	if (ldebug(linkat))
+		printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
+			args->newdfd, to, args->flags);
+#endif
+
+	error = kern_linkat(td, path, to, UIO_SYSSPACE, olddfd, newdfd);
+	LFREEPATH(path);
+	LFREEPATH(to);
+	return (error);
+}
+
+int
 linux_fdatasync(td, uap)
 	struct thread *td;
 	struct linux_fdatasync_args *uap;
@@ -1330,6 +1490,35 @@
 }
 
 int
+linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
+{
+	char *path;
+	int error, dfd;
+
+	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
+		return (EINVAL);	
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(fchownat))
+		printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
+#endif
+
+	if (args->flag & LINUX_AT_SYMLINK_NOFOLLOW)
+		error = kern_lchownat(td, path, UIO_SYSSPACE, args->uid, args->gid, dfd);
+	else
+		error = kern_chownat(td, path, UIO_SYSSPACE, args->uid, args->gid, dfd);
+	LFREEPATH(path);
+	return (error);
+}
+
+int
 linux_lchown(struct thread *td, struct linux_lchown_args *args)
 {
 	char *path;
--- /dev/null	Wed Jun 13 23:11:00 2007
+++ //depot/projects/soc2007/rdivacky/linux_at/sys/compat/linux/linux_file.h	Wed Jun 13 23:19:47 2007
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2007 Roman Divacky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_FILE_H_
+#define	_LINUX_FILE_H_
+
+#define	LINUX_AT_FDCWD			-100
+#define	LINUX_AT_SYMLINK_NOFOLLOW	0x100
+#define	LINUX_AT_REMOVEDIR		0x200
+
+#endif	/* !_LINUX_FILE_H_ */
--- compat/linux/linux_misc.c.orig
+++ compat/linux/linux_misc.c
@@ -86,6 +86,7 @@
 #include <machine/../linux/linux_proto.h>
 #endif
 
+#include <compat/linux/linux_file.h>
 #include <compat/linux/linux_mib.h>
 #include <compat/linux/linux_signal.h>
 #include <compat/linux/linux_util.h>
@@ -820,6 +821,43 @@
 	LFREEPATH(fname);
 	return (error);
 }
+
+int
+linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
+{
+	l_timeval ltv[2];
+	struct timeval tv[2], *tvp = NULL;
+	char *fname;
+	int error, dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->filename, &fname, dfd);
+
+#ifdef DEBUG
+	if (ldebug(futimesat))
+		printf(ARGS(futimesat, "%s, *"), fname);
+#endif
+
+	if (args->utimes!= NULL) {
+		if ((error = copyin(args->utimes, ltv, sizeof ltv))) {
+			LFREEPATH(fname);
+			return (error);
+		}
+		tv[0].tv_sec = ltv[0].tv_sec;
+		tv[0].tv_usec = ltv[0].tv_usec;
+		tv[1].tv_sec = ltv[1].tv_sec;
+		tv[1].tv_usec = ltv[1].tv_usec;
+		tvp = tv;
+	}
+
+	error = kern_utimesat(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE, dfd);
+	LFREEPATH(fname);
+	return (error);
+}
 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 
 #define __WCLONE 0x80000000
@@ -957,6 +995,56 @@
 	return (error);
 }
 
+int
+linux_mknodat(struct thread *td, struct linux_mknodat_args *args)
+{
+	char *path;
+	int error, dfd;
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHCREAT_AT(td, args->filename, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(mknodat))
+		printf(ARGS(mknodat, "%s, %d, %d"), path, args->mode, args->dev);
+#endif
+
+	switch (args->mode & S_IFMT) {
+	case S_IFIFO:
+	case S_IFSOCK:
+		error = kern_mkfifoat(td, path, UIO_SYSSPACE, args->mode, dfd);
+		break;
+
+	case S_IFCHR:
+	case S_IFBLK:
+		error = kern_mknodat(td, path, UIO_SYSSPACE, args->mode,
+		    args->dev, dfd);
+		break;
+
+	case S_IFDIR:
+		error = EPERM;
+		break;
+
+	case 0:
+		args->mode |= S_IFREG;
+		/* FALLTHROUGH */
+	case S_IFREG:
+		error = kern_openat(td, path, UIO_SYSSPACE,
+		    O_WRONLY | O_CREAT | O_TRUNC, args->mode, dfd);
+		break;
+
+	default:
+		error = EINVAL;
+		break;
+	}
+	LFREEPATH(path);
+	return (error);
+}
+
 /*
  * UGH! This is just about the dumbest idea I've ever heard!!
  */
--- compat/linux/linux_stats.c.orig
+++ compat/linux/linux_stats.c
@@ -57,6 +57,7 @@
 #endif
 
 #include <compat/linux/linux_util.h>
+#include <compat/linux/linux_file.h>
 
 #include <security/mac/mac_framework.h>
 
@@ -132,6 +133,25 @@
 	fdclose(fdp, fdp->fd_ofiles[fd], fd, td);
 }
 
+static void
+translate_path_major_minor_at(struct thread *td, char *path, struct stat *buf, int dfd)
+{
+	struct proc *p = td->td_proc;	
+	struct filedesc *fdp = p->p_fd;
+	int fd;
+	int temp;
+
+	if (!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode))
+		return;
+	temp = td->td_retval[0];
+	if (kern_openat(td, path, UIO_SYSSPACE, O_RDONLY, 0, dfd) != 0)
+		return;
+	fd = td->td_retval[0];
+	td->td_retval[0] = temp;
+	translate_fd_major_minor(td, fd, buf);
+	fdclose(fdp, fdp->fd_ofiles[fd], fd, td);
+}
+
 static int
 newstat_copyout(struct stat *buf, void *ubuf)
 {
@@ -578,4 +598,39 @@
 	return (error);
 }
 
+int
+linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
+{
+	char *path;
+	int error, dfd;
+	struct stat buf;
+
+	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
+		return (EINVAL);
+
+	if (args->dfd == LINUX_AT_FDCWD)
+		dfd = AT_FDCWD;
+	else
+		dfd = args->dfd;
+
+	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
+
+#ifdef DEBUG
+	if (ldebug(fstatat64))
+		printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, path, args->flag);
+#endif
+
+	if (args->flag & LINUX_AT_SYMLINK_NOFOLLOW)
+		error = kern_lstatat(td, path, UIO_SYSSPACE, &buf, dfd);
+	else
+		error = kern_statat(td, path, UIO_SYSSPACE, &buf, dfd);
+		
+	translate_path_major_minor_at(td, args->pathname, &buf, dfd);
+	if (!error)
+		error = stat64_copyout(&buf, args->statbuf);
+	LFREEPATH(path);
+	
+	return (error);
+}
+
 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
--- compat/linux/linux_uid16.c.orig
+++ compat/linux/linux_uid16.c
@@ -29,6 +29,7 @@
 
 #include "opt_compat.h"
 
+#include <sys/fcntl.h>
 #include <sys/param.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
--- compat/linux/linux_util.c.orig
+++ compat/linux/linux_util.c
@@ -36,6 +36,7 @@
 
 #include <sys/param.h>
 #include <sys/bus.h>
+#include <sys/fcntl.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/linker_set.h>
@@ -65,16 +66,17 @@
  * named file, i.e. we check if the directory it should be in exists.
  */
 int
-linux_emul_convpath(td, path, pathseg, pbuf, cflag)
+linux_emul_convpath(td, path, pathseg, pbuf, cflag, dfd)
 	struct thread	 *td;
 	char		 *path;
 	enum uio_seg	  pathseg;
 	char		**pbuf;
 	int		  cflag;
+	int		  dfd;		
 {
 
-	return (kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf,
-		cflag));
+	return kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf,
+		cflag, dfd);
 }
 
 void
--- compat/linux/linux_util.h.orig
+++ compat/linux/linux_util.h
@@ -51,23 +51,25 @@
 
 extern const char linux_emul_path[];
 
-int linux_emul_convpath(struct thread *, char *, enum uio_seg, char **, int);
+int linux_emul_convpath(struct thread *, char *, enum uio_seg, char **, int, int);
 
-#define LCONVPATH_SEG(td, upath, pathp, i, seg)				\
+#define LCONVPATH_AT(td, upath, pathp, i, dfd)				\
 	do {								\
 		int _error;						\
 									\
-		_error = linux_emul_convpath(td, upath, seg,		\
-		    pathp, i);						\
+		_error = linux_emul_convpath(td, upath, UIO_USERSPACE,	\
+		    pathp, i, dfd);					\
 		if (*(pathp) == NULL)					\
 			return (_error);				\
 	} while (0)
 
 #define LCONVPATH(td, upath, pathp, i) 	\
-   LCONVPATH_SEG(td, upath, pathp, i, UIO_USERSPACE)
+   LCONVPATH_AT(td, upath, pathp, i, AT_FDCWD)
 
 #define LCONVPATHEXIST(td, upath, pathp) LCONVPATH(td, upath, pathp, 0)
+#define LCONVPATHEXIST_AT(td, upath, pathp, dfd) LCONVPATH_AT(td, upath, pathp, 0, dfd)
 #define LCONVPATHCREAT(td, upath, pathp) LCONVPATH(td, upath, pathp, 1)
+#define LCONVPATHCREAT_AT(td, upath, pathp, dfd) LCONVPATH_AT(td, upath, pathp, 1, dfd)
 #define LFREEPATH(path)	free(path, M_TEMP)
 
 #define DUMMY(s)							\
--- compat/svr4/svr4_sysvec.c.orig
+++ compat/svr4/svr4_sysvec.c
@@ -44,6 +44,7 @@
 #include <sys/sysent.h>
 #include <sys/imgact.h>
 #include <sys/imgact_elf.h>
+#include <sys/fcntl.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
@@ -258,7 +259,7 @@
 {
 
 	return (kern_alternate_path(td, svr4_emul_path, path, pathseg, pbuf,
-	    create));
+	    create, AT_FDCWD));
 }
 
 static int
--- dev/usb/usb_port.h.orig
+++ dev/usb/usb_port.h
@@ -1,6 +1,6 @@
 /*	$OpenBSD: usb_port.h,v 1.18 2000/09/06 22:42:10 rahnds Exp $ */
 /*	$NetBSD: usb_port.h,v 1.68 2005/07/30 06:14:50 skrll Exp $	*/
-/*	$FreeBSD: src/sys/dev/usb/usb_port.h,v 1.90 2007/06/13 20:58:57 imp Exp $       */
+/*	$FreeBSD: src/sys/dev/usb/usb_port.h,v 1.89 2007/06/12 18:52:29 imp Exp $       */
 
 /* Also already merged from NetBSD:
  *	$NetBSD: usb_port.h,v 1.57 2002/09/27 20:42:01 thorpej Exp $
@@ -85,6 +85,14 @@
 #define PWR_RESUME 0
 #define PWR_SUSPEND 1
 
+#define config_detach(dev, flag) \
+	do { \
+		struct usb_attach_arg *uaap = device_get_ivars(dev); \
+		device_detach(dev); \
+		free(uaap, M_USB); \
+		device_delete_child(device_get_parent(dev), dev); \
+	} while (0)
+
 typedef struct malloc_type *usb_malloc_type;
 
 #define USB_DECLARE_DRIVER_INIT(dname, init...) \
--- dev/usb/usb_subr.c.orig
+++ dev/usb/usb_subr.c
@@ -11,7 +11,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.92 2007/06/13 20:58:57 imp Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.91 2007/06/10 01:28:55 mjacob Exp $");
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -1363,12 +1363,7 @@
 			if (up->portno != 0)
 				printf(" port %d", up->portno);
 			printf(" (addr %d) disconnected\n", dev->address);
-			struct usb_attach_arg *uaap =
-			    device_get_ivars(dev->subdevs[i]);
-			device_detach(dev);
-			free(uaap, M_USB);
-			device_delete_child(device_get_parent(dev->subdevs[i]),
-			    dev->subdevs[i]);
+			config_detach(dev->subdevs[i], DETACH_FORCE);
 			dev->subdevs[i] = NULL;
 		}
 	}
--- i386/ibcs2/ibcs2_util.c.orig
+++ i386/ibcs2/ibcs2_util.c
@@ -32,6 +32,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sys/i386/ibcs2/ibcs2_util.c,v 1.19 2005/02/07 22:02:18 jhb Exp $");
 
+#include <sys/fcntl.h>
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/syscallsubr.h>
@@ -55,5 +56,5 @@
 {
 
 	return (kern_alternate_path(td, ibcs2_emul_path, path, pathseg, pbuf,
-	    cflag));
+	    cflag, AT_FDCWD));
 }
--- i386/linux/linux.h.orig
+++ i386/linux/linux.h
@@ -537,8 +537,6 @@
 #define	LINUX_F_WRLCK		1
 #define	LINUX_F_UNLCK		2
 
-#define	LINUX_AT_FDCWD		-100
-
 /*
  * mount flags
  */
--- i386/linux/linux_dummy.c.orig
+++ i386/linux/linux_dummy.c
@@ -87,18 +87,6 @@
 DUMMY(inotify_add_watch);
 DUMMY(inotify_rm_watch);
 DUMMY(migrate_pages);
-DUMMY(mkdirat);
-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);
--- i386/linux/linux_proto.h.orig
+++ i386/linux/linux_proto.h
@@ -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_
@@ -899,40 +899,72 @@
 	char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_mkdirat_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 mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
 };
 struct linux_mknodat_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)];
+	char dev_l_[PADL_(l_uint)]; l_uint dev; char dev_r_[PADR_(l_uint)];
 };
 struct linux_fchownat_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 uid_l_[PADL_(l_uid16_t)]; l_uid16_t uid; char uid_r_[PADR_(l_uid16_t)];
+	char gid_l_[PADL_(l_gid16_t)]; l_gid16_t gid; char gid_r_[PADR_(l_gid16_t)];
+	char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_futimesat_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 utimes_l_[PADL_(struct l_timeval *)]; struct l_timeval * utimes; char utimes_r_[PADR_(struct l_timeval *)];
 };
 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;
+	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 flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)];
 };
 struct linux_renameat_args {
-	register_t dummy;
+	char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)];
+	char oldname_l_[PADL_(char *)]; char * oldname; char oldname_r_[PADR_(char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(char *)]; char * newname; char newname_r_[PADR_(char *)];
 };
 struct linux_linkat_args {
-	register_t dummy;
+	char olddfd_l_[PADL_(l_int)]; l_int olddfd; char olddfd_r_[PADR_(l_int)];
+	char oldname_l_[PADL_(char *)]; char * oldname; char oldname_r_[PADR_(char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(char *)]; char * newname; char newname_r_[PADR_(char *)];
+	char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
 };
 struct linux_symlinkat_args {
-	register_t dummy;
+	char oldname_l_[PADL_(char *)]; char * oldname; char oldname_r_[PADR_(char *)];
+	char newdfd_l_[PADL_(l_int)]; l_int newdfd; char newdfd_r_[PADR_(l_int)];
+	char newname_l_[PADL_(char *)]; char * newname; char newname_r_[PADR_(char *)];
 };
 struct linux_readlinkat_args {
-	register_t dummy;
+	char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
+	char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)];
+	char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)];
+	char bufsiz_l_[PADL_(l_int)]; l_int bufsiz; char bufsiz_r_[PADR_(l_int)];
 };
 struct linux_fchmodat_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_mode_t)]; l_mode_t mode; char mode_r_[PADR_(l_mode_t)];
 };
 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;
--- i386/linux/linux_syscall.h.orig
+++ i386/linux/linux_syscall.h
@@ -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
--- i386/linux/linux_sysent.c.orig
+++ i386/linux/linux_sysent.c
@@ -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>
@@ -315,18 +315,18 @@
 	{ 0, (sy_call_t *)linux_inotify_rm_watch, AUE_NULL, NULL, 0, 0 },	/* 293 = linux_inotify_rm_watch */
 	{ 0, (sy_call_t *)linux_migrate_pages, AUE_NULL, NULL, 0, 0 },	/* 294 = linux_migrate_pages */
 	{ AS(linux_openat_args), (sy_call_t *)linux_openat, AUE_OPEN_RWTC, NULL, 0, 0 },	/* 295 = linux_openat */
-	{ 0, (sy_call_t *)linux_mkdirat, AUE_NULL, NULL, 0, 0 },	/* 296 = linux_mkdirat */
-	{ 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 */
-	{ 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_mkdirat_args), (sy_call_t *)linux_mkdirat, AUE_NULL, NULL, 0, 0 },	/* 296 = linux_mkdirat */
+	{ AS(linux_mknodat_args), (sy_call_t *)linux_mknodat, AUE_NULL, NULL, 0, 0 },	/* 297 = linux_mknodat */
+	{ AS(linux_fchownat_args), (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 },	/* 298 = linux_fchownat */
+	{ AS(linux_futimesat_args), (sy_call_t *)linux_futimesat, AUE_NULL, NULL, 0, 0 },	/* 299 = linux_futimesat */
+	{ AS(linux_fstatat64_args), (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 },	/* 300 = linux_fstatat64 */
+	{ AS(linux_unlinkat_args), (sy_call_t *)linux_unlinkat, AUE_NULL, NULL, 0, 0 },	/* 301 = linux_unlinkat */
+	{ AS(linux_renameat_args), (sy_call_t *)linux_renameat, AUE_NULL, NULL, 0, 0 },	/* 302 = linux_renameat */
+	{ AS(linux_linkat_args), (sy_call_t *)linux_linkat, AUE_NULL, NULL, 0, 0 },	/* 303 = linux_linkat */
+	{ AS(linux_symlinkat_args), (sy_call_t *)linux_symlinkat, AUE_NULL, NULL, 0, 0 },	/* 304 = linux_symlinkat */
+	{ AS(linux_readlinkat_args), (sy_call_t *)linux_readlinkat, AUE_NULL, NULL, 0, 0 },	/* 305 = linux_readlinkat */
+	{ AS(linux_fchmodat_args), (sy_call_t *)linux_fchmodat, AUE_NULL, NULL, 0, 0 },	/* 306 = linux_fchmodat */
+	{ 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 */
--- i386/linux/linux_sysvec.c.orig
+++ i386/linux/linux_sysvec.c
@@ -32,6 +32,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/exec.h>
+#include <sys/fcntl.h>
 #include <sys/imgact.h>
 #include <sys/imgact_aout.h>
 #include <sys/imgact_elf.h>
@@ -775,7 +776,7 @@
 	     */
 	    if ((error = exec_shell_imgact(imgp)) == 0) {
 		    linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
-			imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0);
+			imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, AT_FDCWD);
 		    if (rpath != NULL) {
 			    len = strlen(rpath) + 1;
 
--- i386/linux/syscalls.master.orig
+++ i386/linux/syscalls.master
@@ -475,18 +475,24 @@
 294	AUE_NULL	STD	{ int linux_migrate_pages(void); }
 295	AUE_OPEN_RWTC	STD	{ int linux_openat(l_int dfd, char *filename, \
 					l_int flags, l_int mode); }
-296	AUE_NULL	STD	{ int linux_mkdirat(void); }
-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); }
-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); }
+296	AUE_NULL	STD	{ int linux_mkdirat(l_int dfd, char *pathname, l_int mode); }
+297	AUE_NULL	STD	{ int linux_mknodat(l_int dfd, char *filename, l_int mode, l_uint dev); }
+298	AUE_NULL	STD	{ int linux_fchownat(l_int dfd, char *filename, \
+					l_uid16_t uid, l_gid16_t gid, l_int flag); }
+299	AUE_NULL	STD	{ int linux_futimesat(l_int dfd, char *filename, struct l_timeval *utimes); }
+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(l_int dfd, char *pathname, l_int flag); }
+302	AUE_NULL	STD	{ int linux_renameat(l_int olddfd, char *oldname, l_int newdfd, \
+					char *newname); }
+303	AUE_NULL	STD	{ int linux_linkat(l_int olddfd, char *oldname, \
+					l_int newdfd, char *newname, l_int flags); }
+304	AUE_NULL	STD	{ int linux_symlinkat(char *oldname, l_int newdfd, char *newname); }
+305	AUE_NULL	STD	{ int linux_readlinkat(l_int dfd, char *path, \
+					char *buf, l_int bufsiz); }
+306	AUE_NULL	STD	{ int linux_fchmodat(l_int dfd, char *filename, \
+					l_mode_t mode); }
+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); }
--- kern/vfs_lookup.c.orig
+++ kern/vfs_lookup.c
@@ -44,6 +44,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/fcntl.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/namei.h>
@@ -192,7 +193,10 @@
 	ndp->ni_rootdir = fdp->fd_rdir;
 	ndp->ni_topdir = fdp->fd_jdir;
 
-	dp = fdp->fd_cdir;
+	if (ndp->ni_startdir)
+		dp = ndp->ni_startdir;
+	else
+		dp = fdp->fd_cdir;
 	vfslocked = VFS_LOCK_GIANT(dp->v_mount);
 	VREF(dp);
 	FILEDESC_SUNLOCK(fdp);
@@ -1001,12 +1005,13 @@
  */
 int
 kern_alternate_path(struct thread *td, const char *prefix, char *path,
-    enum uio_seg pathseg, char **pathbuf, int create)
+    enum uio_seg pathseg, char **pathbuf, int create, int dirfd)
 {
 	struct nameidata nd, ndroot;
 	char *ptr, *buf, *cp;
 	size_t len, sz;
 	int error;
+	struct vnode *dir_vn;
 
 	buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
 	*pathbuf = buf;
@@ -1039,6 +1044,18 @@
 		goto keeporig;
 	}
 
+	if (dirfd == AT_FDCWD)
+		dir_vn = NULL;
+	else {
+	   	/* 
+		 * we want the original because the "prefix"
+		 * is included in the already opened dirfd
+		 */
+		bcopy(ptr, buf, len);
+		return (0);
+	}
+
+
 	/*
 	 * We know that there is a / somewhere in this pathname.
 	 * Search backwards for it, to find the file's parent dir
@@ -1051,13 +1068,13 @@
 		for (cp = &ptr[len] - 1; *cp != '/'; cp--);
 		*cp = '\0';
 
-		NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td);
+		NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td, dir_vn);
 		error = namei(&nd);
 		*cp = '/';
 		if (error != 0)
 			goto keeporig;
 	} else {
-		NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td);
+		NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td, dir_vn);
 
 		error = namei(&nd);
 		if (error != 0)
--- kern/vfs_syscalls.c.orig
+++ kern/vfs_syscalls.c
@@ -85,6 +85,7 @@
 static int setfflags(struct thread *td, struct vnode *, int);
 static int setutimes(struct thread *td, struct vnode *,
     const struct timespec *, int, int);
+static int kern_get_at(struct thread *td, int dirfd, struct vnode **dir_vn);
 static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
     struct thread *td);
 
@@ -957,6 +958,35 @@
 kern_open(struct thread *td, char *path, enum uio_seg pathseg, int flags,
     int mode)
 {
+	return kern_openat(td, path, pathseg, flags, mode, AT_FDCWD);
+}
+
+static int
+kern_get_at(struct thread *td, int dirfd, struct vnode **dir_vn)
+{
+	int error;
+
+	if (dirfd == AT_FDCWD)
+		*dir_vn = NULL;
+	else {
+		error = fgetvp(td, dirfd, dir_vn);
+		if (error)
+			return (error);
+		if ((*dir_vn)->v_type != VDIR) {
+			vrele(*dir_vn);
+			return (ENOTDIR);
+		}
+	}
+
+	return (0);
+}
+
+int
+kern_openat(struct thread *td, char *path, enum uio_seg pathseg, int flags,
+    int mode, int dirfd)
+{
+	struct nameidata nd;
+	struct vnode *dir_vn;
 	struct proc *p = td->td_proc;
 	struct filedesc *fdp = p->p_fd;
 	struct file *fp;
@@ -967,23 +997,32 @@
 	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);
+	/* XXX: audit dirfd */
+
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td, dir_vn);
+
+	if ((flags & O_ACCMODE) == O_ACCMODE) {
+		error = EINVAL;
+		goto out;
+	}
 	flags = FFLAGS(flags);
+
 	error = falloc(td, &nfp, &indx);
 	if (error)
-		return (error);
+		goto out;
 	/* 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, fp);
+	error = vn_open(&nd, &flags, cmode, fp);
 	if (error) {
 		/*
 		 * If the vn_open replaced the method vector, something
@@ -993,7 +1032,8 @@
 		if (error == ENXIO && fp->f_ops != &badfileops) {
 			fdrop(fp, td);
 			td->td_retval[0] = indx;
-			return (0);
+			error = 0;
+			goto out;
 		}
 
 		/*
@@ -1007,7 +1047,8 @@
 			dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0) {
 			td->td_retval[0] = indx;
 			fdrop(fp, td);
-			return (0);
+			error = 0;
+			goto out;
 		}
 		/*
 		 * Clean up the descriptor, but only if another thread hadn't
@@ -1018,7 +1059,7 @@
 
 		if (error == ERESTART)
 			error = EINTR;
-		return (error);
+		goto out;
 	}
 	td->td_dupfd = 0;
 	vfslocked = NDHASGIANT(&nd);
@@ -1078,10 +1119,16 @@
 	fdrop(fp, td);
 	td->td_retval[0] = indx;
 	return (0);
+out:
+	if (dir_vn)
+		vrele(dir_vn);
+	return (error);
 bad:
 	VFS_UNLOCK_GIANT(vfslocked);
 	fdclose(fdp, fp, indx, td);
 	fdrop(fp, td);
+	if (dir_vn)
+		vrele(dir_vn);
 	return (error);
 }
 
@@ -1136,7 +1183,14 @@
 kern_mknod(struct thread *td, char *path, enum uio_seg pathseg, int mode,
     int dev)
 {
-	struct vnode *vp;
+	return kern_mknodat(td, path, pathseg, mode, dev, AT_FDCWD);
+}
+
+int
+kern_mknodat(struct thread *td, char *path, enum uio_seg pathseg, int mode,
+    int dev, int dirfd)
+{
+	struct vnode *vp, *dir_vn = NULL;
 	struct mount *mp;
 	struct vattr vattr;
 	int error;
@@ -1164,11 +1218,19 @@
 	if (error)
 		return (error);
 restart:
+	if (dir_vn)
+		vrele(dir_vn);
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
-	if ((error = namei(&nd)) != 0)
+	NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
+	    pathseg, path, td, dir_vn);
+	if ((error = namei(&nd)) != 0) {
+		if (dir_vn)
+			vrele(dir_vn);
 		return (error);
+	}
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
 	if (vp != NULL) {
@@ -1179,6 +1241,8 @@
 			vput(nd.ni_dvp);
 		vrele(vp);
 		VFS_UNLOCK_GIANT(vfslocked);
+		if (dir_vn)
+			vrele(dir_vn);
 		return (EEXIST);
 	} else {
 		VATTR_NULL(&vattr);
@@ -1210,8 +1274,11 @@
 		NDFREE(&nd, NDF_ONLY_PNBUF);
 		vput(nd.ni_dvp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
+		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) {
+			if (dir_vn)
+				vrele(dir_vn);
 			return (error);
+		}
 		goto restart;
 	}
 #ifdef MAC
@@ -1230,6 +1297,8 @@
 				vput(nd.ni_vp);
 		}
 	}
+	if (dir_vn)
+		vrele(dir_vn);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(nd.ni_dvp);
 	vn_finished_write(mp);
@@ -1261,19 +1330,34 @@
 int
 kern_mkfifo(struct thread *td, char *path, enum uio_seg pathseg, int mode)
 {
+	return kern_mkfifoat(td, path, pathseg, mode, AT_FDCWD);
+}
+
+int
+kern_mkfifoat(struct thread *td, char *path, enum uio_seg pathseg, int mode, int dirfd)
+{
 	struct mount *mp;
 	struct vattr vattr;
 	int error;
 	struct nameidata nd;
 	int vfslocked;
+	struct vnode *dir_vn = NULL;
 
 	AUDIT_ARG(mode, mode);
 restart:
+	if (dir_vn)
+		vrele(dir_vn);
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
-	if ((error = namei(&nd)) != 0)
+	NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
+	    pathseg, path, td, dir_vn);
+	if ((error = namei(&nd)) != 0) {
+		if (dir_vn)
+			vrele(dir_vn);
 		return (error);
+	}
 	vfslocked = NDHASGIANT(&nd);
 	if (nd.ni_vp != NULL) {
 		NDFREE(&nd, NDF_ONLY_PNBUF);
@@ -1283,14 +1367,19 @@
 			vput(nd.ni_dvp);
 		vrele(nd.ni_vp);
 		VFS_UNLOCK_GIANT(vfslocked);
+		if (dir_vn)
+			vrele(dir_vn);
 		return (EEXIST);
 	}
 	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
 		NDFREE(&nd, NDF_ONLY_PNBUF);
 		vput(nd.ni_dvp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
+		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) {
+			if (dir_vn)
+				vrele(dir_vn);
 			return (error);
+	}
 		goto restart;
 	}
 	VATTR_NULL(&vattr);
@@ -1311,6 +1400,8 @@
 #ifdef MAC
 out:
 #endif
+	if (dir_vn)
+		vrele(dir_vn);
 	vput(nd.ni_dvp);
 	vn_finished_write(mp);
 	VFS_UNLOCK_GIANT(vfslocked);
@@ -1383,62 +1474,87 @@
 int
 kern_link(struct thread *td, char *path, char *link, enum uio_seg segflg)
 {
+	return kern_linkat(td, path, link, segflg, AT_FDCWD, AT_FDCWD);
+}
+
+int
+kern_linkat(struct thread *td, char *path, char *link, enum uio_seg segflg,
+    int olddirfd, int newdirfd)
+{
+	struct nameidata ndp, ndl;
+	int error;
+	struct vnode *pdir_vn, *ldir_vn;
 	struct vnode *vp;
 	struct mount *mp;
-	struct nameidata nd;
 	int vfslocked;
 	int lvfslocked;
-	int error;
+
+	error = kern_get_at(td, olddirfd, &pdir_vn);
+	if (error)
+		return (error);
+
+	NDINIT_AT(&ndp, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, segflg, path, td, pdir_vn);
+
+	error = kern_get_at(td, newdirfd, &ldir_vn);
+	if (error)
+		return (error);
+
+	NDINIT_AT(&ndl, CREATE, LOCKPARENT | SAVENAME| MPSAFE | AUDITVNODE1, segflg,
+		link, td, ldir_vn);
 
 	bwillwrite();
-	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, segflg, path, td);
-	if ((error = namei(&nd)) != 0)
-		return (error);
-	vfslocked = NDHASGIANT(&nd);
-	NDFREE(&nd, NDF_ONLY_PNBUF);
-	vp = nd.ni_vp;
+	if ((error = namei(&ndp)) != 0)
+		goto out;
+	vfslocked = NDHASGIANT(&ndp);
+	NDFREE(&ndp, NDF_ONLY_PNBUF);
+	vp = ndp.ni_vp;
 	if (vp->v_type == VDIR) {
 		vrele(vp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		return (EPERM);		/* POSIX */
+		error = EPERM;		/* POSIX */
+		goto out;
 	}
 	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
 		vrele(vp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		return (error);
+		goto out;
 	}
-	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE2,
-	    segflg, link, td);
-	if ((error = namei(&nd)) == 0) {
-		lvfslocked = NDHASGIANT(&nd);
-		if (nd.ni_vp != NULL) {
-			if (nd.ni_dvp == nd.ni_vp)
-				vrele(nd.ni_dvp);
+	if ((error = namei(&ndl)) == 0) {
+		lvfslocked = NDHASGIANT(&ndl);
+		if (ndl.ni_vp != NULL) {
+			if (ndl.ni_dvp == ndl.ni_vp)
+				vrele(ndl.ni_dvp);
 			else
-				vput(nd.ni_dvp);
-			vrele(nd.ni_vp);
+				vput(ndl.ni_dvp);
+			vrele(ndl.ni_vp);
 			error = EEXIST;
 		} else if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td))
 		    == 0) {
-			VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
+			VOP_LEASE(ndl.ni_dvp, td, td->td_ucred, LEASE_WRITE);
 			VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
 			error = can_hardlink(vp, td, td->td_ucred);
 			if (error == 0)
 #ifdef MAC
 				error = mac_check_vnode_link(td->td_ucred,
-				    nd.ni_dvp, vp, &nd.ni_cnd);
+				    ndl.ni_dvp, vp, &ndl.ni_cnd);
 			if (error == 0)
 #endif
-				error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
+				error = VOP_LINK(ndl.ni_dvp, vp, &ndl.ni_cnd);
 			VOP_UNLOCK(vp, 0, td);
-			vput(nd.ni_dvp);
+			vput(ndl.ni_dvp);
 		}
-		NDFREE(&nd, NDF_ONLY_PNBUF);
+		NDFREE(&ndl, NDF_ONLY_PNBUF);
 		VFS_UNLOCK_GIANT(lvfslocked);
 	}
 	vrele(vp);
 	vn_finished_write(mp);
 	VFS_UNLOCK_GIANT(vfslocked);
+
+out:
+	if (pdir_vn)
+		vrele(pdir_vn);
+	if (ldir_vn)
+		vrele(ldir_vn);
 	return (error);
 }
 
@@ -1466,12 +1582,20 @@
 int
 kern_symlink(struct thread *td, char *path, char *link, enum uio_seg segflg)
 {
+	return kern_symlinkat(td, path, link, segflg, AT_FDCWD);
+}
+
+int
+kern_symlinkat(struct thread *td, char *path, char *link, enum uio_seg segflg,
+    int dirfd)
+{
 	struct mount *mp;
 	struct vattr vattr;
 	char *syspath;
 	int error;
 	struct nameidata nd;
 	int vfslocked;
+	struct vnode *dir_vn = NULL;
 
 	if (segflg == UIO_SYSSPACE) {
 		syspath = path;
@@ -1482,9 +1606,14 @@
 	}
 	AUDIT_ARG(text, syspath);
 restart:
+	if (dir_vn)
+		vrele(dir_vn);
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
-	    segflg, link, td);
+	NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
+	    segflg, link, td, dir_vn);
 	if ((error = namei(&nd)) != 0)
 		goto out;
 	vfslocked = NDHASGIANT(&nd);
@@ -1530,6 +1659,8 @@
 	vn_finished_write(mp);
 	VFS_UNLOCK_GIANT(vfslocked);
 out:
+	if (dir_vn)
+		vrele(dir_vn);
 	if (segflg != UIO_SYSSPACE)
 		uma_zfree(namei_zone, syspath);
 	return (error);
@@ -1611,18 +1742,32 @@
 int
 kern_unlink(struct thread *td, char *path, enum uio_seg pathseg)
 {
+	return kern_unlinkat(td, path, pathseg, AT_FDCWD);
+}
+
+int
+kern_unlinkat(struct thread *td, char *path, enum uio_seg pathseg, int dirfd)
+{
 	struct mount *mp;
-	struct vnode *vp;
+	struct vnode *vp, *dir_vn = NULL;
 	int error;
 	struct nameidata nd;
 	int vfslocked;
-
+	
 restart:
+	if (dir_vn)
+		vrele(dir_vn);
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
-	if ((error = namei(&nd)) != 0)
+	NDINIT_AT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
+	    pathseg, path, td, dir_vn);
+	if ((error = namei(&nd)) != 0) {
+		if (dir_vn)
+			vrele(dir_vn);		
 		return (error == EINVAL ? EPERM : error);
+	}
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
 	if (vp->v_type == VDIR)
@@ -1646,8 +1791,11 @@
 				vput(vp);
 			VFS_UNLOCK_GIANT(vfslocked);
 			if ((error = vn_start_write(NULL, &mp,
-			    V_XSLEEP | PCATCH)) != 0)
+			    V_XSLEEP | PCATCH)) != 0) {
+				if (dir_vn)
+					vrele(dir_vn);
 				return (error);
+			}
 			goto restart;
 		}
 #ifdef MAC
@@ -1665,6 +1813,8 @@
 	}
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(nd.ni_dvp);
+	if (dir_vn)
+		vrele(dir_vn);
 	if (vp == nd.ni_dvp)
 		vrele(vp);
 	else
@@ -1852,11 +2002,25 @@
 int
 kern_access(struct thread *td, char *path, enum uio_seg pathseg, int flags)
 {
+	return kern_accessat(td, path, pathseg, flags, AT_FDCWD);
+}
+
+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;
 	struct ucred *cred, *tmpcred;
-	register struct vnode *vp;
-	struct nameidata nd;
+	struct vnode *vp;
 	int vfslocked;
-	int error;
+
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
+	    pathseg, path, td, dir_vn);
 
 	/*
 	 * Create and modify a temporary credential instead of one that
@@ -1868,10 +2032,8 @@
 	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)
-		goto out1;
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
 
@@ -1879,9 +2041,11 @@
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(vp);
 	VFS_UNLOCK_GIANT(vfslocked);
-out1:
+out:
 	td->td_ucred = cred;
 	crfree(tmpcred);
+	if (dir_vn)
+		vrele(dir_vn);
 	return (error);
 }
 
@@ -2045,26 +2209,43 @@
 int
 kern_stat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp)
 {
+	return kern_statat(td, path, pathseg, sbp, AT_FDCWD);
+}
+
+int
+kern_statat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp, int dirfd)
+{
 	struct nameidata nd;
+	struct vnode *dir_vn;
 	struct stat sb;
 	int error, vfslocked;
 
-	NDINIT(&nd, LOOKUP,
-	    FOLLOW | LOCKSHARED | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1 | 
+		MPSAFE, pathseg, path, td, dir_vn);
+
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(nd.ni_vp);
 	VFS_UNLOCK_GIANT(vfslocked);
+	/* dont bother with the path as this is hopefully going away soon */
 	if (mtx_owned(&Giant))
-		printf("stat(%d): %s\n", vfslocked, path);
+		printf("stat(%d):\n", vfslocked);
 	if (error)
-		return (error);
+		goto out;
 	*sbp = sb;
-	return (0);
+
+	error = 0;
+out:	
+	if (dir_vn)
+		vrele(dir_vn);
+	return (error);
 }
 
 /*
@@ -2096,16 +2277,27 @@
 int
 kern_lstat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp)
 {
+	return kern_lstatat(td, path, pathseg, sbp, AT_FDCWD);
+}
+
+int
+kern_lstatat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp, int dirfd)
+{
+	struct nameidata nd;
+	struct vnode *dir_vn;
 	struct vnode *vp;
 	struct stat sb;
-	struct nameidata nd;
 	int error, vfslocked;
 
-	NDINIT(&nd, LOOKUP,
-	    NOFOLLOW | LOCKLEAF | LOCKSHARED | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1 | 
+		MPSAFE, pathseg, path, td, dir_vn);
+
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
 	error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
@@ -2113,9 +2305,13 @@
 	vput(vp);
 	VFS_UNLOCK_GIANT(vfslocked);
 	if (error)
-		return (error);
+		goto out;
 	*sbp = sb;
-	return (0);
+	error = 0;
+out:	
+	if (dir_vn)
+		vrele(dir_vn);
+	return (error);
 }
 
 /*
@@ -2272,17 +2468,29 @@
 kern_readlink(struct thread *td, char *path, enum uio_seg pathseg, char *buf,
     enum uio_seg bufseg, int count)
 {
-	register struct vnode *vp;
+	return kern_readlinkat(td, path, pathseg, buf, bufseg, count, AT_FDCWD);
+}
+
+int
+kern_readlinkat(struct thread *td, char *path, enum uio_seg pathseg, char *buf,
+    enum uio_seg bufseg, int count, int dirfd)
+{
+	struct nameidata nd;
+	struct vnode *dir_vn;
+	struct vnode *vp;
 	struct iovec aiov;
 	struct uio auio;
-	int error;
-	struct nameidata nd;
-	int vfslocked;
+	int error, vfslocked;
+
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, pathseg,
+		path, td, dir_vn);
 
-	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
@@ -2291,7 +2499,7 @@
 	if (error) {
 		vput(vp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		return (error);
+		goto out;
 	}
 #endif
 	if (vp->v_type != VLNK)
@@ -2311,6 +2519,9 @@
 	vput(vp);
 	VFS_UNLOCK_GIANT(vfslocked);
 	td->td_retval[0] = count - auio.uio_resid;
+out:
+	if (dir_vn)
+		vrele(dir_vn);
 	return (error);
 }
 
@@ -2455,6 +2666,7 @@
 }
 
 /*
+ *
  * Common implementation code for chmod(), lchmod() and fchmod().
  */
 static int
@@ -2507,19 +2719,32 @@
 int
 kern_chmod(struct thread *td, char *path, enum uio_seg pathseg, int mode)
 {
-	int error;
+	return kern_chmodat(td, path, pathseg, mode, AT_FDCWD);
+}
+
+int
+kern_chmodat(struct thread *td, char *path, enum uio_seg pathseg, int mode, int dirfd)
+{
 	struct nameidata nd;
-	int vfslocked;
+	struct vnode *dir_vn;
+	int error, vfslocked;
+
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn);
 
-	AUDIT_ARG(mode, mode);
-	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td);
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	error = setfmode(td, nd.ni_vp, mode);
 	vrele(nd.ni_vp);
 	VFS_UNLOCK_GIANT(vfslocked);
+out:	
+	if (dir_vn)
+		vrele(dir_vn);
 	return (error);
 }
 
@@ -2653,19 +2878,33 @@
 kern_chown(struct thread *td, char *path, enum uio_seg pathseg, int uid,
     int gid)
 {
-	int error;
+	return kern_chownat(td, path, pathseg, uid, gid, AT_FDCWD);
+}
+
+int
+kern_chownat(struct thread *td, char *path, enum uio_seg pathseg, int uid,
+    int gid, int dirfd)
+{
 	struct nameidata nd;
-	int vfslocked;
+	struct vnode *dir_vn;
+	int error, vfslocked;
+
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn);
 
-	AUDIT_ARG(owner, uid, gid);
-	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td);
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	error = setfown(td, nd.ni_vp, uid, gid);
 	vrele(nd.ni_vp);
 	VFS_UNLOCK_GIANT(vfslocked);
+out:	
+	if (dir_vn)
+		vrele(dir_vn);
 	return (error);
 }
 
@@ -2696,19 +2935,33 @@
 kern_lchown(struct thread *td, char *path, enum uio_seg pathseg, int uid,
     int gid)
 {
-	int error;
+	return kern_lchownat(td, path, pathseg, uid, gid, AT_FDCWD);
+}
+
+int
+kern_lchownat(struct thread *td, char *path, enum uio_seg pathseg, int uid,
+    int gid, int dirfd)
+{
 	struct nameidata nd;
-	int vfslocked;
+	struct vnode *dir_vn;
+	int error, vfslocked;
+
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, NOFOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn);
 
-	AUDIT_ARG(owner, uid, gid);
-	NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td);
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	error = setfown(td, nd.ni_vp, uid, gid);
 	vrele(nd.ni_vp);
 	VFS_UNLOCK_GIANT(vfslocked);
+out:	
+	if (dir_vn)
+		vrele(dir_vn);
 	return (error);
 }
 
@@ -2855,21 +3108,36 @@
 kern_utimes(struct thread *td, char *path, enum uio_seg pathseg,
     struct timeval *tptr, enum uio_seg tptrseg)
 {
+	return kern_utimesat(td, path, pathseg, tptr, tptrseg, AT_FDCWD);
+}
+
+int
+kern_utimesat(struct thread *td, char *path, enum uio_seg pathseg,
+    struct timeval *tptr, enum uio_seg tptrseg, int dirfd)
+{
+	struct nameidata nd;
+	struct vnode *dir_vn;
 	struct timespec ts[2];
-	int error;
-	struct nameidata nd;
-	int vfslocked;
+	int error, vfslocked;
+
+   	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
+
+	NDINIT_AT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td, dir_vn);
 
 	if ((error = getutimes(tptr, tptrseg, ts)) != 0)
-		return (error);
-	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td);
+		goto out;
 	if ((error = namei(&nd)) != 0)
-		return (error);
+		goto out;
 	vfslocked = NDHASGIANT(&nd);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	error = setutimes(td, nd.ni_vp, ts, 2, tptr == NULL);
 	vrele(nd.ni_vp);
 	VFS_UNLOCK_GIANT(vfslocked);
+out:
+	if (dir_vn)
+		vrele(dir_vn);
 	return (error);
 }
 
@@ -3220,23 +3488,40 @@
 int
 kern_rename(struct thread *td, char *from, char *to, enum uio_seg pathseg)
 {
+	return kern_renameat(td, from, to, pathseg, AT_FDCWD, AT_FDCWD);
+}
+
+int
+kern_renameat(struct thread *td, char *from, char *to, enum uio_seg pathseg, int fdirfd, int tdirfd)
+{
+	struct nameidata fromnd, tond;
+	struct vnode *fdir_vn, *tdir_vn;
 	struct mount *mp = NULL;
 	struct vnode *tvp, *fvp, *tdvp;
-	struct nameidata fromnd, tond;
 	int tvfslocked;
 	int fvfslocked;
 	int error;
 
-	bwillwrite();
+	error = kern_get_at(td, fdirfd, &fdir_vn);
+	if (error)
+		return (error);
+	error = kern_get_at(td, tdirfd, &tdir_vn);
+	if (error)
+		return (error);
+
 #ifdef MAC
-	NDINIT(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART | MPSAFE |
-	    AUDITVNODE1, pathseg, from, td);
+	NDINIT_AT(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART | MPSAFE |
+	    AUDITVNODE1, pathseg, from, td, fdir_vn);
 #else
-	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART | MPSAFE |
-	    AUDITVNODE1, pathseg, from, td);
+	NDINIT_AT(&fromnd, DELETE, WANTPARENT | SAVESTART | MPSAFE |
+	    AUDITVNODE1, pathseg, from, td, fdir_vn);
 #endif
+	NDINIT_AT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART |
+	    MPSAFE | AUDITVNODE2, pathseg, to, td, tdir_vn);
+
+	bwillwrite();
 	if ((error = namei(&fromnd)) != 0)
-		return (error);
+		goto out2;
 	fvfslocked = NDHASGIANT(&fromnd);
 	tvfslocked = 0;
 #ifdef MAC
@@ -3255,8 +3540,6 @@
 		vrele(fvp);
 		goto out1;
 	}
-	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART |
-	    MPSAFE | AUDITVNODE2, pathseg, to, td);
 	if (fromnd.ni_vp->v_type == VDIR)
 		tond.ni_cnd.cn_flags |= WILLBEDIR;
 	if ((error = namei(&tond)) != 0) {
@@ -3328,6 +3611,12 @@
 	VFS_UNLOCK_GIANT(tvfslocked);
 	if (error == -1)
 		return (0);
+out2:
+	if (fdir_vn)
+		vrele(fdir_vn);
+	if (tdir_vn)
+		vrele(tdir_vn);
+
 	return (error);
 }
 
@@ -3355,8 +3644,14 @@
 int
 kern_mkdir(struct thread *td, char *path, enum uio_seg segflg, int mode)
 {
+	return kern_mkdirat(td, path, segflg, mode, AT_FDCWD);
+}
+
+int
+kern_mkdirat(struct thread *td, char *path, enum uio_seg segflg, int mode, int dirfd)
+{
 	struct mount *mp;
-	struct vnode *vp;
+	struct vnode *vp, *dir_vn = NULL;
 	struct vattr vattr;
 	int error;
 	struct nameidata nd;
@@ -3364,12 +3659,20 @@
 
 	AUDIT_ARG(mode, mode);
 restart:
+	if (dir_vn)
+		vrele(dir_vn);
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
-	    segflg, path, td);
+	NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
+	    segflg, path, td, dir_vn);
 	nd.ni_cnd.cn_flags |= WILLBEDIR;
-	if ((error = namei(&nd)) != 0)
+	if ((error = namei(&nd)) != 0) {
+		if (dir_vn)
+			vrele(dir_vn);
 		return (error);
+	}
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
 	if (vp != NULL) {
@@ -3385,14 +3688,19 @@
 			vput(nd.ni_dvp);
 		vrele(vp);
 		VFS_UNLOCK_GIANT(vfslocked);
+		if (dir_vn)
+			vrele(dir_vn);
 		return (EEXIST);
 	}
 	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
 		NDFREE(&nd, NDF_ONLY_PNBUF);
 		vput(nd.ni_dvp);
 		VFS_UNLOCK_GIANT(vfslocked);
-		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
+		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) {
+			if (dir_vn)
+				vrele(dir_vn);
 			return (error);
+		}
 		goto restart;
 	}
 	VATTR_NULL(&vattr);
@@ -3411,6 +3719,8 @@
 #ifdef MAC
 out:
 #endif
+	if (dir_vn)
+		vrele(dir_vn);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(nd.ni_dvp);
 	if (!error)
@@ -3442,16 +3752,25 @@
 int
 kern_rmdir(struct thread *td, char *path, enum uio_seg pathseg)
 {
+	return kern_rmdirat(td, path, pathseg, AT_FDCWD);
+}
+
+int
+kern_rmdirat(struct thread *td, char *path, enum uio_seg pathseg, int dirfd)
+{
 	struct mount *mp;
-	struct vnode *vp;
+	struct vnode *vp, *dir_vn = NULL;
 	int error;
 	struct nameidata nd;
 	int vfslocked;
 
 restart:
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 	bwillwrite();
-	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
+	NDINIT_AT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
+	    pathseg, path, td, dir_vn);
 	if ((error = namei(&nd)) != 0)
 		return (error);
 	vfslocked = NDHASGIANT(&nd);
--- modules/Makefile.orig
+++ modules/Makefile
@@ -411,7 +411,6 @@
 _streams=	streams
 _wi=		wi
 _xe=		xe
-.if ${MK_ZFS} != "no" || defined(ALL_MODULES)
 _zfs=		zfs
 .endif
 .if ${MACHINE} == "i386"
@@ -460,7 +459,6 @@
 _pmc=		pmc
 _snc=		snc
 .endif
-.endif
 
 .if ${MACHINE_ARCH} == "amd64"
 _aac=		aac
--- security/audit/audit_trigger.c.orig
+++ security/audit/audit_trigger.c
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/security/audit/audit_trigger.c,v 1.5 2007/06/13 21:17:23 rwatson Exp $
+ * $FreeBSD: src/sys/security/audit/audit_trigger.c,v 1.4 2006/12/28 22:18:43 rwatson Exp $
  */
 
 #include <sys/param.h>
@@ -132,14 +132,15 @@
 {
 	struct trigger_info *ti;
 
+	/* If nobody's listening, we ain't talking. */
+	if (!audit_isopen)
+		return (ENODEV);
+
+	/*
+	 * Note: Use a condition variable instead of msleep/wakeup?
+	 */
 	ti = malloc(sizeof *ti, M_AUDITTRIGGER, M_WAITOK);
 	mtx_lock(&audit_trigger_mtx);
-	if (!audit_isopen) {
-		/* If nobody's listening, we ain't talking. */
-		mtx_unlock(&audit_trigger_mtx);
-		free(ti, M_AUDITTRIGGER);
-		return (ENODEV);
-	}
 	ti->trigger = trigger;
 	TAILQ_INSERT_TAIL(&trigger_list, ti, list);
 	wakeup(&trigger_list);
--- sys/fcntl.h.orig
+++ sys/fcntl.h
@@ -105,6 +105,7 @@
 #ifdef _KERNEL
 #define	FHASLOCK	0x4000		/* descriptor holds advisory lock */
 #endif
+#define	AT_FDCWD	-100		/* CWD for *at syscals */
 
 /* Defined by POSIX 1003.1; BSD default, but must be distinct from O_RDONLY. */
 #define	O_NOCTTY	0x8000		/* don't assign controlling terminal */
--- sys/namei.h.orig
+++ sys/namei.h
@@ -66,7 +66,10 @@
 	/*
 	 * Arguments to lookup.
 	 */
-	struct	vnode *ni_startdir;	/* starting directory */
+	struct	vnode *ni_startdir;	/* 
+					 * starting directory, also used for 
+					 * rename and *at functions 
+					 */
 	struct	vnode *ni_rootdir;	/* logical root directory */
 	struct	vnode *ni_topdir;	/* logical top directory */
 	/*
@@ -148,20 +151,23 @@
 /*
  * Initialization of a nameidata structure.
  */
-static void NDINIT(struct nameidata *, u_long, u_long, enum uio_seg,
-	    const char *, struct thread *);
+#define	NDINIT(ndp, op, flags, segflg, namep, td)	\
+		NDINIT_AT(ndp, op, flags, segflg, namep, td, NULL)
+
 static __inline void
-NDINIT(struct nameidata *ndp,
+NDINIT_AT(struct nameidata *ndp,
 	u_long op, u_long flags,
 	enum uio_seg segflg,
 	const char *namep,
-	struct thread *td)
+	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_startdir = dvp;
 }
 
 #define NDF_NO_DVP_RELE		0x00000001
--- sys/syscallsubr.h.orig
+++ sys/syscallsubr.h
@@ -56,16 +56,22 @@
 	    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,
-	    enum uio_seg pathseg, char **pathbuf, int create);
+	    enum uio_seg pathseg, char **pathbuf, int create, int dirfd);
 int	kern_bind(struct thread *td, int fd, struct sockaddr *sa);
 int	kern_chdir(struct thread *td, char *path, enum uio_seg pathseg);
 int	kern_chmod(struct thread *td, char *path, enum uio_seg pathseg,
 	    int mode);
+int	kern_chmodat(struct thread *td, char *path, enum uio_seg pathseg,
+	    int mode, int dirfd);
 int	kern_chown(struct thread *td, char *path, enum uio_seg pathseg, int uid,
 	    int gid);
+int	kern_chownat(struct thread *td, char *path, enum uio_seg pathseg, int uid,
+	    int gid, int dirfd);
 int	kern_clock_getres(struct thread *td, clockid_t clock_id,
 	    struct timespec *ts);
 int	kern_clock_gettime(struct thread *td, clockid_t clock_id,
@@ -102,18 +108,30 @@
 int	kern_kldunload(struct thread *td, int fileid, int flags);
 int	kern_lchown(struct thread *td, char *path, enum uio_seg pathseg,
 	    int uid, int gid);
+int	kern_lchownat(struct thread *td, char *path, enum uio_seg pathseg,
+	    int uid, int gid, int dirfd);
 int	kern_link(struct thread *td, char *path, char *link,
 	    enum uio_seg segflg);
+int	kern_linkat(struct thread *td, char *path, char *link,
+	    enum uio_seg segflg, int olddfd, int newdfd);
 int	kern_lstat(struct thread *td, char *path, enum uio_seg pathseg,
 	    struct stat *sbp);
+int	kern_lstatat(struct thread *td, char *path, enum uio_seg pathseg,
+	    struct stat *sbp, int dfd);
 int	kern_lutimes(struct thread *td, char *path, enum uio_seg pathseg,
 	    struct timeval *tptr, enum uio_seg tptrseg);
 int	kern_mkdir(struct thread *td, char *path, enum uio_seg segflg,
 	    int mode);
+int	kern_mkdirat(struct thread *td, char *path, enum uio_seg segflg,
+	    int mode, int dirfd);
 int	kern_mkfifo(struct thread *td, char *path, enum uio_seg pathseg,
 	    int mode);
+int	kern_mkfifoat(struct thread *td, char *path, enum uio_seg pathseg,
+	    int mode, int dirfd);
 int	kern_mknod(struct thread *td, char *path, enum uio_seg pathseg,
 	    int mode, int dev);
+int	kern_mknodat(struct thread *td, char *path, enum uio_seg pathseg,
+	    int mode, int dev, int dirfd);
 int	kern_msgctl(struct thread *, int, int, struct msqid_ds *);
 int	kern_msgsnd(struct thread *, int, const void *, size_t, int, long);
 int	kern_msgrcv(struct thread *, int, void *, size_t, long, int, long *);
@@ -121,6 +139,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);
@@ -129,12 +149,17 @@
 int	kern_pwritev(struct thread *td, int fd, struct uio *auio, off_t offset);
 int	kern_readlink(struct thread *td, char *path, enum uio_seg pathseg,
 	    char *buf, enum uio_seg bufseg, int count);
+int	kern_readlinkat(struct thread *td, char *path, enum uio_seg pathseg,
+	    char *buf, enum uio_seg bufseg, int count, int dirfd);
 int	kern_readv(struct thread *td, int fd, struct uio *auio);
 int	kern_recvit(struct thread *td, int s, struct msghdr *mp,
 	    enum uio_seg fromseg, struct mbuf **controlp);
 int	kern_rename(struct thread *td, char *from, char *to,
 	    enum uio_seg pathseg);
+int	kern_renameat(struct thread *td, char *from, char *to,
+	    enum uio_seg pathseg, int fdirfd, int tdirfd);
 int	kern_rmdir(struct thread *td, char *path, enum uio_seg pathseg);
+int	kern_rmdirat(struct thread *td, char *path, enum uio_seg pathseg, int dirfd);
 int	kern_sched_rr_get_interval(struct thread *td, pid_t pid,
 	    struct timespec *ts);
 int	kern_semctl(struct thread *td, int semid, int semnum, int cmd,
@@ -165,17 +190,24 @@
 int	kern_sigsuspend(struct thread *td, sigset_t mask);
 int	kern_stat(struct thread *td, char *path, enum uio_seg pathseg,
 	    struct stat *sbp);
+int	kern_statat(struct thread *td, char *path, enum uio_seg pathseg,
+	    struct stat *sbp, int dfd);
 int	kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
 	    struct statfs *buf);
 int	kern_symlink(struct thread *td, char *path, char *link,
 	    enum uio_seg segflg);
+int	kern_symlinkat(struct thread *td, char *path, char *link,
+	    enum uio_seg segflg, int dirfd);
 int	kern_thr_new(struct thread *td, struct thr_param *param);
 int	kern_thr_suspend(struct thread *td, struct timespec *tsp);
 int	kern_truncate(struct thread *td, char *path, enum uio_seg pathseg,
 	    off_t length);
 int	kern_unlink(struct thread *td, char *path, enum uio_seg pathseg);
+int	kern_unlinkat(struct thread *td, char *path, enum uio_seg pathseg, int dirfd);
 int	kern_utimes(struct thread *td, char *path, enum uio_seg pathseg,
 	    struct timeval *tptr, enum uio_seg tptrseg);
+int	kern_utimesat(struct thread *td, char *path, enum uio_seg pathseg,
+	    struct timeval *tptr, enum uio_seg tptrseg, int dirfd);
 int	kern_wait(struct thread *td, pid_t pid, int *status, int options,
 	    struct rusage *rup);
 int	kern_writev(struct thread *td, int fd, struct uio *auio);
