diff options
-rw-r--r-- | cmd/zfs/zfs_main.c | 9 | ||||
-rw-r--r-- | include/libzfs.h | 3 | ||||
-rw-r--r-- | lib/libzfs/libzfs_sendrecv.c | 9 | ||||
-rw-r--r-- | man/man8/zfs-receive.8 | 13 | ||||
-rw-r--r-- | tests/runfiles/common.run | 7 | ||||
-rw-r--r-- | tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am | 1 | ||||
-rwxr-xr-x | tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_016_pos.ksh | 85 |
7 files changed, 113 insertions, 14 deletions
diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index d2ec39893..82b91754e 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -298,10 +298,10 @@ get_usage(zfs_help_t idx) case HELP_PROMOTE: return (gettext("\tpromote <clone-filesystem>\n")); case HELP_RECEIVE: - return (gettext("\treceive [-vnsFhu] " + return (gettext("\treceive [-vMnsFhu] " "[-o <property>=<value>] ... [-x <property>] ...\n" "\t <filesystem|volume|snapshot>\n" - "\treceive [-vnsFhu] [-o <property>=<value>] ... " + "\treceive [-vMnsFhu] [-o <property>=<value>] ... " "[-x <property>] ... \n" "\t [-d | -e] <filesystem>\n" "\treceive -A <filesystem|volume>\n")); @@ -4552,7 +4552,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)) { @@ -4587,6 +4587,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 7f728e3a5..236a73130 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -758,6 +758,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 3dc7b0705..39bad750a 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 ac5711ca6..30b509140 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 February 16, 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,9 @@ 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. +This option is not supported on Linux. .It Fl n Do not actually receive the stream. This can be useful in conjunction with the diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index c57989fe4..96700becb 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -208,9 +208,10 @@ tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_003_pos', 'zfs_receive_007_neg', 'zfs_receive_008_pos', 'zfs_receive_009_neg', 'zfs_receive_010_pos', 'zfs_receive_011_pos', 'zfs_receive_012_pos', 'zfs_receive_013_pos', 'zfs_receive_014_pos', 'zfs_receive_015_pos', - 'receive-o-x_props_override', 'zfs_receive_from_encrypted', - 'zfs_receive_to_encrypted', 'zfs_receive_raw', - 'zfs_receive_raw_incremental', 'zfs_receive_-e', 'zfs_receive_raw_-d'] + 'zfs_receive_016_pos', 'receive-o-x_props_override', + 'zfs_receive_from_encrypted', 'zfs_receive_to_encrypted', + 'zfs_receive_raw', 'zfs_receive_raw_incremental', 'zfs_receive_-e', + 'zfs_receive_raw_-d'] tags = ['functional', 'cli_root', 'zfs_receive'] [tests/functional/cli_root/zfs_rename] diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am index 7b2037b9f..d3d81f869 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am @@ -17,6 +17,7 @@ dist_pkgdata_SCRIPTS = \ zfs_receive_013_pos.ksh \ zfs_receive_014_pos.ksh \ zfs_receive_015_pos.ksh \ + zfs_receive_016_pos.ksh \ receive-o-x_props_override.ksh \ zfs_receive_from_encrypted.ksh \ zfs_receive_to_encrypted.ksh \ diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_016_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_016_pos.ksh new file mode 100755 index 000000000..04d20ebd3 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_016_pos.ksh @@ -0,0 +1,85 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# +# Copyright (c) 2020 by Mariusz Zaborski <[email protected]>. + +# +# DESCRIPTION: +# Verify 'zfs recv' can forcibly unmount filesystem while receiving +# stream. +# +# STRATEGY: +# 1. Create snapshot of file system +# 2. Make a zfs filesystem mountpoint busy +# 3. Receive filesystem with force flag. +# 4. Verify that stream was received or failed on Linux. +# + +. $STF_SUITE/tests/functional/cli_root/cli_common.kshlib + +verify_runnable "both" + +function cleanup +{ + cd $curpath + + for snap in $init_snap $rst_snap; do + snapexists $snap && \ + destroy_snapshot $snap + done + + datasetexists $rst_root && \ + destroy_dataset $rst_root + + for file in $full_bkup + do + [[ -e $file ]] && \ + log_must rm -f $file + done + + [[ -d $TESTDIR1 ]] && \ + log_must rm -rf $TESTDIR1 +} + +log_assert "Verify 'zfs recv' can forcibly unmount busy filesystem." +log_onexit cleanup + +curpath=`dirname $0` +init_snap=$TESTPOOL/$TESTFS@init_snap +full_bkup=$TEST_BASE_DIR/fullbkup.$$ +rst_root=$TESTPOOL/rst_ctr +rst_snap=$rst_root@init_snap + +log_note "Verify 'zfs recv' can forcible unmount busy filesystem." + +# Preparation +log_must zfs create $rst_root +[[ ! -d $TESTDIR1 ]] && \ + log_must mkdir -p $TESTDIR1 +log_must zfs set mountpoint=$TESTDIR1 $rst_root + +log_must zfs snapshot $init_snap +log_must eval "zfs send $init_snap > $full_bkup" + +# Test +log_must cd $TESTDIR1 +if is_linux; then + # Linux does not support it. + log_mustnot zfs receive -MF $rst_snap < $full_bkup +else + log_must zfs receive -MF $rst_snap < $full_bkup +fi + +log_pass "The busy filesystem was unmounted or busy as expected." |