OpenZFS 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>
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
This commit is contained in:
Chunwei Chen 2016-03-25 15:21:56 -04:00 committed by Brian Behlendorf
parent b3744ae611
commit 32c8c946ea
2 changed files with 35 additions and 11 deletions

View 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 || ASSERT(zap->zap_dbuf == NULL ||
zap_f_phys(zap) == zap->zap_dbuf->db_data); 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); idx = ZAP_HASH_IDX(h, zap_f_phys(zap)->zap_ptrtbl.zt_shift);
err = zap_idx_to_blk(zap, idx, &blk); err = zap_idx_to_blk(zap, idx, &blk);
if (err != 0) if (err != 0)

View File

@ -366,6 +366,9 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
zap_t *winner; zap_t *winner;
zap_t *zap; zap_t *zap;
int i; 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)); 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_object = obj;
zap->zap_dbuf = db; 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); mutex_init(&zap->zap_f.zap_num_entries_mtx, 0, 0, 0);
zap->zap_f.zap_block_shift = highbit64(db->db_size) - 1; 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 { } else {
zap->zap_ismicro = TRUE; 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); dmu_buf_init_user(&zap->zap_dbu, zap_evict, &zap->zap_dbuf);
winner = dmu_buf_set_user(db, &zap->zap_dbu); winner = dmu_buf_set_user(db, &zap->zap_dbu);
if (winner != NULL) { if (winner != NULL)
rw_exit(&zap->zap_rwlock); goto handle_winner;
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) { if (zap->zap_ismicro) {
zap->zap_salt = zap_m_phys(zap)->mz_salt; 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); rw_exit(&zap->zap_rwlock);
return (zap); 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 int
@ -468,8 +477,17 @@ zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
return (SET_ERROR(EINVAL)); return (SET_ERROR(EINVAL));
zap = dmu_buf_get_user(db); zap = dmu_buf_get_user(db);
if (zap == NULL) if (zap == NULL) {
zap = mzap_open(os, obj, db); 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 * We're checking zap_ismicro without the lock held, in order to