From 23dceddce5c91889a27cf3639bed16cadb5356b1 Mon Sep 17 00:00:00 2001 From: Mariusz Zaborski Date: Mon, 27 Jan 2020 21:20:46 +0100 Subject: [PATCH] zfs: add option for forcible unmounting dataset while receiving snapshot. Currently when the dataset is in use we can't receive snapshot. zfs send test/1@asd | zfs recv -FM test/2 cannot unmount '/test/2': Device busy The same goes for the Linux version: oshogbo@u-wing:/test$ sudo sudo zfs send test/1@b | sudo zfs recv -F test/2 umount: /test/2: target is busy. cannot unmount '/test/2': umount failed oshogbo@u-wing:/test$ uname -a Linux u-wing 4.18.0-25-generic #26-Ubuntu SMP Mon Jun 24 09:32:08 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux This commits add option 'M' which forcible unmounting the dataset. Thanks to to that we can enforce receiving snapshot in single step. Discussed with: pjd Reviewed by: AllanJude (FreeBSD version) FreeBSD review: https://reviews.freebsd.org/D22306 Signed-off-by: Mariusz Zaborski --- cmd/zfs/zfs_main.c | 9 ++++++--- include/libzfs.h | 3 +++ lib/libzfs/libzfs_sendrecv.c | 9 ++++++--- man/man8/zfs-receive.8 | 12 +++++++----- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 20ecb30314c3..18b108243844 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -297,10 +297,10 @@ get_usage(zfs_help_t idx) case HELP_PROMOTE: return (gettext("\tpromote \n")); case HELP_RECEIVE: - return (gettext("\treceive [-vnsFhu] " + return (gettext("\treceive [-vMnsFhu] " "[-o =] ... [-x ] ...\n" "\t \n" - "\treceive [-vnsFhu] [-o =] ... " + "\treceive [-vMnsFhu] [-o =] ... " "[-x ] ... \n" "\t [-d | -e] \n" "\treceive -A \n")); @@ -4550,7 +4550,7 @@ zfs_do_receive(int argc, char **argv) nomem(); /* check options */ - while ((c = getopt(argc, argv, ":o:x:dehnuvFsA")) != -1) { + while ((c = getopt(argc, argv, ":o:x:dehMnuvFsA")) != -1) { switch (c) { case 'o': if (!parseprop(props, optarg)) { @@ -4585,6 +4585,9 @@ zfs_do_receive(int argc, char **argv) case 'h': flags.skipholds = B_TRUE; break; + case 'M': + flags.forceunmount = B_TRUE; + break; case 'n': flags.dryrun = B_TRUE; break; diff --git a/include/libzfs.h b/include/libzfs.h index 05abfdf89ece..298409bf2bf5 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -755,6 +755,9 @@ typedef struct recvflags { /* mount the filesystem unless nomount is specified */ boolean_t domount; + + /* force unmount while recv snapshot (private) */ + boolean_t forceunmount; } recvflags_t; extern int zfs_receive(libzfs_handle_t *, const char *, nvlist_t *, diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 6179d4dda6b9..142e97bf2058 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -4059,7 +4059,8 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname, ZFS_TYPE_FILESYSTEM); if (zhp != NULL) { clp = changelist_gather(zhp, - ZFS_PROP_MOUNTPOINT, 0, 0); + ZFS_PROP_MOUNTPOINT, 0, + flags->forceunmount ? MS_FORCE : 0); zfs_close(zhp); if (clp != NULL) { softerr |= @@ -4876,7 +4877,8 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, if (!flags->dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM && stream_wantsnewfs) { /* We can't do online recv in this case */ - clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0); + clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, + flags->forceunmount ? MS_FORCE : 0); if (clp == NULL) { zfs_close(zhp); err = -1; @@ -5556,7 +5558,8 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props, } clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, - CL_GATHER_MOUNT_ALWAYS, 0); + CL_GATHER_MOUNT_ALWAYS, + flags->forceunmount ? MS_FORCE : 0); zfs_close(zhp); if (clp == NULL) { err = -1; diff --git a/man/man8/zfs-receive.8 b/man/man8/zfs-receive.8 index ac5711ca6712..d4b76c05be5f 100644 --- a/man/man8/zfs-receive.8 +++ b/man/man8/zfs-receive.8 @@ -30,7 +30,7 @@ .\" Copyright 2018 Nexenta Systems, Inc. .\" Copyright 2019 Joyent, Inc. .\" -.Dd June 30, 2019 +.Dd January 27, 2020 .Dt ZFS-RECEIVE 8 .Os Linux .Sh NAME @@ -39,14 +39,14 @@ .Sh SYNOPSIS .Nm .Cm receive -.Op Fl Fhnsuv +.Op Fl FhMnsuv .Op Fl o Sy origin Ns = Ns Ar snapshot .Op Fl o Ar property Ns = Ns Ar value .Op Fl x Ar property .Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot .Nm .Cm receive -.Op Fl Fhnsuv +.Op Fl FhMnsuv .Op Fl d Ns | Ns Fl e .Op Fl o Sy origin Ns = Ns Ar snapshot .Op Fl o Ar property Ns = Ns Ar value @@ -61,7 +61,7 @@ .It Xo .Nm .Cm receive -.Op Fl Fhnsuv +.Op Fl FhMnsuv .Op Fl o Sy origin Ns = Ns Ar snapshot .Op Fl o Ar property Ns = Ns Ar value .Op Fl x Ar property @@ -70,7 +70,7 @@ .It Xo .Nm .Cm receive -.Op Fl Fhnsuv +.Op Fl FhMnsuv .Op Fl d Ns | Ns Fl e .Op Fl o Sy origin Ns = Ns Ar snapshot .Op Fl o Ar property Ns = Ns Ar value @@ -229,6 +229,8 @@ that element to determine the name of the target file system for the new snapshot as described in the paragraph above. .It Fl h Skip the receive of holds. There is no effect if holds are not sent. +.It Fl M +Force an unmount of the file system while receiving a snapshot. .It Fl n Do not actually receive the stream. This can be useful in conjunction with the