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