Skip to content

Commit

Permalink
dbuf_free_range() overzealously frees dbufs
Browse files Browse the repository at this point in the history
When called to free a spill block from a dnode, dbuf_free_range() has a
bug that results in all dbufs for the dnode getting freed.  A variety of
problems may result from this bug, but a common one was a zap lookup
tripping an ASSERT because the zap buffers had been zeroed out.  This
could happen on a dataset with xattr=sa set when extended attributes are
written and removed on a directory concurrently with I/O to files in
that directory.

Signed-off-by: Ned Bass <bass6@llnl.gov>
Signed-off-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Fixes #3195
Fixes #3204
Fixes #3222
  • Loading branch information
nedbass authored and behlendorf committed Mar 25, 2015
1 parent ded576e commit 58806b4
Showing 1 changed file with 6 additions and 1 deletion.
7 changes: 6 additions & 1 deletion module/zfs/dbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -898,9 +898,14 @@ dbuf_free_range(dnode_t *dn, uint64_t start, uint64_t end, dmu_tx_t *tx)
db_next = list_next(&dn->dn_dbufs, db);
ASSERT(db->db_blkid != DMU_BONUS_BLKID);

/* Skip indirect blocks. */
if (db->db_level != 0)
continue;
if ((db->db_blkid < start || db->db_blkid > end) && !freespill)
/* Skip direct blocks outside the range. */
if (!freespill && (db->db_blkid < start || db->db_blkid > end))
continue;
/* Skip all direct blocks, only free spill blocks. */
if (freespill && (db->db_blkid != DMU_SPILL_BLKID))
continue;

/* found a level 0 buffer in the range */
Expand Down

0 comments on commit 58806b4

Please sign in to comment.