Skip to content

Commit 60f714e

Browse files
amotinbehlendorf
authored andcommitted
Implement physical rewrites
Based on previous commit this implements `zfs rewrite -P` flag, making ZFS to keep blocks logical birth times while rewriting files. It should exclude the rewritten blocks from incremental sends, snapshot diffs, etc. Snapshots space usage same time will reflect the additional space usage from newly allocated blocks. Since this begins to use new "rewrite" flag in the block pointers, this commit introduces a new read-compatible per-dataset feature physical_rewrite. It must be enabled for the command to not fail, it is activated on first use and deactivated on deletion of the last affected dataset. Reviewed-by: Rob Norris <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Closes #17565
1 parent 4ae8bf4 commit 60f714e

File tree

19 files changed

+270
-18
lines changed

19 files changed

+270
-18
lines changed

cmd/zfs/zfs_main.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ get_usage(zfs_help_t idx)
440440
return (gettext("\tredact <snapshot> <bookmark> "
441441
"<redaction_snapshot> ...\n"));
442442
case HELP_REWRITE:
443-
return (gettext("\trewrite [-rvx] [-o <offset>] [-l <length>] "
443+
return (gettext("\trewrite [-Prvx] [-o <offset>] [-l <length>] "
444444
"<directory|file ...>\n"));
445445
case HELP_JAIL:
446446
return (gettext("\tjail <jailid|jailname> <filesystem>\n"));
@@ -9177,8 +9177,11 @@ zfs_do_rewrite(int argc, char **argv)
91779177
zfs_rewrite_args_t args;
91789178
memset(&args, 0, sizeof (args));
91799179

9180-
while ((c = getopt(argc, argv, "l:o:rvx")) != -1) {
9180+
while ((c = getopt(argc, argv, "Pl:o:rvx")) != -1) {
91819181
switch (c) {
9182+
case 'P':
9183+
args.flags |= ZFS_REWRITE_PHYSICAL;
9184+
break;
91829185
case 'l':
91839186
args.len = strtoll(optarg, NULL, 0);
91849187
break;

include/sys/dbuf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ typedef struct dbuf_dirty_record {
164164
boolean_t dr_nopwrite;
165165
boolean_t dr_brtwrite;
166166
boolean_t dr_diowrite;
167+
boolean_t dr_rewrite;
167168
boolean_t dr_has_raw_params;
168169

169170
/* Override and raw params are mutually exclusive. */

include/sys/dmu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@ struct blkptr *dmu_buf_get_blkptr(dmu_buf_t *db);
825825
*/
826826
void dmu_buf_will_dirty(dmu_buf_t *db, dmu_tx_t *tx);
827827
void dmu_buf_will_dirty_flags(dmu_buf_t *db, dmu_tx_t *tx, dmu_flags_t flags);
828+
void dmu_buf_will_rewrite(dmu_buf_t *db, dmu_tx_t *tx);
828829
boolean_t dmu_buf_is_dirty(dmu_buf_t *db, dmu_tx_t *tx);
829830
void dmu_buf_set_crypt_params(dmu_buf_t *db_fake, boolean_t byteorder,
830831
const uint8_t *salt, const uint8_t *iv, const uint8_t *mac, dmu_tx_t *tx);

include/sys/fs/zfs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,9 @@ typedef struct zfs_rewrite_args {
16271627
uint64_t arg;
16281628
} zfs_rewrite_args_t;
16291629

1630+
/* zfs_rewrite_args flags */
1631+
#define ZFS_REWRITE_PHYSICAL 0x1 /* Preserve logical birth time. */
1632+
16301633
#define ZFS_IOC_REWRITE _IOW(0x83, 3, zfs_rewrite_args_t)
16311634

16321635
/*

include/sys/zio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ typedef struct zio_prop {
374374
boolean_t zp_encrypt;
375375
boolean_t zp_byteorder;
376376
boolean_t zp_direct_write;
377+
boolean_t zp_rewrite;
377378
uint8_t zp_salt[ZIO_DATA_SALT_LEN];
378379
uint8_t zp_iv[ZIO_DATA_IV_LEN];
379380
uint8_t zp_mac[ZIO_DATA_MAC_LEN];

include/zfeature_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ typedef enum spa_feature {
8989
SPA_FEATURE_LARGE_MICROZAP,
9090
SPA_FEATURE_DYNAMIC_GANG_HEADER,
9191
SPA_FEATURE_BLOCK_CLONING_ENDIAN,
92+
SPA_FEATURE_PHYSICAL_REWRITE,
9293
SPA_FEATURES
9394
} spa_feature_t;
9495

lib/libzfs/libzfs.abi

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@
639639
<elf-symbol name='fletcher_4_superscalar_ops' size='128' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
640640
<elf-symbol name='libzfs_config_ops' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
641641
<elf-symbol name='sa_protocol_names' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
642-
<elf-symbol name='spa_feature_table' size='2576' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
642+
<elf-symbol name='spa_feature_table' size='2632' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
643643
<elf-symbol name='zfeature_checks_disable' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
644644
<elf-symbol name='zfs_deleg_perm_tab' size='528' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
645645
<elf-symbol name='zfs_history_event_names' size='328' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -6399,7 +6399,8 @@
63996399
<enumerator name='SPA_FEATURE_LARGE_MICROZAP' value='43'/>
64006400
<enumerator name='SPA_FEATURE_DYNAMIC_GANG_HEADER' value='44'/>
64016401
<enumerator name='SPA_FEATURE_BLOCK_CLONING_ENDIAN' value='45'/>
6402-
<enumerator name='SPA_FEATURES' value='46'/>
6402+
<enumerator name='SPA_FEATURE_PHYSICAL_REWRITE' value='46'/>
6403+
<enumerator name='SPA_FEATURES' value='47'/>
64036404
</enum-decl>
64046405
<typedef-decl name='spa_feature_t' type-id='33ecb627' id='d6618c78'/>
64056406
<qualified-type-def type-id='80f4b756' const='yes' id='b99c00c9'/>
@@ -9614,8 +9615,8 @@
96149615
</function-decl>
96159616
</abi-instr>
96169617
<abi-instr address-size='64' path='module/zcommon/zfeature_common.c' language='LANG_C99'>
9617-
<array-type-def dimensions='1' type-id='83f29ca2' size-in-bits='20608' id='b9408bab'>
9618-
<subrange length='46' type-id='7359adad' id='8b86bc1b'/>
9618+
<array-type-def dimensions='1' type-id='83f29ca2' size-in-bits='21056' id='fd43354e'>
9619+
<subrange length='47' type-id='7359adad' id='8f8900fe'/>
96199620
</array-type-def>
96209621
<enum-decl name='zfeature_flags' id='6db816a4'>
96219622
<underlying-type type-id='9cac1fee'/>
@@ -9693,7 +9694,7 @@
96939694
<pointer-type-def type-id='611586a1' size-in-bits='64' id='2e243169'/>
96949695
<qualified-type-def type-id='eaa32e2f' const='yes' id='83be723c'/>
96959696
<pointer-type-def type-id='83be723c' size-in-bits='64' id='7acd98a2'/>
9696-
<var-decl name='spa_feature_table' type-id='b9408bab' mangled-name='spa_feature_table' visibility='default' elf-symbol-id='spa_feature_table'/>
9697+
<var-decl name='spa_feature_table' type-id='fd43354e' mangled-name='spa_feature_table' visibility='default' elf-symbol-id='spa_feature_table'/>
96979698
<var-decl name='zfeature_checks_disable' type-id='c19b74c3' mangled-name='zfeature_checks_disable' visibility='default' elf-symbol-id='zfeature_checks_disable'/>
96989699
<function-decl name='opendir' visibility='default' binding='global' size-in-bits='64'>
96999700
<parameter type-id='80f4b756'/>

man/man7/zpool-features.7

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,23 @@ when the
853853
command is used on a top-level vdev, and will never return to being
854854
.Sy enabled .
855855
.
856+
.feature com.truenas physical_rewrite yes extensible_dataset
857+
This feature enables physical block rewriting that preserves logical birth
858+
times, avoiding unnecessary inclusion of rewritten blocks in incremental
859+
.Nm zfs Cm send
860+
streams.
861+
When enabled, the
862+
.Nm zfs Cm rewrite Fl P
863+
command can be used.
864+
.Pp
865+
This feature becomes
866+
.Sy active
867+
the first time
868+
.Nm zfs Cm rewrite Fl P
869+
is used on any dataset, and will return to being
870+
.Sy enabled
871+
once all datasets that have ever used physical rewrite are destroyed.
872+
.
856873
.feature org.zfsonlinux project_quota yes extensible_dataset
857874
This feature allows administrators to account the spaces and objects usage
858875
information against the project identifier

man/man8/zfs-rewrite.8

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
.Sh SYNOPSIS
3232
.Nm zfs
3333
.Cm rewrite
34-
.Oo Fl rvx Ns Oc
34+
.Oo Fl Prvx Ns Oc
3535
.Op Fl l Ar length
3636
.Op Fl o Ar offset
3737
.Ar file Ns | Ns Ar directory Ns
@@ -43,6 +43,15 @@ as is without modification at a new location and possibly with new
4343
properties, such as checksum, compression, dedup, copies, etc,
4444
as if they were atomically read and written back.
4545
.Bl -tag -width "-r"
46+
.It Fl P
47+
Perform physical rewrite, preserving logical birth time of blocks.
48+
By default, rewrite updates logical birth times, making blocks appear
49+
as modified in snapshots and incremental send streams.
50+
Physical rewrite preserves logical birth times, avoiding unnecessary
51+
inclusion in incremental streams.
52+
Physical rewrite requires the
53+
.Sy physical_rewrite
54+
feature to be enabled on the pool.
4655
.It Fl l Ar length
4756
Rewrite at most this number of bytes.
4857
.It Fl o Ar offset
@@ -60,17 +69,22 @@ same as some property changes may increase pool space usage.
6069
Holes that were never written or were previously zero-compressed are
6170
not rewritten and will remain holes even if compression is disabled.
6271
.Pp
63-
Rewritten blocks will be seen as modified in next snapshot and as such
64-
included into the incremental
65-
.Nm zfs Cm send
66-
stream.
67-
.Pp
6872
If a
6973
.Fl l
7074
or
7175
.Fl o
7276
value request a rewrite to regions past the end of the file, then those
7377
regions are silently ignored, and no error is reported.
78+
.Pp
79+
By default, rewritten blocks update their logical birth time,
80+
meaning they will be included in incremental
81+
.Nm zfs Cm send
82+
streams as modified data.
83+
When the
84+
.Fl P
85+
flag is used, rewritten blocks preserve their logical birth time, since
86+
there are no user data changes.
7487
.
7588
.Sh SEE ALSO
76-
.Xr zfsprops 7
89+
.Xr zfsprops 7 ,
90+
.Xr zpool-features 7

module/zcommon/zfeature_common.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,18 @@ zpool_feature_init(void)
798798
ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_NO_UPGRADE,
799799
ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
800800

801+
{
802+
static const spa_feature_t physical_rewrite_deps[] = {
803+
SPA_FEATURE_EXTENSIBLE_DATASET,
804+
SPA_FEATURE_NONE
805+
};
806+
zfeature_register(SPA_FEATURE_PHYSICAL_REWRITE,
807+
"com.truenas:physical_rewrite", "physical_rewrite",
808+
"Support for preserving logical birth time during rewrite.",
809+
ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
810+
ZFEATURE_TYPE_BOOLEAN, physical_rewrite_deps, sfeatures);
811+
}
812+
801813
zfs_mod_list_supported_free(sfeatures);
802814
}
803815

0 commit comments

Comments
 (0)