Undirty freed spill blocks.
If a spill block's dbuf hasn't yet been written when a spill block is freed, the unwritten version will still be written. This patch handles the case in which a spill block's dbuf is freed and undirties it to prevent it from being written. The most common case in which this could happen is when xattr=sa is being used and a long xattr is immediately replaced by a short xattr as in: setfattr -n user.test -v very_very_very..._long_value <file> setfattr -n user.test -v short_value <file> The first value must be sufficiently long that a spill block is generated and the second value must be short enough to not require a spill block. In practice, this would typically happen due to internal xattr operations as a result of setting acltype=posixacl. Signed-off-by: Tim Chase <tim@chase2k.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #2663 Closes #2700 Closes #2701 Closes #2717 Closes #2863 Closes #2884
This commit is contained in:
parent
5b2926547f
commit
a85804ecb5
|
@ -875,15 +875,18 @@ dbuf_free_range(dnode_t *dn, uint64_t start, uint64_t end, dmu_tx_t *tx)
|
||||||
int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
|
int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
|
||||||
uint64_t first_l1 = start >> epbs;
|
uint64_t first_l1 = start >> epbs;
|
||||||
uint64_t last_l1 = end >> epbs;
|
uint64_t last_l1 = end >> epbs;
|
||||||
|
boolean_t freespill =
|
||||||
|
(start == DMU_SPILL_BLKID || end == DMU_SPILL_BLKID);
|
||||||
|
|
||||||
if (end > dn->dn_maxblkid && (end != DMU_SPILL_BLKID)) {
|
if (end > dn->dn_maxblkid && !freespill) {
|
||||||
end = dn->dn_maxblkid;
|
end = dn->dn_maxblkid;
|
||||||
last_l1 = end >> epbs;
|
last_l1 = end >> epbs;
|
||||||
}
|
}
|
||||||
dprintf_dnode(dn, "start=%llu end=%llu\n", start, end);
|
dprintf_dnode(dn, "start=%llu end=%llu\n", start, end);
|
||||||
|
|
||||||
mutex_enter(&dn->dn_dbufs_mtx);
|
mutex_enter(&dn->dn_dbufs_mtx);
|
||||||
if (start >= dn->dn_unlisted_l0_blkid * dn->dn_datablksz) {
|
if (start >= dn->dn_unlisted_l0_blkid * dn->dn_datablksz &&
|
||||||
|
!freespill) {
|
||||||
/* There can't be any dbufs in this range; no need to search. */
|
/* There can't be any dbufs in this range; no need to search. */
|
||||||
mutex_exit(&dn->dn_dbufs_mtx);
|
mutex_exit(&dn->dn_dbufs_mtx);
|
||||||
return;
|
return;
|
||||||
|
@ -919,7 +922,7 @@ dbuf_free_range(dnode_t *dn, uint64_t start, uint64_t end, dmu_tx_t *tx)
|
||||||
if (db->db_level != 0)
|
if (db->db_level != 0)
|
||||||
continue;
|
continue;
|
||||||
dprintf_dbuf(db, "found buf %s\n", "");
|
dprintf_dbuf(db, "found buf %s\n", "");
|
||||||
if (db->db_blkid < start || db->db_blkid > end)
|
if ((db->db_blkid < start || db->db_blkid > end) && !freespill)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* found a level 0 buffer in the range */
|
/* found a level 0 buffer in the range */
|
||||||
|
|
Loading…
Reference in New Issue