svn commit: r249599 - in stable/9/sys: kern sys ufs/ufs
Kirk McKusick
mckusick at FreeBSD.org
Thu Apr 18 00:53:49 UTC 2013
Author: mckusick
Date: Thu Apr 18 00:53:47 2013
New Revision: 249599
URL: http://svnweb.freebsd.org/changeset/base/249599
Log:
MFC of 248561:
When renaming a directory from one parent directory to another,
we need to call ufs_checkpath() to walk from our new location to
the root of the filesystem to ensure that we do not encounter
ourselves along the way. Until now, we accomplished this by reading
the ".." entries of each directory in our path until we reached
the root (or encountered an error). This change tries to avoid the
I/O of reading the ".." entries by first looking them up in the
name cache and only doing the I/O when the name cache lookup fails.
Reviewed by: kib
Tested by: Peter Holm
Modified:
stable/9/sys/kern/vfs_cache.c
stable/9/sys/sys/vnode.h
stable/9/sys/ufs/ufs/ufs_lookup.c
Directory Properties:
stable/9/sys/ (props changed)
stable/9/sys/sys/ (props changed)
Modified: stable/9/sys/kern/vfs_cache.c
==============================================================================
--- stable/9/sys/kern/vfs_cache.c Thu Apr 18 00:14:51 2013 (r249598)
+++ stable/9/sys/kern/vfs_cache.c Thu Apr 18 00:53:47 2013 (r249599)
@@ -1387,6 +1387,28 @@ vn_fullpath1(struct thread *td, struct v
return (0);
}
+struct vnode *
+vn_dir_dd_ino(struct vnode *vp)
+{
+ struct namecache *ncp;
+ struct vnode *ddvp;
+
+ ASSERT_VOP_LOCKED(vp, "vn_dir_dd_ino");
+ CACHE_RLOCK();
+ TAILQ_FOREACH(ncp, &(vp->v_cache_dst), nc_dst) {
+ if ((ncp->nc_flag & NCF_ISDOTDOT) != 0)
+ continue;
+ ddvp = ncp->nc_dvp;
+ VI_LOCK(ddvp);
+ CACHE_RUNLOCK();
+ if (vget(ddvp, LK_INTERLOCK | LK_SHARED | LK_NOWAIT, curthread))
+ return (NULL);
+ return (ddvp);
+ }
+ CACHE_RUNLOCK();
+ return (NULL);
+}
+
int
vn_commname(struct vnode *vp, char *buf, u_int buflen)
{
Modified: stable/9/sys/sys/vnode.h
==============================================================================
--- stable/9/sys/sys/vnode.h Thu Apr 18 00:14:51 2013 (r249598)
+++ stable/9/sys/sys/vnode.h Thu Apr 18 00:53:47 2013 (r249599)
@@ -621,6 +621,8 @@ int vn_fullpath(struct thread *td, struc
char **retbuf, char **freebuf);
int vn_fullpath_global(struct thread *td, struct vnode *vn,
char **retbuf, char **freebuf);
+struct vnode *
+ vn_dir_dd_ino(struct vnode *vp);
int vn_commname(struct vnode *vn, char *buf, u_int buflen);
int vn_path_to_global_path(struct thread *td, struct vnode *vp,
char *path, u_int pathlen);
Modified: stable/9/sys/ufs/ufs/ufs_lookup.c
==============================================================================
--- stable/9/sys/ufs/ufs/ufs_lookup.c Thu Apr 18 00:14:51 2013 (r249598)
+++ stable/9/sys/ufs/ufs/ufs_lookup.c Thu Apr 18 00:53:47 2013 (r249599)
@@ -1385,13 +1385,29 @@ ufs_dirempty(ip, parentino, cred)
}
static int
-ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino)
+ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino,
+ struct vnode **dd_vp)
{
struct dirtemplate dirbuf;
+ struct vnode *ddvp;
int error, namlen;
+ ASSERT_VOP_LOCKED(vp, "ufs_dir_dd_ino");
if (vp->v_type != VDIR)
return (ENOTDIR);
+ /*
+ * First check to see if we have it in the name cache.
+ */
+ if ((ddvp = vn_dir_dd_ino(vp)) != NULL) {
+ KASSERT(ddvp->v_mount == vp->v_mount,
+ ("ufs_dir_dd_ino: Unexpected mount point crossing"));
+ *dd_ino = VTOI(ddvp)->i_number;
+ *dd_vp = ddvp;
+ return (0);
+ }
+ /*
+ * Have to read the directory.
+ */
error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL, NULL);
@@ -1409,6 +1425,7 @@ ufs_dir_dd_ino(struct vnode *vp, struct
dirbuf.dotdot_name[1] != '.')
return (ENOTDIR);
*dd_ino = dirbuf.dotdot_ino;
+ *dd_vp = NULL;
return (0);
}
@@ -1433,7 +1450,7 @@ ufs_checkpath(ino_t source_ino, ino_t pa
if (target->i_number == ROOTINO)
return (0);
for (;;) {
- error = ufs_dir_dd_ino(vp, cred, &dd_ino);
+ error = ufs_dir_dd_ino(vp, cred, &dd_ino, &vp1);
if (error != 0)
break;
if (dd_ino == source_ino) {
@@ -1444,22 +1461,16 @@ ufs_checkpath(ino_t source_ino, ino_t pa
break;
if (dd_ino == parent_ino)
break;
- error = VFS_VGET(mp, dd_ino, LK_SHARED | LK_NOWAIT, &vp1);
- if (error != 0) {
- *wait_ino = dd_ino;
- break;
- }
- /* Recheck that ".." still points to vp1 after relock of vp */
- error = ufs_dir_dd_ino(vp, cred, &dd_ino);
- if (error != 0) {
- vput(vp1);
- break;
- }
- /* Redo the check of ".." if directory was reparented */
- if (dd_ino != VTOI(vp1)->i_number) {
- vput(vp1);
- continue;
+ if (vp1 == NULL) {
+ error = VFS_VGET(mp, dd_ino, LK_SHARED | LK_NOWAIT,
+ &vp1);
+ if (error != 0) {
+ *wait_ino = dd_ino;
+ break;
+ }
}
+ KASSERT(dd_ino == VTOI(vp1)->i_number,
+ ("directory %d reparented\n", VTOI(vp1)->i_number));
if (vp != tvp)
vput(vp);
vp = vp1;
@@ -1467,6 +1478,8 @@ ufs_checkpath(ino_t source_ino, ino_t pa
if (error == ENOTDIR)
panic("checkpath: .. not a directory\n");
+ if (vp1 != NULL)
+ vput(vp1);
if (vp != tvp)
vput(vp);
return (error);
More information about the svn-src-stable-9
mailing list