hammer2 - error handling 2/N (chain_lookup/chain_next)
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 31 Aug 2017 05:11:46 +0000 (22:11 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 31 Aug 2017 05:19:01 +0000 (22:19 -0700)
* Implement error handling for hammer2_chain_lookup() and
  hammer2_chain_next().

* Shim use cases for this commit.  Ultimately the intent is to
  convert the entire error path to HAMMER2_ERROR_* codes.

sys/vfs/hammer2/hammer2.h
sys/vfs/hammer2/hammer2_bulkfree.c
sys/vfs/hammer2/hammer2_chain.c
sys/vfs/hammer2/hammer2_freemap.c
sys/vfs/hammer2/hammer2_inode.c
sys/vfs/hammer2/hammer2_iocom.c
sys/vfs/hammer2/hammer2_ioctl.c
sys/vfs/hammer2/hammer2_strategy.c
sys/vfs/hammer2/hammer2_synchro.c
sys/vfs/hammer2/hammer2_vfsops.c
sys/vfs/hammer2/hammer2_xops.c

index eea38fc..6aac09b 100644 (file)
@@ -1451,12 +1451,12 @@ hammer2_chain_t *hammer2_chain_repparent(hammer2_chain_t **chainp, int how);
 hammer2_chain_t *hammer2_chain_lookup(hammer2_chain_t **parentp,
                                hammer2_key_t *key_nextp,
                                hammer2_key_t key_beg, hammer2_key_t key_end,
-                               int flags);
+                               int *errorp, int flags);
 hammer2_chain_t *hammer2_chain_next(hammer2_chain_t **parentp,
                                hammer2_chain_t *chain,
                                hammer2_key_t *key_nextp,
                                hammer2_key_t key_beg, hammer2_key_t key_end,
-                               int flags);
+                               int *errorp, int flags);
 int hammer2_chain_scan(hammer2_chain_t *parent,
                                hammer2_chain_t **chainp,
                                hammer2_blockref_t *bref,
index 17f9110..38514a6 100644 (file)
@@ -252,7 +252,7 @@ static void hammer2_bulkfree_thread(void *arg __unused);
 static void cbinfo_bmap_init(hammer2_bulkfree_info_t *cbinfo, size_t size);
 static int h2_bulkfree_callback(hammer2_bulkfree_info_t *cbinfo,
                        hammer2_blockref_t *bref);
-static void h2_bulkfree_sync(hammer2_bulkfree_info_t *cbinfo);
+static int h2_bulkfree_sync(hammer2_bulkfree_info_t *cbinfo);
 static void h2_bulkfree_sync_adjust(hammer2_bulkfree_info_t *cbinfo,
                        hammer2_off_t data_off, hammer2_bmap_data_t *live,
                        hammer2_bmap_data_t *bmap, hammer2_key_t alloc_base);
@@ -425,7 +425,7 @@ hammer2_bulkfree_pass(hammer2_dev_t *hmp, hammer2_chain_t *vchain,
                 * filled-out in-memory freemap.
                 */
                if (error == 0) {
-                       h2_bulkfree_sync(&cbinfo);
+                       error = h2_bulkfree_sync(&cbinfo);
 
                        hammer2_voldata_lock(hmp);
                        hammer2_voldata_modify(hmp);
@@ -667,7 +667,7 @@ h2_bulkfree_callback(hammer2_bulkfree_info_t *cbinfo, hammer2_blockref_t *bref)
  *                       ** -> 11      nominally warn of corruption
  * 
  */
-static void
+static int
 h2_bulkfree_sync(hammer2_bulkfree_info_t *cbinfo)
 {
        hammer2_off_t data_off;
@@ -678,6 +678,7 @@ h2_bulkfree_sync(hammer2_bulkfree_info_t *cbinfo)
        hammer2_chain_t *live_parent;
        hammer2_chain_t *live_chain;
        int bmapindex;
+       int error;
 
        kprintf("hammer2_bulkfree - range ");
 
@@ -702,6 +703,7 @@ h2_bulkfree_sync(hammer2_bulkfree_info_t *cbinfo)
        hammer2_chain_ref(live_parent);
        hammer2_chain_lock(live_parent, HAMMER2_RESOLVE_ALWAYS);
        live_chain = NULL;
+       error = 0;
 
        /*
         * Iterate each hammer2_bmap_data_t line (128 bytes) managing
@@ -733,30 +735,15 @@ h2_bulkfree_sync(hammer2_bulkfree_info_t *cbinfo)
                                            &key_dummy,
                                            key,
                                            key + HAMMER2_FREEMAP_LEVEL1_MASK,
+                                           &error,
                                            HAMMER2_LOOKUP_ALWAYS);
-
-#if 0
-                       /*
-                        * If recent allocations were made we avoid races by
-                        * not staging or freeing any blocks.  We can still
-                        * remark blocks as fully allocated.
-                        */
-                       if (live_chain) {
-                               if (hammer2_debug & 1) {
-                                       kprintf("live_chain %016jx\n",
-                                               (intmax_t)key);
-                               }
-                               if (live_chain->bref.mirror_tid >
-                                   cbinfo->saved_mirror_tid) {
-                                       kprintf("hammer2_bulkfree: "
-                                               "avoid %016jx\n",
-                                               data_off);
-                                       nofree = 1;
-                               } else {
-                                       nofree = 0;
-                               }
+                       if (error) {
+                               kprintf("hammer2_bulkfree: freemap lookup "
+                                       "error near %016jx, error %s\n",
+                                       (intmax_t)data_off,
+                                       hammer2_error_str(live_chain->error));
+                               break;
                        }
-#endif
                }
                if (live_chain == NULL) {
                        /*
@@ -774,10 +761,10 @@ h2_bulkfree_sync(hammer2_bulkfree_info_t *cbinfo)
                        goto next;
                }
                if (live_chain->error) {
-                       kprintf("hammer2_bulkfree: error %s looking up "
-                               "live leaf for allocated data near %016jx\n",
-                               hammer2_error_str(live_chain->error),
-                               (intmax_t)data_off);
+                       kprintf("hammer2_bulkfree: unable to access freemap "
+                               "near %016jx, error %s\n",
+                               (intmax_t)data_off,
+                               hammer2_error_str(live_chain->error));
                        hammer2_chain_unlock(live_chain);
                        hammer2_chain_drop(live_chain);
                        live_chain = NULL;
@@ -830,6 +817,7 @@ next:
                hammer2_chain_unlock(live_parent);
                hammer2_chain_drop(live_parent);
        }
+       return error;
 }
 
 /*
index 1d45feb..0d2ff2a 100644 (file)
@@ -2278,7 +2278,7 @@ again:
 hammer2_chain_t *
 hammer2_chain_lookup(hammer2_chain_t **parentp, hammer2_key_t *key_nextp,
                     hammer2_key_t key_beg, hammer2_key_t key_end,
-                    int flags)
+                    int *errorp, int flags)
 {
        hammer2_dev_t *hmp;
        hammer2_chain_t *parent;
@@ -2318,6 +2318,7 @@ hammer2_chain_lookup(hammer2_chain_t **parentp, hammer2_key_t *key_nextp,
         */
        parent = *parentp;
        hmp = parent->hmp;
+       *errorp = 0;
 
        while (parent->bref.type == HAMMER2_BREF_TYPE_INDIRECT ||
               parent->bref.type == HAMMER2_BREF_TYPE_FREEMAP_NODE) {
@@ -2425,6 +2426,16 @@ again:
                count = 0;      /* safety */
        }
 
+       /*
+        * No lookup is possible if the parent is errored.  We delayed
+        * this check as long as we could to ensure that the parent backup,
+        * embedded data, and MATCHIND code could still execute.
+        */
+       if (parent->error) {
+               *errorp = parent->error;
+               return NULL;
+       }
+
        /*
         * Merged scan to find next candidate.
         *
@@ -2564,6 +2575,10 @@ done:
         * a ref.  Perhaps this can eventually be optimized to not obtain the
         * lock in the first place for situations where the data does not
         * need to be resolved.
+        *
+        * NOTE! A chain->error must be tested by the caller upon return.
+        *       *errorp is only set based on issues which occur while
+        *       trying to reach the chain.
         */
        if (chain) {
                if (flags & HAMMER2_LOOKUP_NOLOCK)
@@ -2595,7 +2610,7 @@ hammer2_chain_t *
 hammer2_chain_next(hammer2_chain_t **parentp, hammer2_chain_t *chain,
                   hammer2_key_t *key_nextp,
                   hammer2_key_t key_beg, hammer2_key_t key_end,
-                  int flags)
+                  int *errorp, int flags)
 {
        hammer2_chain_t *parent;
        int how_maybe;
@@ -2608,6 +2623,7 @@ hammer2_chain_next(hammer2_chain_t **parentp, hammer2_chain_t *chain,
                how_maybe |= HAMMER2_RESOLVE_SHARED;
 
        parent = *parentp;
+       *errorp = 0;
 
        /*
         * Calculate the next index and recalculate the parent if necessary.
@@ -2659,7 +2675,7 @@ hammer2_chain_next(hammer2_chain_t **parentp, hammer2_chain_t *chain,
         */
        return (hammer2_chain_lookup(parentp, key_nextp,
                                     key_beg, key_end,
-                                    flags));
+                                    errorp, flags));
 }
 
 /*
@@ -2961,6 +2977,8 @@ done:
  *
  * When creating a PFSROOT inode under the super-root, pmp is typically NULL
  * and will be reassigned.
+ *
+ * NOTE: returns HAMMER_ERROR_* flags
  */
 int
 hammer2_chain_create(hammer2_chain_t **parentp, hammer2_chain_t **chainp,
@@ -3519,6 +3537,8 @@ _hammer2_chain_delete_helper(hammer2_chain_t *parent, hammer2_chain_t *chain,
  * can be inserted.
  *
  * Must be called with an exclusively locked parent.
+ *
+ * NOTE: *errorp set to HAMMER_ERROR_* flags
  */
 static int hammer2_chain_indkey_freemap(hammer2_chain_t *parent,
                                hammer2_key_t *keyp, int keybits,
@@ -5218,6 +5238,7 @@ hammer2_chain_inode_find(hammer2_pfs_t *pmp, hammer2_key_t inum,
        hammer2_chain_t *rchain;
        hammer2_key_t key_dummy;
        int resolve_flags;
+       int error;
 
        resolve_flags = (flags & HAMMER2_LOOKUP_SHARED) ?
                        HAMMER2_RESOLVE_SHARED : 0;
@@ -5245,12 +5266,14 @@ hammer2_chain_inode_find(hammer2_pfs_t *pmp, hammer2_key_t inum,
        if (parent) {
                rchain = hammer2_chain_lookup(&parent, &key_dummy,
                                              inum, inum,
-                                             flags);
+                                             &error, flags);
+       } else {
+               error = HAMMER2_ERROR_IO;
        }
        *parentp = parent;
        *chainp = rchain;
 
-       return (rchain ? 0 : EINVAL);
+       return error;
 }
 
 /*
index 5a97f64..cd01fb2 100644 (file)
@@ -322,7 +322,7 @@ hammer2_freemap_try_alloc(hammer2_chain_t **parentp,
        hammer2_off_t key;
        size_t bytes;
        uint16_t class;
-       int error = 0;
+       int error;
 
        /*
         * Calculate the number of bytes being allocated, the number
@@ -346,8 +346,10 @@ hammer2_freemap_try_alloc(hammer2_chain_t **parentp,
        l1mask = l1size - 1;
 
        chain = hammer2_chain_lookup(parentp, &key_dummy, key, key + l1mask,
+                                    &error,
                                     HAMMER2_LOOKUP_ALWAYS |
                                     HAMMER2_LOOKUP_MATCHIND);
+       error = hammer2_error_to_errno(error);
 
        if (chain == NULL) {
                /*
@@ -971,8 +973,10 @@ hammer2_freemap_adjust(hammer2_dev_t *hmp, hammer2_blockref_t *bref,
        hammer2_chain_lock(parent, HAMMER2_RESOLVE_ALWAYS);
 
        chain = hammer2_chain_lookup(&parent, &key_dummy, key, key + l1mask,
+                                    &error,
                                     HAMMER2_LOOKUP_ALWAYS |
                                     HAMMER2_LOOKUP_MATCHIND);
+       error = hammer2_error_to_errno(error);
 
        /*
         * Stop early if we are trying to free something but no leaf exists.
index 08f25eb..a86c6b5 100644 (file)
@@ -1321,7 +1321,8 @@ hammer2_inode_xop_mkdirent(hammer2_thread_t *thr, hammer2_xop_t *arg)
        }
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     xop->lhc, xop->lhc,
-                                    0);
+                                    &error, 0);
+       error = hammer2_error_to_errno(error);
        if (chain) {
                error = EEXIST;
                goto fail;
@@ -1402,7 +1403,8 @@ hammer2_inode_xop_create(hammer2_thread_t *thr, hammer2_xop_t *arg)
        }
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     xop->lhc, xop->lhc,
-                                    0);
+                                    &error, 0);
+       error = hammer2_error_to_errno(error);
        if (chain) {
                error = EEXIST;
                goto fail;
@@ -1495,6 +1497,7 @@ hammer2_inode_xop_unlinkall(hammer2_thread_t *thr, hammer2_xop_t *arg)
        hammer2_chain_t *parent;
        hammer2_chain_t *chain;
        hammer2_key_t key_next;
+       int error;
 
        /*
         * We need the precise parent chain to issue the deletion.
@@ -1503,12 +1506,13 @@ hammer2_inode_xop_unlinkall(hammer2_thread_t *thr, hammer2_xop_t *arg)
                                     HAMMER2_RESOLVE_ALWAYS);
        chain = NULL;
        if (parent == NULL) {
-               /* XXX error */
+               error = 0;
                goto done;
        }
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     xop->key_beg, xop->key_end,
-                                    HAMMER2_LOOKUP_ALWAYS);
+                                    &error, HAMMER2_LOOKUP_ALWAYS);
+       error = hammer2_error_to_errno(error);
        while (chain) {
                hammer2_chain_delete(parent, chain,
                                     xop->head.mtid, HAMMER2_DELETE_PERMANENT);
@@ -1516,10 +1520,14 @@ hammer2_inode_xop_unlinkall(hammer2_thread_t *thr, hammer2_xop_t *arg)
                /* depend on function to unlock the shared lock */
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                           key_next, xop->key_end,
+                                          &error,
                                           HAMMER2_LOOKUP_ALWAYS);
        }
+       error = hammer2_error_to_errno(error);
 done:
-       hammer2_xop_feed(&xop->head, NULL, thr->clindex, ENOENT);
+       if (error == 0)
+               error = ENOENT;
+       hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
        if (parent) {
                hammer2_chain_unlock(parent);
                hammer2_chain_drop(parent);
@@ -1555,7 +1563,8 @@ hammer2_inode_xop_connect(hammer2_thread_t *thr, hammer2_xop_t *arg)
        }
        chain = hammer2_chain_lookup(&parent, &key_dummy,
                                     xop->lhc, xop->lhc,
-                                    0);
+                                    &error, 0);
+       error = hammer2_error_to_errno(error);
        if (chain) {
                hammer2_chain_unlock(chain);
                hammer2_chain_drop(chain);
@@ -1563,6 +1572,8 @@ hammer2_inode_xop_connect(hammer2_thread_t *thr, hammer2_xop_t *arg)
                error = EEXIST;
                goto fail;
        }
+       if (error)
+               goto fail;
 
        /*
         * Adjust the filename in the inode, set the name key.
@@ -1647,6 +1658,7 @@ hammer2_inode_xop_chain_sync(hammer2_thread_t *thr, hammer2_xop_t *arg)
                        ~HAMMER2_PBUFMASK64;
                chain = hammer2_chain_lookup(&parent, &key_next,
                                             lbase, HAMMER2_KEY_MAX,
+                                            &error,
                                             HAMMER2_LOOKUP_NODATA |
                                             HAMMER2_LOOKUP_NODIRECT);
                while (chain) {
@@ -1666,9 +1678,11 @@ hammer2_inode_xop_chain_sync(hammer2_thread_t *thr, hammer2_xop_t *arg)
                        }
                        chain = hammer2_chain_next(&parent, chain, &key_next,
                                                   key_next, HAMMER2_KEY_MAX,
+                                                  &error,
                                                   HAMMER2_LOOKUP_NODATA |
                                                   HAMMER2_LOOKUP_NODIRECT);
                }
+               error = hammer2_error_to_errno(error);
 
                /*
                 * Reset to point at inode for following code, if necessary.
index 0957eff..f58583e 100644 (file)
@@ -294,6 +294,7 @@ hammer2_update_spans(hammer2_dev_t *hmp, kdmsg_state_t *state)
        hammer2_key_t key_next;
        kdmsg_msg_t *rmsg;
        size_t name_len;
+       int error;
 
        /*
         * Lookup mount point under the media-localized super-root.
@@ -303,6 +304,7 @@ hammer2_update_spans(hammer2_dev_t *hmp, kdmsg_state_t *state)
         */
        spmp = hmp->spmp;
        hammer2_inode_lock(spmp->iroot, 0);
+       error = 0;
 
        parent = hammer2_inode_chain(spmp->iroot, 0, HAMMER2_RESOLVE_ALWAYS);
        chain = NULL;
@@ -310,7 +312,7 @@ hammer2_update_spans(hammer2_dev_t *hmp, kdmsg_state_t *state)
                goto done;
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     HAMMER2_KEY_MIN, HAMMER2_KEY_MAX,
-                                    0);
+                                    &error, 0);
        while (chain) {
                if (chain->bref.type != HAMMER2_BREF_TYPE_INODE)
                        continue;
@@ -336,9 +338,11 @@ hammer2_update_spans(hammer2_dev_t *hmp, kdmsg_state_t *state)
 
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                               key_next, HAMMER2_KEY_MAX,
-                                              0);
+                                              &error, 0);
        }
        hammer2_inode_unlock(spmp->iroot);
+       error = hammer2_error_to_errno(error);
+       /* XXX do something with error */
 done:
        if (chain) {
                hammer2_chain_unlock(chain);
index dbd2f69..5031608 100644 (file)
@@ -430,6 +430,7 @@ hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
                                            HAMMER2_RESOLVE_SHARED);
                chain = hammer2_chain_lookup(&parent, &key_next,
                                            pfs->name_key, HAMMER2_KEY_MAX,
+                                           &error,
                                            HAMMER2_LOOKUP_SHARED);
        }
 
@@ -447,13 +448,15 @@ hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
                }
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                            key_next, HAMMER2_KEY_MAX,
+                                           &error,
                                            HAMMER2_LOOKUP_SHARED);
        }
+       error = hammer2_error_to_errno(error);
 
        /*
         * Load the data being returned by the ioctl.
         */
-       if (chain) {
+       if (chain && chain->error == 0) {
                ripdata = &chain->data->ipdata;
                pfs->name_key = ripdata->meta.name_key;
                pfs->pfs_type = ripdata->meta.pfs_type;
@@ -466,13 +469,16 @@ hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
                ripdata = NULL; /* safety */
 
                /*
-                * Calculate name_next, if any.
+                * Calculate name_next, if any.  We are only accessing
+                * chain->bref so we can ignore chain->error (if the key
+                * is used later it will error then).
                 */
                if (parent == NULL) {
                        pfs->name_next = (hammer2_key_t)-1;
                } else {
                        chain = hammer2_chain_next(&parent, chain, &key_next,
                                                    key_next, HAMMER2_KEY_MAX,
+                                                   &error,
                                                    HAMMER2_LOOKUP_SHARED);
                        if (chain)
                                pfs->name_next = chain->bref.key;
@@ -538,20 +544,21 @@ hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data)
 
        chain = hammer2_chain_lookup(&parent, &key_next,
                                         lhc, lhc + HAMMER2_DIRHASH_LOMASK,
-                                        HAMMER2_LOOKUP_SHARED);
+                                        &error, HAMMER2_LOOKUP_SHARED);
        while (chain) {
                if (hammer2_chain_dirent_test(chain, pfs->name, len))
                        break;
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                           key_next,
                                           lhc + HAMMER2_DIRHASH_LOMASK,
-                                          HAMMER2_LOOKUP_SHARED);
+                                          &error, HAMMER2_LOOKUP_SHARED);
        }
+       error = hammer2_error_to_errno(error);
 
        /*
         * Load the data being returned by the ioctl.
         */
-       if (chain) {
+       if (chain && chain->error == 0) {
                KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_INODE);
                ripdata = &chain->data->ipdata;
                pfs->name_key = ripdata->meta.name_key;
@@ -563,7 +570,7 @@ hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data)
 
                hammer2_chain_unlock(chain);
                hammer2_chain_drop(chain);
-       } else {
+       } else if (error == 0) {
                error = ENOENT;
        }
        if (parent) {
index 45a2404..a1a7e2e 100644 (file)
@@ -319,9 +319,12 @@ hammer2_strategy_xop_read(hammer2_thread_t *thr, hammer2_xop_t *arg)
        if (parent) {
                chain = hammer2_chain_lookup(&parent, &key_dummy,
                                             lbase, lbase,
+                                            &error,
                                             HAMMER2_LOOKUP_ALWAYS |
                                             HAMMER2_LOOKUP_SHARED);
-               error = chain ? chain->error : 0;
+               if (chain)
+                       error = chain->error;
+               error = hammer2_error_to_errno(error);
        } else {
                error = EIO;
                chain = NULL;
@@ -597,6 +600,7 @@ hammer2_strategy_xop_write(hammer2_thread_t *thr, hammer2_xop_t *arg)
        hammer2_write_file_core(bio_data, ip, &parent,
                                lbase, IO_ASYNC, pblksize,
                                xop->head.mtid, &error);
+       error = hammer2_error_to_errno(error);
        if (parent) {
                hammer2_chain_unlock(parent);
                hammer2_chain_drop(parent);
@@ -670,7 +674,8 @@ hammer2_bioq_sync(hammer2_pfs_t *pmp)
 /* 
  * Create a new cluster at (cparent, lbase) and assign physical storage,
  * returning a cluster suitable for I/O.  The cluster will be in a modified
- * state.
+ * state.  Any chain->error will be rolled up into *errorp, but still
+ * returned.  Caller must check *errorp.  Caller need not check chain->error.
  *
  * cparent can wind up being anything.
  *
@@ -697,11 +702,11 @@ hammer2_assign_physical(hammer2_inode_t *ip, hammer2_chain_t **parentp,
         * device buffer) because we will be using direct IO via the
         * logical buffer cache buffer.
         */
-       *errorp = 0;
        KKASSERT(pblksize >= HAMMER2_ALLOC_MIN);
 retry:
        chain = hammer2_chain_lookup(parentp, &key_dummy,
                                     lbase, lbase,
+                                    errorp,
                                     HAMMER2_LOOKUP_NODATA);
 
        /*
@@ -741,7 +746,7 @@ retry:
                        goto retry;
                }
                /*ip->delta_dcount += pblksize;*/
-       } else {
+       } else if (chain->error == 0) {
                switch (chain->bref.type) {
                case HAMMER2_BREF_TYPE_INODE:
                        /*
@@ -775,6 +780,8 @@ retry:
                        /* NOT REACHED */
                        break;
                }
+       } else {
+               *errorp = chain->error;
        }
        return (chain);
 }
@@ -812,7 +819,9 @@ hammer2_write_file_core(char *data, hammer2_inode_t *ip,
                bdata = data;
                chain = hammer2_assign_physical(ip, parentp, lbase, pblksize,
                                                mtid, &bdata, errorp);
-               if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
+               if (*errorp) {
+                       /* skip modifications */
+               } else if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
                        hammer2_inode_data_t *wipdata;
 
                        wipdata = &chain->data->ipdata;
@@ -1179,7 +1188,9 @@ hammer2_zero_check_and_write(char *data, hammer2_inode_t *ip,
                bdata = data;
                chain = hammer2_assign_physical(ip, parentp, lbase, pblksize,
                                                mtid, &bdata, errorp);
-               if (bdata) {
+               if (*errorp) {
+                       /* do nothing */
+               } else if (bdata) {
                        hammer2_write_bp(chain, data, ioflag, pblksize,
                                         mtid, errorp, check_algo);
                } else {
@@ -1229,9 +1240,9 @@ zero_write(char *data, hammer2_inode_t *ip,
        hammer2_chain_t *chain;
        hammer2_key_t key_dummy;
 
-       *errorp = 0;
        chain = hammer2_chain_lookup(parentp, &key_dummy,
                                     lbase, lbase,
+                                    errorp,
                                     HAMMER2_LOOKUP_NODATA);
        if (chain) {
                if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
index 0a9b5ed..2b043d5 100644 (file)
@@ -346,6 +346,8 @@ dumpcluster(const char *label,
  * issues to all nodes.  However, this is the only way we can safely
  * synchronize nodes which might have disparate I/O bandwidths and the only
  * way we can safely deal with stalled nodes.
+ *
+ * XXX serror / merror rollup and handling.
  */
 static
 int
@@ -360,8 +362,9 @@ hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip,
        hammer2_tid_t sync_tid;
        int needrescan;
        int want_update;
-       int error;
-       int nerror;
+       int serror;             /* slave error */
+       int merror;             /* master error (from xop_collect) */
+       int nerror;             /* temporary error */
        int idx;
        int n;
 
@@ -384,7 +387,7 @@ hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip,
                return(HAMMER2_ERROR_INCOMPLETE);
 #endif
 
-       error = 0;
+       merror = 0;
 
        /*
         * Resolve the root inode of the PFS and determine if synchronization
@@ -403,8 +406,8 @@ hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip,
                hammer2_xop_start_except(&xop2->head, hammer2_xop_ipcluster,
                                         idx);
                hammer2_inode_unlock(ip);
-               error = hammer2_xop_collect(&xop2->head, 0);
-               if (error == 0 && (focus = xop2->head.cluster.focus) != NULL) {
+               merror = hammer2_xop_collect(&xop2->head, 0);
+               if (merror == 0 && (focus = xop2->head.cluster.focus) != NULL) {
                        sync_tid = focus->bref.modify_tid;
                        chain = hammer2_inode_chain_and_parent(ip, idx,
                                                    &parent,
@@ -451,10 +454,12 @@ hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip,
 
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     HAMMER2_KEY_MIN, HAMMER2_KEY_MAX,
+                                    &serror,
                                     HAMMER2_LOOKUP_SHARED |
                                     HAMMER2_LOOKUP_NODIRECT |
                                     HAMMER2_LOOKUP_NODATA);
-       error = hammer2_xop_collect(&xop->head, 0);
+       serror = hammer2_error_to_errno(serror);
+       merror = hammer2_xop_collect(&xop->head, 0);
        if (hammer2_debug & 0x8000) {
                kprintf("START_SCAN IP=%016jx chain=%p (%016jx)\n",
                        ip->meta.name_key, chain,
@@ -472,15 +477,15 @@ hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip,
                int dodefer = 0;
                hammer2_chain_t *focus;
 
-               if (chain == NULL && error == ENOENT)
+               if (chain == NULL && merror == ENOENT)
                        break;
-               if (error && error != ENOENT)
+               if (merror && merror != ENOENT)
                        break;
 
                /*
                 * Compare
                 */
-               if (chain && error == ENOENT) {
+               if (chain && merror == ENOENT) {
                        /*
                         * If we have local chains but the XOP scan is done,
                         * the chains need to be deleted.
@@ -580,7 +585,7 @@ hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip,
                 * The deferral is pushed onto a LIFO list for bottom-up
                 * synchronization.
                 */
-               if (error == 0 && dodefer) {
+               if (merror == 0 && dodefer) {
                        hammer2_inode_t *nip;
                        hammer2_deferred_ip_t *defer;
 
@@ -618,14 +623,16 @@ hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip,
                 * Advancements for iteration.
                 */
                if (advance_xop) {
-                       error = hammer2_xop_collect(&xop->head, 0);
+                       merror = hammer2_xop_collect(&xop->head, 0);
                }
                if (advance_local) {
                        chain = hammer2_chain_next(&parent, chain, &key_next,
                                                   key_next, HAMMER2_KEY_MAX,
+                                                  &serror,
                                                   HAMMER2_LOOKUP_SHARED |
                                                   HAMMER2_LOOKUP_NODIRECT |
                                                   HAMMER2_LOOKUP_NODATA);
+                       serror = hammer2_error_to_errno(serror);
                }
        }
        hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
@@ -645,8 +652,8 @@ hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip,
         * NOTE: In this situation we do not yet want to synchronize our
         *       inode, setting the error code also has that effect.
         */
-       if ((error == 0 || error == ENOENT) && needrescan)
-               error = EAGAIN;
+       if ((merror == 0 || merror == ENOENT) && needrescan)
+               merror = EAGAIN;
 
        /*
         * If no error occurred we can synchronize the inode meta-data
@@ -654,7 +661,7 @@ hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip,
         *
         * XXX inode lock was lost
         */
-       if (error == 0 || error == ENOENT) {
+       if (merror == 0 || merror == ENOENT) {
                hammer2_xop_ipcluster_t *xop2;
                hammer2_chain_t *focus;
 
@@ -663,8 +670,8 @@ hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip,
                hammer2_xop_start_except(&xop2->head, hammer2_xop_ipcluster,
                                         idx);
                hammer2_inode_unlock(ip);
-               error = hammer2_xop_collect(&xop2->head, 0);
-               if (error == 0) {
+               merror = hammer2_xop_collect(&xop2->head, 0);
+               if (merror == 0) {
                        focus = xop2->head.cluster.focus;
                        if (hammer2_debug & 0x8000) {
                                kprintf("syncthr: update inode %p (%s)\n",
@@ -692,7 +699,7 @@ hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip,
                hammer2_xop_retire(&xop2->head, HAMMER2_XOPMASK_VOP);
        }
 
-       return error;
+       return merror;
 }
 
 /*
@@ -709,6 +716,7 @@ hammer2_sync_insert(hammer2_thread_t *thr,
 {
        hammer2_chain_t *chain;
        hammer2_key_t dummy;
+       int error;
 
 #if HAMMER2_SYNCHRO_DEBUG
        if (hammer2_debug & 1)
@@ -739,67 +747,71 @@ hammer2_sync_insert(hammer2_thread_t *thr,
         */
        chain = hammer2_chain_lookup(parentp, &dummy,
                                     focus->bref.key, focus->bref.key,
+                                    &error,
                                     HAMMER2_LOOKUP_NODIRECT |
                                     HAMMER2_LOOKUP_ALWAYS);
        KKASSERT(chain == NULL);
 
        chain = NULL;
-       hammer2_chain_create(parentp, &chain,
-                            thr->pmp, focus->bref.methods,
-                            focus->bref.key, focus->bref.keybits,
-                            focus->bref.type, focus->bytes,
-                            mtid, 0, 0);
-       hammer2_chain_modify(chain, mtid, 0, 0);
+       error = hammer2_chain_create(parentp, &chain,
+                                    thr->pmp, focus->bref.methods,
+                                    focus->bref.key, focus->bref.keybits,
+                                    focus->bref.type, focus->bytes,
+                                    mtid, 0, 0);
+       if (error == 0) {
+               hammer2_chain_modify(chain, mtid, 0, 0);
 
-       /*
-        * Copy focus to new chain
-        */
+               /*
+                * Copy focus to new chain
+                */
 
-       /* type already set */
-       chain->bref.methods = focus->bref.methods;
-       /* keybits already set */
-       chain->bref.vradix = focus->bref.vradix;
-       /* mirror_tid set by flush */
-       KKASSERT(chain->bref.modify_tid == mtid);
-       chain->bref.flags = focus->bref.flags;
-       /* key already present */
-       /* check code will be recalculated */
+               /* type already set */
+               chain->bref.methods = focus->bref.methods;
+               /* keybits already set */
+               chain->bref.vradix = focus->bref.vradix;
+               /* mirror_tid set by flush */
+               KKASSERT(chain->bref.modify_tid == mtid);
+               chain->bref.flags = focus->bref.flags;
+               /* key already present */
+               /* check code will be recalculated */
 
-       /*
-        * Copy data body.
-        */
-       switch(chain->bref.type) {
-       case HAMMER2_BREF_TYPE_INODE:
-               if ((focus->data->ipdata.meta.op_flags &
-                    HAMMER2_OPFLAG_DIRECTDATA) == 0) {
-                       /* do not copy block table */
-                       bcopy(focus->data, chain->data,
-                             offsetof(hammer2_inode_data_t, u));
-                       break;
-               }
-               /* fall through copy whole thing */
-       case HAMMER2_BREF_TYPE_DATA:
-               bcopy(focus->data, chain->data, chain->bytes);
-               hammer2_chain_setcheck(chain, chain->data);
-               break;
-       case HAMMER2_BREF_TYPE_DIRENT:
                /*
-                * Directory entries embed data in the blockref.
+                * Copy data body.
                 */
-               if (chain->bytes) {
+               switch(chain->bref.type) {
+               case HAMMER2_BREF_TYPE_INODE:
+                       if ((focus->data->ipdata.meta.op_flags &
+                            HAMMER2_OPFLAG_DIRECTDATA) == 0) {
+                               /* do not copy block table */
+                               bcopy(focus->data, chain->data,
+                                     offsetof(hammer2_inode_data_t, u));
+                               break;
+                       }
+                       /* fall through copy whole thing */
+               case HAMMER2_BREF_TYPE_DATA:
                        bcopy(focus->data, chain->data, chain->bytes);
                        hammer2_chain_setcheck(chain, chain->data);
-               } else {
-                       chain->bref.check = focus->bref.check;
+                       break;
+               case HAMMER2_BREF_TYPE_DIRENT:
+                       /*
+                        * Directory entries embed data in the blockref.
+                        */
+                       if (chain->bytes) {
+                               bcopy(focus->data, chain->data, chain->bytes);
+                               hammer2_chain_setcheck(chain, chain->data);
+                       } else {
+                               chain->bref.check = focus->bref.check;
+                       }
+                       chain->bref.embed = focus->bref.embed;
+                       break;
+               default:
+                       KKASSERT(0);
+                       break;
                }
-               chain->bref.embed = focus->bref.embed;
-               break;
-       default:
-               KKASSERT(0);
-               break;
        }
 
-       hammer2_chain_unlock(chain);            /* unlock, leave ref */
+       if (chain)
+               hammer2_chain_unlock(chain);    /* unlock, leave ref */
        *chainp = chain;                        /* will be returned locked */
 
        /*
@@ -808,10 +820,13 @@ hammer2_sync_insert(hammer2_thread_t *thr,
        hammer2_chain_unlock(*parentp);
        hammer2_chain_lock(*parentp, HAMMER2_RESOLVE_SHARED |
                                     HAMMER2_RESOLVE_ALWAYS);
-       hammer2_chain_lock(chain, HAMMER2_RESOLVE_SHARED |
-                                 HAMMER2_RESOLVE_ALWAYS);
+       if (chain) {
+               hammer2_chain_lock(chain, HAMMER2_RESOLVE_SHARED |
+                                         HAMMER2_RESOLVE_ALWAYS);
+               error = chain->error;
+       }
 
-       return 0;
+       return error;
 }
 
 /*
@@ -831,6 +846,7 @@ hammer2_sync_destroy(hammer2_thread_t *thr,
        hammer2_chain_t *chain;
        hammer2_key_t key_next;
        hammer2_key_t save_key;
+       int error;
 
        chain = *chainp;
 
@@ -866,10 +882,11 @@ hammer2_sync_destroy(hammer2_thread_t *thr,
                                     HAMMER2_RESOLVE_ALWAYS);
        *chainp = hammer2_chain_lookup(parentp, &key_next,
                                     save_key, HAMMER2_KEY_MAX,
+                                    &error,
                                     HAMMER2_LOOKUP_SHARED |
                                     HAMMER2_LOOKUP_NODIRECT |
                                     HAMMER2_LOOKUP_NODATA);
-       return 0;
+       return error;
 }
 
 /*
@@ -883,8 +900,8 @@ hammer2_sync_replace(hammer2_thread_t *thr,
                     hammer2_tid_t mtid, int idx,
                     hammer2_chain_t *focus, int isroot)
 {
-       int nradix;
        uint8_t otype;
+       int nradix;
 
 #if HAMMER2_SYNCHRO_DEBUG
        if (hammer2_debug & 1)
@@ -895,121 +912,123 @@ hammer2_sync_replace(hammer2_thread_t *thr,
 #endif
        hammer2_chain_unlock(chain);
        hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS);
-       if (chain->bytes != focus->bytes) {
-               /* XXX what if compressed? */
-               nradix = hammer2_getradix(chain->bytes);
-               hammer2_chain_resize(chain, mtid, 0, nradix, 0);
-       }
-       hammer2_chain_modify(chain, mtid, 0, 0);
-       otype = chain->bref.type;
-       chain->bref.type = focus->bref.type;
-       chain->bref.methods = focus->bref.methods;
-       chain->bref.keybits = focus->bref.keybits;
-       chain->bref.vradix = focus->bref.vradix;
-       /* mirror_tid updated by flush */
-       KKASSERT(mtid == 0 || chain->bref.modify_tid == mtid);
-       chain->bref.flags = focus->bref.flags;
-       /* key already present */
-       /* check code will be recalculated */
-       chain->error = 0;
+       if (chain->error == 0) {
+               if (chain->bytes != focus->bytes) {
+                       /* XXX what if compressed? */
+                       nradix = hammer2_getradix(chain->bytes);
+                       hammer2_chain_resize(chain, mtid, 0, nradix, 0);
+               }
+               hammer2_chain_modify(chain, mtid, 0, 0);
+               otype = chain->bref.type;
+               chain->bref.type = focus->bref.type;
+               chain->bref.methods = focus->bref.methods;
+               chain->bref.keybits = focus->bref.keybits;
+               chain->bref.vradix = focus->bref.vradix;
+               /* mirror_tid updated by flush */
+               KKASSERT(mtid == 0 || chain->bref.modify_tid == mtid);
+               chain->bref.flags = focus->bref.flags;
+               /* key already present */
+               /* check code will be recalculated */
 
-       /*
-        * Copy data body.
-        */
-       switch(chain->bref.type) {
-       case HAMMER2_BREF_TYPE_INODE:
                /*
-                * Special case PFSROOTs, only limited changes can be made
-                * since the meta-data contains miscellanious distinguishing
-                * fields.
+                * Copy data body.
                 */
-               if (isroot) {
-                       chain->data->ipdata.meta.uflags =
-                               focus->data->ipdata.meta.uflags;
-                       chain->data->ipdata.meta.rmajor =
-                               focus->data->ipdata.meta.rmajor;
-                       chain->data->ipdata.meta.rminor =
-                               focus->data->ipdata.meta.rminor;
-                       chain->data->ipdata.meta.ctime =
-                               focus->data->ipdata.meta.ctime;
-                       chain->data->ipdata.meta.mtime =
-                               focus->data->ipdata.meta.mtime;
-                       chain->data->ipdata.meta.atime =
-                               focus->data->ipdata.meta.atime;
-                       /* not btime */
-                       chain->data->ipdata.meta.uid =
-                               focus->data->ipdata.meta.uid;
-                       chain->data->ipdata.meta.gid =
-                               focus->data->ipdata.meta.gid;
-                       chain->data->ipdata.meta.mode =
-                               focus->data->ipdata.meta.mode;
-                       chain->data->ipdata.meta.ncopies =
-                               focus->data->ipdata.meta.ncopies;
-                       chain->data->ipdata.meta.comp_algo =
-                               focus->data->ipdata.meta.comp_algo;
-                       chain->data->ipdata.meta.check_algo =
-                               focus->data->ipdata.meta.check_algo;
-                       chain->data->ipdata.meta.data_quota =
-                               focus->data->ipdata.meta.data_quota;
-                       chain->data->ipdata.meta.inode_quota =
-                               focus->data->ipdata.meta.inode_quota;
-
+               switch(chain->bref.type) {
+               case HAMMER2_BREF_TYPE_INODE:
                        /*
-                        * last snapshot tid controls overwrite
+                        * Special case PFSROOTs, only limited changes can
+                        * be made since the meta-data contains miscellanious
+                        * distinguishing fields.
                         */
-                       if (chain->data->ipdata.meta.pfs_lsnap_tid <
-                           focus->data->ipdata.meta.pfs_lsnap_tid) {
-                               chain->data->ipdata.meta.pfs_lsnap_tid =
+                       if (isroot) {
+                               chain->data->ipdata.meta.uflags =
+                                       focus->data->ipdata.meta.uflags;
+                               chain->data->ipdata.meta.rmajor =
+                                       focus->data->ipdata.meta.rmajor;
+                               chain->data->ipdata.meta.rminor =
+                                       focus->data->ipdata.meta.rminor;
+                               chain->data->ipdata.meta.ctime =
+                                       focus->data->ipdata.meta.ctime;
+                               chain->data->ipdata.meta.mtime =
+                                       focus->data->ipdata.meta.mtime;
+                               chain->data->ipdata.meta.atime =
+                                       focus->data->ipdata.meta.atime;
+                               /* not btime */
+                               chain->data->ipdata.meta.uid =
+                                       focus->data->ipdata.meta.uid;
+                               chain->data->ipdata.meta.gid =
+                                       focus->data->ipdata.meta.gid;
+                               chain->data->ipdata.meta.mode =
+                                       focus->data->ipdata.meta.mode;
+                               chain->data->ipdata.meta.ncopies =
+                                       focus->data->ipdata.meta.ncopies;
+                               chain->data->ipdata.meta.comp_algo =
+                                       focus->data->ipdata.meta.comp_algo;
+                               chain->data->ipdata.meta.check_algo =
+                                       focus->data->ipdata.meta.check_algo;
+                               chain->data->ipdata.meta.data_quota =
+                                       focus->data->ipdata.meta.data_quota;
+                               chain->data->ipdata.meta.inode_quota =
+                                       focus->data->ipdata.meta.inode_quota;
+
+                               /*
+                                * last snapshot tid controls overwrite
+                                */
+                               if (chain->data->ipdata.meta.pfs_lsnap_tid <
+                                   focus->data->ipdata.meta.pfs_lsnap_tid) {
+                                       chain->data->ipdata.meta.pfs_lsnap_tid =
                                        focus->data->ipdata.meta.pfs_lsnap_tid;
+                               }
+
+                               hammer2_chain_setcheck(chain, chain->data);
+                               break;
                        }
 
+                       /*
+                        * Normal replacement.
+                        */
+                       if ((focus->data->ipdata.meta.op_flags &
+                            HAMMER2_OPFLAG_DIRECTDATA) == 0) {
+                               /*
+                                * If DIRECTDATA is transitioning to 0 or the
+                                * old chain is not an inode we have to
+                                * initialize the block table.
+                                */
+                               if (otype != HAMMER2_BREF_TYPE_INODE ||
+                                   (chain->data->ipdata.meta.op_flags &
+                                    HAMMER2_OPFLAG_DIRECTDATA)) {
+                                       kprintf("chain inode trans "
+                                               "away from dd\n");
+                                       bzero(&chain->data->ipdata.u,
+                                             sizeof(chain->data->ipdata.u));
+                               }
+                               bcopy(focus->data, chain->data,
+                                     offsetof(hammer2_inode_data_t, u));
+                               /* XXX setcheck on inode should not be needed */
+                               hammer2_chain_setcheck(chain, chain->data);
+                               break;
+                       }
+                       /* fall through */
+               case HAMMER2_BREF_TYPE_DATA:
+                       bcopy(focus->data, chain->data, chain->bytes);
                        hammer2_chain_setcheck(chain, chain->data);
                        break;
-               }
-
-               /*
-                * Normal replacement.
-                */
-               if ((focus->data->ipdata.meta.op_flags &
-                    HAMMER2_OPFLAG_DIRECTDATA) == 0) {
+               case HAMMER2_BREF_TYPE_DIRENT:
                        /*
-                        * If DIRECTDATA is transitioning to 0 or the old
-                        * chain is not an inode we have to initialize
-                        * the block table.
+                        * Directory entries embed data in the blockref.
                         */
-                       if (otype != HAMMER2_BREF_TYPE_INODE ||
-                           (chain->data->ipdata.meta.op_flags &
-                            HAMMER2_OPFLAG_DIRECTDATA)) {
-                               kprintf("chain inode trans away from dd\n");
-                               bzero(&chain->data->ipdata.u,
-                                     sizeof(chain->data->ipdata.u));
+                       if (chain->bytes) {
+                               bcopy(focus->data, chain->data, chain->bytes);
+                               hammer2_chain_setcheck(chain, chain->data);
+                       } else {
+                               chain->bref.check = focus->bref.check;
                        }
-                       bcopy(focus->data, chain->data,
-                             offsetof(hammer2_inode_data_t, u));
-                       /* XXX setcheck on inode should not be needed */
-                       hammer2_chain_setcheck(chain, chain->data);
+                       chain->bref.embed = focus->bref.embed;
+                       break;
+               default:
+                       KKASSERT(0);
                        break;
                }
-               /* fall through */
-       case HAMMER2_BREF_TYPE_DATA:
-               bcopy(focus->data, chain->data, chain->bytes);
-               hammer2_chain_setcheck(chain, chain->data);
-               break;
-       case HAMMER2_BREF_TYPE_DIRENT:
-               /*
-                * Directory entries embed data in the blockref.
-                */
-               if (chain->bytes) {
-                       bcopy(focus->data, chain->data, chain->bytes);
-                       hammer2_chain_setcheck(chain, chain->data);
-               } else {
-                       chain->bref.check = focus->bref.check;
-               }
-               chain->bref.embed = focus->bref.embed;
-               break;
-       default:
-               KKASSERT(0);
-               break;
        }
 
        hammer2_chain_unlock(chain);
index 61ac8de..40f6c60 100644 (file)
@@ -1189,7 +1189,7 @@ hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data,
                parent = hammer2_chain_lookup_init(&hmp->vchain, 0);
                schain = hammer2_chain_lookup(&parent, &key_dummy,
                                      HAMMER2_SROOT_KEY, HAMMER2_SROOT_KEY,
-                                     0);
+                                     &error, 0);
                hammer2_chain_lookup_done(parent);
                if (schain == NULL) {
                        kprintf("hammer2_mount: invalid super-root\n");
@@ -1298,7 +1298,7 @@ hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data,
        lhc = hammer2_dirhash(label, strlen(label));
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
-                                    0);
+                                    &error, 0);
        while (chain) {
                if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
                    strcmp(label, chain->data->ipdata.filename) == 0) {
@@ -1307,7 +1307,7 @@ hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data,
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                            key_next,
                                            lhc + HAMMER2_DIRHASH_LOMASK,
-                                           0);
+                                           &error, 0);
        }
        if (parent) {
                hammer2_chain_unlock(parent);
@@ -1319,7 +1319,10 @@ hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data,
         * PFS could not be found?
         */
        if (chain == NULL) {
-               kprintf("hammer2_mount: PFS label not found\n");
+               if (error)
+                       kprintf("hammer2_mount: PFS label I/O error\n");
+               else
+                       kprintf("hammer2_mount: PFS label not found\n");
                hammer2_unmount_helper(mp, NULL, hmp);
                lockmgr(&hammer2_mntlk, LK_RELEASE);
                hammer2_vfs_unmount(mp, MNT_FORCE);
@@ -1335,10 +1338,14 @@ hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data,
         * Check if the cluster has already been mounted.  A cluster can
         * only be mounted once, use null mounts to mount additional copies.
         */
-       ripdata = &chain->data->ipdata;
-       bref = chain->bref;
-       pmp = hammer2_pfsalloc(NULL, ripdata,
-                              bref.modify_tid, force_local);
+       if (chain->error) {
+               kprintf("hammer2_mount: PFS label I/O error\n");
+       } else {
+               ripdata = &chain->data->ipdata;
+               bref = chain->bref;
+               pmp = hammer2_pfsalloc(NULL, ripdata,
+                                      bref.modify_tid, force_local);
+       }
        hammer2_chain_unlock(chain);
        hammer2_chain_drop(chain);
 
@@ -1429,6 +1436,7 @@ hammer2_update_pmps(hammer2_dev_t *hmp)
        hammer2_pfs_t *spmp;
        hammer2_pfs_t *pmp;
        hammer2_key_t key_next;
+       int error;
 
        /*
         * Force local mount (disassociate all PFSs from their clusters).
@@ -1447,19 +1455,23 @@ hammer2_update_pmps(hammer2_dev_t *hmp)
        parent = hammer2_inode_chain(spmp->iroot, 0, HAMMER2_RESOLVE_ALWAYS);
        chain = hammer2_chain_lookup(&parent, &key_next,
                                         HAMMER2_KEY_MIN, HAMMER2_KEY_MAX,
-                                        0);
+                                        &error, 0);
        while (chain) {
                if (chain->bref.type != HAMMER2_BREF_TYPE_INODE)
                        continue;
-               ripdata = &chain->data->ipdata;
-               bref = chain->bref;
-               kprintf("ADD LOCAL PFS: %s\n", ripdata->filename);
+               if (chain->error) {
+                       kprintf("I/O error scanning PFS labels\n");
+               } else {
+                       ripdata = &chain->data->ipdata;
+                       bref = chain->bref;
+                       kprintf("ADD LOCAL PFS: %s\n", ripdata->filename);
 
-               pmp = hammer2_pfsalloc(chain, ripdata,
-                                      bref.modify_tid, force_local);
+                       pmp = hammer2_pfsalloc(chain, ripdata,
+                                              bref.modify_tid, force_local);
+               }
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                           key_next, HAMMER2_KEY_MAX,
-                                          0);
+                                          &error, 0);
        }
        if (parent) {
                hammer2_chain_unlock(parent);
index 46deedd..cb5fc96 100644 (file)
@@ -86,6 +86,7 @@ checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex)
                error = hammer2_chain_inode_find(chain->pmp, inum,
                                                 clindex, 0,
                                                 &parent, &chain);
+               error = hammer2_error_to_errno(error);
                if (parent) {
                        hammer2_chain_unlock(parent);
                        hammer2_chain_drop(parent);
@@ -112,14 +113,14 @@ checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex)
                chain = hammer2_chain_lookup(&parent, &key_next,
                                             HAMMER2_DIRHASH_VISIBLE,
                                             HAMMER2_KEY_MAX,
-                                            0);
+                                            &error, 0);
        }
        if (chain) {
                error = ENOTEMPTY;
                hammer2_chain_unlock(chain);
                hammer2_chain_drop(chain);
        } else {
-               error = 0;
+               error = hammer2_error_to_errno(error); /* may be 0 */
        }
        hammer2_chain_lookup_done(parent);
 
@@ -188,20 +189,22 @@ hammer2_xop_readdir(hammer2_thread_t *thr, hammer2_xop_t *arg)
         * lock so do not unlock it on the iteration.
         */
        chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
-                                    HAMMER2_LOOKUP_SHARED);
+                                    &error, HAMMER2_LOOKUP_SHARED);
        if (chain == NULL) {
                chain = hammer2_chain_lookup(&parent, &key_next,
                                             lkey, HAMMER2_KEY_MAX,
-                                            HAMMER2_LOOKUP_SHARED);
+                                            &error, HAMMER2_LOOKUP_SHARED);
        }
        while (chain) {
                error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
                if (error)
-                       break;
+                       goto break2;
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                           key_next, HAMMER2_KEY_MAX,
-                                          HAMMER2_LOOKUP_SHARED);
+                                          &error, HAMMER2_LOOKUP_SHARED);
        }
+       error = hammer2_error_to_errno(error);
+break2:
        if (chain) {
                hammer2_chain_unlock(chain);
                hammer2_chain_drop(chain);
@@ -245,6 +248,7 @@ hammer2_xop_nresolve(hammer2_thread_t *thr, hammer2_xop_t *arg)
        lhc = hammer2_dirhash(name, name_len);
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
+                                    &error,
                                     HAMMER2_LOOKUP_ALWAYS |
                                     HAMMER2_LOOKUP_SHARED);
        while (chain) {
@@ -253,15 +257,16 @@ hammer2_xop_nresolve(hammer2_thread_t *thr, hammer2_xop_t *arg)
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                           key_next,
                                           lhc + HAMMER2_DIRHASH_LOMASK,
+                                          &error,
                                           HAMMER2_LOOKUP_ALWAYS |
                                           HAMMER2_LOOKUP_SHARED);
        }
+       error = hammer2_error_to_errno(error);
 
        /*
         * If the entry is a hardlink pointer, resolve it.
         */
-       error = 0;
-       if (chain) {
+       if (chain && chain->error == 0) {
                if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
                        lhc = chain->bref.embed.dirent.inum;
                        error = hammer2_chain_inode_find(chain->pmp,
@@ -271,7 +276,10 @@ hammer2_xop_nresolve(hammer2_thread_t *thr, hammer2_xop_t *arg)
                                                         &parent,
                                                         &chain);
                }
+       } else if (chain && error == 0) {
+               error = chain->error;
        }
+       error = hammer2_error_to_errno(error);
 done:
        error = hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
        if (chain) {
@@ -330,14 +338,14 @@ again:
        lhc = hammer2_dirhash(name, name_len);
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
-                                    HAMMER2_LOOKUP_ALWAYS);
+                                    &error, HAMMER2_LOOKUP_ALWAYS);
        while (chain) {
                if (hammer2_chain_dirent_test(chain, name, name_len))
                        break;
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                           key_next,
                                           lhc + HAMMER2_DIRHASH_LOMASK,
-                                          HAMMER2_LOOKUP_ALWAYS);
+                                          &error, HAMMER2_LOOKUP_ALWAYS);
        }
 
        /*
@@ -350,8 +358,7 @@ again:
         * anything fancy here.  The frontend deals with nlinks
         * synchronization.
         */
-       error = 0;
-       if (chain) {
+       if (chain && chain->error == 0) {
                int dopermanent = xop->dopermanent & 1;
                int doforce = xop->dopermanent & 2;
                uint8_t type;
@@ -385,7 +392,7 @@ again:
                         * If doforce then execute the operation even if
                         * the directory is not empty.
                         */
-                       error = chain->error;
+                       error = hammer2_error_to_errno(chain->error);
                        hammer2_chain_delete(parent, chain,
                                             xop->head.mtid, dopermanent);
                } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
@@ -411,10 +418,14 @@ again:
                         * Delete the directory entry.  chain might also
                         * be a directly-embedded inode.
                         */
-                       error = chain->error;
+                       error = hammer2_error_to_errno(chain->error);
                        hammer2_chain_delete(parent, chain,
                                             xop->head.mtid, dopermanent);
                }
+       } else {
+               if (chain && error == 0)
+                       error = chain->error;
+               error = hammer2_error_to_errno(error);
        }
 
        /*
@@ -431,6 +442,7 @@ again:
                error2 = hammer2_chain_inode_find(chain->pmp, lhc,
                                                  thr->clindex, 0,
                                                  &parent, &chain);
+               error2 = hammer2_error_to_errno(error2);
                if (error2) {
                        kprintf("inode_find: %016jx %p failed\n",
                                lhc, chain);
@@ -489,6 +501,7 @@ hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg)
        ip = xop->head.ip2;
        pmp = ip->pmp;
        chain = NULL;
+       error = 0;
 
        if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
                /*
@@ -531,23 +544,31 @@ hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg)
                lhc = hammer2_dirhash(name, name_len);
                chain = hammer2_chain_lookup(&parent, &key_next,
                                             lhc, lhc + HAMMER2_DIRHASH_LOMASK,
-                                            HAMMER2_LOOKUP_ALWAYS);
+                                            &error, HAMMER2_LOOKUP_ALWAYS);
                while (chain) {
                        if (hammer2_chain_dirent_test(chain, name, name_len))
                                break;
                        chain = hammer2_chain_next(&parent, chain, &key_next,
                                                   key_next,
                                                   lhc + HAMMER2_DIRHASH_LOMASK,
+                                                  &error,
                                                   HAMMER2_LOOKUP_ALWAYS);
                }
        }
+       error = hammer2_error_to_errno(error);
 
        if (chain == NULL) {
                /* XXX shouldn't happen, but does under fsstress */
                kprintf("hammer2_xop_rename: \"%s\" -> \"%s\"  ENOENT\n",
                        xop->head.name1,
                        xop->head.name2);
-               error = ENOENT;
+               if (error == 0)
+                       error = ENOENT;
+               goto done;
+       }
+
+       if (chain->error) {
+               error = hammer2_error_to_errno(chain->error);
                goto done;
        }
 
@@ -646,6 +667,7 @@ hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg)
        tmp = hammer2_chain_lookup(&parent, &key_next,
                                   xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
                                   xop->lhc | HAMMER2_DIRHASH_LOMASK,
+                                  &error,
                                   HAMMER2_LOOKUP_ALWAYS);
        while (tmp) {
                if (hammer2_chain_dirent_test(tmp, xop->head.name2,
@@ -655,23 +677,27 @@ hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg)
                tmp = hammer2_chain_next(&parent, tmp, &key_next,
                                         key_next,
                                         xop->lhc | HAMMER2_DIRHASH_LOMASK,
+                                        &error,
                                         HAMMER2_LOOKUP_ALWAYS);
        }
+       error = hammer2_error_to_errno(error);
 
-       /*
-        * A relookup is required before the create to properly position
-        * the parent chain.
-        */
-       tmp = hammer2_chain_lookup(&parent, &key_next,
-                                  xop->lhc, xop->lhc,
-                                  0);
-       KKASSERT(tmp == NULL);
-       error = hammer2_chain_create(&parent, &chain,
-                                    pmp, HAMMER2_METH_DEFAULT,
-                                    xop->lhc, 0,
-                                    HAMMER2_BREF_TYPE_INODE,
-                                    HAMMER2_INODE_BYTES,
-                                    xop->head.mtid, 0, 0);
+       if (error == 0) {
+               /*
+                * A relookup is required before the create to properly
+                * position the parent chain.
+                */
+               tmp = hammer2_chain_lookup(&parent, &key_next,
+                                          xop->lhc, xop->lhc,
+                                          &error, 0);
+               KKASSERT(tmp == NULL);
+               error = hammer2_chain_create(&parent, &chain,
+                                            pmp, HAMMER2_METH_DEFAULT,
+                                            xop->lhc, 0,
+                                            HAMMER2_BREF_TYPE_INODE,
+                                            HAMMER2_INODE_BYTES,
+                                            xop->head.mtid, 0, 0);
+       }
 done:
        hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
        if (parent) {
@@ -715,23 +741,25 @@ hammer2_xop_scanlhc(hammer2_thread_t *thr, hammer2_xop_t *arg)
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     xop->lhc,
                                     xop->lhc + HAMMER2_DIRHASH_LOMASK,
+                                    &error,
                                     HAMMER2_LOOKUP_ALWAYS |
                                     HAMMER2_LOOKUP_SHARED);
        while (chain) {
-               error = hammer2_xop_feed(&xop->head, chain, thr->clindex,
-                                        chain->error);
+               error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
                if (error) {
                        hammer2_chain_unlock(chain);
                        hammer2_chain_drop(chain);
                        chain = NULL;   /* safety */
-                       break;
+                       goto done;
                }
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                           key_next,
                                           xop->lhc + HAMMER2_DIRHASH_LOMASK,
+                                          &error,
                                           HAMMER2_LOOKUP_ALWAYS |
                                           HAMMER2_LOOKUP_SHARED);
        }
+       error = hammer2_error_to_errno(error);
 done:
        hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
        if (parent) {
@@ -769,12 +797,17 @@ hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *arg)
         */
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     xop->lhc, xop->lhc,
+                                    &error,
                                     HAMMER2_LOOKUP_ALWAYS |
                                     HAMMER2_LOOKUP_SHARED);
-       if (chain)
-               hammer2_xop_feed(&xop->head, chain, thr->clindex, chain->error);
-       else
-               hammer2_xop_feed(&xop->head, NULL, thr->clindex, ENOENT);
+       error = hammer2_error_to_errno(error);
+       if (error == 0) {
+               if (chain)
+                       error = hammer2_error_to_errno(chain->error);
+               else
+                       error = ENOENT;
+       }
+       hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
 
 done:
        if (chain) {
@@ -827,15 +860,17 @@ hammer2_xop_scanall(hammer2_thread_t *thr, hammer2_xop_t *arg)
         */
        chain = hammer2_chain_lookup(&parent, &key_next,
                                     xop->key_beg, xop->key_end,
-                                    xop->lookup_flags);
+                                    &error, xop->lookup_flags);
        while (chain) {
                error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
                if (error)
-                       break;
+                       goto break2;
                chain = hammer2_chain_next(&parent, chain, &key_next,
                                           key_next, xop->key_end,
-                                          xop->lookup_flags);
+                                          &error, xop->lookup_flags);
        }
+       error = hammer2_error_to_errno(error);
+break2:
        if (chain) {
                hammer2_chain_unlock(chain);
                hammer2_chain_drop(chain);