hammer2 - Revamp snapshot code
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 1 Oct 2013 00:40:40 +0000 (17:40 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 1 Oct 2013 00:40:40 +0000 (17:40 -0700)
* Change the snapshot code to not use chain_duplicate().  Instead
  get the thing working by flushing the original sub-tree, creating
  a new directory under the super-root, and then simply copying the
  blockset.

  The previous code called chain_duplicate() to create the snapshot
  but the coding still required a flush.  Doing it without a flush
  is possible for a read-only snapshot but very difficult otherwise.

* This will simplify coding down the line.

sys/vfs/hammer2/hammer2.h
sys/vfs/hammer2/hammer2_chain.c
sys/vfs/hammer2/hammer2_flush.c
sys/vfs/hammer2/hammer2_inode.c
sys/vfs/hammer2/hammer2_ioctl.c
sys/vfs/hammer2/hammer2_vfsops.c

index 8518062..beacd55 100644 (file)
@@ -203,7 +203,7 @@ RB_PROTOTYPE(hammer2_chain_tree, hammer2_chain, rbnode, hammer2_chain_cmp);
 #define HAMMER2_CHAIN_DEFERRED         0x00000200      /* on a deferral list */
 #define HAMMER2_CHAIN_DESTROYED                0x00000400      /* destroying inode */
 #define HAMMER2_CHAIN_VOLUMESYNC       0x00000800      /* needs volume sync */
-#define HAMMER2_CHAIN_RECYCLE          0x00001000      /* force recycle */
+#define HAMMER2_CHAIN_UNUSED1000       0x00001000
 #define HAMMER2_CHAIN_MOUNTED          0x00002000      /* PFS is mounted */
 #define HAMMER2_CHAIN_ONRBTREE         0x00004000      /* on parent RB tree */
 #define HAMMER2_CHAIN_SNAPSHOT         0x00008000      /* snapshot special */
index f413186..f06bd15 100644 (file)
@@ -461,6 +461,7 @@ hammer2_chain_lastdrop(hammer2_chain_t *chain)
                 * would revert to the prior deleted chain.
                 */
                if ((chain->flags & HAMMER2_CHAIN_DELETED) == 0 &&
+                   (chain->flags & HAMMER2_CHAIN_SNAPSHOT) == 0 &&
                    TAILQ_FIRST(&core->ownerq) != chain) {
                        if (atomic_cmpset_int(&chain->refs, 1, 0))
                                chain = NULL;   /* success */
@@ -2558,9 +2559,12 @@ hammer2_chain_duplicate(hammer2_trans_t *trans, hammer2_chain_t *parent,
        hmp = ochain->hmp;
        if (bref == NULL)
                bref = &ochain->bref;
-       nchain = hammer2_chain_alloc(hmp, ochain->pmp, trans, bref);
-       if (snapshot)
+       if (snapshot) {
+               nchain = hammer2_chain_alloc(hmp, NULL, trans, bref);
                atomic_set_int(&nchain->flags, HAMMER2_CHAIN_SNAPSHOT);
+       } else {
+               nchain = hammer2_chain_alloc(hmp, ochain->pmp, trans, bref);
+       }
        hammer2_chain_core_alloc(trans, nchain, ochain);
        bytes = (hammer2_off_t)1 <<
                (int)(bref->data_off & HAMMER2_OFF_MASK_RADIX);
@@ -2887,15 +2891,19 @@ hammer2_chain_snapshot(hammer2_trans_t *trans, hammer2_chain_t *ochain,
 {
        hammer2_mount_t *hmp;
        hammer2_chain_t *nchain;
-       hammer2_chain_t *chain;
-       hammer2_chain_t *parent;
        hammer2_inode_data_t *ipdata;
+       hammer2_inode_t *nip;
        size_t name_len;
-       hammer2_key_t key_dummy;
        hammer2_key_t lhc;
+#if 0
+       hammer2_chain_t *chain;
+       hammer2_chain_t *parent;
+       hammer2_key_t key_dummy;
+       int cache_index = -1;
+#endif
+       struct vattr vat;
        uuid_t opfs_clid;
        int error;
-       int cache_index = -1;
 
        name_len = strlen(pfs->name);
        lhc = hammer2_dirhash(pfs->name, name_len);
@@ -2905,6 +2913,55 @@ hammer2_chain_snapshot(hammer2_trans_t *trans, hammer2_chain_t *ochain,
        KKASSERT((trans->flags & HAMMER2_TRANS_RESTRICTED) == 0);
 
        /*
+        * Issue a restricted flush of the original.  This is a synchronous
+        * operation.  This will synchronize the blockrefs.
+        */
+       /* trans->flags |= HAMMER2_TRANS_RESTRICTED; */
+       hammer2_chain_flush(trans, ochain);
+       /* trans->flags &= ~HAMMER2_TRANS_RESTRICTED; */
+       kprintf("snapshot %s ochain->refs %d ochain->flags %08x\n",
+               pfs->name, ochain->refs, ochain->flags);
+
+       /*
+        * Create the snapshot directory under the super-root
+        *
+        * Set PFS type, generate a unique filesystem id, and generate
+        * a cluster id.  Use the same clid when snapshotting a PFS root,
+        * which theoretically allows the snapshot to be used as part of
+        * the same cluster (perhaps as a cache).
+        *
+        * Copy the (flushed) ochain's blockref array.  Theoretically we
+        * could use chain_duplicate() but it becomes difficult to disentangle
+        * the shared core so for now just brute-force it.
+        */
+       VATTR_NULL(&vat);
+       vat.va_type = VDIR;
+       vat.va_mode = 0755;
+       nchain = NULL;
+       nip = hammer2_inode_create(trans, hmp->sroot, &vat, proc0.p_ucred,
+                                  pfs->name, name_len, &nchain, &error);
+
+       if (nip) {
+               ipdata = hammer2_chain_modify_ip(trans, nip, &nchain, 0);
+               ipdata->pfs_type = HAMMER2_PFSTYPE_SNAPSHOT;
+               kern_uuidgen(&ipdata->pfs_fsid, 1);
+               if (ochain->flags & HAMMER2_CHAIN_PFSROOT)
+                       ipdata->pfs_clid = opfs_clid;
+               else
+                       kern_uuidgen(&ipdata->pfs_clid, 1);
+               atomic_set_int(&nchain->flags, HAMMER2_CHAIN_PFSROOT);
+               ipdata->u.blockset = ochain->data->ipdata.u.blockset;
+
+               hammer2_inode_unlock_ex(nip, nchain);
+       }
+       return (error);
+
+#if 0
+
+
+
+
+       /*
         * Get second lock for duplication to replace, original lock
         * will be left intact (caller must unlock the original chain).
         */
@@ -2914,7 +2971,6 @@ hammer2_chain_snapshot(hammer2_trans_t *trans, hammer2_chain_t *ochain,
        /*
         * Create disconnected duplicate flagged as a snapshot
         */
-       atomic_set_int(&nchain->flags, HAMMER2_CHAIN_RECYCLE);
        hammer2_chain_duplicate(trans, NULL, &nchain, NULL, 1);
 
        /*
@@ -2949,51 +3005,15 @@ hammer2_chain_snapshot(hammer2_trans_t *trans, hammer2_chain_t *ochain,
        ksnprintf(ipdata->filename, sizeof(ipdata->filename), "%s", pfs->name);
 
        /*
-        * Set PFS type, generate a unique filesystem id, and generate
-        * a cluster id.  Use the same clid when snapshotting a PFS root,
-        * which theoretically allows the snapshot to be used as part of
-        * the same cluster (perhaps as a cache).
-        */
-       ipdata->pfs_type = HAMMER2_PFSTYPE_SNAPSHOT;
-       kern_uuidgen(&ipdata->pfs_fsid, 1);
-       if (ochain->flags & HAMMER2_CHAIN_PFSROOT)
-               ipdata->pfs_clid = opfs_clid;
-       else
-               kern_uuidgen(&ipdata->pfs_clid, 1);
-       atomic_set_int(&nchain->flags, HAMMER2_CHAIN_PFSROOT);
-
-       /*
-        * Issue a restricted flush of the snapshot.  This is a synchronous
-        * operation.
+        * Unlock nchain.  This should cause nchain to be freed by virtue
+        * of its SNAPSHOT flag, which serves to disconnect its core.  If
+        * we were to retain nchain it would be a problem because the shared
+        * core would pick up changes made in the original after the snapshot
+        * operation has returned.
         */
-       trans->flags |= HAMMER2_TRANS_RESTRICTED;
-       kprintf("SNAPSHOTA\n");
-       tsleep(trans, 0, "snapslp", hz*4);
-       kprintf("SNAPSHOTB\n");
-       hammer2_chain_flush(trans, nchain);
-       trans->flags &= ~HAMMER2_TRANS_RESTRICTED;
-
-#if 0
-       /*
-        * Remove the link b/c nchain is a snapshot and snapshots don't
-        * follow CHAIN_DELETED semantics ?
-        */
-       chain = ip->chain;
-
-
-       KKASSERT(chain->duplink == nchain);
-       KKASSERT(chain->core == nchain->core);
-       KKASSERT(nchain->refs >= 2);
-       chain->duplink = nchain->duplink;
-       atomic_clear_int(&nchain->flags, HAMMER2_CHAIN_DUPTARGET);
-       hammer2_chain_drop(nchain);
-#endif
-
-       kprintf("snapshot %s nchain->refs %d nchain->flags %08x\n",
-               pfs->name, nchain->refs, nchain->flags);
+       kprintf("nchain refs %d %08x\n", nchain->refs, nchain->flags);
        hammer2_chain_unlock(nchain);
-
-       return (error);
+#endif
 }
 
 /*
index f1ad53c..98aa86f 100644 (file)
@@ -392,7 +392,9 @@ hammer2_chain_flush_core(hammer2_flush_info_t *info, hammer2_chain_t *chain)
        hammer2_off_t pbase;
        hammer2_off_t pmask;
        hammer2_tid_t saved_sync;
+#if 0
        hammer2_trans_t *trans = info->trans;
+#endif
        hammer2_chain_core_t *core;
        size_t psize;
        size_t boff;
@@ -425,6 +427,7 @@ hammer2_chain_flush_core(hammer2_flush_info_t *info, hammer2_chain_t *chain)
        if (chain->modify_tid > info->sync_tid)
                return;
 
+#if 0
        /*
         * Deleted chains which have not been destroyed must be retained,
         * and we probably have to recurse to clean-up any sub-trees.
@@ -438,6 +441,7 @@ hammer2_chain_flush_core(hammer2_flush_info_t *info, hammer2_chain_t *chain)
                if (trans->flags & HAMMER2_TRANS_RESTRICTED)
                        return;
        }
+#endif
 
        saved_sync = info->sync_tid;
        core = chain->core;
index ed72877..3bba430 100644 (file)
@@ -644,7 +644,7 @@ retry:
                nipdata->mode = vap->va_mode;
        nipdata->nlinks = 1;
        if (vap) {
-               if (dip) {
+               if (dip && dip->pmp) {
                        xuid = hammer2_to_unix_xid(&dip_uid);
                        xuid = vop_helper_create_uid(dip->pmp->mp,
                                                     dip_mode,
@@ -652,6 +652,7 @@ retry:
                                                     cred,
                                                     &vap->va_mode);
                } else {
+                       /* super-root has no dip and/or pmp */
                        xuid = 0;
                }
                if (vap->va_vaflags & VA_UID_UUID_VALID)
index 339b476..f161c30 100644 (file)
@@ -363,7 +363,7 @@ hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
        hmp = ip->pmp->cluster.chains[0]->hmp; /* XXX */
        pfs = data;
        parent = hammer2_inode_lock_ex(hmp->sroot);
-       rchain = ip->pmp->cluster.chains[0];    /* XXX */
+       rchain = hammer2_inode_lock_ex(ip->pmp->iroot);
 
        /*
         * Search for the first key or specific key.  Remember that keys
@@ -383,6 +383,8 @@ hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
                                             pfs->name_key, pfs->name_key,
                                             &cache_index, 0);
        }
+       hammer2_inode_unlock_ex(ip->pmp->iroot, rchain);
+
        while (chain && chain->bref.type != HAMMER2_BREF_TYPE_INODE) {
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                           key_next, (hammer2_key_t)-1,
index daad3db..ea65067 100644 (file)
@@ -623,20 +623,25 @@ hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data,
 
        if (rchain == NULL) {
                kprintf("hammer2_mount: PFS label not found\n");
+               --hmp->pmp_count;
                hammer2_vfs_unmount(mp, MNT_FORCE);
                return EINVAL;
        }
        if (rchain->flags & HAMMER2_CHAIN_MOUNTED) {
                hammer2_chain_unlock(rchain);
                kprintf("hammer2_mount: PFS label already mounted!\n");
+               --hmp->pmp_count;
                hammer2_vfs_unmount(mp, MNT_FORCE);
                return EBUSY;
        }
+#if 0
        if (rchain->flags & HAMMER2_CHAIN_RECYCLE) {
                kprintf("hammer2_mount: PFS label currently recycling\n");
+               --hmp->pmp_count;
                hammer2_vfs_unmount(mp, MNT_FORCE);
                return EBUSY;
        }
+#endif
 
        atomic_set_int(&rchain->flags, HAMMER2_CHAIN_MOUNTED);
 
@@ -1371,6 +1376,8 @@ hammer2_vfs_unmount(struct mount *mp, int mntflags)
        ccms_domain_uninit(&pmp->ccms_dom);
        kdmsg_iocom_uninit(&pmp->iocom);        /* XXX chain dependency */
 
+       lockmgr(&hammer2_mntlk, LK_EXCLUSIVE);
+
        for (i = 0; i < pmp->cluster.nchains; ++i) {
                hmp = pmp->cluster.chains[i]->hmp;
 
@@ -1390,10 +1397,9 @@ hammer2_vfs_unmount(struct mount *mp, int mntflags)
 
                if (error) {
                        hammer2_mount_unlock(hmp);
-                       return error;
+                       goto failed;
                }
 
-               lockmgr(&hammer2_mntlk, LK_EXCLUSIVE);
                --hmp->pmp_count;
                kprintf("hammer2_unmount hmp=%p pmpcnt=%d\n",
                        hmp, hmp->pmp_count);
@@ -1517,6 +1523,9 @@ hammer2_vfs_unmount(struct mount *mp, int mntflags)
        kmalloc_destroy(&pmp->minode);
 
        kfree(pmp, M_HAMMER2);
+       error = 0;
+
+failed:
        lockmgr(&hammer2_mntlk, LK_RELEASE);
 
        return (error);