Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6513 partially filled holes lose birth time #4754

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions cmd/ztest/ztest.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ ztest_func_t ztest_split_pool;
ztest_func_t ztest_reguid;
ztest_func_t ztest_spa_upgrade;
ztest_func_t ztest_fletcher;
ztest_func_t ztest_dmu_free_long_range;

uint64_t zopt_always = 0ULL * NANOSEC; /* all the time */
uint64_t zopt_incessant = 1ULL * NANOSEC / 10; /* every 1/10 second */
Expand Down Expand Up @@ -375,6 +376,7 @@ ztest_info_t ztest_info[] = {
ZTI_INIT(ztest_vdev_add_remove, 1, &ztest_opts.zo_vdevtime),
ZTI_INIT(ztest_vdev_aux_add_remove, 1, &ztest_opts.zo_vdevtime),
ZTI_INIT(ztest_fletcher, 1, &zopt_rarely),
ZTI_INIT(ztest_dmu_free_long_range, 1, &zopt_always),
};

#define ZTEST_FUNCS (sizeof (ztest_info) / sizeof (ztest_info_t))
Expand Down Expand Up @@ -4310,6 +4312,182 @@ ztest_dmu_write_parallel(ztest_ds_t *zd, uint64_t id)
umem_free(od, sizeof (ztest_od_t));
}

static void
ztest_write_free(ztest_ds_t *zd, ztest_od_t *od, dmu_object_info_t *doi)
{
objset_t *os = zd->zd_os;
uint64_t object = od->od_object;
uint64_t size = 1ULL << 40;
uint64_t blocksize = doi->doi_data_block_size;
uint64_t mblocksize = doi->doi_metadata_block_size;
uint64_t l1_range = (mblocksize / sizeof (blkptr_t)) *
blocksize;
void *data = umem_alloc(blocksize, UMEM_NOFAIL);

(void) memset(data, 'a' + (object + l1_range) % 5, blocksize);

while (ztest_random(10)) {
int i, nranges = 0, minoffset = 0, maxoffset = 0;
ztest_zrl_t *zrl;
struct ztest_range {
uint64_t offset;
uint64_t size;
} range[10];
/*
* Touch a few L1 ranges
*/
bzero((void *)range, sizeof (struct ztest_range)*10);
nranges = ztest_random(10);
if (nranges == 0)
nranges = 3;

for (i = 0; i < nranges; i++) {
range[i].offset = ztest_random(size/l1_range)*l1_range;
range[i].size = ztest_random(10)*l1_range;
}

(void) rw_rdlock(&zd->zd_zilog_lock);
for (i = 0; i < nranges; i++) {
if ((ztest_write(zd, object, range[i].offset, blocksize,
data)) ||
(ztest_write(zd, object, range[i].offset +
range[i].size - blocksize, blocksize, data))) {
fatal(0, "dmu_free_long_range() failed\n");
}
}
(void) rw_unlock(&zd->zd_zilog_lock);

/*
* Free all ranges in a variable number of steps
*/
for (i = 0; i < nranges; i ++) {
minoffset = MIN(minoffset, range[i].offset);
maxoffset = MAX(maxoffset, range[i].offset +
range[i].size);
}

ztest_object_lock(zd, object, RL_READER);
zrl = ztest_range_lock(zd, object, minoffset,
maxoffset-minoffset, RL_WRITER);

switch (ztest_random(4)) {
case 0:
/* Free each range separately */
for (i = 0; i < nranges; i++) {
if ((dmu_free_long_range(os, object,
range[i].offset, range[i].size))) {
fatal(0, "dmu_free_long_range() "
"failed\n");
}
}
break;
case 1:
/* Free two ranges at a time */
for (i = 0; i < ((nranges % 2) ? nranges - 1 : nranges);
i += 2) {
uint64_t start =
MIN(range[i].offset, range[i+1].offset);
uint64_t end =
MAX(range[i].offset + range[i].size,
range[i+1].offset + range[i+1].size);
if ((dmu_free_long_range(os, object, start,
end-start))) {
fatal(0, "dmu_free_long_range() "
"failed\n");
}
}
/* Free the last range for odd nranges */
if ((nranges % 2) &&
(dmu_free_long_range(os, object,
range[nranges-1].offset,
range[nranges-1].size))) {
fatal(0, "dmu_free_long_range() failed\n");
}
break;
case 2:
{
/*
* Merge the ranges in two super-ranges and
* free in two steps
*/
uint64_t start = 0, end = 0;
int inranges = ztest_random(nranges);

for (i = 0; i < inranges; i++) {
start = MIN(start, range[i].offset);
end = MAX(end, range[i].offset + range[i].size);
}
if ((inranges != 0) &&
(dmu_free_long_range(os, object, start,
end-start))) {
fatal(0, "dmu_free_long_range() failed\n");
}

for (i = inranges; i < nranges; i++) {
start = MIN(start, range[i].offset);
end = MAX(end, range[i].offset + range[i].size);
}
if ((inranges != nranges) &&
(dmu_free_long_range(os, object, start,
end-start))) {
fatal(0, "dmu_free_long_range() failed\n");
}
}
break;
case 3:
{
/* Merge in one range and free in one step */
uint64_t start = minoffset, end = maxoffset;

if ((dmu_free_long_range(os, object, start,
end-start))) {
fatal(0, "dmu_free_long_range() failed\n");
}
}
break;
case 4:
default:
/* Free the whole logical range of the object */
if ((dmu_free_long_range(os, object, 0, size))) {
fatal(0, "dmu_free_long_range() failed\n");
}
break;
}

ztest_range_unlock(zd, zrl);
ztest_object_unlock(zd, object);
}

umem_free(data, blocksize);
}

/*
* Test punching holes in an object to verify consistency of
* the dmu structures for various corner cases
*
* Force reallocation of dnode between iterations
*/
void
ztest_dmu_free_long_range(ztest_ds_t *zd, uint64_t id)
{
ztest_od_t *od = NULL;
uint64_t blocksize = ztest_random_blocksize();
dmu_object_info_t doi = {0};

od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);

ztest_od_init(od, ID_PARALLEL, FTAG, 0, DMU_OT_UINT64_OTHER,
blocksize, 0);
if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0)
goto out;

VERIFY3U(0, ==, dmu_object_info(zd->zd_os, od->od_object, &doi));
ztest_write_free(zd, od, &doi);

out:
umem_free(od, sizeof (ztest_od_t));
}

void
ztest_dmu_prealloc(ztest_ds_t *zd, uint64_t id)
{
Expand Down
10 changes: 6 additions & 4 deletions include/sys/arc.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
*/

Expand Down Expand Up @@ -193,9 +193,11 @@ int arc_read(zio_t *pio, spa_t *spa, const blkptr_t *bp,
arc_flags_t *arc_flags, const zbookmark_phys_t *zb);
zio_t *arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
blkptr_t *bp, arc_buf_t *buf, boolean_t l2arc, boolean_t l2arc_compress,
const zio_prop_t *zp, arc_done_func_t *ready, arc_done_func_t *physdone,
arc_done_func_t *done, void *private, zio_priority_t priority,
int zio_flags, const zbookmark_phys_t *zb);
const zio_prop_t *zp,
arc_done_func_t *ready, arc_done_func_t *child_ready,
arc_done_func_t *physdone, arc_done_func_t *done,
void *private, zio_priority_t priority, int zio_flags,
const zbookmark_phys_t *zb);

arc_prune_t *arc_add_prune_callback(arc_prune_func_t *func, void *private);
void arc_remove_prune_callback(arc_prune_t *p);
Expand Down
1 change: 1 addition & 0 deletions include/sys/arc_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ typedef struct arc_write_callback arc_write_callback_t;
struct arc_write_callback {
void *awcb_private;
arc_done_func_t *awcb_ready;
arc_done_func_t *awcb_children_ready;
arc_done_func_t *awcb_physdone;
arc_done_func_t *awcb_done;
arc_buf_t *awcb_buf;
Expand Down
12 changes: 7 additions & 5 deletions include/sys/zio.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
*/

Expand Down Expand Up @@ -400,7 +400,8 @@ struct zio {
zio_transform_t *io_transform_stack;

/* Callback info */
zio_done_func_t *io_ready;
zio_done_func_t *io_ready;
zio_done_func_t *io_children_ready;
zio_done_func_t *io_physdone;
zio_done_func_t *io_done;
void *io_private;
Expand Down Expand Up @@ -468,9 +469,10 @@ extern zio_t *zio_read(zio_t *pio, spa_t *spa, const blkptr_t *bp, void *data,

extern zio_t *zio_write(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp,
void *data, uint64_t size, const zio_prop_t *zp,
zio_done_func_t *ready, zio_done_func_t *physdone, zio_done_func_t *done,
void *private,
zio_priority_t priority, enum zio_flag flags, const zbookmark_phys_t *zb);
zio_done_func_t *ready, zio_done_func_t *children_ready,
zio_done_func_t *physdone, zio_done_func_t *done,
void *private, zio_priority_t priority, enum zio_flag flags,
const zbookmark_phys_t *zb);

extern zio_t *zio_rewrite(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp,
void *data, uint64_t size, zio_done_func_t *done, void *private,
Expand Down
19 changes: 16 additions & 3 deletions module/zfs/arc.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
* Copyright (c) 2011, 2016 by Delphix. All rights reserved.
* Copyright (c) 2014 by Saso Kiselkov. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
Expand Down Expand Up @@ -4981,6 +4981,15 @@ arc_write_ready(zio_t *zio)
hdr->b_flags |= ARC_FLAG_IO_IN_PROGRESS;
}

static void
arc_write_children_ready(zio_t *zio)
{
arc_write_callback_t *callback = zio->io_private;
arc_buf_t *buf = callback->awcb_buf;

callback->awcb_children_ready(zio, buf, callback->awcb_private);
}

/*
* The SPA calls this callback for each physical write that happens on behalf
* of a logical write. See the comment in dbuf_write_physdone() for details.
Expand Down Expand Up @@ -5077,7 +5086,8 @@ arc_write_done(zio_t *zio)
zio_t *
arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
blkptr_t *bp, arc_buf_t *buf, boolean_t l2arc, boolean_t l2arc_compress,
const zio_prop_t *zp, arc_done_func_t *ready, arc_done_func_t *physdone,
const zio_prop_t *zp, arc_done_func_t *ready,
arc_done_func_t *children_ready, arc_done_func_t *physdone,
arc_done_func_t *done, void *private, zio_priority_t priority,
int zio_flags, const zbookmark_phys_t *zb)
{
Expand All @@ -5097,13 +5107,16 @@ arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
hdr->b_flags |= ARC_FLAG_L2COMPRESS;
callback = kmem_zalloc(sizeof (arc_write_callback_t), KM_SLEEP);
callback->awcb_ready = ready;
callback->awcb_children_ready = children_ready;
callback->awcb_physdone = physdone;
callback->awcb_done = done;
callback->awcb_private = private;
callback->awcb_buf = buf;

zio = zio_write(pio, spa, txg, bp, buf->b_data, hdr->b_size, zp,
arc_write_ready, arc_write_physdone, arc_write_done, callback,
arc_write_ready,
(children_ready != NULL) ? arc_write_children_ready : NULL,
arc_write_physdone, arc_write_done, callback,
priority, zio_flags, zb);

return (zio);
Expand Down
Loading