mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
Allow rewrite skip cloned and snapshotted blocks
Rewrite of cloned and snapshotted blocks can allocate additional space, that may be undesired. In some cases it may have sense to still rewrite snapshotted blocks, expecting the snapshots to rotate with time, freeing space. In other cases rewrite of cloned blocks may be acceptable, despite persistent space usage increase. For this reason add them as separate flags to `zfs rewrite`. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Rob Norris <robn@despairlabs.com> Reviewed-by: Ameer Hamza <ahamza@ixsystems.com> Signed-off-by: Alexander Motin <alexander.motin@TrueNAS.com> Closes #18179
This commit is contained in:
@@ -3046,6 +3046,24 @@ dmu_objset_willuse_space(objset_t *os, int64_t space, dmu_tx_t *tx)
|
||||
dsl_pool_dirty_space(dmu_tx_pool(tx), space, tx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a block is shared with a snapshot in this objset.
|
||||
* Returns B_TRUE if block was created before or at the time of the
|
||||
* previous snapshot, B_FALSE otherwise.
|
||||
*/
|
||||
boolean_t
|
||||
dmu_objset_block_is_shared(objset_t *os, const blkptr_t *bp)
|
||||
{
|
||||
if (BP_IS_HOLE(bp))
|
||||
return (B_FALSE);
|
||||
|
||||
dsl_dataset_t *ds = os->os_dsl_dataset;
|
||||
if (ds == NULL)
|
||||
return (B_FALSE);
|
||||
|
||||
return (BP_GET_BIRTH(bp) <= dsl_dataset_phys(ds)->ds_prev_snap_txg);
|
||||
}
|
||||
|
||||
#if defined(_KERNEL)
|
||||
EXPORT_SYMBOL(dmu_objset_zil);
|
||||
EXPORT_SYMBOL(dmu_objset_pool);
|
||||
@@ -3090,4 +3108,5 @@ EXPORT_SYMBOL(dmu_objset_projectquota_enabled);
|
||||
EXPORT_SYMBOL(dmu_objset_projectquota_present);
|
||||
EXPORT_SYMBOL(dmu_objset_projectquota_upgradable);
|
||||
EXPORT_SYMBOL(dmu_objset_id_quota_upgrade);
|
||||
EXPORT_SYMBOL(dmu_objset_block_is_shared);
|
||||
#endif
|
||||
|
||||
+38
-1
@@ -53,6 +53,7 @@
|
||||
#include <sys/dsl_dataset.h>
|
||||
#include <sys/spa.h>
|
||||
#include <sys/txg.h>
|
||||
#include <sys/brt.h>
|
||||
#include <sys/dbuf.h>
|
||||
#include <sys/policy.h>
|
||||
#include <sys/zfeature.h>
|
||||
@@ -1095,6 +1096,34 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a block should be skipped during rewrite.
|
||||
* Returns B_TRUE if block should be skipped.
|
||||
*/
|
||||
static boolean_t
|
||||
zfs_rewrite_skip(dmu_buf_t *db, objset_t *os, uint64_t flags)
|
||||
{
|
||||
/*
|
||||
* This may be slightly stale and racy, but should be OK for
|
||||
* the advisory use.
|
||||
*/
|
||||
blkptr_t *bp = dmu_buf_get_blkptr(db);
|
||||
if (bp == NULL)
|
||||
return (B_TRUE);
|
||||
|
||||
if (flags & ZFS_REWRITE_SKIP_SNAPSHOT) {
|
||||
if (dmu_objset_block_is_shared(os, bp))
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
if (flags & ZFS_REWRITE_SKIP_BRT) {
|
||||
if (brt_maybe_exists(os->os_spa, bp))
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rewrite a range of file as-is without modification.
|
||||
*
|
||||
@@ -1113,7 +1142,11 @@ zfs_rewrite(znode_t *zp, uint64_t off, uint64_t len, uint64_t flags,
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((flags & ~ZFS_REWRITE_PHYSICAL) != 0 || arg != 0)
|
||||
#define ZFS_REWRITE_VALID_FLAGS \
|
||||
(ZFS_REWRITE_PHYSICAL | ZFS_REWRITE_SKIP_SNAPSHOT | \
|
||||
ZFS_REWRITE_SKIP_BRT)
|
||||
|
||||
if ((flags & ~ZFS_REWRITE_VALID_FLAGS) != 0 || arg != 0)
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
zfsvfs_t *zfsvfs = ZTOZSB(zp);
|
||||
@@ -1214,6 +1247,10 @@ zfs_rewrite(znode_t *zp, uint64_t off, uint64_t len, uint64_t flags,
|
||||
nr += dbp[i]->db_size;
|
||||
if (dmu_buf_is_dirty(dbp[i], tx))
|
||||
continue;
|
||||
|
||||
if (zfs_rewrite_skip(dbp[i], zfsvfs->z_os, flags))
|
||||
continue;
|
||||
|
||||
nw += dbp[i]->db_size;
|
||||
if (flags & ZFS_REWRITE_PHYSICAL)
|
||||
dmu_buf_will_rewrite(dbp[i], tx);
|
||||
|
||||
Reference in New Issue
Block a user