From owner-p4-projects@FreeBSD.ORG Mon Jun 4 17:23:59 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 3CED516A46C; Mon, 4 Jun 2007 17:23:59 +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 CF7A116A421 for ; Mon, 4 Jun 2007 17:23:58 +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 BE82813C45E for ; Mon, 4 Jun 2007 17:23:58 +0000 (UTC) (envelope-from rdivacky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.8/8.13.8) with ESMTP id l54HNwGP082727 for ; Mon, 4 Jun 2007 17:23:58 GMT (envelope-from rdivacky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.8/8.13.8/Submit) id l54HNwjT082718 for perforce@freebsd.org; Mon, 4 Jun 2007 17:23:58 GMT (envelope-from rdivacky@FreeBSD.org) Date: Mon, 4 Jun 2007 17:23:58 GMT Message-Id: <200706041723.l54HNwjT082718@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 120919 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: Mon, 04 Jun 2007 17:23:59 -0000 http://perforce.freebsd.org/chv.cgi?CH=120919 Change 120919 by rdivacky@rdivacky_witten on 2007/06/04 17:23:48 o Introduce kern_get_at() function instead of duplicating the same code everywhere o Reimplement kern_symlink and kern_unlink as wrappers around their *at counterparts to avoid code duplication o vrele(dir_vn) in kern_symlink and kern_unlink as necessary The code upto this commit has bugs :( including panics, deadlocks etc. Affected files ... .. //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_syscalls.c#15 edit Differences ... ==== //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_syscalls.c#15 (text+ko) ==== @@ -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); static int kern_common_open(struct thread *td, int flags, int mode, @@ -984,6 +985,26 @@ return kern_common_open(td, flags, mode, &nd); } +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) @@ -996,22 +1017,14 @@ AUDIT_ARG(mode, mode); /* XXX: audit dirfd */ - if (dirfd == AT_FDCWD) - dir_vn = NULL; - else { - error = fgetvp(td, dirfd, &dir_vn); - if (error) - return (error); - if (dir_vn->v_type != VDIR) { - vrele(dir_vn); - return (ENOTDIR); - } - } + error = kern_get_at(td, dirfd, &dir_vn); + if (error) + return (error); NDINIT_AT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td, dir_vn); error = kern_common_open(td, flags, mode, &nd); - if (dirfd != AT_FDCWD) + if (dir_vn) vrele(dir_vn); return (error); } @@ -1462,47 +1475,25 @@ int error; struct vnode *pdir_vn, *ldir_vn; - if (olddirfd == AT_FDCWD) - pdir_vn = NULL; - else { - error = fgetvp(td, olddirfd, &pdir_vn); - if (error) - return (error); - if (pdir_vn->v_type != VDIR) { - vrele(pdir_vn); - return (ENOTDIR); - } - } + error = kern_get_at(td, olddirfd, &pdir_vn); + if (error) + return (error); NDINIT_AT(&ndp, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, segflg, path, td, pdir_vn); - if (newdirfd == AT_FDCWD) - ldir_vn = NULL; - else { - error = fgetvp(td, newdirfd, &ldir_vn); - if (error) - return (error); - if (ldir_vn->v_type != VDIR) { - vrele(ldir_vn); - return (ENOTDIR); - } - } + 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); error = kern_common_link(td, &ndp, &ndl); - if (olddirfd != AT_FDCWD) + if (pdir_vn) vrele(pdir_vn); - if (newdirfd != AT_FDCWD) + if (ldir_vn) vrele(ldir_vn); return (error); - - NDINIT(&ndp, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, segflg, path, td); - NDINIT(&ndl, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE2, - segflg, link, td); - - return kern_common_link(td, &ndp, &ndl); } static int @@ -1587,73 +1578,7 @@ int kern_symlink(struct thread *td, char *path, char *link, enum uio_seg segflg) { - struct mount *mp; - struct vattr vattr; - char *syspath; - int error; - struct nameidata nd; - int vfslocked; - - if (segflg == UIO_SYSSPACE) { - syspath = path; - } else { - syspath = uma_zalloc(namei_zone, M_WAITOK); - if ((error = copyinstr(path, syspath, MAXPATHLEN, NULL)) != 0) - goto out; - } - AUDIT_ARG(text, syspath); -restart: - bwillwrite(); - NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1, - segflg, link, td); - if ((error = namei(&nd)) != 0) - goto out; - vfslocked = NDHASGIANT(&nd); - if (nd.ni_vp) { - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_vp == nd.ni_dvp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - vrele(nd.ni_vp); - VFS_UNLOCK_GIANT(vfslocked); - error = EEXIST; - goto out; - } - 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) - goto out; - goto restart; - } - VATTR_NULL(&vattr); - FILEDESC_SLOCK(td->td_proc->p_fd); - vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask; - FILEDESC_SUNLOCK(td->td_proc->p_fd); -#ifdef MAC - vattr.va_type = VLNK; - error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, - &vattr); - if (error) - goto out2; -#endif - VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); - error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, syspath); - if (error == 0) - vput(nd.ni_vp); -#ifdef MAC -out2: -#endif - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_dvp); - vn_finished_write(mp); - VFS_UNLOCK_GIANT(vfslocked); -out: - if (segflg != UIO_SYSSPACE) - uma_zfree(namei_zone, syspath); - return (error); + return kern_symlinkat(td, path, link, segflg, AT_FDCWD); } int @@ -1666,7 +1591,7 @@ int error; struct nameidata nd; int vfslocked; - struct vnode *dir_vn; + struct vnode *dir_vn = NULL; if (segflg == UIO_SYSSPACE) { syspath = path; @@ -1677,17 +1602,11 @@ } AUDIT_ARG(text, syspath); restart: - 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); - } - } + if (dir_vn) + vrele(dir_vn); + error = kern_get_at(td, dirfd, &dir_vn); + if (error) + return (error); bwillwrite(); NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1, segflg, link, td, dir_vn); @@ -1736,6 +1655,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); @@ -1817,94 +1738,32 @@ int kern_unlink(struct thread *td, char *path, enum uio_seg pathseg) { - struct mount *mp; - struct vnode *vp; - int error; - struct nameidata nd; - int vfslocked; - -restart: - bwillwrite(); - NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1, - pathseg, path, td); - if ((error = namei(&nd)) != 0) - return (error == EINVAL ? EPERM : error); - vfslocked = NDHASGIANT(&nd); - vp = nd.ni_vp; - if (vp->v_type == VDIR) - error = EPERM; /* POSIX */ - else { - /* - * The root of a mounted filesystem cannot be deleted. - * - * XXX: can this only be a VDIR case? - */ - if (vp->v_vflag & VV_ROOT) - error = EBUSY; - } - if (error == 0) { - if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_dvp); - if (vp == nd.ni_dvp) - vrele(vp); - else - vput(vp); - VFS_UNLOCK_GIANT(vfslocked); - if ((error = vn_start_write(NULL, &mp, - V_XSLEEP | PCATCH)) != 0) - return (error); - goto restart; - } -#ifdef MAC - error = mac_check_vnode_delete(td->td_ucred, nd.ni_dvp, vp, - &nd.ni_cnd); - if (error) - goto out; -#endif - VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); - error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); -#ifdef MAC -out: -#endif - vn_finished_write(mp); - } - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_dvp); - if (vp == nd.ni_dvp) - vrele(vp); - else - vput(vp); - VFS_UNLOCK_GIANT(vfslocked); - return (error); + 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, *dir_vn; + struct vnode *vp, *dir_vn = NULL; int error; struct nameidata nd; int vfslocked; restart: - 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); - } - } + if (dir_vn) + vrele(dir_vn); + error = kern_get_at(td, dirfd, &dir_vn); + if (error) + return (error); bwillwrite(); NDINIT_AT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn); - if ((error = namei(&nd)) != 0) + 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) @@ -1928,8 +1787,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 @@ -1947,6 +1809,8 @@ } NDFREE(&nd, NDF_ONLY_PNBUF); vput(nd.ni_dvp); + if (dir_vn) + vrele(dir_vn); if (vp == nd.ni_dvp) vrele(vp); else @@ -2149,23 +2013,15 @@ struct nameidata nd; struct vnode *dir_vn; - if (dirfd == AT_FDCWD) - dir_vn = NULL; - else { - error = fgetvp(td, dirfd, &dir_vn); - if (error) - return (error); - if (dir_vn->v_type != VDIR) { - vrele(dir_vn); - return (ENOTDIR); - } - } + 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); error = kern_common_access(td, flags, &nd); - if (dirfd != AT_FDCWD) + if (dir_vn) vrele(dir_vn); return (error); } @@ -2379,23 +2235,15 @@ struct nameidata nd; struct vnode *dir_vn; - if (dirfd == AT_FDCWD) - dir_vn = NULL; - else { - error = fgetvp(td, dirfd, &dir_vn); - if (error) - return (error); - if (dir_vn->v_type != VDIR) { - vrele(dir_vn); - return (ENOTDIR); - } - } + 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); error = kern_common_stat(td, sbp, &nd); - if (dirfd != AT_FDCWD) + if (dir_vn) vrele(dir_vn); return (error); } @@ -2466,23 +2314,15 @@ struct nameidata nd; struct vnode *dir_vn; - if (dirfd == AT_FDCWD) - dir_vn = NULL; - else { - error = fgetvp(td, dirfd, &dir_vn); - if (error) - return (error); - if (dir_vn->v_type != VDIR) { - vrele(dir_vn); - return (ENOTDIR); - } - } + 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); error = kern_common_lstat(td, sbp, &nd); - if (dirfd != AT_FDCWD) + if (dir_vn) vrele(dir_vn); return (error); } @@ -2677,23 +2517,15 @@ struct nameidata nd; struct vnode *dir_vn; - if (dirfd == AT_FDCWD) - dir_vn = NULL; - else { - error = fgetvp(td, dirfd, &dir_vn); - if (error) - return (error); - if (dir_vn->v_type != VDIR) { - vrele(dir_vn); - return (ENOTDIR); - } - } + 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); error = kern_common_readlink(td, buf, bufseg, count, &nd); - if (dirfd != AT_FDCWD) + if (dir_vn) vrele(dir_vn); return (error); } @@ -2950,22 +2782,14 @@ struct nameidata nd; struct vnode *dir_vn; - if (dirfd == AT_FDCWD) - dir_vn = NULL; - else { - error = fgetvp(td, dirfd, &dir_vn); - if (error) - return (error); - if (dir_vn->v_type != VDIR) { - vrele(dir_vn); - return (ENOTDIR); - } - } + error = kern_get_at(td, dirfd, &dir_vn); + if (error) + return (error); NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn); error = kern_common_chmod(td, mode, &nd); - if (dirfd != AT_FDCWD) + if (dir_vn) vrele(dir_vn); return (error); } @@ -3132,22 +2956,14 @@ struct nameidata nd; struct vnode *dir_vn; - if (dirfd == AT_FDCWD) - dir_vn = NULL; - else { - error = fgetvp(td, dirfd, &dir_vn); - if (error) - return (error); - if (dir_vn->v_type != VDIR) { - vrele(dir_vn); - return (ENOTDIR); - } - } + error = kern_get_at(td, dirfd, &dir_vn); + if (error) + return (error); NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn); error = kern_common_chown(td, uid, gid, &nd); - if (dirfd != AT_FDCWD) + if (dir_vn) vrele(dir_vn); return (error); } @@ -3211,22 +3027,14 @@ struct nameidata nd; struct vnode *dir_vn; - if (dirfd == AT_FDCWD) - dir_vn = NULL; - else { - error = fgetvp(td, dirfd, &dir_vn); - if (error) - return (error); - if (dir_vn->v_type != VDIR) { - vrele(dir_vn); - return (ENOTDIR); - } - } + error = kern_get_at(td, dirfd, &dir_vn); + if (error) + return (error); NDINIT_AT(&nd, LOOKUP, NOFOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn); error = kern_common_chown(td, uid, gid, &nd); - if (dirfd != AT_FDCWD) + if (dir_vn) vrele(dir_vn); return (error); @@ -3978,69 +3786,7 @@ int kern_rmdir(struct thread *td, char *path, enum uio_seg pathseg) { - struct mount *mp; - struct vnode *vp; - int error; - struct nameidata nd; - int vfslocked; - -restart: - bwillwrite(); - NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1, - pathseg, path, td); - if ((error = namei(&nd)) != 0) - return (error); - vfslocked = NDHASGIANT(&nd); - vp = nd.ni_vp; - if (vp->v_type != VDIR) { - error = ENOTDIR; - goto out; - } - /* - * No rmdir "." please. - */ - if (nd.ni_dvp == vp) { - error = EINVAL; - goto out; - } - /* - * The root of a mounted filesystem cannot be deleted. - */ - if (vp->v_vflag & VV_ROOT) { - error = EBUSY; - goto out; - } -#ifdef MAC - error = mac_check_vnode_delete(td->td_ucred, nd.ni_dvp, vp, - &nd.ni_cnd); - if (error) - goto out; -#endif - if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(vp); - if (nd.ni_dvp == vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - VFS_UNLOCK_GIANT(vfslocked); - if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) - return (error); - goto restart; - } - VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); - VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); - error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); - vn_finished_write(mp); -out: - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(vp); - if (nd.ni_dvp == vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - VFS_UNLOCK_GIANT(vfslocked); - return (error); + return kern_rmdirat(td, path, pathseg, AT_FDCWD); } int @@ -4053,17 +3799,9 @@ int vfslocked; restart: - 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); - } - } + error = kern_get_at(td, dirfd, &dir_vn); + if (error) + return (error); bwillwrite(); NDINIT_AT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn);