aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/zfs/zfs_main.c9
-rw-r--r--include/libzfs.h3
-rw-r--r--lib/libzfs/libzfs_sendrecv.c9
-rw-r--r--man/man8/zfs-receive.813
-rw-r--r--tests/runfiles/common.run7
-rw-r--r--tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am1
-rwxr-xr-xtests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_016_pos.ksh85
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."