Date: Sun, 14 Jan 2007 09:47:47 GMT From: Roman Divacky <rdivacky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 112887 for review Message-ID: <200701140947.l0E9llto034185@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 <sys/malloc.h> #include <sys/mount.h> #include <sys/mutex.h> +#include <sys/namei.h> #include <sys/proc.h> #include <sys/stat.h> #include <sys/syscallsubr.h> @@ -84,52 +85,42 @@ return (error); } -int -linux_open(struct thread *td, struct linux_open_args *args) + +static int +linux_common_open(struct thread *td, char *path, int l_flags, int mode, int openat) { struct proc *p = td->td_proc; - char *path; int bsd_flags, error; - if (args->flags & LINUX_O_CREAT) - LCONVPATHCREAT(td, args->path, &path); - else - LCONVPATHEXIST(td, args->path, &path); - -#ifdef DEBUG - if (ldebug(open)) - printf(ARGS(open, "%s, 0x%x, 0x%x"), - path, args->flags, args->mode); -#endif bsd_flags = 0; - if (args->flags & LINUX_O_RDONLY) + if (l_flags & LINUX_O_RDONLY) bsd_flags |= O_RDONLY; - if (args->flags & LINUX_O_WRONLY) + if (l_flags & LINUX_O_WRONLY) bsd_flags |= O_WRONLY; - if (args->flags & LINUX_O_RDWR) + if (l_flags & LINUX_O_RDWR) bsd_flags |= O_RDWR; - if (args->flags & LINUX_O_NDELAY) + if (l_flags & LINUX_O_NDELAY) bsd_flags |= O_NONBLOCK; - if (args->flags & LINUX_O_APPEND) + if (l_flags & LINUX_O_APPEND) bsd_flags |= O_APPEND; - if (args->flags & LINUX_O_SYNC) + if (l_flags & LINUX_O_SYNC) bsd_flags |= O_FSYNC; - if (args->flags & LINUX_O_NONBLOCK) + if (l_flags & LINUX_O_NONBLOCK) bsd_flags |= O_NONBLOCK; - if (args->flags & LINUX_FASYNC) + if (l_flags & LINUX_FASYNC) bsd_flags |= O_ASYNC; - if (args->flags & LINUX_O_CREAT) + if (l_flags & LINUX_O_CREAT) bsd_flags |= O_CREAT; - if (args->flags & LINUX_O_TRUNC) + if (l_flags & LINUX_O_TRUNC) bsd_flags |= O_TRUNC; - if (args->flags & LINUX_O_EXCL) + if (l_flags & LINUX_O_EXCL) bsd_flags |= O_EXCL; - if (args->flags & LINUX_O_NOCTTY) + if (l_flags & LINUX_O_NOCTTY) bsd_flags |= O_NOCTTY; - if (args->flags & LINUX_O_DIRECT) + if (l_flags & LINUX_O_DIRECT) bsd_flags |= O_DIRECT; - error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, args->mode); + error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode); PROC_LOCK(p); if (!error && !(bsd_flags & O_NOCTTY) && SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { @@ -150,10 +141,121 @@ printf(LMSG("open returns error %d"), error); #endif } - LFREEPATH(path); + if (!openat) + LFREEPATH(path); return error; } +/* + * common code for linux *at set of syscalls + * + * works like this: + * if filename is absolute + * ignore dirfd + * else + * if dirfd == AT_FDCWD + * return CWD/filename + * else + * return DIRFD/filename + */ +static int +linux_at(struct thread *td, int dirfd, char *filename, char **newpath, char **freebuf) +{ + struct file *fp; + int error = 0; + struct vnode *dvp; + struct filedesc *fdp = td->td_proc->p_fd; + char *fullpath = "unknown"; + char *freepath = NULL; + + /* dont do anything if the pathname is absolute */ + if (*filename == '/') { + *newpath= filename; + return (0); + } + + /* check for AT_FDWCD */ + if (dirfd == LINUX_AT_FDCWD) { + FILEDESC_LOCK(fdp); + dvp = fdp->fd_cdir; + FILEDESC_UNLOCK(fdp); + } else { + error = fget(td, dirfd, &fp); + if (error) + return (error); + dvp = fp->f_vnode; + /* only a dir can be dfd */ + if (dvp->v_type != VDIR) { + fdrop(fp, td); + return (ENOTDIR); + } + fdrop(fp, td); + } + + error = vn_fullpath(td, dvp, &fullpath, &freepath); + if (!error) { + *newpath = malloc(strlen(fullpath) + strlen(filename) + 2, M_TEMP, M_WAITOK | M_ZERO); + *freebuf = freepath; + sprintf(*newpath, "%s/%s", fullpath, filename); + } + + return (error); +} + +int +linux_openat(struct thread *td, struct linux_openat_args *args) +{ + char *newpath, *oldpath, *freebuf = NULL, *path; + int error, len; + + oldpath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + error = copyinstr(args->filename, oldpath, MAXPATHLEN, &len); + +#ifdef DEBUG + if (ldebug(openat)) + printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd, + oldpath, args->flags, args->mode); +#endif + + error = linux_at(td, args->dfd, oldpath, &newpath, &freebuf); + if (error) + return (error); +#ifdef DEBUG + printf(LMSG("newpath: %s"), newpath); +#endif + if (args->flags & LINUX_O_CREAT) + LCONVPATH_SEG(td, newpath, &path, 1, UIO_SYSSPACE); + else + LCONVPATH_SEG(td, newpath, &path, 0, UIO_SYSSPACE); + if (freebuf) + free(freebuf, M_TEMP); + if (*oldpath != '/') + free(newpath, M_TEMP); + + error = linux_common_open(td, path, args->flags, args->mode, 1); + free(oldpath, M_TEMP); + return (error); +} + +int +linux_open(struct thread *td, struct linux_open_args *args) +{ + char *path; + + if (args->flags & LINUX_O_CREAT) + LCONVPATHCREAT(td, args->path, &path); + else + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(open)) + printf(ARGS(open, "%s, 0x%x, 0x%x"), + path, args->flags, args->mode); +#endif + + return linux_common_open(td, path, args->flags, args->mode, 0); +} + int linux_lseek(struct thread *td, struct linux_lseek_args *args) { ==== //depot/projects/linuxolator/src/sys/compat/linux/linux_util.h#2 (text+ko) ==== @@ -53,16 +53,19 @@ int linux_emul_convpath(struct thread *, char *, enum uio_seg, char **, int); -#define LCONVPATH(td, upath, pathp, i) \ +#define LCONVPATH_SEG(td, upath, pathp, i, seg) \ do { \ int _error; \ \ - _error = linux_emul_convpath(td, upath, UIO_USERSPACE, \ + _error = linux_emul_convpath(td, upath, seg, \ pathp, i); \ if (*(pathp) == NULL) \ return (_error); \ } while (0) +#define LCONVPATH(td, upath, pathp, i) \ + LCONVPATH_SEG(td, upath, pathp, i, UIO_USERSPACE) + #define LCONVPATHEXIST(td, upath, pathp) LCONVPATH(td, upath, pathp, 0) #define LCONVPATHCREAT(td, upath, pathp) LCONVPATH(td, upath, pathp, 1) #define LFREEPATH(path) free(path, M_TEMP) ==== //depot/projects/linuxolator/src/sys/i386/linux/linux.h#10 (text+ko) ==== @@ -527,6 +527,8 @@ #define LINUX_F_WRLCK 1 #define LINUX_F_UNLCK 2 +#define LINUX_AT_FDCWD -100 + /* * mount flags */ ==== //depot/projects/linuxolator/src/sys/i386/linux/linux_dummy.c#8 (text+ko) ==== @@ -86,7 +86,6 @@ DUMMY(inotify_add_watch); DUMMY(inotify_rm_watch); DUMMY(migrate_pages); -DUMMY(openat); DUMMY(mkdirat); DUMMY(mknodat); DUMMY(fchownat); ==== //depot/projects/linuxolator/src/sys/kern/vfs_lookup.c#4 (text+ko) ====
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200701140947.l0E9llto034185>