Skip to content

Commit 40534fe

Browse files
committed
Remove dedupditto functionality
If dedup is in use, the `dedupditto` property can be set, causing ZFS to keep an extra copy of data that is referenced many times (>100x). The idea was that this data is more important than other data and thus we want to be really sure that it is not lost if the disk experiences a small amount of random corruption. ZFS (and system administrators) rely on the pool-level redundancy to protect their data (e.g. mirroring or RAIDZ). Since the user/sysadmin doesn't have control over what data will be offered extra redundancy by dedupditto, this extra redundancy is not very useful. The bulk of the data is still vulnerable to loss based on the pool-level redundancy. For example, if particle strikes corrupt 0.1% of blocks, you will either be saved by mirror/raidz, or you will be sad. This is true even if dedupditto saved another 0.01% of blocks from being corrupted. Therefore, the dedupditto functionality is rarely enabled (i.e. the property is rarely set), and it fulfills its promise of increased redundancy even more rarely. Additionally, this feature does not work as advertised (on existing releases), because scrub/resilver did not repair the extra (dedupditto) copy (see #8270). In summary, this seldom-used feature doesn't work, and even if it did it wouldn't provide useful data protection. It has a non-trivial maintenance burden (again see #8270). We should remove the dedupditto functionality. For backwards compatibility with the existing CLI, "zpool set dedupditto" will still "succeed" (exit code zero), but won't have any effect. For backwards compatibility with existing pools that had dedupditto enabled at some point, the code will still be able to understand dedupditto blocks and free them when appropriate. However, ZFS won't write any new dedupditto blocks.
1 parent 1a75920 commit 40534fe

File tree

12 files changed

+30
-340
lines changed

12 files changed

+30
-340
lines changed

cmd/ztest/ztest.c

Lines changed: 8 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,6 @@ ztest_func_t ztest_dsl_prop_get_set;
358358
ztest_func_t ztest_spa_prop_get_set;
359359
ztest_func_t ztest_spa_create_destroy;
360360
ztest_func_t ztest_fault_inject;
361-
ztest_func_t ztest_ddt_repair;
362361
ztest_func_t ztest_dmu_snapshot_hold;
363362
ztest_func_t ztest_mmp_enable_disable;
364363
ztest_func_t ztest_scrub;
@@ -412,7 +411,6 @@ ztest_info_t ztest_info[] = {
412411
ZTI_INIT(ztest_dmu_snapshot_create_destroy, 1, &zopt_sometimes),
413412
ZTI_INIT(ztest_spa_create_destroy, 1, &zopt_sometimes),
414413
ZTI_INIT(ztest_fault_inject, 1, &zopt_sometimes),
415-
ZTI_INIT(ztest_ddt_repair, 1, &zopt_sometimes),
416414
ZTI_INIT(ztest_dmu_snapshot_hold, 1, &zopt_sometimes),
417415
ZTI_INIT(ztest_mmp_enable_disable, 1, &zopt_sometimes),
418416
ZTI_INIT(ztest_reguid, 1, &zopt_rarely),
@@ -1281,18 +1279,18 @@ ztest_dsl_prop_set_uint64(char *osname, zfs_prop_t prop, uint64_t value,
12811279
}
12821280

12831281
static int
1284-
ztest_spa_prop_set_uint64(zpool_prop_t prop, uint64_t value)
1282+
ztest_spa_prop_set_string(zpool_prop_t prop, const char *value)
12851283
{
12861284
spa_t *spa = ztest_spa;
12871285
nvlist_t *props = NULL;
12881286
int error;
12891287

1290-
VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
1291-
VERIFY(nvlist_add_uint64(props, zpool_prop_to_name(prop), value) == 0);
1288+
props = fnvlist_alloc();
1289+
fnvlist_add_string(props, zpool_prop_to_name(prop), value);
12921290

12931291
error = spa_prop_set(spa, props);
12941292

1295-
nvlist_free(props);
1293+
fnvlist_free(props);
12961294

12971295
if (error == ENOSPC) {
12981296
ztest_record_enospc(FTAG);
@@ -1520,31 +1518,6 @@ ztest_tx_assign(dmu_tx_t *tx, uint64_t txg_how, const char *tag)
15201518
return (txg);
15211519
}
15221520

1523-
static void
1524-
ztest_pattern_set(void *buf, uint64_t size, uint64_t value)
1525-
{
1526-
uint64_t *ip = buf;
1527-
uint64_t *ip_end = (uint64_t *)((uintptr_t)buf + (uintptr_t)size);
1528-
1529-
while (ip < ip_end)
1530-
*ip++ = value;
1531-
}
1532-
1533-
#ifndef NDEBUG
1534-
static boolean_t
1535-
ztest_pattern_match(void *buf, uint64_t size, uint64_t value)
1536-
{
1537-
uint64_t *ip = buf;
1538-
uint64_t *ip_end = (uint64_t *)((uintptr_t)buf + (uintptr_t)size);
1539-
uint64_t diff = 0;
1540-
1541-
while (ip < ip_end)
1542-
diff |= (value - *ip++);
1543-
1544-
return (diff == 0);
1545-
}
1546-
#endif
1547-
15481521
static void
15491522
ztest_bt_generate(ztest_block_tag_t *bt, objset_t *os, uint64_t object,
15501523
uint64_t dnodesize, uint64_t offset, uint64_t gen, uint64_t txg,
@@ -5564,8 +5537,10 @@ ztest_spa_prop_get_set(ztest_ds_t *zd, uint64_t id)
55645537

55655538
(void) pthread_rwlock_rdlock(&ztest_name_lock);
55665539

5567-
(void) ztest_spa_prop_set_uint64(ZPOOL_PROP_DEDUPDITTO,
5568-
ZIO_DEDUPDITTO_MIN + ztest_random(ZIO_DEDUPDITTO_MIN));
5540+
char *propval = kmem_asprintf("test property value %u",
5541+
(int)ztest_random(100));
5542+
(void) ztest_spa_prop_set_string(ZPOOL_PROP_COMMENT, propval);
5543+
strfree(propval);
55695544

55705545
VERIFY0(spa_prop_get(ztest_spa, &props));
55715546

@@ -6005,136 +5980,6 @@ ztest_fault_inject(ztest_ds_t *zd, uint64_t id)
60055980
umem_free(pathrand, MAXPATHLEN);
60065981
}
60075982

6008-
/*
6009-
* Verify that DDT repair works as expected.
6010-
*/
6011-
void
6012-
ztest_ddt_repair(ztest_ds_t *zd, uint64_t id)
6013-
{
6014-
ztest_shared_t *zs = ztest_shared;
6015-
spa_t *spa = ztest_spa;
6016-
objset_t *os = zd->zd_os;
6017-
ztest_od_t *od;
6018-
uint64_t object, blocksize, txg, pattern;
6019-
enum zio_checksum checksum = spa_dedup_checksum(spa);
6020-
dmu_buf_t *db;
6021-
dmu_tx_t *tx;
6022-
6023-
od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
6024-
ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, 0);
6025-
6026-
if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) {
6027-
umem_free(od, sizeof (ztest_od_t));
6028-
return;
6029-
}
6030-
6031-
/*
6032-
* Take the name lock as writer to prevent anyone else from changing
6033-
* the pool and dataset properties we need to maintain during this test.
6034-
*/
6035-
(void) pthread_rwlock_wrlock(&ztest_name_lock);
6036-
6037-
if (ztest_dsl_prop_set_uint64(zd->zd_name, ZFS_PROP_DEDUP, checksum,
6038-
B_FALSE) != 0 ||
6039-
ztest_dsl_prop_set_uint64(zd->zd_name, ZFS_PROP_COPIES, 1,
6040-
B_FALSE) != 0) {
6041-
(void) pthread_rwlock_unlock(&ztest_name_lock);
6042-
umem_free(od, sizeof (ztest_od_t));
6043-
return;
6044-
}
6045-
6046-
dmu_objset_stats_t dds;
6047-
dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
6048-
dmu_objset_fast_stat(os, &dds);
6049-
dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
6050-
6051-
object = od[0].od_object;
6052-
blocksize = od[0].od_blocksize;
6053-
pattern = zs->zs_guid ^ dds.dds_guid;
6054-
6055-
/*
6056-
* The numbers of copies written must always be greater than or
6057-
* equal to the threshold set by the dedupditto property. This
6058-
* is initialized in ztest_run() and then randomly changed by
6059-
* ztest_spa_prop_get_set(), these function will never set it
6060-
* larger than 2 * ZIO_DEDUPDITTO_MIN.
6061-
*/
6062-
int copies = 2 * ZIO_DEDUPDITTO_MIN;
6063-
6064-
/*
6065-
* The block size is limited by DMU_MAX_ACCESS (64MB) which
6066-
* caps the maximum transaction size. A block size of up to
6067-
* SPA_OLD_MAXBLOCKSIZE is allowed which results in a maximum
6068-
* transaction size of: 128K * 200 (copies) = ~25MB
6069-
*
6070-
* The actual block size is checked here, rather than requested
6071-
* above, because the way ztest_od_init() is implemented it does
6072-
* not guarantee the block size requested will be used.
6073-
*/
6074-
if (blocksize > SPA_OLD_MAXBLOCKSIZE) {
6075-
(void) pthread_rwlock_unlock(&ztest_name_lock);
6076-
umem_free(od, sizeof (ztest_od_t));
6077-
return;
6078-
}
6079-
6080-
ASSERT(object != 0);
6081-
6082-
tx = dmu_tx_create(os);
6083-
dmu_tx_hold_write(tx, object, 0, copies * blocksize);
6084-
txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
6085-
if (txg == 0) {
6086-
(void) pthread_rwlock_unlock(&ztest_name_lock);
6087-
umem_free(od, sizeof (ztest_od_t));
6088-
return;
6089-
}
6090-
6091-
/*
6092-
* Write all the copies of our block.
6093-
*/
6094-
for (int i = 0; i < copies; i++) {
6095-
uint64_t offset = i * blocksize;
6096-
int error = dmu_buf_hold(os, object, offset, FTAG, &db,
6097-
DMU_READ_NO_PREFETCH);
6098-
if (error != 0) {
6099-
fatal(B_FALSE, "dmu_buf_hold(%p, %llu, %llu) = %u",
6100-
os, (long long)object, (long long) offset, error);
6101-
}
6102-
ASSERT(db->db_offset == offset);
6103-
ASSERT(db->db_size == blocksize);
6104-
ASSERT(ztest_pattern_match(db->db_data, db->db_size, pattern) ||
6105-
ztest_pattern_match(db->db_data, db->db_size, 0ULL));
6106-
dmu_buf_will_fill(db, tx);
6107-
ztest_pattern_set(db->db_data, db->db_size, pattern);
6108-
dmu_buf_rele(db, FTAG);
6109-
}
6110-
6111-
dmu_tx_commit(tx);
6112-
txg_wait_synced(spa_get_dsl(spa), txg);
6113-
6114-
/*
6115-
* Find out what block we got.
6116-
*/
6117-
VERIFY0(dmu_buf_hold(os, object, 0, FTAG, &db, DMU_READ_NO_PREFETCH));
6118-
blkptr_t blk = *((dmu_buf_impl_t *)db)->db_blkptr;
6119-
dmu_buf_rele(db, FTAG);
6120-
6121-
/*
6122-
* Damage the block. Dedup-ditto will save us when we read it later.
6123-
*/
6124-
uint64_t psize = BP_GET_PSIZE(&blk);
6125-
abd_t *abd = abd_alloc_linear(psize, B_TRUE);
6126-
ztest_pattern_set(abd_to_buf(abd), psize, ~pattern);
6127-
6128-
(void) zio_wait(zio_rewrite(NULL, spa, 0, &blk,
6129-
abd, psize, NULL, NULL, ZIO_PRIORITY_SYNC_WRITE,
6130-
ZIO_FLAG_CANFAIL | ZIO_FLAG_INDUCE_DAMAGE, NULL));
6131-
6132-
abd_free(abd);
6133-
6134-
(void) pthread_rwlock_unlock(&ztest_name_lock);
6135-
umem_free(od, sizeof (ztest_od_t));
6136-
}
6137-
61385983
/*
61395984
* By design ztest will never inject uncorrectable damage in to the pool.
61405985
* Issue a scrub, wait for it to complete, and verify there is never any
@@ -7015,8 +6860,6 @@ ztest_run(ztest_shared_t *zs)
70156860
zs->zs_guid = dds.dds_guid;
70166861
dmu_objset_disown(os, B_TRUE, FTAG);
70176862

7018-
spa->spa_dedup_ditto = 2 * ZIO_DEDUPDITTO_MIN;
7019-
70206863
/*
70216864
* Create a thread to periodically resume suspended I/O.
70226865
*/

include/sys/ddt.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ typedef struct ddt_phys {
103103
uint64_t ddp_phys_birth;
104104
} ddt_phys_t;
105105

106+
/*
107+
* Note, we no longer generate new DDT_PHYS_DITTO-type blocks. However,
108+
* we maintain the ability to free existing dedup-ditto blocks.
109+
*/
106110
enum ddt_phys_type {
107111
DDT_PHYS_DITTO = 0,
108112
DDT_PHYS_SINGLE = 1,
@@ -216,10 +220,6 @@ extern void ddt_get_dedup_stats(spa_t *spa, ddt_stat_t *dds_total);
216220
extern uint64_t ddt_get_dedup_dspace(spa_t *spa);
217221
extern uint64_t ddt_get_pool_dedup_ratio(spa_t *spa);
218222

219-
extern int ddt_ditto_copies_needed(ddt_t *ddt, ddt_entry_t *dde,
220-
ddt_phys_t *ddp_willref);
221-
extern int ddt_ditto_copies_present(ddt_entry_t *dde);
222-
223223
extern size_t ddt_compress(void *src, uchar_t *dst, size_t s_len, size_t d_len);
224224
extern void ddt_decompress(uchar_t *src, void *dst, size_t s_len, size_t d_len);
225225

include/sys/spa_impl.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,6 @@ struct spa {
350350
ddt_t *spa_ddt[ZIO_CHECKSUM_FUNCTIONS]; /* in-core DDTs */
351351
uint64_t spa_ddt_stat_object; /* DDT statistics */
352352
uint64_t spa_dedup_dspace; /* Cache get_dedup_dspace() */
353-
uint64_t spa_dedup_ditto; /* dedup ditto threshold */
354353
uint64_t spa_dedup_checksum; /* default dedup checksum */
355354
uint64_t spa_dspace; /* dspace in normal class */
356355
kmutex_t spa_vdev_top_lock; /* dueling offline/remove */

include/sys/zio.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ enum zio_checksum {
102102
#define ZIO_CHECKSUM_VERIFY (1 << 8)
103103

104104
#define ZIO_DEDUPCHECKSUM ZIO_CHECKSUM_SHA256
105-
#define ZIO_DEDUPDITTO_MIN 100
106105

107106
/* supported encryption algorithms */
108107
enum zio_encrypt {

lib/libzfs/libzfs_pool.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -722,15 +722,8 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
722722
}
723723
break;
724724
case ZPOOL_PROP_DEDUPDITTO:
725-
if (intval < ZIO_DEDUPDITTO_MIN && intval != 0) {
726-
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
727-
"property '%s' value %d is invalid; only "
728-
"values of 0 or >= %" PRId32 " are allowed "
729-
"for this property."),
730-
propname, intval, ZIO_DEDUPDITTO_MIN);
731-
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
732-
goto error;
733-
}
725+
printf("Note: property '%s' no longer has "
726+
"any effect\n", propname);
734727
break;
735728

736729
default:

man/man8/zpool.8

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -768,14 +768,7 @@ such that it is available even if the pool becomes faulted.
768768
An administrator can provide additional information about a pool using this
769769
property.
770770
.It Sy dedupditto Ns = Ns Ar number
771-
Threshold for the number of block ditto copies.
772-
If the reference count for a deduplicated block increases above this number, a
773-
new ditto copy of this block is automatically stored.
774-
The default setting is
775-
.Sy 0
776-
which causes no ditto copies to be created for deduplicated blocks.
777-
The minimum legal nonzero setting is
778-
.Sy 100 .
771+
This property is deprecated and no longer has any effect.
779772
.It Sy delegation Ns = Ns Sy on Ns | Ns Sy off
780773
Controls whether a non-privileged user is granted access based on the dataset
781774
permissions defined on the dataset.

module/zcommon/zpool_prop.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,6 @@ zpool_prop_init(void)
104104
/* default number properties */
105105
zprop_register_number(ZPOOL_PROP_VERSION, "version", SPA_VERSION,
106106
PROP_DEFAULT, ZFS_TYPE_POOL, "<version>", "VERSION");
107-
zprop_register_number(ZPOOL_PROP_DEDUPDITTO, "dedupditto", 0,
108-
PROP_DEFAULT, ZFS_TYPE_POOL, "<threshold (min 100)>", "DEDUPDITTO");
109107
zprop_register_number(ZPOOL_PROP_ASHIFT, "ashift", 0, PROP_DEFAULT,
110108
ZFS_TYPE_POOL, "<ashift, 9-16, or 0=default>", "ASHIFT");
111109

@@ -140,6 +138,8 @@ zpool_prop_init(void)
140138
PROP_ONETIME, ZFS_TYPE_POOL, "TNAME");
141139
zprop_register_hidden(ZPOOL_PROP_MAXDNODESIZE, "maxdnodesize",
142140
PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_POOL, "MAXDNODESIZE");
141+
zprop_register_hidden(ZPOOL_PROP_DEDUPDITTO, "dedupditto",
142+
PROP_TYPE_NUMBER, PROP_DEFAULT, ZFS_TYPE_POOL, "DEDUPDITTO");
143143
}
144144

145145
/*

0 commit comments

Comments
 (0)