Project

General

Profile

Bug #3740 » zfs-send-hold-opt-v2.patch

Steven Hartland, 2013-04-24 07:57 PM

View differences:

cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h 2013-04-24 15:55:00.045597680 +0000
612 612
extern int zfs_promote(zfs_handle_t *);
613 613
extern int zfs_hold(zfs_handle_t *, const char *, const char *,
614 614
    boolean_t, boolean_t, int);
615
extern int zfs_hold_add(zfs_handle_t *, const char *, const char *,
616
    boolean_t, nvlist_t *);
617
extern int zfs_hold_apply(zfs_handle_t *, boolean_t, int, nvlist_t *);
615 618
extern int zfs_release(zfs_handle_t *, const char *, const char *, boolean_t);
616 619
extern int zfs_get_holds(zfs_handle_t *, nvlist_t **);
617 620
extern uint64_t zvol_volsize_to_reservation(uint64_t, nvlist_t *);
618
-- cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c.orig	2013-04-24 15:49:05.360621492 +0000
621
++ cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c	2013-04-24 15:54:08.546600315 +0000
......
4188 4188
}
4189 4189

  
4190 4190
int
4191
zfs_hold_add(zfs_handle_t *zhp, const char *snapname, const char *tag,
4192
    boolean_t enoent_ok, nvlist_t *holds)
4193
{
4194
	zfs_handle_t *szhp;
4195
	char name[ZFS_MAXNAMELEN];
4196
	char errbuf[1024];
4197
	int ret;
4198

  
4199
	(void) snprintf(name, sizeof (name),
4200
	    "%s@%s", zhp->zfs_name, snapname);
4201

  
4202
	szhp = make_dataset_handle(zhp->zfs_hdl, name);
4203
	if (szhp) {
4204
		fnvlist_add_string(holds, name, tag);
4205
		zfs_close(szhp);
4206
		return (0);
4207
	}
4208

  
4209
	ret = ENOENT;
4210
	if (enoent_ok)
4211
		return (ret);
4212

  
4213
	(void) snprintf(errbuf, sizeof (errbuf),
4214
	    dgettext(TEXT_DOMAIN, "cannot hold snapshot '%s@%s'"),
4215
	    zhp->zfs_name, snapname);
4216
	(void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf);
4217

  
4218
	return (ret);
4219
}
4220

  
4221
int
4191 4222
zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4192 4223
    boolean_t recursive, boolean_t enoent_ok, int cleanup_fd)
4193 4224
{
......
4207 4238
	if (nvlist_next_nvpair(ha.nvl, NULL) == NULL) {
4208 4239
		fnvlist_free(ha.nvl);
4209 4240
		ret = ENOENT;
4241
		if (enoent_ok)
4242
			return (ret);
4243

  
4210 4244
		(void) snprintf(errbuf, sizeof (errbuf),
4211 4245
		    dgettext(TEXT_DOMAIN, "cannot hold snapshot '%s@%s'"),
4212 4246
		    zhp->zfs_name, snapname);
......
4214 4248
		return (ret);
4215 4249
	}
4216 4250

  
4217
	ret = lzc_hold(ha.nvl, cleanup_fd, &errors);
4251
	ret = zfs_hold_apply(zhp, enoent_ok, cleanup_fd, &ha.nvl);
4218 4252
	fnvlist_free(ha.nvl);
4219 4253

  
4254
	return (ret);
4255
}
4256

  
4257
int
4258
zfs_hold_apply(zfs_handle_t *zhp, boolean_t enoent_ok, int cleanup_fd, nvlist_t *holds)
4259
{
4260
	int ret;
4261
	nvlist_t *errors;
4262
	libzfs_handle_t *hdl = zhp->zfs_hdl;
4263
	char errbuf[1024];
4264
	nvpair_t *elem;
4265

  
4266
	ret = lzc_hold(holds, cleanup_fd, &errors);
4267

  
4220 4268
	if (ret == 0)
4221 4269
		return (0);
4222 4270

  
......
4274 4322
	return (ret);
4275 4323
}
4276 4324

  
4277
struct releasearg {
4278
	nvlist_t *nvl;
4279
	const char *snapname;
4280
	const char *tag;
4281
	boolean_t recursive;
4282
};
4283

  
4284 4325
static int
4285 4326
zfs_release_one(zfs_handle_t *zhp, void *arg)
4286 4327
{
......
4297 4338
		nvlist_t *holds = fnvlist_alloc();
4298 4339
		fnvlist_add_boolean(holds, ha->tag);
4299 4340
		fnvlist_add_nvlist(ha->nvl, name, holds);
4341
		fnvlist_free(holds);
4300 4342
		zfs_close(szhp);
4301 4343
	}
4302 4344

  
4303
-- cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c.orig	2013-04-22 19:13:01.224334570 +0000
4345
++ cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c	2013-04-24 19:29:47.709713870 +0000
......
802 802
	int outfd;
803 803
	boolean_t err;
804 804
	nvlist_t *fss;
805
	nvlist_t *snapholds;
805 806
	avl_tree_t *fsavl;
806 807
	snapfilter_cb_t *filter_cb;
807 808
	void *filter_cb_arg;
......
961 962

  
962 963
	assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
963 964

  
964
	if (sdd->dryrun)
965
		return (0);
966

  
967 965
	/*
968
	 * zfs_send() only opens a cleanup_fd for sends that need it,
969
	 * e.g. replication and doall.
966
	 * We process if snapholds is not NULL even if on a dry run as
967
	 * this is used to pre-calculate the required holds so they can
968
	 * be processed in one kernel request
970 969
	 */
971
	if (sdd->cleanup_fd == -1)
970
	if (sdd->snapholds == NULL)
972 971
		return (0);
973 972

  
974 973
	thissnap = strchr(zhp->zfs_name, '@') + 1;
......
981 980
	 * handle that error.
982 981
	 */
983 982
	if (pzhp) {
984
		error = zfs_hold(pzhp, thissnap, sdd->holdtag,
985
		    B_FALSE, B_TRUE, sdd->cleanup_fd);
983
		error = zfs_hold_add(pzhp, thissnap, sdd->holdtag, B_TRUE,
984
		    sdd->snapholds);
986 985
		zfs_close(pzhp);
987 986
	}
988 987

  
......
1552 1551
			err = errno;
1553 1552
			goto stderr_out;
1554 1553
		}
1554
		sdd.snapholds = fnvlist_alloc();
1555 1555
	} else {
1556 1556
		sdd.cleanup_fd = -1;
1557
		sdd.snapholds = NULL;
1557 1558
	}
1558 1559
	if (flags->verbose) {
1559 1560
		/*
......
1575 1576
			    "total estimated size is %s\n"), buf);
1576 1577
		}
1577 1578
	}
1579

  
1580
	if (sdd.snapholds != NULL) {
1581
		/* Holds are required */
1582
		if (!flags->verbose) {
1583
			/*
1584
			 * A verbose dry run wasn't done so do a non-verbose
1585
			 * dry run to collate snapshot hold's.
1586
			 */
1587
			sdd.dryrun = B_TRUE;
1588
			err = dump_filesystems(zhp, &sdd);
1589
			sdd.dryrun = flags->dryrun;
1590
		}
1591

  
1592
		if (err != 0) {
1593
			fnvlist_free(sdd.snapholds);
1594
			goto stderr_out;
1595
		}
1596

  
1597
		err = zfs_hold_apply(zhp, B_TRUE, sdd.cleanup_fd, sdd.snapholds);
1598
		fnvlist_free(sdd.snapholds);
1599
		if (err != 0)
1600
			goto stderr_out;
1601
	}
1602
	
1578 1603
	err = dump_filesystems(zhp, &sdd);
1579 1604
	fsavl_destroy(fsavl);
1580 1605
	nvlist_free(fss);
1581
-- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_userhold.c.orig	2013-04-23 11:11:43.424335634 +0000
1606
++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_userhold.c	2013-04-24 19:26:13.986727888 +0000
......
147 147
	if (minor != 0) {
148 148
		VERIFY0(dsl_pool_user_hold(dp, ds->ds_object,
149 149
		    htag, now, tx));
150
		dsl_register_onexit_hold_cleanup(ds, htag, minor);
151 150
	}
152 151

  
153 152
	spa_history_log_internal_ds(ds, "hold", tx,
......
166 165
	for (pair = nvlist_next_nvpair(dduha->dduha_holds, NULL); pair != NULL;
167 166
	    pair = nvlist_next_nvpair(dduha->dduha_holds, pair)) {
168 167
		dsl_dataset_t *ds;
168

  
169 169
		VERIFY0(dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds));
170 170
		dsl_dataset_user_hold_sync_one(ds, fnvpair_value_string(pair),
171 171
		    dduha->dduha_minor, now, tx);
......
186 186
{
187 187
	dsl_dataset_user_hold_arg_t dduha;
188 188
	nvpair_t *pair;
189
	int ret;
189 190

  
190 191
	pair = nvlist_next_nvpair(holds, NULL);
191 192
	if (pair == NULL)
......
195 196
	dduha.dduha_errlist = errlist;
196 197
	dduha.dduha_minor = cleanup_minor;
197 198

  
198
	return (dsl_sync_task(nvpair_name(pair), dsl_dataset_user_hold_check,
199
	    dsl_dataset_user_hold_sync, &dduha, fnvlist_num_pairs(holds)));
199
	ret = dsl_sync_task(nvpair_name(pair), dsl_dataset_user_hold_check,
200
	    dsl_dataset_user_hold_sync, &dduha, fnvlist_num_pairs(holds));
201
	if (ret == 0)
202
		dsl_register_onexit_hold_cleanup(holds, cleanup_minor);
203

  
204
	return (ret);
200 205
}
201 206

  
202 207
typedef struct dsl_dataset_user_release_arg {
......
351 356
dsl_dataset_user_release(nvlist_t *holds, nvlist_t *errlist)
352 357
{
353 358
	dsl_dataset_user_release_arg_t ddura;
354
	nvpair_t *pair;
359
	nvpair_t *pair, *pair2;
355 360
	int error;
356 361

  
357 362
	pair = nvlist_next_nvpair(holds, NULL);
358 363
	if (pair == NULL)
359 364
		return (0);
360 365

  
366
#ifdef _KERNEL
367
	/*
368
	 * The release may cause the snapshot to be destroyed; make sure it
369
	 * is not mounted.
370
	 */
371
	for (pair2 = pair; pair2 != NULL;
372
	    pair2 = nvlist_next_nvpair(holds, pair2)) {
373
		zfs_unmount_snap(nvpair_name(pair2));
374
	}
375
#endif
376

  
361 377
	ddura.ddura_holds = holds;
362 378
	ddura.ddura_errlist = errlist;
363 379
	ddura.ddura_todelete = fnvlist_alloc();
......
368 384
	return (error);
369 385
}
370 386

  
371
typedef struct dsl_dataset_user_release_tmp_arg {
372
	uint64_t ddurta_dsobj;
373
	nvlist_t *ddurta_holds;
374
	boolean_t ddurta_deleteme;
375
} dsl_dataset_user_release_tmp_arg_t;
376

  
377
static int
378
dsl_dataset_user_release_tmp_check(void *arg, dmu_tx_t *tx)
379
{
380
	dsl_dataset_user_release_tmp_arg_t *ddurta = arg;
381
	dsl_pool_t *dp = dmu_tx_pool(tx);
382
	dsl_dataset_t *ds;
383
	int error;
384

  
385
	if (!dmu_tx_is_syncing(tx))
386
		return (0);
387

  
388
	error = dsl_dataset_hold_obj(dp, ddurta->ddurta_dsobj, FTAG, &ds);
389
	if (error)
390
		return (error);
391

  
392
	error = dsl_dataset_user_release_check_one(ds,
393
	    ddurta->ddurta_holds, &ddurta->ddurta_deleteme);
394
	dsl_dataset_rele(ds, FTAG);
395
	return (error);
396
}
397

  
398 387
static void
399
dsl_dataset_user_release_tmp_sync(void *arg, dmu_tx_t *tx)
388
dsl_dataset_user_release_onexit(void *arg)
400 389
{
401
	dsl_dataset_user_release_tmp_arg_t *ddurta = arg;
402
	dsl_pool_t *dp = dmu_tx_pool(tx);
403
	dsl_dataset_t *ds;
390
	nvlist_t *holds = arg;
404 391

  
405
	VERIFY0(dsl_dataset_hold_obj(dp, ddurta->ddurta_dsobj, FTAG, &ds));
406
	dsl_dataset_user_release_sync_one(ds, ddurta->ddurta_holds, tx);
407
	if (ddurta->ddurta_deleteme) {
408
		ASSERT(ds->ds_userrefs == 0 &&
409
		    ds->ds_phys->ds_num_children == 1 &&
410
		    DS_IS_DEFER_DESTROY(ds));
411
		dsl_destroy_snapshot_sync_impl(ds, B_FALSE, tx);
412
	}
413
	dsl_dataset_rele(ds, FTAG);
392
	(void) dsl_dataset_user_release(holds, NULL);
393
	fnvlist_free(holds);
414 394
}
415 395

  
416
/*
417
 * Called at spa_load time to release a stale temporary user hold.
418
 * Also called by the onexit code.
419
 */
420 396
void
421
dsl_dataset_user_release_tmp(dsl_pool_t *dp, uint64_t dsobj, const char *htag)
397
dsl_register_onexit_hold_cleanup(nvlist_t *holds, minor_t minor)
422 398
{
423
	dsl_dataset_user_release_tmp_arg_t ddurta;
424
	dsl_dataset_t *ds;
425
	int error;
426

  
427
#ifdef _KERNEL
428
	/* Make sure it is not mounted. */
429
	dsl_pool_config_enter(dp, FTAG);
430
	error = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
431
	if (error == 0) {
432
		char name[MAXNAMELEN];
433
		dsl_dataset_name(ds, name);
434
		dsl_dataset_rele(ds, FTAG);
435
		dsl_pool_config_exit(dp, FTAG);
436
		zfs_unmount_snap(name);
437
	} else {
438
		dsl_pool_config_exit(dp, FTAG);
439
	}
440
#endif
441

  
442
	ddurta.ddurta_dsobj = dsobj;
443
	ddurta.ddurta_holds = fnvlist_alloc();
444
	fnvlist_add_boolean(ddurta.ddurta_holds, htag);
445

  
446
	(void) dsl_sync_task(spa_name(dp->dp_spa),
447
	    dsl_dataset_user_release_tmp_check,
448
	    dsl_dataset_user_release_tmp_sync, &ddurta, 1);
449
	fnvlist_free(ddurta.ddurta_holds);
450
}
451

  
452
typedef struct zfs_hold_cleanup_arg {
453
	char zhca_spaname[MAXNAMELEN];
454
	uint64_t zhca_spa_load_guid;
455
	uint64_t zhca_dsobj;
456
	char zhca_htag[MAXNAMELEN];
457
} zfs_hold_cleanup_arg_t;
458

  
459
static void
460
dsl_dataset_user_release_onexit(void *arg)
461
{
462
	zfs_hold_cleanup_arg_t *ca = arg;
463
	spa_t *spa;
464
	int error;
399
	nvlist_t *ca;
400
	nvpair_t *pair;
401
	char *htag;
465 402

  
466
	error = spa_open(ca->zhca_spaname, &spa, FTAG);
467
	if (error != 0) {
468
		zfs_dbgmsg("couldn't release hold on pool=%s ds=%llu tag=%s "
469
		    "because pool is no longer loaded",
470
		    ca->zhca_spaname, ca->zhca_dsobj, ca->zhca_htag);
471
		return;
472
	}
473
	if (spa_load_guid(spa) != ca->zhca_spa_load_guid) {
474
		zfs_dbgmsg("couldn't release hold on pool=%s ds=%llu tag=%s "
475
		    "because pool is no longer loaded (guid doesn't match)",
476
		    ca->zhca_spaname, ca->zhca_dsobj, ca->zhca_htag);
477
		spa_close(spa, FTAG);
478
		return;
479
	}
480

  
481
	dsl_dataset_user_release_tmp(spa_get_dsl(spa),
482
	    ca->zhca_dsobj, ca->zhca_htag);
483
	kmem_free(ca, sizeof (zfs_hold_cleanup_arg_t));
484
	spa_close(spa, FTAG);
485
}
403
	ca = fnvlist_alloc();
404
	/*
405
	 * Convert from hold format: nvl of snapname -> holdname
406
	 * to release format: nvl of snapname -> { holdname, ... }
407
	 */
408
	for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
409
	    pair = nvlist_next_nvpair(holds, pair)) {
410
		if (nvpair_value_string(pair, &htag) == 0) {
411
			nvlist_t *tags;
486 412

  
487
void
488
dsl_register_onexit_hold_cleanup(dsl_dataset_t *ds, const char *htag,
489
    minor_t minor)
490
{
491
	zfs_hold_cleanup_arg_t *ca = kmem_alloc(sizeof (*ca), KM_SLEEP);
492
	spa_t *spa = dsl_dataset_get_spa(ds);
493
	(void) strlcpy(ca->zhca_spaname, spa_name(spa),
494
	    sizeof (ca->zhca_spaname));
495
	ca->zhca_spa_load_guid = spa_load_guid(spa);
496
	ca->zhca_dsobj = ds->ds_object;
497
	(void) strlcpy(ca->zhca_htag, htag, sizeof (ca->zhca_htag));
413
			tags = fnvlist_alloc();
414
			fnvlist_add_boolean(tags, htag);
415
			fnvlist_add_nvlist(ca, nvpair_name(pair), tags);
416
			fnvlist_free(tags);
417
		}
418
	}
498 419
	VERIFY0(zfs_onexit_add_cb(minor,
499 420
	    dsl_dataset_user_release_onexit, ca, NULL));
500 421
}
501
-- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h.orig	2013-04-23 13:07:36.990900411 +0000
422
++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h	2013-04-23 13:07:58.639898371 +0000
......
187 187
void dsl_dataset_disown(dsl_dataset_t *ds, void *tag);
188 188
void dsl_dataset_name(dsl_dataset_t *ds, char *name);
189 189
boolean_t dsl_dataset_tryown(dsl_dataset_t *ds, void *tag);
190
void dsl_register_onexit_hold_cleanup(dsl_dataset_t *ds, const char *htag,
191
    minor_t minor);
190
void dsl_register_onexit_hold_cleanup(nvlist_t *holds, minor_t minor);
192 191
uint64_t dsl_dataset_create_sync(dsl_dir_t *pds, const char *lastname,
193 192
    dsl_dataset_t *origin, uint64_t flags, cred_t *, dmu_tx_t *);
194 193
uint64_t dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
195
-- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_userhold.h.orig	2013-04-23 19:12:48.579690392 +0000
194
++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_userhold.h	2013-04-23 19:13:23.789684539 +0000
......
43 43
    nvlist_t *errlist);
44 44
int dsl_dataset_user_release(nvlist_t *holds, nvlist_t *errlist);
45 45
int dsl_dataset_get_holds(const char *dsname, nvlist_t *nvl);
46
void dsl_dataset_user_release_tmp(struct dsl_pool *dp, uint64_t dsobj,
47
    const char *htag);
48 46
int dsl_dataset_user_hold_check_one(struct dsl_dataset *ds, const char *htag,
49 47
    boolean_t temphold, struct dmu_tx *tx);
50 48
void dsl_dataset_user_hold_sync_one(struct dsl_dataset *ds, const char *htag,
51
-- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c.orig	2013-04-23 23:17:48.382680968 +0000
49
++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c	2013-04-23 23:17:55.854678480 +0000
......
5074 5074
static int
5075 5075
zfs_ioc_release(const char *pool, nvlist_t *holds, nvlist_t *errlist)
5076 5076
{
5077
	nvpair_t *pair;
5078

  
5079
	/*
5080
	 * The release may cause the snapshot to be destroyed; make sure it
5081
	 * is not mounted.
5082
	 */
5083
	for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
5084
	    pair = nvlist_next_nvpair(holds, pair))
5085
		zfs_unmount_snap(nvpair_name(pair));
5086

  
5087 5077
	return (dsl_dataset_user_release(holds, errlist));
5088 5078
}
5089 5079

  
(2-2/2)