hammer2 - Refactor frontend part 13/many
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 26 Jun 2015 05:53:23 +0000 (22:53 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 27 Jun 2015 02:16:12 +0000 (19:16 -0700)
* Fix improper unlock in xop_scanlhc.

* Move the flush sequencing to the XOP backend.

* Make a kmalloc'd copy of the namecache name for backends still
  in-progress when the frontend returns (we will need to do something
  similar for bio data too).

* Do not pass the nch to hammer2_unlink_file(), pass more portable
  integer state instead.

sys/vfs/hammer2/TODO
sys/vfs/hammer2/hammer2.h
sys/vfs/hammer2/hammer2_flush.c
sys/vfs/hammer2/hammer2_inode.c
sys/vfs/hammer2/hammer2_ioctl.c
sys/vfs/hammer2/hammer2_thread.c
sys/vfs/hammer2/hammer2_vfsops.c
sys/vfs/hammer2/hammer2_vnops.c
sys/vfs/hammer2/hammer2_xops.c

index 83c6e1d..05f174f 100644 (file)
@@ -1,4 +1,6 @@
 
+* See if we can remove hammer2_inode_repoint()
+
 * FIXME - logical buffer associated with write-in-progress on backend
   disappears once the cluster validates, even if more backend nodes
   are in progress.
index 256dbff..4d75245 100644 (file)
@@ -838,6 +838,8 @@ struct hammer2_xop_head {
        uint32_t                chk_mask;
        int                     state;
        int                     error;
+       char                    *name;
+       size_t                  name_len;
        hammer2_key_t           lkey;
        hammer2_key_t           nkey;
        hammer2_xop_fifo_t      collect[HAMMER2_MAXCLUSTER];
@@ -859,8 +861,6 @@ struct hammer2_xop_readdir {
 
 struct hammer2_xop_nresolve {
        hammer2_xop_head_t      head;
-       const char              *name;
-       size_t                  name_len;
 };
 
 struct hammer2_xop_scanlhc {
@@ -873,8 +873,6 @@ struct hammer2_xop_create {
        hammer2_inode_meta_t    meta;           /* initial metadata */
        hammer2_key_t           lhc;
        int                     flags;
-       const char              *name;
-       size_t                  name_len;
 };
 
 struct hammer2_xop_destroy {
@@ -883,12 +881,17 @@ struct hammer2_xop_destroy {
        int                     flags;
 };
 
+struct hammer2_xop_flush {
+       hammer2_xop_head_t      head;
+};
+
 typedef struct hammer2_xop_readdir hammer2_xop_readdir_t;
 typedef struct hammer2_xop_nresolve hammer2_xop_nresolve_t;
 typedef struct hammer2_xop_strategy hammer2_xop_strategy_t;
 typedef struct hammer2_xop_create hammer2_xop_create_t;
 typedef struct hammer2_xop_destroy hammer2_xop_destroy_t;
 typedef struct hammer2_xop_scanlhc hammer2_xop_scanlhc_t;
+typedef struct hammer2_xop_flush hammer2_xop_flush_t;
 
 union hammer2_xop {
        hammer2_xop_head_t      head;
@@ -898,6 +901,7 @@ union hammer2_xop {
        hammer2_xop_create_t    xop_create;
        hammer2_xop_destroy_t   xop_destroy;
        hammer2_xop_scanlhc_t   xop_scanlhc;
+       hammer2_xop_flush_t     xop_flush;
 };
 
 typedef union hammer2_xop hammer2_xop_t;
@@ -917,6 +921,7 @@ typedef struct hammer2_xop_group hammer2_xop_group_t;
  * flags to hammer2_xop_collect()
  */
 #define HAMMER2_XOP_COLLECT_NOWAIT     0x00000001
+#define HAMMER2_XOP_COLLECT_WAITALL    0x00000002
 
 /*
  * flags to hammer2_xop_alloc()
@@ -1243,7 +1248,7 @@ hammer2_inode_t *hammer2_inode_common_parent(hammer2_inode_t *fdip,
 void hammer2_inode_fsync(hammer2_inode_t *ip, hammer2_cluster_t *cparent);
 int hammer2_unlink_file(hammer2_inode_t *dip, hammer2_inode_t *ip,
                        const uint8_t *name, size_t name_len, int isdir,
-                       int *hlinkp, struct nchandle *nch, int nlinks);
+                       int *hlinkp, int isopen, int isrename);
 int hammer2_cluster_hardlink_consolidate(hammer2_inode_t *ip,
                        hammer2_cluster_t **clusterp,
                        hammer2_inode_t *cdip, hammer2_cluster_t *cdcluster,
@@ -1405,6 +1410,7 @@ void hammer2_xop_nresolve(hammer2_xop_t *xop, int clidx);
 void hammer2_inode_xop_scanlhc(hammer2_xop_t *xop, int clidx);
 void hammer2_inode_xop_create(hammer2_xop_t *xop, int clidx);
 void hammer2_inode_xop_destroy(hammer2_xop_t *xop, int clidx);
+void hammer2_inode_xop_flush(hammer2_xop_t *xop, int clidx);
 #if 0
 int hammer2_xop_nmkdir(struct vop_nmkdir_args *ap);
 int hammer2_xop_advlock(struct vop_advlock_args *ap);
index f2ea67d..b5eb675 100644 (file)
@@ -991,3 +991,165 @@ hammer2_flush_recurse(hammer2_chain_t *child, void *data)
 
        return (0);
 }
+
+/*
+ * flush helper (backend threaded)
+ *
+ * Flushes core chains, issues disk sync, flushes volume roots.
+ *
+ * Primarily called from vfs_sync().
+ */
+void
+hammer2_inode_xop_flush(hammer2_xop_t *arg, int clindex)
+{
+       hammer2_xop_flush_t *xop = &arg->xop_flush;
+       hammer2_chain_t *chain;
+       hammer2_chain_t *parent;
+       hammer2_dev_t *hmp;
+       int error = 0;
+       int total_error = 0;
+       int j;
+
+       /*
+        * Flush core chains
+        */
+       chain = hammer2_inode_chain(xop->head.ip, clindex,
+                                   HAMMER2_RESOLVE_ALWAYS);
+       if (chain) {
+               hmp = chain->hmp;
+               if (chain->flags & HAMMER2_CHAIN_FLUSH_MASK) {
+                       hammer2_flush(chain, 1);
+                       parent = chain->parent;
+                       KKASSERT(chain->pmp != parent->pmp);
+                       hammer2_chain_setflush(parent);
+               }
+               hammer2_chain_unlock(chain);
+               hammer2_chain_drop(chain);
+               chain = NULL;
+       } else {
+               hmp = NULL;
+       }
+
+       /*
+        * Flush volume roots.  Avoid replication, we only want to
+        * flush each hammer2_dev (hmp) once.
+        */
+       for (j = clindex - 1; j >= 0; --j) {
+               if ((chain = xop->head.ip->cluster.array[j].chain) != NULL) {
+                       if (chain->hmp == hmp) {
+                               chain = NULL;   /* safety */
+                               goto skip;
+                       }
+               }
+       }
+       chain = NULL;   /* safety */
+
+       /*
+        * spmp transaction.  The super-root is never directly mounted so
+        * there shouldn't be any vnodes, let alone any dirty vnodes
+        * associated with it.
+        */
+       hammer2_trans_init(hmp->spmp, HAMMER2_TRANS_ISFLUSH);
+
+       /*
+        * Media mounts have two 'roots', vchain for the topology
+        * and fchain for the free block table.  Flush both.
+        *
+        * Note that the topology and free block table are handled
+        * independently, so the free block table can wind up being
+        * ahead of the topology.  We depend on the bulk free scan
+        * code to deal with any loose ends.
+        */
+       hammer2_chain_ref(&hmp->vchain);
+       hammer2_chain_lock(&hmp->vchain, HAMMER2_RESOLVE_ALWAYS);
+       hammer2_chain_ref(&hmp->fchain);
+       hammer2_chain_lock(&hmp->fchain, HAMMER2_RESOLVE_ALWAYS);
+       if (hmp->fchain.flags & HAMMER2_CHAIN_FLUSH_MASK) {
+               /*
+                * This will also modify vchain as a side effect,
+                * mark vchain as modified now.
+                */
+               hammer2_voldata_modify(hmp);
+               chain = &hmp->fchain;
+               hammer2_flush(chain, 1);
+               KKASSERT(chain == &hmp->fchain);
+       }
+       hammer2_chain_unlock(&hmp->fchain);
+       hammer2_chain_unlock(&hmp->vchain);
+       hammer2_chain_drop(&hmp->fchain);
+       /* vchain dropped down below */
+
+       hammer2_chain_lock(&hmp->vchain, HAMMER2_RESOLVE_ALWAYS);
+       if (hmp->vchain.flags & HAMMER2_CHAIN_FLUSH_MASK) {
+               chain = &hmp->vchain;
+               hammer2_flush(chain, 1);
+               KKASSERT(chain == &hmp->vchain);
+       }
+       hammer2_chain_unlock(&hmp->vchain);
+       hammer2_chain_drop(&hmp->vchain);
+
+       error = 0;
+
+       /*
+        * We can't safely flush the volume header until we have
+        * flushed any device buffers which have built up.
+        *
+        * XXX this isn't being incremental
+        */
+       vn_lock(hmp->devvp, LK_EXCLUSIVE | LK_RETRY);
+       error = VOP_FSYNC(hmp->devvp, MNT_WAIT, 0);
+       vn_unlock(hmp->devvp);
+
+       /*
+        * The flush code sets CHAIN_VOLUMESYNC to indicate that the
+        * volume header needs synchronization via hmp->volsync.
+        *
+        * XXX synchronize the flag & data with only this flush XXX
+        */
+       if (error == 0 &&
+           (hmp->vchain.flags & HAMMER2_CHAIN_VOLUMESYNC)) {
+               struct buf *bp;
+
+               /*
+                * Synchronize the disk before flushing the volume
+                * header.
+                */
+               bp = getpbuf(NULL);
+               bp->b_bio1.bio_offset = 0;
+               bp->b_bufsize = 0;
+               bp->b_bcount = 0;
+               bp->b_cmd = BUF_CMD_FLUSH;
+               bp->b_bio1.bio_done = biodone_sync;
+               bp->b_bio1.bio_flags |= BIO_SYNC;
+               vn_strategy(hmp->devvp, &bp->b_bio1);
+               biowait(&bp->b_bio1, "h2vol");
+               relpbuf(bp, NULL);
+
+               /*
+                * Then we can safely flush the version of the
+                * volume header synchronized by the flush code.
+                */
+               j = hmp->volhdrno + 1;
+               if (j >= HAMMER2_NUM_VOLHDRS)
+                       j = 0;
+               if (j * HAMMER2_ZONE_BYTES64 + HAMMER2_SEGSIZE >
+                   hmp->volsync.volu_size) {
+                       j = 0;
+               }
+               kprintf("sync volhdr %d %jd\n",
+                       j, (intmax_t)hmp->volsync.volu_size);
+               bp = getblk(hmp->devvp, j * HAMMER2_ZONE_BYTES64,
+                           HAMMER2_PBUFSIZE, 0, 0);
+               atomic_clear_int(&hmp->vchain.flags,
+                                HAMMER2_CHAIN_VOLUMESYNC);
+               bcopy(&hmp->volsync, bp->b_data, HAMMER2_PBUFSIZE);
+               bawrite(bp);
+               hmp->volhdrno = j;
+       }
+       if (error)
+               total_error = error;
+
+       hammer2_trans_done(hmp->spmp);  /* spmp trans */
+skip:
+       error = hammer2_xop_feed(&xop->head, NULL, clindex, total_error);
+}
index 117fc0e..ee577a0 100644 (file)
@@ -625,6 +625,7 @@ hammer2_inode_create(hammer2_inode_t *dip,
        hammer2_xop_scanlhc_t *sxop;
        hammer2_xop_create_t *xop;
        hammer2_inode_t *nip;
+       hammer2_key_t lhcbase;
        hammer2_key_t lhc;
        int error;
        uid_t xuid;
@@ -661,6 +662,7 @@ hammer2_inode_create(hammer2_inode_t *dip,
        /*
         * Locate an unused key in the collision space.
         */
+       lhcbase = lhc;
        sxop = &hammer2_xop_alloc(dip)->xop_scanlhc;
        sxop->lhc = lhc;
        hammer2_xop_start(&sxop->head, hammer2_inode_xop_scanlhc);
@@ -677,7 +679,7 @@ hammer2_inode_create(hammer2_inode_t *dip,
                ++lhc;
                error = 0;
        }
-       if ((sxop->lhc ^ lhc) & ~HAMMER2_DIRHASH_LOMASK) {
+       if ((lhcbase ^ lhc) & ~HAMMER2_DIRHASH_LOMASK) {
                error = ENOSPC;
                goto done2;
        }
@@ -754,8 +756,9 @@ hammer2_inode_create(hammer2_inode_t *dip,
                xop->meta.op_flags |= HAMMER2_OPFLAG_DIRECTDATA;
        }
 
-       xop->name = name;
-       xop->name_len = name_len;
+       xop->head.name = kmalloc(name_len + 1, M_HAMMER2, M_WAITOK | M_ZERO);
+       xop->head.name_len = name_len;
+       bcopy(name, xop->head.name, name_len);
        xop->meta.name_len = name_len;
        xop->meta.name_key = lhc;
        KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
@@ -1179,8 +1182,8 @@ hammer2_inode_repoint_one(hammer2_inode_t *ip, hammer2_cluster_t *cluster,
 int
 hammer2_unlink_file(hammer2_inode_t *dip, hammer2_inode_t *ip,
                    const uint8_t *name, size_t name_len,
-                   int isdir, int *hlinkp, struct nchandle *nch,
-                   int nlinks)
+                   int isdir, int *hlinkp,
+                   int isopen, int isrename)
 {
        const hammer2_inode_data_t *ripdata;
        hammer2_cluster_t *cparent;
@@ -1353,10 +1356,6 @@ again:
         *       (which does not represent a ref for the open-test), and to
         *       force finalization of the vnode if/when the last ref gets
         *       dropped.
-        *
-        * NOTE! Files are unlinked by rename and then relinked.  nch will be
-        *       passed as NULL in this situation.  hammer2_inode_connect()
-        *       will bump nlinks.
         */
        KKASSERT(cluster != NULL);
 
@@ -1373,28 +1372,29 @@ again:
         * Note: nlinks is negative when decrementing, positive when
         *       incrementing.
         */
-       last_link = (ip->meta.nlinks + nlinks == 0);
+       last_link = (ip->meta.nlinks - (isrename ? 0 : 1) == 0);
 
        if (last_link) {
                /*
                 * Target nlinks has reached 0, file now unlinked (but may
                 * still be open).
                 *
-                * nlinks will be -1 for a normal remove().  If this is the
-                * last link we must flag the inode so we can optimally
-                * throw away buffer data and destroy the file on reclaim.
+                * On the last link when not renaming, we have to special
+                * case the file if it is still open to prevent the bulk
+                * free from freeing blocks out from under it.
                 */
-               if (nlinks == -1)
+               if (isrename == 0)
                        atomic_set_int(&ip->flags, HAMMER2_INODE_ISUNLINKED);
 
-               if (nch && cache_isopen(nch)) {
+               if (isrename == 0 && isopen) {
                        /*
                         * If an unlinked file is still open we must update
                         * the inodes link count.
                         */
                        /*hammer2_cluster_modify(cluster, 0);*/
                        hammer2_inode_modify(ip);
-                       ip->meta.nlinks += nlinks;
+                       if (isrename == 0)
+                               --ip->meta.nlinks;
                        if ((int64_t)ip->meta.nlinks < 0)       /* safety */
                                ip->meta.nlinks = 0;
                        hammer2_inode_move_to_hidden(&cparent, &cluster,
@@ -1413,15 +1413,15 @@ again:
                /*
                 * In this situation a normal non-hardlinked file (which can
                 * only have nlinks == 1) still has a non-zero nlinks, the
-                * caller must be doing a RENAME operation and so is passing
-                * a nlinks adjustment of 0, and only wishes to remove file
-                * in order to be able to reconnect it under a different name.
+                * caller must be doing a RENAME operation, and only wishes
+                * to remove file in order to be able to reconnect it under
+                * a different name.
                 *
                 * In this situation we do a temporary deletion of the
                 * chain in order to allow the file to be reconnected in
                 * a different location.
                 */
-               KKASSERT(nlinks == 0);
+               KKASSERT(isrename != 0);
                hammer2_cluster_delete(cparent, cluster, 0);
        } else {
                /*
@@ -1429,7 +1429,8 @@ again:
                 */
                /*hammer2_cluster_modify(cluster, 0);*/
                hammer2_inode_modify(ip);
-               ip->meta.nlinks += nlinks;
+               if (isrename == 0)
+                       --ip->meta.nlinks;
                if ((int64_t)ip->meta.nlinks < 0)
                        ip->meta.nlinks = 0;
                /* hammer2_cluster_modsync(cluster); */
@@ -1770,3 +1771,70 @@ hammer2_inode_fsync(hammer2_inode_t *ip, hammer2_cluster_t *cparent)
                hammer2_cluster_modsync(cparent);
        }
 }
+
+/*
+ * Inode create helper (threaded, backend).
+ *
+ * Frontend holds the parent directory ip locked exclusively.  We
+ * create the inode and feed the exclusively locked chain to the
+ * frontend.
+ */
+void
+hammer2_inode_xop_create(hammer2_xop_t *arg, int clindex)
+{
+       hammer2_xop_create_t *xop = &arg->xop_create;
+       hammer2_chain_t *parent;
+       hammer2_chain_t *chain;
+       hammer2_key_t key_next;
+       int cache_index = -1;
+       int error;
+
+       chain = NULL;
+       parent = hammer2_inode_chain(xop->head.ip, clindex,
+                                    HAMMER2_RESOLVE_ALWAYS);
+       if (parent == NULL) {
+               error = EIO;
+               goto fail;
+       }
+       chain = hammer2_chain_lookup(&parent, &key_next,
+                                    xop->lhc, xop->lhc,
+                                    &cache_index, 0);
+       if (chain) {
+               hammer2_chain_unlock(chain);
+               error = EEXIST;
+               goto fail;
+       }
+
+       error = hammer2_chain_create(&parent, &chain,
+                                    xop->head.ip->pmp,
+                                    xop->lhc, 0,
+                                    HAMMER2_BREF_TYPE_INODE,
+                                    HAMMER2_INODE_BYTES,
+                                    xop->flags);
+       if (error == 0) {
+               hammer2_chain_modify(chain, 0);
+               chain->data->ipdata.meta = xop->meta;
+               bcopy(xop->head.name, chain->data->ipdata.filename,
+                     xop->head.name_len);
+       }
+       hammer2_chain_unlock(chain);
+       hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS |
+                                 HAMMER2_RESOLVE_SHARED);
+fail:
+       if (parent) {
+               hammer2_chain_unlock(parent);
+               hammer2_chain_drop(parent);
+       }
+       error = hammer2_xop_feed(&xop->head, chain, clindex, error);
+       if (chain)
+               hammer2_chain_drop(chain);
+}
+
+/*
+ * Inode delete helper
+ */
+void
+hammer2_inode_xop_destroy(hammer2_xop_t *arg, int clindex)
+{
+       /*hammer2_xop_inode_t *xop = &arg->xop_inode;*/
+}
index 235408b..baef345 100644 (file)
@@ -615,7 +615,7 @@ hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data)
        hammer2_trans_init(hmp->spmp, 0);
        error = hammer2_unlink_file(hmp->spmp->iroot, NULL,
                                    pfs->name, strlen(pfs->name),
-                                   2, NULL, NULL, -1);
+                                   2, NULL, 0, 0);
        hammer2_trans_done(hmp->spmp);
 
        return (error);
index 74d676d..95886d0 100644 (file)
@@ -963,6 +963,7 @@ hammer2_xop_alloc(hammer2_inode_t *ip)
        hammer2_xop_t *xop;
 
        xop = objcache_get(cache_xops, M_WAITOK);
+       KKASSERT(xop->head.cluster.array[0].chain == NULL);
        xop->head.ip = ip;
        xop->head.func = NULL;
        xop->head.state = 0;
@@ -1003,7 +1004,6 @@ hammer2_xop_helper_create(hammer2_pfs_t *pmp)
        int i;
        int j;
 
-       kprintf("XOP_HELPER_CREATE: %d\n",  pmp->pfs_nmasters);
        for (i = 0; i < pmp->pfs_nmasters; ++i) {
                for (j = 0; j < HAMMER2_XOPGROUPS; ++j) {
                        if (pmp->xop_groups[j].thrs[i].td)
@@ -1136,6 +1136,11 @@ hammer2_xop_retire(hammer2_xop_head_t *xop, uint32_t mask)
                hammer2_inode_drop(xop->ip);
                xop->ip = NULL;
        }
+       if (xop->name) {
+               kfree(xop->name, M_HAMMER2);
+               xop->name = NULL;
+               xop->name_len = 0;
+       }
 
        objcache_put(cache_xops, xop);
 }
index 4ea12e5..cdca8b1 100644 (file)
@@ -1817,17 +1817,12 @@ hammer2_recovery_scan(hammer2_dev_t *hmp, hammer2_chain_t *parent,
 int
 hammer2_vfs_sync(struct mount *mp, int waitfor)
 {
+       hammer2_xop_flush_t *xop;
        struct hammer2_sync_info info;
        hammer2_inode_t *iroot;
-       hammer2_chain_t *chain;
-       hammer2_chain_t *parent;
        hammer2_pfs_t *pmp;
-       hammer2_dev_t *hmp;
        int flags;
        int error;
-       int total_error;
-       int i;
-       int j;
 
        pmp = MPTOPMP(mp);
        iroot = pmp->iroot;
@@ -1891,173 +1886,29 @@ hammer2_vfs_sync(struct mount *mp, int waitfor)
        hammer2_bioq_sync(pmp);
        atomic_clear_int(&pmp->trans.flags, HAMMER2_TRANS_PREFLUSH);
 
-       total_error = 0;
-
        /*
-        * Flush all nodes to synchronize the PFSROOT subtopology to the media.
+        * Use the XOP interface to concurrently flush all nodes to
+        * synchronize the PFSROOT subtopology to the media.  A standard
+        * end-of-scan ENOENT error indicates cluster sufficiency.
         *
         * Note that this flush will not be visible on crash recovery until
         * we flush the super-root topology in the next loop.
-        */
-       for (i = 0; iroot && i < iroot->cluster.nchains; ++i) {
-               chain = iroot->cluster.array[i].chain;
-               if (chain == NULL)
-                       continue;
-
-               hammer2_chain_ref(chain);
-               hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS);
-               if (chain->flags & HAMMER2_CHAIN_FLUSH_MASK) {
-                       hammer2_flush(chain, 1);
-                       parent = chain->parent;
-                       KKASSERT(chain->pmp != parent->pmp);
-                       hammer2_chain_setflush(parent);
-               }
-               hammer2_chain_unlock(chain);
-               hammer2_chain_drop(chain);
-       }
-       hammer2_trans_done(pmp);
-
-       /*
-        * Flush all volume roots to synchronize PFS flushes with the
-        * storage media volume header.  This will flush the freemap and
-        * the superroot topology but stops when it reaches a PFSROOT
-        * (which we already flushed above).
         *
-        * This is the last step which connects the volume root to the
-        * PFSROOT dirs flushed above.
-        *
-        * Each spmp (representing the hmp's super-root) requires its own
-        * transaction.
+        * XXX For now wait for all flushes to complete.
         */
-       for (i = 0; iroot && i < iroot->cluster.nchains; ++i) {
-               hammer2_chain_t *tmp;
-
-               chain = iroot->cluster.array[i].chain;
-               if (chain == NULL)
-                       continue;
-
-               hmp = chain->hmp;
-
-               /*
-                * We only have to flush each hmp once
-                */
-               for (j = i - 1; j >= 0; --j) {
-                       if ((tmp = iroot->cluster.array[j].chain) != NULL) {
-                               if (tmp->hmp == hmp)
-                                       break;
-                       }
-               }
-               if (j >= 0)
-                       continue;
-
-               /*
-                * spmp transaction.  The super-root is never directly
-                * mounted so there shouldn't be any vnodes, let alone any
-                * dirty vnodes associated with it.
-                */
-               hammer2_trans_init(hmp->spmp, HAMMER2_TRANS_ISFLUSH);
-
-               /*
-                * Media mounts have two 'roots', vchain for the topology
-                * and fchain for the free block table.  Flush both.
-                *
-                * Note that the topology and free block table are handled
-                * independently, so the free block table can wind up being
-                * ahead of the topology.  We depend on the bulk free scan
-                * code to deal with any loose ends.
-                */
-               hammer2_chain_ref(&hmp->vchain);
-               hammer2_chain_lock(&hmp->vchain, HAMMER2_RESOLVE_ALWAYS);
-               hammer2_chain_ref(&hmp->fchain);
-               hammer2_chain_lock(&hmp->fchain, HAMMER2_RESOLVE_ALWAYS);
-               if (hmp->fchain.flags & HAMMER2_CHAIN_FLUSH_MASK) {
-                       /*
-                        * This will also modify vchain as a side effect,
-                        * mark vchain as modified now.
-                        */
-                       hammer2_voldata_modify(hmp);
-                       chain = &hmp->fchain;
-                       hammer2_flush(chain, 1);
-                       KKASSERT(chain == &hmp->fchain);
-               }
-               hammer2_chain_unlock(&hmp->fchain);
-               hammer2_chain_unlock(&hmp->vchain);
-               hammer2_chain_drop(&hmp->fchain);
-               /* vchain dropped down below */
-
-               hammer2_chain_lock(&hmp->vchain, HAMMER2_RESOLVE_ALWAYS);
-               if (hmp->vchain.flags & HAMMER2_CHAIN_FLUSH_MASK) {
-                       chain = &hmp->vchain;
-                       hammer2_flush(chain, 1);
-                       KKASSERT(chain == &hmp->vchain);
-               }
-               hammer2_chain_unlock(&hmp->vchain);
-               hammer2_chain_drop(&hmp->vchain);
-
+       if (iroot) {
+               xop = &hammer2_xop_alloc(iroot)->xop_flush;
+               hammer2_xop_start(&xop->head, hammer2_inode_xop_flush);
+               error = hammer2_xop_collect(&xop->head,
+                                           HAMMER2_XOP_COLLECT_WAITALL);
+               if (error == ENOENT)
+                       error = 0;
+       } else {
                error = 0;
-
-               /*
-                * We can't safely flush the volume header until we have
-                * flushed any device buffers which have built up.
-                *
-                * XXX this isn't being incremental
-                */
-               vn_lock(hmp->devvp, LK_EXCLUSIVE | LK_RETRY);
-               error = VOP_FSYNC(hmp->devvp, MNT_WAIT, 0);
-               vn_unlock(hmp->devvp);
-
-               /*
-                * The flush code sets CHAIN_VOLUMESYNC to indicate that the
-                * volume header needs synchronization via hmp->volsync.
-                *
-                * XXX synchronize the flag & data with only this flush XXX
-                */
-               if (error == 0 &&
-                   (hmp->vchain.flags & HAMMER2_CHAIN_VOLUMESYNC)) {
-                       struct buf *bp;
-
-                       /*
-                        * Synchronize the disk before flushing the volume
-                        * header.
-                        */
-                       bp = getpbuf(NULL);
-                       bp->b_bio1.bio_offset = 0;
-                       bp->b_bufsize = 0;
-                       bp->b_bcount = 0;
-                       bp->b_cmd = BUF_CMD_FLUSH;
-                       bp->b_bio1.bio_done = biodone_sync;
-                       bp->b_bio1.bio_flags |= BIO_SYNC;
-                       vn_strategy(hmp->devvp, &bp->b_bio1);
-                       biowait(&bp->b_bio1, "h2vol");
-                       relpbuf(bp, NULL);
-
-                       /*
-                        * Then we can safely flush the version of the
-                        * volume header synchronized by the flush code.
-                        */
-                       i = hmp->volhdrno + 1;
-                       if (i >= HAMMER2_NUM_VOLHDRS)
-                               i = 0;
-                       if (i * HAMMER2_ZONE_BYTES64 + HAMMER2_SEGSIZE >
-                           hmp->volsync.volu_size) {
-                               i = 0;
-                       }
-                       kprintf("sync volhdr %d %jd\n",
-                               i, (intmax_t)hmp->volsync.volu_size);
-                       bp = getblk(hmp->devvp, i * HAMMER2_ZONE_BYTES64,
-                                   HAMMER2_PBUFSIZE, 0, 0);
-                       atomic_clear_int(&hmp->vchain.flags,
-                                        HAMMER2_CHAIN_VOLUMESYNC);
-                       bcopy(&hmp->volsync, bp->b_data, HAMMER2_PBUFSIZE);
-                       bawrite(bp);
-                       hmp->volhdrno = i;
-               }
-               if (error)
-                       total_error = error;
-
-               hammer2_trans_done(hmp->spmp);  /* spmp trans */
        }
-       return (total_error);
+       hammer2_trans_done(pmp);
+
+       return (error);
 }
 
 /*
index 42964da..5e8e704 100644 (file)
@@ -1074,8 +1074,10 @@ hammer2_vop_nresolve(struct vop_nresolve_args *ap)
        xop = &hammer2_xop_alloc(dip)->xop_nresolve;
 
        ncp = ap->a_nch->ncp;
-       xop->name = ncp->nc_name;
-       xop->name_len = ncp->nc_nlen;
+       xop->head.name = kmalloc(ncp->nc_nlen + 1, M_HAMMER2,
+                                M_WAITOK | M_ZERO);
+       xop->head.name_len = ncp->nc_nlen;
+       bcopy(ncp->nc_name, xop->head.name, ncp->nc_nlen);
 
        /*
         * Note: In DragonFly the kernel handles '.' and '..'.
@@ -1548,7 +1550,8 @@ hammer2_vop_nremove(struct vop_nremove_args *ap)
        hammer2_pfs_memory_wait(dip->pmp);
        hammer2_trans_init(dip->pmp, 0);
        error = hammer2_unlink_file(dip, NULL, name, name_len,
-                                   0, NULL, ap->a_nch, -1);
+                                   0, NULL,
+                                   cache_isopen(ap->a_nch), 0);
        hammer2_run_unlinkq(dip->pmp);
        hammer2_trans_done(dip->pmp);
        if (error == 0)
@@ -1585,7 +1588,8 @@ hammer2_vop_nrmdir(struct vop_nrmdir_args *ap)
        hammer2_trans_init(dip->pmp, 0);
        hammer2_run_unlinkq(dip->pmp);
        error = hammer2_unlink_file(dip, NULL, name, name_len,
-                                   1, NULL, ap->a_nch, -1);
+                                   1, NULL,
+                                   cache_isopen(ap->a_nch), 0);
        hammer2_trans_done(dip->pmp);
        if (error == 0)
                cache_unlink(ap->a_nch);
@@ -1687,7 +1691,8 @@ hammer2_vop_nrename(struct vop_nrename_args *ap)
         * Remove target if it exists.
         */
        error = hammer2_unlink_file(tdip, NULL, tname, tname_len,
-                                   -1, NULL, ap->a_tnch, -1);
+                                   -1, NULL,
+                                   cache_isopen(ap->a_tnch), 0);
        tnch_error = error;
        if (error && error != ENOENT)
                goto done2;
@@ -1730,7 +1735,7 @@ hammer2_vop_nrename(struct vop_nrename_args *ap)
         *       link count.
         */
        error = hammer2_unlink_file(fdip, ip, fname, fname_len,
-                                   -1, &hlink, NULL, 0);
+                                   -1, &hlink, 0, 1);
        KKASSERT(error != EAGAIN);
        if (error)
                goto done1;
index dabd214..9077fc9 100644 (file)
@@ -88,10 +88,8 @@ hammer2_xop_readdir(hammer2_xop_t *arg, int clindex)
        }
 
        /*
-        * Directory scan [re]start and loop.
-        *
-        * We feed the share-locked chain back to the frontend and must be
-        * sure not to unlock it in our iteration.
+        * Directory scan [re]start and loop, the feed inherits the chain's
+        * lock so do not unlock it on the iteration.
         */
        chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
                             &cache_index, HAMMER2_LOOKUP_SHARED);
@@ -126,6 +124,8 @@ hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex)
        hammer2_chain_t *parent;
        hammer2_chain_t *chain;
        const hammer2_inode_data_t *ripdata;
+       const char *name;
+       size_t name_len;
        hammer2_key_t key_next;
        hammer2_key_t lhc;
        int cache_index = -1;   /* XXX */
@@ -140,11 +140,13 @@ hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex)
                error = EIO;
                goto done;
        }
+       name = xop->head.name;
+       name_len = xop->head.name_len;
 
        /*
         * Lookup the directory entry
         */
-       lhc = hammer2_dirhash(xop->name, xop->name_len);
+       lhc = hammer2_dirhash(name, name_len);
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
                                     &cache_index,
@@ -153,8 +155,8 @@ hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex)
        while (chain) {
                ripdata = &chain->data->ipdata;
                if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
-                   ripdata->meta.name_len == xop->name_len &&
-                   bcmp(ripdata->filename, xop->name, xop->name_len) == 0) {
+                   ripdata->meta.name_len == name_len &&
+                   bcmp(ripdata->filename, name, name_len) == 0) {
                        break;
                }
                chain = hammer2_chain_next(&parent, chain, &key_next,
@@ -187,8 +189,9 @@ done:
 }
 
 /*
- * Scan directory collision entries for the specified lhc.  Used by
- * the inode create code to locate an unused lhc.
+ * Directory collision resolver scan helper (backend, threaded).
+ *
+ * Used by the inode create code to locate an unused lhc.
  */
 void
 hammer2_inode_xop_scanlhc(hammer2_xop_t *arg, int clindex)
@@ -211,7 +214,8 @@ hammer2_inode_xop_scanlhc(hammer2_xop_t *arg, int clindex)
        }
 
        /*
-        * Lookup the directory entry
+        * Lookup all possibly conflicting directory entries, the feed
+        * inherits the chain's lock so do not unlock it on the iteration.
         */
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     xop->lhc,
@@ -232,7 +236,8 @@ hammer2_inode_xop_scanlhc(hammer2_xop_t *arg, int clindex)
                                           xop->lhc + HAMMER2_DIRHASH_LOMASK,
                                           &cache_index,
                                           HAMMER2_LOOKUP_ALWAYS |
-                                          HAMMER2_LOOKUP_SHARED);
+                                          HAMMER2_LOOKUP_SHARED |
+                                          HAMMER2_LOOKUP_NOUNLOCK);
        }
 done:
        hammer2_xop_feed(&xop->head, NULL, clindex, error);
@@ -241,70 +246,3 @@ done:
                hammer2_chain_drop(parent);
        }
 }
-
-/*
- * Inode create helper.
- *
- * Frontend holds the parent directory ip locked exclusively.  We
- * create the inode and feed the exclusively locked chain to the
- * frontend.
- */
-void
-hammer2_inode_xop_create(hammer2_xop_t *arg, int clindex)
-{
-       hammer2_xop_create_t *xop = &arg->xop_create;
-       hammer2_chain_t *parent;
-       hammer2_chain_t *chain;
-       hammer2_key_t key_next;
-       int cache_index = -1;
-       int error;
-
-       chain = NULL;
-       parent = hammer2_inode_chain(xop->head.ip, clindex,
-                                    HAMMER2_RESOLVE_ALWAYS);
-       if (parent == NULL) {
-               error = EIO;
-               goto fail;
-       }
-       chain = hammer2_chain_lookup(&parent, &key_next,
-                                    xop->lhc, xop->lhc,
-                                    &cache_index, 0);
-       if (chain) {
-               hammer2_chain_unlock(chain);
-               error = EEXIST;
-               goto fail;
-       }
-
-       error = hammer2_chain_create(&parent, &chain,
-                                    xop->head.ip->pmp,
-                                    xop->lhc, 0,
-                                    HAMMER2_BREF_TYPE_INODE,
-                                    HAMMER2_INODE_BYTES,
-                                    xop->flags);
-       if (error == 0) {
-               hammer2_chain_modify(chain, 0);
-               chain->data->ipdata.meta = xop->meta;
-               bcopy(xop->name, chain->data->ipdata.filename,
-                     xop->name_len);
-       }
-       hammer2_chain_unlock(chain);
-       hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS |
-                                 HAMMER2_RESOLVE_SHARED);
-fail:
-       if (parent) {
-               hammer2_chain_unlock(parent);
-               hammer2_chain_drop(parent);
-       }
-       error = hammer2_xop_feed(&xop->head, chain, clindex, error);
-       if (chain)
-               hammer2_chain_drop(chain);
-}
-
-/*
- * Inode delete helper
- */
-void
-hammer2_inode_xop_destroy(hammer2_xop_t *arg, int clindex)
-{
-       /*hammer2_xop_inode_t *xop = &arg->xop_inode;*/
-}