Skip to content

Commit

Permalink
Merge pull request openzfs#14 from bgly/fixes
Browse files Browse the repository at this point in the history
Fixes
  • Loading branch information
Bryant G. Ly authored Dec 10, 2019
2 parents 11278d4 + a3b527e commit ec9c367
Show file tree
Hide file tree
Showing 20 changed files with 474 additions and 39 deletions.
65 changes: 56 additions & 9 deletions cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,8 @@ get_usage(zfs_help_t idx)
return (gettext("\tset <property=value> ... "
"<filesystem|volume|snapshot> ...\n"));
case HELP_SHARE:
return (gettext("\tshare [-l] <-a [nfs|smb] | filesystem>\n"));
return (gettext("\tshare [-l] <-a [nfs|smb] | filesystem>\n"
"\tshare <-g [nfs]\n"));
case HELP_SNAPSHOT:
return (gettext("\tsnapshot [-r] [-o property=value] ... "
"<filesystem|volume>@<snap> ...\n"));
Expand Down Expand Up @@ -6234,6 +6235,7 @@ typedef enum { OP_SHARE, OP_MOUNT } share_mount_op_t;
typedef struct share_mount_state {
share_mount_op_t sm_op;
boolean_t sm_verbose;
boolean_t sm_generate;
int sm_flags;
char *sm_options;
char *sm_proto; /* only valid for OP_SHARE */
Expand All @@ -6248,7 +6250,7 @@ typedef struct share_mount_state {
*/
static int
share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
boolean_t explicit, const char *options)
boolean_t explicit, boolean_t generate, const char *options)
{
char mountpoint[ZFS_MAXPROPLEN];
char shareopts[ZFS_MAXPROPLEN];
Expand Down Expand Up @@ -6355,10 +6357,21 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
"'canmount' property is set to 'off'\n"), cmdname,
zfs_get_name(zhp));
return (1);
} else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) {
return (0);
} else if (canmount == ZFS_CANMOUNT_NOAUTO) {
/*
* Skip this request when noauto is set and we wanted all
* mounts|shares (i.e. -a) or we're not generating exports
*/
if (!explicit && !generate)
return (0);
}

/*
* When generating shares and the filesystem isn't mounted then skip it
*/
if (generate && !zfs_is_mounted(zhp, NULL))
return (0);

/*
* If this filesystem is encrypted and does not have
* a loaded key, we can not mount it.
Expand Down Expand Up @@ -6403,6 +6416,15 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
switch (op) {
case OP_SHARE:

/*
* Generate a linux-specific exports file. This will create
* an NFS only file that can be used by the linux NFS utils
* to automatically share out ZFS filesystems.
*/
if (generate) {
return (zfs_share_generate(zhp));
}

shared_nfs = zfs_is_shared_nfs(zhp, NULL);
shared_smb = zfs_is_shared_smb(zhp, NULL);

Expand Down Expand Up @@ -6527,7 +6549,7 @@ share_mount_one_cb(zfs_handle_t *zhp, void *arg)
int ret;

ret = share_mount_one(zhp, sms->sm_op, sms->sm_flags, sms->sm_proto,
B_FALSE, sms->sm_options);
B_FALSE, sms->sm_generate, sms->sm_options);

pthread_mutex_lock(&sms->sm_lock);
if (ret != 0)
Expand Down Expand Up @@ -6561,18 +6583,19 @@ append_options(char *mntopts, char *newopts)
static int
share_mount(int op, int argc, char **argv)
{
int do_all = 0;
boolean_t do_all = B_FALSE;
boolean_t verbose = B_FALSE;
boolean_t do_generate = B_FALSE;
int c, ret = 0;
char *options = NULL;
int flags = 0;

/* check options */
while ((c = getopt(argc, argv, op == OP_MOUNT ? ":alvo:O" : "al"))
while ((c = getopt(argc, argv, op == OP_MOUNT ? ":alvo:O" : "agl"))
!= -1) {
switch (c) {
case 'a':
do_all = 1;
do_all = B_TRUE;
break;
case 'v':
verbose = B_TRUE;
Expand All @@ -6596,6 +6619,14 @@ share_mount(int op, int argc, char **argv)
case 'O':
flags |= MS_OVERLAY;
break;
case 'g':
/*
* Generating the share information can only be
* performed on all shares.
*/
do_all = B_TRUE;
do_generate = B_TRUE;
break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
Expand All @@ -6622,6 +6653,13 @@ share_mount(int op, int argc, char **argv)
"must be 'nfs' or 'smb'\n"));
usage(B_FALSE);
}
if (do_generate && strcmp(argv[0], "smb") == 0) {
(void) fprintf(stderr, gettext("export file "
"generation is not compatible fow smb "
"shares\n"));
usage(B_FALSE);
}

protocol = argv[0];
argc--;
argv++;
Expand All @@ -6645,12 +6683,16 @@ share_mount(int op, int argc, char **argv)
share_mount_state_t share_mount_state = { 0 };
share_mount_state.sm_op = op;
share_mount_state.sm_verbose = verbose;
share_mount_state.sm_generate = do_generate;
share_mount_state.sm_flags = flags;
share_mount_state.sm_options = options;
share_mount_state.sm_proto = protocol;
share_mount_state.sm_total = cb.cb_used;
pthread_mutex_init(&share_mount_state.sm_lock, NULL);

if (do_generate)
verify(nfs_exports_lock() == 0);

/*
* libshare isn't mt-safe, so only do the operation in parallel
* if we're mounting. Additionally, the key-loading option must
Expand All @@ -6660,6 +6702,10 @@ share_mount(int op, int argc, char **argv)
zfs_foreach_mountpoint(g_zfs, cb.cb_handles, cb.cb_used,
share_mount_one_cb, &share_mount_state,
op == OP_MOUNT && !(flags & MS_CRYPT));

if (do_generate)
verify(nfs_exports_unlock() == 0);

ret = share_mount_state.sm_status;

for (int i = 0; i < cb.cb_used; i++)
Expand Down Expand Up @@ -6711,7 +6757,7 @@ share_mount(int op, int argc, char **argv)
ret = 1;
} else {
ret = share_mount_one(zhp, op, flags, NULL, B_TRUE,
options);
B_FALSE, options);
zfs_close(zhp);
}
}
Expand All @@ -6724,6 +6770,7 @@ share_mount(int op, int argc, char **argv)

/*
* zfs mount -a [nfs]
* zfs mount -g [nfs]
* zfs mount filesystem
*
* Mount all filesystems, or mount the given filesystem.
Expand Down
60 changes: 60 additions & 0 deletions debian/tree/zfsutils-linux/usr/lib/zfs-linux/share-cleanup
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash -u

#
# Copyright (c) 2019 by Delphix. All rights reserved.
#

#
# Cleanup the ZFS exports
#
# The zfs-share service generates 'zfs.exports' which is consumed by the
# nfs-server service in ExecStartPre. To catch any zfs shares that were
# enabled since the zfs-share service started, we must re-generate the
# 'zfs.exports' file and check for any changes. If there is a delta, we
# run 'exportfs -a' to export the new additions.
#

function die() {
echo "$(basename $0): $1" >&2
# always remove the zfs.exports file
if [[ -f "$ZFS_EXPORTS" ]]; then
/bin/rm -f "$ZFS_EXPORTS"
fi
exit 1
}

ZFS_EXPORTS=/etc/exports.d/zfs.exports
ZFS_EXPORTS_BAK=${ZFS_EXPORTS}.bak
changes=0

if [[ -f "$ZFS_EXPORTS" ]]; then
# save the zfs-share service generated copy
/bin/mv -f "$ZFS_EXPORTS" "$ZFS_EXPORTS_BAK" || die "rename failed"

# generate a new zfs.exports
/sbin/zfs share -g || die "failed to generate zfs exports"

cmp --silent "$ZFS_EXPORTS" "$ZFS_EXPORTS_BAK"
changes=$?

/bin/rm -f "$ZFS_EXPORTS_BAK"

[[ $changes -eq 2 ]] && die "compare failed"
else
# generate a new zfs.exports
/sbin/zfs share -g || die "failed to generate zfs exports"
if [[ -f "$ZFS_EXPORTS" ]]; then
changes=1
fi
fi

# if the zfs.exports content has changed then re-export
if [[ $changes -eq 1 ]]; then
shares=$(wc -l < $ZFS_EXPORTS)
echo re-exporting, zfs shares exported: $shares
/usr/sbin/exportfs -a || die "re-exporting failed"
fi

/bin/rm -f "$ZFS_EXPORTS"

exit 0
1 change: 1 addition & 0 deletions etc/systemd/system/50-zfs.preset.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ disable zfs-import-scan.service
enable zfs-import.target
enable zfs-mount.service
enable zfs-share.service
enable zfs-share-cleanup.service
enable zfs-zed.service
enable zfs-volume-wait.service
enable zfs.target
2 changes: 2 additions & 0 deletions etc/systemd/system/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ systemdunit_DATA = \
zfs-import-scan.service \
zfs-mount.service \
zfs-share.service \
zfs-share-cleanup.service \
zfs-volume-wait.service \
zfs-import.target \
zfs-volumes.target \
Expand All @@ -18,6 +19,7 @@ EXTRA_DIST = \
$(top_srcdir)/etc/systemd/system/zfs-import-scan.service.in \
$(top_srcdir)/etc/systemd/system/zfs-mount.service.in \
$(top_srcdir)/etc/systemd/system/zfs-share.service.in \
$(top_srcdir)/etc/systemd/system/zfs-share-cleanup.service.in \
$(top_srcdir)/etc/systemd/system/zfs-import.target.in \
$(top_srcdir)/etc/systemd/system/zfs-volume-wait.service.in \
$(top_srcdir)/etc/systemd/system/zfs-volumes.target.in \
Expand Down
12 changes: 12 additions & 0 deletions etc/systemd/system/zfs-share-cleanup.service.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[Unit]
Description=ZFS file system shares cleanup
After=nfs-server.service
PartOf=nfs-server.service nfs-kernel-server.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=-/usr/lib/zfs-linux/share-cleanup

[Install]
WantedBy=zfs.target
5 changes: 2 additions & 3 deletions etc/systemd/system/zfs-share.service.in
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[Unit]
Description=ZFS file system shares
Documentation=man:zfs(8)
After=nfs-server.service nfs-kernel-server.service
After=smb.service
Before=nfs-config.service
Before=rpc-statd-notify.service
Wants=zfs-mount.service
After=zfs-mount.service
Expand All @@ -12,8 +12,7 @@ PartOf=smb.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=-/bin/rm -f /etc/dfs/sharetab
ExecStart=@sbindir@/zfs share -a
ExecStart=@sbindir@/zfs share -g

[Install]
WantedBy=zfs.target
5 changes: 3 additions & 2 deletions include/libzfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@

/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2018 by Delphix. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2011, 2019 by Delphix. All rights reserved.
* Copyright Joyent, Inc.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2016, Intel Corporation.
* Copyright 2016 Nexenta Systems, Inc.
Expand Down Expand Up @@ -789,6 +789,7 @@ extern boolean_t zfs_is_shared_smb(zfs_handle_t *, char **);
extern int zfs_share_nfs(zfs_handle_t *);
extern int zfs_share_smb(zfs_handle_t *);
extern int zfs_shareall(zfs_handle_t *);
extern int zfs_share_generate(zfs_handle_t *);
extern int zfs_unshare_nfs(zfs_handle_t *, const char *);
extern int zfs_unshare_smb(zfs_handle_t *, const char *);
extern int zfs_unshareall_nfs(zfs_handle_t *);
Expand Down
4 changes: 3 additions & 1 deletion include/libzfs_impl.h
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) 2011, 2017 by Delphix. All rights reserved.
* Copyright (c) 2011, 2019 by Delphix. All rights reserved.
* Copyright (c) 2018 Datto Inc.
*/

Expand Down Expand Up @@ -205,6 +205,8 @@ extern int zfs_parse_options(char *, zfs_share_proto_t);

extern int zfs_unshare_proto(zfs_handle_t *,
const char *, zfs_share_proto_t *);
int nfs_exports_lock(void);
int nfs_exports_unlock(void);

#ifdef __cplusplus
}
Expand Down
40 changes: 39 additions & 1 deletion lib/libshare/libshare.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
/*
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Gunnar Beutner
* Copyright (c) 2018, 2019 by Delphix. All rights reserved.
*/

#include <stdio.h>
Expand Down Expand Up @@ -434,7 +435,7 @@ process_share(sa_handle_impl_t impl_handle, sa_share_impl_t impl_share,
FSINFO(impl_share, fstype)->resource = resource_dup;

rc = fstype->ops->update_shareopts(impl_share,
resource, options);
resource, options, B_FALSE);

if (rc == SA_OK && from_sharetab)
FSINFO(impl_share, fstype)->active = B_TRUE;
Expand Down Expand Up @@ -599,6 +600,43 @@ sa_disable_share(sa_share_t share, char *protocol)
return (found_protocol ? ret : SA_INVALID_PROTOCOL);
}

int
sa_generate_share(const char *mountpoint, const char *shareopts)
{
int rc = SA_OK;

/*
* Allocate a new share structure and populate the mountpoint and
* shareopts within it. We use this structure as a tempoary placeholder
* to allow for code reuse within the libshare and NFS code and
* free the structure before returning.
*/
sa_share_impl_t impl_share = alloc_share(mountpoint);
if (impl_share == NULL)
return (SA_NO_MEMORY);

sa_fstype_t *fstype = fstypes;
while (fstype != NULL) {
if (strcmp(fstype->name, "nfs") == 0) {
rc = fstype->ops->update_shareopts(impl_share, NULL,
shareopts, B_TRUE);
if (rc != SA_OK)
goto out;

rc = fstype->ops->generate_share(impl_share);
if (rc != SA_OK)
goto out;
}

fstype = fstype->next;
}

out:
free_share(impl_share);
return (rc);
}


/*
* sa_errorstr(err)
*
Expand Down
Loading

0 comments on commit ec9c367

Please sign in to comment.