hammer2 - Get snapshots working again master
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 1 Aug 2014 06:03:51 +0000 (23:03 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 1 Aug 2014 06:03:51 +0000 (23:03 -0700)
* Clean up null-pointer dereference panics and sequencing issues when
  creating a snapshot.

* Fix panic on mount if the requested label is not found or is not
  mountable.

* Automatically flush the snapshot before taking and automatically flush
  the super-root entry before returning.

sys/vfs/hammer2/hammer2.h
sys/vfs/hammer2/hammer2_cluster.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 86a7542..fecd0cc 100644 (file)
@@ -293,7 +293,7 @@ RB_PROTOTYPE(hammer2_chain_tree, hammer2_chain, rbnode, hammer2_chain_cmp);
 #define HAMMER2_CHAIN_BMAPPED          0x00040000      /* present in blkmap */
 #define HAMMER2_CHAIN_BMAPUPD          0x00080000      /* +needs updating */
 #define HAMMER2_CHAIN_UNUSED00100000   0x00100000
-#define HAMMER2_CHAIN_PFSROOT          0x00200000      /* in pfs->cluster */
+#define HAMMER2_CHAIN_UNUSED00200000   0x00200000
 #define HAMMER2_CHAIN_PFSBOUNDARY      0x00400000      /* super->pfs inode */
 
 #define HAMMER2_CHAIN_FLUSH_MASK       (HAMMER2_CHAIN_MODIFIED |       \
index 591de55..56866e0 100644 (file)
@@ -967,6 +967,7 @@ hammer2_cluster_snapshot(hammer2_trans_t *trans, hammer2_cluster_t *ocluster,
        struct vattr vat;
        uuid_t opfs_clid;
        int error;
+       int i;
 
        kprintf("snapshot %s\n", pfs->name);
 
@@ -1001,17 +1002,35 @@ hammer2_cluster_snapshot(hammer2_trans_t *trans, hammer2_cluster_t *ocluster,
                wipdata = hammer2_cluster_modify_ip(trans, nip, ncluster, 0);
                wipdata->pfs_type = HAMMER2_PFSTYPE_SNAPSHOT;
                kern_uuidgen(&wipdata->pfs_fsid, 1);
-               if (ocluster->focus->flags & HAMMER2_CHAIN_PFSROOT)
+               if (ocluster->focus->flags & HAMMER2_CHAIN_PFSBOUNDARY)
                        wipdata->pfs_clid = opfs_clid;
                else
                        kern_uuidgen(&wipdata->pfs_clid, 1);
-               hammer2_cluster_set_chainflags(ncluster, HAMMER2_CHAIN_PFSROOT);
+
+               for (i = 0; i < ncluster->nchains; ++i) {
+                       if (ncluster->array[i]) {
+                               ncluster->array[i]->bref.flags |=
+                                   HAMMER2_BREF_FLAG_PFSROOT;
+                       }
+               }
+#if 0
+               /* XXX can't set this unless we do an explicit flush, which
+                  we also need a pmp assigned to do, else the flush code
+                  won't flush ncluster because it thinks it is crossing a
+                  flush boundary */
+               hammer2_cluster_set_chainflags(ncluster,
+                                              HAMMER2_CHAIN_PFSBOUNDARY);
+#endif
 
                /* XXX hack blockset copy */
                /* XXX doesn't work with real cluster */
                KKASSERT(ocluster->nchains == 1);
                wipdata->u.blockset = ocluster->focus->data->ipdata.u.blockset;
                hammer2_cluster_modsync(ncluster);
+               for (i = 0; i < ncluster->nchains; ++i) {
+                       if (ncluster->array[i])
+                               hammer2_flush(trans, ncluster->array[i]);
+               }
                hammer2_inode_unlock_ex(nip, ncluster);
        }
        return (error);
index 140150a..74a0d6f 100644 (file)
@@ -526,14 +526,14 @@ hammer2_flush_core(hammer2_flush_info_t *info, hammer2_chain_t *chain,
        }
 
        hmp = chain->hmp;
-       pmp = chain->pmp;
+       pmp = chain->pmp;               /* can be NULL */
        diddeferral = info->diddeferral;
        parent = info->parent;          /* can be NULL */
 
        /*
         * mirror_tid should not be forward-indexed
         */
-       KKASSERT(chain->bref.mirror_tid <= pmp->flush_tid);
+       KKASSERT(pmp == NULL || chain->bref.mirror_tid <= pmp->flush_tid);
 
        /*
         * Downward search recursion
@@ -612,8 +612,10 @@ again:
                KKASSERT((chain->flags & HAMMER2_CHAIN_UPDATE) ||
                         chain == &hmp->vchain);
                atomic_clear_int(&chain->flags, HAMMER2_CHAIN_MODIFIED);
-               hammer2_pfs_memory_wakeup(pmp);
-               chain->bref.mirror_tid = pmp->flush_tid;
+               if (pmp) {
+                       hammer2_pfs_memory_wakeup(pmp);
+                       chain->bref.mirror_tid = pmp->flush_tid;
+               }
 
                if ((chain->flags & HAMMER2_CHAIN_UPDATE) ||
                    chain == &hmp->vchain ||
@@ -735,16 +737,15 @@ again:
                            HAMMER2_OPFLAG_PFSROOT) {
                                /*
                                 * non-NULL pmp if mounted as a PFS.  We must
-                                * sync fields cached in the pmp.
+                                * sync fields cached in the pmp? XXX
                                 */
                                hammer2_inode_data_t *ipdata;
 
                                ipdata = &chain->data->ipdata;
-                               ipdata->pfs_inum = pmp->inode_tid;
+                               if (pmp)
+                                       ipdata->pfs_inum = pmp->inode_tid;
                        } else {
                                /* can't be mounted as a PFS */
-                               KKASSERT((chain->flags &
-                                         HAMMER2_CHAIN_PFSROOT) == 0);
                        }
 
                        /*
@@ -924,7 +925,8 @@ again:
         */
 done:
        KKASSERT(chain->refs > 1);
-       KKASSERT(chain->bref.mirror_tid <= chain->pmp->flush_tid);
+       KKASSERT(pmp == NULL ||
+                chain->bref.mirror_tid <= chain->pmp->flush_tid);
        if (hammer2_debug & 0x200) {
                if (info->debug == chain)
                        info->debug = NULL;
index e64b495..678c492 100644 (file)
@@ -1331,6 +1331,7 @@ again:
                 * Target nlinks has reached 0, file now unlinked (but may
                 * still be open).
                 */
+               /* XXX need interlock if mounted
                if ((cluster->focus->flags & HAMMER2_CHAIN_PFSROOT) &&
                    cluster->pmp) {
                        error = EINVAL;
@@ -1339,6 +1340,7 @@ again:
                                wipdata->filename);
                        goto done;
                }
+               */
                if (nch && cache_isopen(nch)) {
                        hammer2_inode_move_to_hidden(trans, &cparent, &cluster,
                                                     wipdata->inum);
index bb85f85..eb27c1a 100644 (file)
@@ -595,7 +595,8 @@ hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data)
 
        hammer2_vfs_sync(ip->pmp->mp, MNT_WAIT);
 
-       hammer2_trans_init(&trans, ip->pmp, HAMMER2_TRANS_NEWINODE);
+       hammer2_trans_init(&trans, ip->pmp,
+                          HAMMER2_TRANS_ISFLUSH | HAMMER2_TRANS_NEWINODE);
        cparent = hammer2_inode_lock_ex(ip);
        error = hammer2_cluster_snapshot(&trans, cparent, pfs);
        hammer2_inode_unlock_ex(ip, cparent);
index cc190d6..ab5af70 100644 (file)
@@ -631,7 +631,6 @@ hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data,
                spmp->pfs_clid = schain->data->ipdata.pfs_clid;
 
                /*
-                * NOTE: The CHAIN_PFSROOT is not set on the super-root inode.
                 * NOTE: inode_get sucks up schain's lock.
                 */
                cluster = hammer2_cluster_from_chain(schain);
@@ -1687,9 +1686,11 @@ hammer2_vfs_unmount_hmp1(struct mount *mp, hammer2_mount_t *hmp)
         */
        hammer2_voldata_lock(hmp);
        hammer2_voldata_unlock(hmp);
-       hammer2_vfs_sync(mp, MNT_WAIT);
-       hammer2_vfs_sync(mp, MNT_WAIT);
-       hammer2_vfs_sync(mp, MNT_WAIT);
+       if (mp->mnt_data) {
+               hammer2_vfs_sync(mp, MNT_WAIT);
+               hammer2_vfs_sync(mp, MNT_WAIT);
+               hammer2_vfs_sync(mp, MNT_WAIT);
+       }
 
        if (hmp->pmp_count == 0) {
                if ((hmp->vchain.flags | hmp->fchain.flags) &