Deny block cloning is dbuf size doesn't match BP size.
I don't know an easy way to shrink down dbuf size, so just deny block cloning into dbufs that don't match our BP's size. This fixes the following situation: 1. Create a small file, eg. 1kB of random bytes. Its dbuf will be 1kB. 2. Create a larger file, eg. 2kB of random bytes. Its dbuf will be 2kB. 3. Truncate the large file to 0. Its dbuf will remain 2kB. 4. Clone the small file into the large file. Small file's BP lsize is 1kB, but the large file's dbuf is 2kB. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Pawel Jakub Dawidek <pawel@dawidek.net> Closes #14825
This commit is contained in:
parent
555ef90c5c
commit
bd8c6bd66f
|
@ -1066,7 +1066,7 @@ int dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole,
|
||||||
|
|
||||||
int dmu_read_l0_bps(objset_t *os, uint64_t object, uint64_t offset,
|
int dmu_read_l0_bps(objset_t *os, uint64_t object, uint64_t offset,
|
||||||
uint64_t length, dmu_tx_t *tx, struct blkptr *bps, size_t *nbpsp);
|
uint64_t length, dmu_tx_t *tx, struct blkptr *bps, size_t *nbpsp);
|
||||||
void dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset,
|
int dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset,
|
||||||
uint64_t length, dmu_tx_t *tx, const struct blkptr *bps, size_t nbps,
|
uint64_t length, dmu_tx_t *tx, const struct blkptr *bps, size_t nbps,
|
||||||
boolean_t replay);
|
boolean_t replay);
|
||||||
|
|
||||||
|
|
|
@ -2257,7 +2257,7 @@ out:
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset, uint64_t length,
|
dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset, uint64_t length,
|
||||||
dmu_tx_t *tx, const blkptr_t *bps, size_t nbps, boolean_t replay)
|
dmu_tx_t *tx, const blkptr_t *bps, size_t nbps, boolean_t replay)
|
||||||
{
|
{
|
||||||
|
@ -2267,7 +2267,7 @@ dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset, uint64_t length,
|
||||||
struct dirty_leaf *dl;
|
struct dirty_leaf *dl;
|
||||||
dbuf_dirty_record_t *dr;
|
dbuf_dirty_record_t *dr;
|
||||||
const blkptr_t *bp;
|
const blkptr_t *bp;
|
||||||
int numbufs;
|
int error = 0, i, numbufs;
|
||||||
|
|
||||||
spa = os->os_spa;
|
spa = os->os_spa;
|
||||||
|
|
||||||
|
@ -2275,7 +2275,26 @@ dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset, uint64_t length,
|
||||||
&numbufs, &dbp));
|
&numbufs, &dbp));
|
||||||
ASSERT3U(nbps, ==, numbufs);
|
ASSERT3U(nbps, ==, numbufs);
|
||||||
|
|
||||||
for (int i = 0; i < numbufs; i++) {
|
/*
|
||||||
|
* Before we start cloning make sure that the dbufs sizes much new BPs
|
||||||
|
* sizes. If they don't, that's a no-go, as we are not able to shrink
|
||||||
|
* dbufs.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < numbufs; i++) {
|
||||||
|
dbuf = dbp[i];
|
||||||
|
db = (dmu_buf_impl_t *)dbuf;
|
||||||
|
bp = &bps[i];
|
||||||
|
|
||||||
|
ASSERT0(db->db_level);
|
||||||
|
ASSERT(db->db_blkid != DMU_BONUS_BLKID);
|
||||||
|
|
||||||
|
if (!BP_IS_HOLE(bp) && BP_GET_LSIZE(bp) != dbuf->db_size) {
|
||||||
|
error = SET_ERROR(EXDEV);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < numbufs; i++) {
|
||||||
dbuf = dbp[i];
|
dbuf = dbp[i];
|
||||||
db = (dmu_buf_impl_t *)dbuf;
|
db = (dmu_buf_impl_t *)dbuf;
|
||||||
bp = &bps[i];
|
bp = &bps[i];
|
||||||
|
@ -2319,8 +2338,10 @@ dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset, uint64_t length,
|
||||||
brt_pending_add(spa, bp, tx);
|
brt_pending_add(spa, bp, tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
dmu_buf_rele_array(dbp, numbufs, FTAG);
|
dmu_buf_rele_array(dbp, numbufs, FTAG);
|
||||||
|
|
||||||
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -1309,8 +1309,12 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
|
||||||
((len - 1) / inblksz + 1) * inblksz);
|
((len - 1) / inblksz + 1) * inblksz);
|
||||||
}
|
}
|
||||||
|
|
||||||
dmu_brt_clone(outos, outzp->z_id, outoff, size, tx, bps, nbps,
|
error = dmu_brt_clone(outos, outzp->z_id, outoff, size, tx,
|
||||||
B_FALSE);
|
bps, nbps, B_FALSE);
|
||||||
|
if (error != 0) {
|
||||||
|
dmu_tx_commit(tx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
zfs_clear_setid_bits_if_necessary(outzfsvfs, outzp, cr,
|
zfs_clear_setid_bits_if_necessary(outzfsvfs, outzp, cr,
|
||||||
&clear_setid_bits_txg, tx);
|
&clear_setid_bits_txg, tx);
|
||||||
|
|
Loading…
Reference in New Issue