Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/ufs/ufs Move ufs_wapbl_rename to ufs_vnops.c next to the...



details:   https://anonhg.NetBSD.org/src/rev/f76129e85d56
branches:  trunk
changeset: 767423:f76129e85d56
user:      dholland <dholland%NetBSD.org@localhost>
date:      Mon Jul 18 06:45:27 2011 +0000

description:
Move ufs_wapbl_rename to ufs_vnops.c next to the old ufs_rename.

diffstat:

 sys/ufs/ufs/ufs_vnops.c |  870 +++++++++++++++++++++++++++++++++++++++++++++++-
 sys/ufs/ufs/ufs_wapbl.c |  870 +-----------------------------------------------
 2 files changed, 870 insertions(+), 870 deletions(-)

diffs (truncated from 1789 to 300 lines):

diff -r 641f674852f5 -r f76129e85d56 sys/ufs/ufs/ufs_vnops.c
--- a/sys/ufs/ufs/ufs_vnops.c   Mon Jul 18 06:31:59 2011 +0000
+++ b/sys/ufs/ufs/ufs_vnops.c   Mon Jul 18 06:45:27 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ufs_vnops.c,v 1.198 2011/07/18 02:35:11 dholland Exp $ */
+/*     $NetBSD: ufs_vnops.c,v 1.199 2011/07/18 06:45:27 dholland Exp $ */
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.198 2011/07/18 02:35:11 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.199 2011/07/18 06:45:27 dholland Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -1103,6 +1103,872 @@
  * once.)
  */
 
+/* XXX following lifted from ufs_lookup.c */
+#define        FSFMT(vp)       (((vp)->v_mount->mnt_iflag & IMNT_DTYPE) == 0)
+
+/*
+ * Check if either entry referred to by FROM_ULR is within the range
+ * of entries named by TO_ULR.
+ */
+static int
+ulr_overlap(const struct ufs_lookup_results *from_ulr,
+           const struct ufs_lookup_results *to_ulr)
+{
+       doff_t from_start, from_prevstart;
+       doff_t to_start, to_end;
+
+       /*
+        * FROM is a DELETE result; offset points to the entry to
+        * remove and subtracting count gives the previous entry.
+        */
+       from_start = from_ulr->ulr_offset - from_ulr->ulr_count;
+       from_prevstart = from_ulr->ulr_offset;
+
+       /*
+        * TO is a RENAME (thus non-DELETE) result; offset points
+        * to the beginning of a region to write in, and adding
+        * count gives the end of the region.
+        */
+       to_start = to_ulr->ulr_offset;
+       to_end = to_ulr->ulr_offset + to_ulr->ulr_count;
+
+       if (from_prevstart >= to_start && from_prevstart < to_end) {
+               return 1;
+       }
+       if (from_start >= to_start && from_start < to_end) {
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * Wrapper for relookup that also updates the supplemental results.
+ */
+static int
+do_relookup(struct vnode *dvp, struct ufs_lookup_results *ulr,
+           struct vnode **vp, struct componentname *cnp)
+{
+       int error;
+
+       error = relookup(dvp, vp, cnp, 0);
+       if (error) {
+               return error;
+       }
+       /* update the supplemental reasults */
+       *ulr = VTOI(dvp)->i_crap;
+       UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
+       return 0;
+}
+
+/*
+ * Lock and relookup a sequence of two directories and two children.
+ *
+ */
+static int
+lock_vnode_sequence(struct vnode *d1, struct ufs_lookup_results *ulr1,
+                   struct vnode **v1_ret, struct componentname *cn1, 
+                   int v1_missing_ok,
+                   int overlap_error,
+                   struct vnode *d2, struct ufs_lookup_results *ulr2,
+                   struct vnode **v2_ret, struct componentname *cn2, 
+                   int v2_missing_ok)
+{
+       struct vnode *v1, *v2;
+       int error;
+
+       KASSERT(d1 != d2);
+
+       vn_lock(d1, LK_EXCLUSIVE | LK_RETRY);
+       if (VTOI(d1)->i_size == 0) {
+               /* d1 has been rmdir'd */
+               VOP_UNLOCK(d1);
+               return ENOENT;
+       }
+       error = do_relookup(d1, ulr1, &v1, cn1);
+       if (v1_missing_ok) {
+               if (error == ENOENT) {
+                       /*
+                        * Note: currently if the name doesn't exist,
+                        * relookup succeeds (it intercepts the
+                        * EJUSTRETURN from VOP_LOOKUP) and sets tvp
+                        * to NULL. Therefore, we will never get
+                        * ENOENT and this branch is not needed.
+                        * However, in a saner future the EJUSTRETURN
+                        * garbage will go away, so let's DTRT.
+                        */
+                       v1 = NULL;
+                       error = 0;
+               }
+       } else {
+               if (error == 0 && v1 == NULL) {
+                       /* This is what relookup sets if v1 disappeared. */
+                       error = ENOENT;
+               }
+       }
+       if (error) {
+               VOP_UNLOCK(d1);
+               return error;
+       }
+       if (v1 && v1 == d2) {
+               VOP_UNLOCK(d1);
+               VOP_UNLOCK(v1);
+               vrele(v1);
+               return overlap_error;
+       }
+
+       /*
+        * The right way to do this is to do lookups without locking
+        * the results, and lock the results afterwards; then at the
+        * end we can avoid trying to lock v2 if v2 == v1.
+        *
+        * However, for the reasons described in the fdvp == tdvp case
+        * in rename below, we can't do that safely. So, in the case
+        * where v1 is not a directory, unlock it and lock it again
+        * afterwards. This is safe in locking order because a
+        * non-directory can't be above anything else in the tree. If
+        * v1 *is* a directory, that's not true, but then because d1
+        * != d2, v1 != v2.
+        */
+       if (v1 && v1->v_type != VDIR) {
+               VOP_UNLOCK(v1);
+       }
+       vn_lock(d2, LK_EXCLUSIVE | LK_RETRY);
+       if (VTOI(d2)->i_size == 0) {
+               /* d2 has been rmdir'd */
+               VOP_UNLOCK(d2);
+               if (v1 && v1->v_type == VDIR) {
+                       VOP_UNLOCK(v1);
+               }
+               VOP_UNLOCK(d1);
+               if (v1) {
+                       vrele(v1);
+               }
+               return ENOENT;
+       }
+       error = do_relookup(d2, ulr2, &v2, cn2);
+       if (v2_missing_ok) {
+               if (error == ENOENT) {
+                       /* as above */
+                       v2 = NULL;
+                       error = 0;
+               }
+       } else {
+               if (error == 0 && v2 == NULL) {
+                       /* This is what relookup sets if v2 disappeared. */
+                       error = ENOENT;
+               }
+       }
+       if (error) {
+               VOP_UNLOCK(d2);
+               if (v1 && v1->v_type == VDIR) {
+                       VOP_UNLOCK(v1);
+               }
+               VOP_UNLOCK(d1);
+               if (v1) {
+                       vrele(v1);
+               }
+               return error;
+       }
+       if (v1 && v1->v_type != VDIR && v1 != v2) {
+               vn_lock(v1, LK_EXCLUSIVE | LK_RETRY);
+       }
+       *v1_ret = v1;
+       *v2_ret = v2;
+       return 0;
+}
+
+/*
+ * Rename vnode operation
+ *     rename("foo", "bar");
+ * is essentially
+ *     unlink("bar");
+ *     link("foo", "bar");
+ *     unlink("foo");
+ * but ``atomically''.  Can't do full commit without saving state in the
+ * inode on disk which isn't feasible at this time.  Best we can do is
+ * always guarantee the target exists.
+ *
+ * Basic algorithm is:
+ *
+ * 1) Bump link count on source while we're linking it to the
+ *    target.  This also ensure the inode won't be deleted out
+ *    from underneath us while we work (it may be truncated by
+ *    a concurrent `trunc' or `open' for creation).
+ * 2) Link source to destination.  If destination already exists,
+ *    delete it first.
+ * 3) Unlink source reference to inode if still around. If a
+ *    directory was moved and the parent of the destination
+ *    is different from the source, patch the ".." entry in the
+ *    directory.
+ *
+ * WAPBL NOTE: wapbl_ufs_rename derived from ufs_rename in ufs_vnops.c
+ * ufs_vnops.c netbsd cvs revision 1.108
+ * which has the berkeley copyright above
+ * changes introduced to ufs_rename since netbsd cvs revision 1.164
+ * will need to be ported into wapbl_ufs_rename
+ */
+int
+wapbl_ufs_rename(void *v)
+{
+       struct vop_rename_args  /* {
+               struct vnode            *a_fdvp;
+               struct vnode            *a_fvp;
+               struct componentname    *a_fcnp;
+               struct vnode            *a_tdvp;
+               struct vnode            *a_tvp;
+               struct componentname    *a_tcnp;
+       } */ *ap = v;
+       struct vnode            *tvp, *tdvp, *fvp, *fdvp;
+       struct componentname    *tcnp, *fcnp;
+       struct inode            *ip, *txp, *fxp, *tdp, *fdp;
+       struct mount            *mp;
+       struct direct           *newdir;
+       int                     doingdirectory, oldparent, newparent, error;
+
+       struct ufs_lookup_results from_ulr, to_ulr;
+
+       tvp = ap->a_tvp;
+       tdvp = ap->a_tdvp;
+       fvp = ap->a_fvp;
+       fdvp = ap->a_fdvp;
+       tcnp = ap->a_tcnp;
+       fcnp = ap->a_fcnp;
+       doingdirectory = oldparent = newparent = error = 0;
+
+       /* save the supplemental lookup results as they currently exist */
+       from_ulr = VTOI(fdvp)->i_crap;
+       to_ulr = VTOI(tdvp)->i_crap;
+       UFS_CHECK_CRAPCOUNTER(VTOI(fdvp));
+       UFS_CHECK_CRAPCOUNTER(VTOI(tdvp));
+
+       /*
+        * Owing to VFS oddities we are currently called with tdvp/tvp
+        * locked and not fdvp/fvp. In a sane world we'd be passed
+        * tdvp and fdvp only, unlocked, and two name strings. Pretend
+        * we have a sane world and unlock tdvp and tvp.
+        */
+       VOP_UNLOCK(tdvp);
+       if (tvp && tvp != tdvp) {
+               VOP_UNLOCK(tvp);
+       }
+
+       /* Also pretend we have a sane world and vrele fvp/tvp. */
+       vrele(fvp);
+       fvp = NULL;
+       if (tvp) {
+               vrele(tvp);
+               tvp = NULL;
+       }
+
+       /*
+        * Check for cross-device rename.
+        */
+       if (fdvp->v_mount != tdvp->v_mount) {
+               error = EXDEV;
+               goto abort;
+       }
+
+       /*
+        * Reject "." and ".."
+        */
+       if ((fcnp->cn_flags & ISDOTDOT) || (tcnp->cn_flags & ISDOTDOT) ||
+           (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
+           (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.')) {
+               error = EINVAL;
+               goto abort;
+       }
+           
+       /*
+        * Get locks.
+        */



Home | Main Index | Thread Index | Old Index