Print this page
6842 Fix empty xattr dir causing lockup
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
        
*** 365,374 ****
--- 365,377 ----
  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));
  
          zap = kmem_zalloc(sizeof (zap_t), KM_SLEEP);
          rw_init(&zap->zap_rwlock, 0, 0, 0);
*** 375,387 ****
          rw_enter(&zap->zap_rwlock, RW_WRITER);
          zap->zap_objset = os;
          zap->zap_object = obj;
          zap->zap_dbuf = db;
  
!         if (*(uint64_t *)db->db_data != 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;
          } else {
                  zap->zap_ismicro = TRUE;
          }
  
          /*
--- 378,394 ----
          rw_enter(&zap->zap_rwlock, RW_WRITER);
          zap->zap_objset = os;
          zap->zap_object = obj;
          zap->zap_dbuf = db;
  
!         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;
          }
  
          /*
*** 390,407 ****
           * held.
           */
          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 (zap->zap_ismicro) {
                  zap->zap_salt = zap_m_phys(zap)->mz_salt;
                  zap->zap_normflags = zap_m_phys(zap)->mz_normflags;
                  zap->zap_m.zap_num_chunks = db->db_size / MZAP_ENT_LEN - 1;
--- 397,408 ----
           * held.
           */
          dmu_buf_init_user(&zap->zap_dbu, zap_evict, &zap->zap_dbuf);
          winner = dmu_buf_set_user(db, &zap->zap_dbu);
  
!         if (winner != NULL)
!                 goto handle_winner;
  
          if (zap->zap_ismicro) {
                  zap->zap_salt = zap_m_phys(zap)->mz_salt;
                  zap->zap_normflags = zap_m_phys(zap)->mz_normflags;
                  zap->zap_m.zap_num_chunks = db->db_size / MZAP_ENT_LEN - 1;
*** 444,453 ****
--- 445,462 ----
                      (uintptr_t)zap_f_phys(zap), ==,
                      zap->zap_dbuf->db_size);
          }
          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
  zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
      krw_t lti, boolean_t fatreader, boolean_t adding, zap_t **zapp)
*** 470,481 ****
                  ASSERT3U(DMU_OT_BYTESWAP(doi.doi_type), ==, DMU_BSWAP_ZAP);
          }
  #endif
  
          zap = dmu_buf_get_user(db);
!         if (zap == NULL)
                  zap = mzap_open(os, obj, db);
  
          /*
           * We're checking zap_ismicro without the lock held, in order to
           * tell what type of lock we want.  Once we have some sort of
           * lock, see if it really is the right type.  In practice this
--- 479,499 ----
                  ASSERT3U(DMU_OT_BYTESWAP(doi.doi_type), ==, DMU_BSWAP_ZAP);
          }
  #endif
  
          zap = dmu_buf_get_user(db);
!         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
           * tell what type of lock we want.  Once we have some sort of
           * lock, see if it really is the right type.  In practice this