]> granicus.if.org Git - zfs/commitdiff
OpenZFS 6842 - Fix empty xattr dir causing lockup
authorChunwei Chen <tuxoko@gmail.com>
Fri, 25 Mar 2016 19:21:56 +0000 (15:21 -0400)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 10 May 2016 17:38:21 +0000 (10:38 -0700)
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Ported-by: Denys Rtveliashvili <denys@rtveliashvili.name>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
An initial version of this patch was applied in commit 29572cc and
subsequently refined upstream.  Since the implementations do not
conflict with each other both are left applied for now.

OpenZFS-issue: https://www.illumos.org/issues/6842
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/02525cd
Closes #4615

module/zfs/zap.c
module/zfs/zap_micro.c

index 9d06cce74023583c39ec7584ec81e9da652711d1..454b4be62ed34fcb221e6ae8710946ba9ba6b1ba 100644 (file)
@@ -585,7 +585,13 @@ zap_deref_leaf(zap_t *zap, uint64_t h, dmu_tx_t *tx, krw_t lt, zap_leaf_t **lp)
 
        ASSERT(zap->zap_dbuf == NULL ||
            zap_f_phys(zap) == zap->zap_dbuf->db_data);
-       ASSERT3U(zap_f_phys(zap)->zap_magic, ==, ZAP_MAGIC);
+
+       /* Reality check for corrupt zap objects (leaf or header). */
+       if ((zap_f_phys(zap)->zap_block_type != ZBT_LEAF &&
+           zap_f_phys(zap)->zap_block_type != ZBT_HEADER) ||
+           zap_f_phys(zap)->zap_magic != ZAP_MAGIC) {
+               return (SET_ERROR(EIO));
+       }
        idx = ZAP_HASH_IDX(h, zap_f_phys(zap)->zap_ptrtbl.zt_shift);
        err = zap_idx_to_blk(zap, idx, &blk);
        if (err != 0)
index 85b465b0528465fd8673fecebafe5367526c55c5..3faf27ce364660dfaf3ec59d25d2a23aab11706b 100644 (file)
@@ -366,6 +366,9 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
        zap_t *winner;
        zap_t *zap;
        int i;
+       uint64_t *zap_hdr = (uint64_t *)db->db_data;
+       uint64_t zap_block_type = zap_hdr[0];
+       uint64_t zap_magic = zap_hdr[1];
 
        ASSERT3U(MZAP_ENT_LEN, ==, sizeof (mzap_ent_phys_t));
 
@@ -376,9 +379,13 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
        zap->zap_object = obj;
        zap->zap_dbuf = db;
 
-       if (*(uint64_t *)db->db_data != ZBT_MICRO) {
+       if (zap_block_type != ZBT_MICRO) {
                mutex_init(&zap->zap_f.zap_num_entries_mtx, 0, 0, 0);
                zap->zap_f.zap_block_shift = highbit64(db->db_size) - 1;
+               if (zap_block_type != ZBT_HEADER || zap_magic != ZAP_MAGIC) {
+                       winner = NULL;  /* No actual winner here... */
+                       goto handle_winner;
+               }
        } else {
                zap->zap_ismicro = TRUE;
        }
@@ -391,14 +398,8 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
        dmu_buf_init_user(&zap->zap_dbu, zap_evict, &zap->zap_dbuf);
        winner = dmu_buf_set_user(db, &zap->zap_dbu);
 
-       if (winner != NULL) {
-               rw_exit(&zap->zap_rwlock);
-               rw_destroy(&zap->zap_rwlock);
-               if (!zap->zap_ismicro)
-                       mutex_destroy(&zap->zap_f.zap_num_entries_mtx);
-               kmem_free(zap, sizeof (zap_t));
-               return (winner);
-       }
+       if (winner != NULL)
+               goto handle_winner;
 
        if (zap->zap_ismicro) {
                zap->zap_salt = zap_m_phys(zap)->mz_salt;
@@ -445,6 +446,14 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
        }
        rw_exit(&zap->zap_rwlock);
        return (zap);
+
+handle_winner:
+       rw_exit(&zap->zap_rwlock);
+       rw_destroy(&zap->zap_rwlock);
+       if (!zap->zap_ismicro)
+               mutex_destroy(&zap->zap_f.zap_num_entries_mtx);
+       kmem_free(zap, sizeof (zap_t));
+       return (winner);
 }
 
 int
@@ -468,8 +477,17 @@ zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
                return (SET_ERROR(EINVAL));
 
        zap = dmu_buf_get_user(db);
-       if (zap == NULL)
+       if (zap == NULL) {
                zap = mzap_open(os, obj, db);
+               if (zap == NULL) {
+                       /*
+                        * mzap_open() didn't like what it saw on-disk.
+                        * Check for corruption!
+                        */
+                       dmu_buf_rele(db, NULL);
+                       return (SET_ERROR(EIO));
+               }
+       }
 
        /*
         * We're checking zap_ismicro without the lock held, in order to