summaryrefslogtreecommitdiffstats
path: root/module/zfs/zap_micro.c
diff options
context:
space:
mode:
authorChunwei Chen <[email protected]>2016-03-25 15:21:56 -0400
committerBrian Behlendorf <[email protected]>2016-05-10 10:38:21 -0700
commit32c8c946ea3228de86946fdd637c85eeeff1726a (patch)
treed761c4db5c8d034c3a25f5c2c7e6b4a104128317 /module/zfs/zap_micro.c
parentb3744ae611a1920aa37b44aa3b37f02c7f23a5ba (diff)
OpenZFS 6842 - Fix empty xattr dir causing lockup
Reviewed by: Brian Behlendorf <[email protected]> Reviewed by: Dan McDonald <[email protected]> Reviewed by: Matthew Ahrens <[email protected]> Approved by: Robert Mustacchi <[email protected]> Ported-by: Denys Rtveliashvili <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> 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
Diffstat (limited to 'module/zfs/zap_micro.c')
-rw-r--r--module/zfs/zap_micro.c38
1 files changed, 28 insertions, 10 deletions
diff --git a/module/zfs/zap_micro.c b/module/zfs/zap_micro.c
index 85b465b05..3faf27ce3 100644
--- a/module/zfs/zap_micro.c
+++ b/module/zfs/zap_micro.c
@@ -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