From owner-p4-projects@FreeBSD.ORG Fri Jun 4 16:04:19 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 1685D1065679; Fri, 4 Jun 2010 16:04:19 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C1AF61065674 for ; Fri, 4 Jun 2010 16:04:18 +0000 (UTC) (envelope-from gpf@FreeBSD.org) Received: from repoman.freebsd.org (unknown [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id AEB668FC16 for ; Fri, 4 Jun 2010 16:04:18 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id o54G4I3u098393 for ; Fri, 4 Jun 2010 16:04:18 GMT (envelope-from gpf@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id o54G4IXF098391 for perforce@freebsd.org; Fri, 4 Jun 2010 16:04:18 GMT (envelope-from gpf@FreeBSD.org) Date: Fri, 4 Jun 2010 16:04:18 GMT Message-Id: <201006041604.o54G4IXF098391@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to gpf@FreeBSD.org using -f From: Efstratios Karatzas To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 179180 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 04 Jun 2010 16:04:19 -0000 http://p4web.freebsd.org/@@179180?ac=10 Change 179180 by gpf@gpf_desktop on 2010/06/04 16:04:06 - Implemented Exhaustive Search for UFS (yeah it works this time) I actually changed how VOP_GETPARENT works internally, meaning ffs_getparent() and dir_ilookup(). Now, a depth first search is performed if we supply the EXHAUSTSEARCH flag. I am not going to change NFS code so that this flag is given to vn_fullpath_nocache() because it is a huge penalty to performance. Perhaps we should add a new mount_nfs option so that a sys/admin can choose if he wants this functionality or not. Anyhoo, tested vn_fullpath_nocache() with a lkm and this seems to work fine. Please refer to the updated comment headers of the functions for more info. ta ta Affected files ... .. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/ufs/ffs/ffs_vnops.c#5 edit Differences ... ==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/ufs/ffs/ffs_vnops.c#5 (text+ko) ==== @@ -1802,13 +1802,24 @@ #define WANTNAME 0x0004 /* - * XXXgpf: used by VOP_GETPARENT + * XXXgpf: this function is used by VOP_GETPARENT * - * find the name that is used to reference vp inside the directory vnode dvp. + * find 'a' name that is used to reference vp inside some parent directory. * flags should be set to WANTNAME if the filename should be copied to * the supplied buffer. * - * locks: dvp must be locked on entry and will still be locked on exit + * flags should be set to EXHAUSTSEARCH if want to perform a depth first search + * on the filesystem that contains vp. In this case, tmpdvp should be the root vnode + * of the filesystem. If a parent directory is found, dvp will point to it, unless the + * third parameter is NULL which is a bad idea because that vnode will be locked/referenced on success + * and needs to be vput()d by the caller. + * + * If flags is not set to EXHAUSTSEARCH, only tmpdvp will be searched for the vnode in question - vp. + * In this case, it is acceptable to provide NULL as the third parameter. + * + * locks: tmpdvp must be locked on entry and will still be locked on exit. + * If we are performing an exhaustive search, dvp will be locked and have its reference count incremented + * on success. * * returns: * - ENOENT a file that corresponds to vp was not found inside dvp, @@ -1817,23 +1828,26 @@ * - EOVERFLOW result does not fit in buffer "name" */ static int -dir_ilookup(struct vnode *vp, struct vnode *dvp, char *name, int *namelen, int flags) +dir_ilookup(struct vnode *vp, struct vnode *tmpdvp, struct vnode **dvp, char *name, int *namelen, int flags) { struct uio io; struct iovec iov; struct dirent *dp, *edp; struct thread *td; + struct mount *mp; + struct vnode *childvp; char *dirbuf; u_int64_t dirbuflen; int error, eofflag; char foundit; - - if (dvp->v_type != VDIR) { + + if (tmpdvp->v_type != VDIR) { return ENOENT; } - + foundit = 0; - dirbuflen = ((struct inode *)dvp->v_data)->i_size; + mp = vp->v_mount; + dirbuflen = ((struct inode *)tmpdvp->v_data)->i_size; dirbuf = malloc(dirbuflen, M_TEMP, M_WAITOK); td = curthread; @@ -1849,7 +1863,7 @@ io.uio_td = td; eofflag = 0; - error = VOP_READDIR(dvp, &io, td->td_ucred, &eofflag, NULL, NULL); + error = VOP_READDIR(tmpdvp, &io, td->td_ucred, &eofflag, NULL, NULL); if (error) { error = EIO; goto out; @@ -1858,12 +1872,21 @@ /* search for the correct inode number inside the directory */ edp = (struct dirent *)&dirbuf[dirbuflen - io.uio_resid]; for (dp = (struct dirent *)dirbuf; dp < edp; ) { + if (!strcmp(((struct dirent *)dp)->d_name, ".") || + !strcmp(((struct dirent *)dp)->d_name, "..")) { + dp = (struct dirent *)((char *)dp + dp->d_reclen); + continue; + } + if (dp->d_reclen > 0) { /* found it */ if ( ((struct inode *)vp->v_data)->i_number == ((struct dirent *)dp)->d_fileno) { char *pch; int len; + if (dvp != NULL) + *dvp = tmpdvp; + if (flags & WANTNAME) { pch = ((struct dirent *)dp)->d_name; len = strlen(pch); @@ -1876,10 +1899,32 @@ strlcpy(name, ((struct dirent *)dp)->d_name, *namelen); *namelen -= len + 1; } - + foundit = 1; + error = 0; break; } + /* recusivly traverse the fs if we have the EXHAUSTSEARCH flag set */ + else if ((flags & EXHAUSTSEARCH) && ((struct dirent *)dp)->d_type == DT_DIR) { + error = VFS_VGET(mp, ((struct dirent *)dp)->d_fileno, LK_SHARED, &childvp); + /* no reason to traverse other filesystems */ + if (!error && !(childvp->v_vflag & VV_ROOT)) { + error = dir_ilookup(vp, childvp, dvp, name, namelen, flags); + if (error) { + vput(childvp); + } + /* don't vput the directory vnode that contains vp */ + else if (childvp != *dvp) { + vput(childvp); + } + + if (!error) { + foundit = 1; + error = 0; + break; + } + } + } dp = (struct dirent *)((char *)dp + dp->d_reclen); } else { @@ -1893,7 +1938,7 @@ free(dirbuf, M_TEMP); } - if (foundit == 0 && error != 0) { + if (foundit == 0 && error == 0) { error = ENOENT; } @@ -1932,17 +1977,21 @@ */ { struct mount *mp; - struct vnode *vp, *dvp; - int error, flags; + struct vnode *vp, *dvp, *startdvp; + int error, flags, tmpflags; error = 0; vp = ap->a_vp; mp = vp->v_mount; + dvp = NULL; flags = ap->a_flags; KASSERT(vp != NULL, ("VOP_GEPARENT: null vp")); if (flags & WANTNAME) KASSERT(ap->a_buf != NULL, ("VOP_GEPARENT: null buffer")); + + MNT_REF(mp); + /* XXXgpf:is this check necessary? */ if (vp->v_type == VBAD) { error = ENOENT; @@ -1957,51 +2006,32 @@ if (error) { dvp = NULL; } - else if (flags & WANTNAME) { - /* grab the name that is being used to reference vp */ - error = dir_ilookup(vp, dvp, ap->a_buf, ap->a_buflen, flags); + /* make sure this directory contains vp */ + else { + /* avoid exhaustive search for now */ + tmpflags = flags & (PARENTHINT | WANTNAME); + error = dir_ilookup(vp, dvp, NULL, ap->a_buf, ap->a_buflen, tmpflags); if (error) { vput(dvp); dvp = NULL; } } - } - + } + /* * if our target is not a directory and we haven't found 'a' parent directory, * do an exhaustive search on the filesystem */ if ((flags & EXHAUSTSEARCH) && dvp == NULL) { - /* - * XXXgpf: this actually does not work because when the thread will try to sleep, - * e.g. in VOP_READDIR, the kernel will panic because we have ilocked mp >.< - * - * Not, it also kernel panics because we have locked vp >.<' - */ - MNT_ILOCK(mp); - if (!TAILQ_EMPTY(&mp->mnt_nvnodelist)) { - struct vnode *tvp; - - TAILQ_FOREACH(tvp, &mp->mnt_nvnodelist, v_nmntvnodes) { - if (tvp->v_type == VDIR) { - vn_lock(tvp, LK_SHARED); - /* grab the name that is being used to reference vp */ - error = dir_ilookup(vp, tvp, ap->a_buf, ap->a_buflen, flags); - - /* found it */ - if (error == 0) { - dvp = tvp; - vref(dvp); - break; - } - VOP_UNLOCK(tvp, 0); - } + error = VFS_VGET(mp, ROOTINO, LK_SHARED, &startdvp); + if (error == 0) { + error = dir_ilookup(vp, startdvp, &dvp, ap->a_buf, ap->a_buflen, flags); + /* dont vput if the parent vnode is the root vnode */ + if (error || startdvp != dvp) { + vput(startdvp); } } - MNT_IUNLOCK(mp); - - /* we failed to find a directory that contains the vnode, exit */ - if (error != 0) { + if (error) { error = ENOENT; } } @@ -2017,6 +2047,8 @@ else { *(ap->a_vpp) = NULL; } + + MNT_REL(mp); return error; }