Skip to content

Commit

Permalink
Add temporary mount options
Browse files Browse the repository at this point in the history
Add the required kernel side infrastructure to parse arbitrary
mount options.  This enables us to support temporary mount
options in largely the same way it is handled on other platforms.

See the 'Temporary Mount Point Properties' section of zfs(8)
for complete details.

Signed-off-by: Brian Behlendorf <[email protected]>
Closes #985
Closes #3351
  • Loading branch information
behlendorf committed Sep 3, 2015
1 parent 69de342 commit 0282c41
Show file tree
Hide file tree
Showing 13 changed files with 332 additions and 62 deletions.
27 changes: 19 additions & 8 deletions cmd/mount_zfs/mount_zfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@
#include <unistd.h>
#include <sys/file.h>
#include <sys/mount.h>
#include <sys/mntent.h>
#include <sys/stat.h>
#include <libzfs.h>
#include <locale.h>

#define ZS_COMMENT 0x00000000 /* comment */
#define ZS_ZFSUTIL 0x00000001 /* caller is zfs(8) */

libzfs_handle_t *g_zfs;

typedef struct option_map {
Expand Down Expand Up @@ -335,14 +339,18 @@ mtab_update(char *dataset, char *mntpoint, char *type, char *mntopts)
}

static void
__zfs_selinux_setcontext(const char *name, const char *context, char *mntopts,
char *mtabopt)
append_mntopt(const char *name, const char *val, char *mntopts,
char *mtabopt, boolean_t quote)
{
char tmp[MNT_LINE_MAX];

snprintf(tmp, MNT_LINE_MAX, ",%s=\"%s\"", name, context);
strlcat(mntopts, tmp, MNT_LINE_MAX);
strlcat(mtabopt, tmp, MNT_LINE_MAX);
snprintf(tmp, MNT_LINE_MAX, quote ? ",%s=\"%s\"" : ",%s=%s", name, val);

if (mntopts)
strlcat(mntopts, tmp, MNT_LINE_MAX);

if (mtabopt)
strlcat(mtabopt, tmp, MNT_LINE_MAX);
}

static void
Expand All @@ -354,7 +362,7 @@ zfs_selinux_setcontext(zfs_handle_t *zhp, zfs_prop_t zpt, const char *name,
if (zfs_prop_get(zhp, zpt, context, sizeof (context),
NULL, NULL, 0, B_FALSE) == 0) {
if (strcmp(context, "none") != 0)
__zfs_selinux_setcontext(name, context, mntopts, mtabopt);
append_mntopt(name, context, mntopts, mtabopt, B_TRUE);
}
}

Expand Down Expand Up @@ -506,11 +514,14 @@ main(int argc, char **argv)
ZFS_PROP_SELINUX_ROOTCONTEXT, MNTOPT_ROOTCONTEXT,
mntopts, mtabopt);
} else {
__zfs_selinux_setcontext(MNTOPT_CONTEXT,
prop, mntopts, mtabopt);
append_mntopt(MNTOPT_CONTEXT, prop,
mntopts, mtabopt, B_TRUE);
}
}

/* A hint used to determine an auto-mounted snapshot mount point */
append_mntopt(MNTOPT_MNTPOINT, mntpoint, mntopts, NULL, B_FALSE);

/* treat all snapshots as legacy mount points */
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)
(void) strlcpy(prop, ZFS_MOUNTPOINT_LEGACY, ZFS_MAXPROPLEN);
Expand Down
1 change: 1 addition & 0 deletions include/sys/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ COMMON_H = \
$(top_srcdir)/include/sys/efi_partition.h \
$(top_srcdir)/include/sys/metaslab.h \
$(top_srcdir)/include/sys/metaslab_impl.h \
$(top_srcdir)/include/sys/mntent.h \
$(top_srcdir)/include/sys/multilist.h \
$(top_srcdir)/include/sys/nvpair.h \
$(top_srcdir)/include/sys/nvpair_impl.h \
Expand Down
4 changes: 1 addition & 3 deletions lib/libspl/include/sys/mntent.h → include/sys/mntent.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@
#define MNTOPT_ACL "acl" /* passed by util-linux-2.24 mount */
#define MNTOPT_NOACL "noacl" /* likewise */
#define MNTOPT_POSIXACL "posixacl" /* likewise */

#define ZS_COMMENT 0x00000000 /* comment */
#define ZS_ZFSUTIL 0x00000001 /* caller is zfs(8) */
#define MNTOPT_MNTPOINT "mntpoint" /* mount point hint */

#endif /* _SYS_MNTENT_H */
31 changes: 28 additions & 3 deletions include/sys/zfs_vfsops.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,33 @@ extern "C" {
struct zfs_sb;
struct znode;

typedef struct zfs_mntopts {
char *z_osname; /* Objset name */
char *z_mntpoint; /* Primary mount point */
boolean_t z_readonly;
boolean_t z_do_readonly;
boolean_t z_setuid;
boolean_t z_do_setuid;
boolean_t z_exec;
boolean_t z_do_exec;
boolean_t z_devices;
boolean_t z_do_devices;
boolean_t z_xattr;
boolean_t z_do_xattr;
boolean_t z_atime;
boolean_t z_do_atime;
boolean_t z_relatime;
boolean_t z_do_relatime;
boolean_t z_nbmand;
boolean_t z_do_nbmand;
} zfs_mntopts_t;

typedef struct zfs_sb {
struct super_block *z_sb; /* generic super_block */
struct backing_dev_info z_bdi; /* generic backing dev info */
struct zfs_sb *z_parent; /* parent fs */
objset_t *z_os; /* objset reference */
zfs_mntopts_t *z_mntopts; /* passed mount options */
uint64_t z_flags; /* super_block flags */
uint64_t z_root; /* id of root znode */
uint64_t z_unlinkedobj; /* id of unlinked zapobj */
Expand Down Expand Up @@ -170,7 +192,10 @@ extern boolean_t zfs_fuid_overquota(zfs_sb_t *zsb, boolean_t isgroup,
extern int zfs_set_version(zfs_sb_t *zsb, uint64_t newvers);
extern int zfs_get_zplprop(objset_t *os, zfs_prop_t prop,
uint64_t *value);
extern int zfs_sb_create(const char *name, zfs_sb_t **zsbp);
extern zfs_mntopts_t *zfs_mntopts_alloc(void);
extern void zfs_mntopts_free(zfs_mntopts_t *zmo);
extern int zfs_sb_create(const char *name, zfs_mntopts_t *zmo,
zfs_sb_t **zsbp);
extern int zfs_sb_setup(zfs_sb_t *zsb, boolean_t mounting);
extern void zfs_sb_free(zfs_sb_t *zsb);
extern int zfs_sb_prune(struct super_block *sb, unsigned long nr_to_scan,
Expand All @@ -181,10 +206,10 @@ extern boolean_t zfs_is_readonly(zfs_sb_t *zsb);

extern int zfs_register_callbacks(zfs_sb_t *zsb);
extern void zfs_unregister_callbacks(zfs_sb_t *zsb);
extern int zfs_domount(struct super_block *sb, void *data, int silent);
extern int zfs_domount(struct super_block *sb, zfs_mntopts_t *zmo, int silent);
extern void zfs_preumount(struct super_block *sb);
extern int zfs_umount(struct super_block *sb);
extern int zfs_remount(struct super_block *sb, int *flags, char *data);
extern int zfs_remount(struct super_block *sb, int *flags, zfs_mntopts_t *zmo);
extern int zfs_root(zfs_sb_t *zsb, struct inode **ipp);
extern int zfs_statvfs(struct dentry *dentry, struct kstatfs *statp);
extern int zfs_vget(struct super_block *sb, struct inode **ipp, fid_t *fidp);
Expand Down
7 changes: 2 additions & 5 deletions include/sys/zpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@
#ifndef _SYS_ZPL_H
#define _SYS_ZPL_H

#include <sys/mntent.h>
#include <sys/vfs.h>
#include <linux/aio.h>
#include <linux/dcache_compat.h>
#include <linux/exportfs.h>
#include <linux/falloc.h>
#include <linux/file_compat.h>
#include <linux/parser.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/vfs_compat.h>
#include <linux/writeback.h>
Expand Down Expand Up @@ -65,11 +67,6 @@ extern const struct file_operations zpl_dir_file_operations;
/* zpl_super.c */
extern void zpl_prune_sb(int64_t nr_to_scan, void *arg);

typedef struct zpl_mount_data {
const char *z_osname; /* Dataset name */
void *z_data; /* Mount options string */
} zpl_mount_data_t;

extern const struct super_operations zpl_super_operations;
extern const struct export_operations zpl_export_operations;
extern struct file_system_type zpl_fs_type;
Expand Down
1 change: 0 additions & 1 deletion lib/libspl/include/sys/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ libspl_HEADERS = \
$(top_srcdir)/lib/libspl/include/sys/list_impl.h \
$(top_srcdir)/lib/libspl/include/sys/mhd.h \
$(top_srcdir)/lib/libspl/include/sys/mkdev.h \
$(top_srcdir)/lib/libspl/include/sys/mntent.h \
$(top_srcdir)/lib/libspl/include/sys/mnttab.h \
$(top_srcdir)/lib/libspl/include/sys/mount.h \
$(top_srcdir)/lib/libspl/include/sys/note.h \
Expand Down
2 changes: 1 addition & 1 deletion lib/libspl/include/sys/mnttab.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
#endif /* MNTTAB */

#define MNTTAB "/etc/mtab"
#define MNT_LINE_MAX 1024
#define MNT_LINE_MAX 4096

#define MNT_TOOLONG 1 /* entry exceeds MNT_LINE_MAX */
#define MNT_TOOMANY 2 /* too many fields in line */
Expand Down
1 change: 0 additions & 1 deletion lib/libspl/include/sys/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#ifndef _LIBSPL_SYS_MOUNT_H
#define _LIBSPL_SYS_MOUNT_H

#include <sys/mntent.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
Expand Down
4 changes: 2 additions & 2 deletions lib/libzfs/libzfs_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -1922,6 +1922,8 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
mnt.mnt_mntopts = zhp->zfs_mntopts;

switch (prop) {
case ZFS_PROP_ATIME:
case ZFS_PROP_RELATIME:
case ZFS_PROP_DEVICES:
case ZFS_PROP_EXEC:
case ZFS_PROP_READONLY:
Expand All @@ -1944,8 +1946,6 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
}
break;

case ZFS_PROP_ATIME:
case ZFS_PROP_RELATIME:
case ZFS_PROP_CANMOUNT:
case ZFS_PROP_VOLSIZE:
case ZFS_PROP_QUOTA:
Expand Down
3 changes: 3 additions & 0 deletions man/man8/zfs.8
Original file line number Diff line number Diff line change
Expand Up @@ -1535,6 +1535,9 @@ When a file system is mounted, either through \fBmount\fR(8) for legacy mounts o
readonly ro/rw
setuid setuid/nosetuid
xattr xattr/noxattr
atime atime/noatime
relatime relatime/norelatime
nbmand nbmand/nonbmand
.fi
.in -2
.sp
Expand Down
2 changes: 1 addition & 1 deletion module/zfs/zfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1449,7 +1449,7 @@ zfs_sb_hold(const char *name, void *tag, zfs_sb_t **zsbp, boolean_t writer)
int error = 0;

if (get_zfs_sb(name, zsbp) != 0)
error = zfs_sb_create(name, zsbp);
error = zfs_sb_create(name, NULL, zsbp);
if (error == 0) {
rrm_enter(&(*zsbp)->z_teardown_lock, (writer) ? RW_WRITER :
RW_READER, tag);
Expand Down
85 changes: 69 additions & 16 deletions module/zfs/zfs_vfsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,22 @@ zfs_register_callbacks(zfs_sb_t *zsb)
{
struct dsl_dataset *ds = NULL;
objset_t *os = zsb->z_os;
boolean_t do_readonly = B_FALSE;
zfs_mntopts_t *zmo = zsb->z_mntopts;
int error = 0;

if (zfs_is_readonly(zsb) || !spa_writeable(dmu_objset_spa(os)))
do_readonly = B_TRUE;
ASSERT(zsb);
ASSERT(zmo);

/*
* The act of registering our callbacks will destroy any mount
* options we may have. In order to enable temporary overrides
* of mount options, we stash away the current values and
* restore them after we register the callbacks.
*/
if (zfs_is_readonly(zsb) || !spa_writeable(dmu_objset_spa(os))) {
zmo->z_do_readonly = B_TRUE;
zmo->z_readonly = B_TRUE;
}

/*
* Register property callbacks.
Expand Down Expand Up @@ -307,8 +318,25 @@ zfs_register_callbacks(zfs_sb_t *zsb)
if (error)
goto unregister;

if (do_readonly)
readonly_changed_cb(zsb, B_TRUE);
/*
* Invoke our callbacks to restore temporary mount options.
*/
if (zmo->z_do_readonly)
readonly_changed_cb(zsb, zmo->z_readonly);
if (zmo->z_do_setuid)
setuid_changed_cb(zsb, zmo->z_setuid);
if (zmo->z_do_exec)
exec_changed_cb(zsb, zmo->z_exec);
if (zmo->z_do_devices)
devices_changed_cb(zsb, zmo->z_devices);
if (zmo->z_do_xattr)
xattr_changed_cb(zsb, zmo->z_xattr);
if (zmo->z_do_atime)
atime_changed_cb(zsb, zmo->z_atime);
if (zmo->z_do_relatime)
relatime_changed_cb(zsb, zmo->z_relatime);
if (zmo->z_do_nbmand)
nbmand_changed_cb(zsb, zmo->z_nbmand);

return (0);

Expand Down Expand Up @@ -642,8 +670,26 @@ zfs_owner_overquota(zfs_sb_t *zsb, znode_t *zp, boolean_t isgroup)
}
EXPORT_SYMBOL(zfs_owner_overquota);

zfs_mntopts_t *
zfs_mntopts_alloc(void)
{
return (kmem_zalloc(sizeof (zfs_mntopts_t), KM_SLEEP));
}

void
zfs_mntopts_free(zfs_mntopts_t *zmo)
{
if (zmo->z_osname)
strfree(zmo->z_osname);

if (zmo->z_mntpoint)
strfree(zmo->z_mntpoint);

kmem_free(zmo, sizeof (zfs_mntopts_t));
}

int
zfs_sb_create(const char *osname, zfs_sb_t **zsbp)
zfs_sb_create(const char *osname, zfs_mntopts_t *zmo, zfs_sb_t **zsbp)
{
objset_t *os;
zfs_sb_t *zsb;
Expand All @@ -663,6 +709,11 @@ zfs_sb_create(const char *osname, zfs_sb_t **zsbp)
return (error);
}

/*
* Optional temporary mount options, free'd in zfs_sb_free().
*/
zsb->z_mntopts = (zmo ? zmo : zfs_mntopts_alloc());

/*
* Initialize the zfs-specific filesystem structure.
* Should probably make this a kmem cache, shuffle fields,
Expand Down Expand Up @@ -892,6 +943,7 @@ zfs_sb_free(zfs_sb_t *zsb)
for (i = 0; i != ZFS_OBJ_MTX_SZ; i++)
mutex_destroy(&zsb->z_hold_mtx[i]);
vmem_free(zsb->z_hold_mtx, sizeof (kmutex_t) * ZFS_OBJ_MTX_SZ);
zfs_mntopts_free(zsb->z_mntopts);
kmem_free(zsb, sizeof (zfs_sb_t));
}
EXPORT_SYMBOL(zfs_sb_free);
Expand Down Expand Up @@ -1310,16 +1362,15 @@ atomic_long_t zfs_bdi_seq = ATOMIC_LONG_INIT(0);
#endif

int
zfs_domount(struct super_block *sb, void *data, int silent)
zfs_domount(struct super_block *sb, zfs_mntopts_t *zmo, int silent)
{
zpl_mount_data_t *zmd = data;
const char *osname = zmd->z_osname;
const char *osname = zmo->z_osname;
zfs_sb_t *zsb;
struct inode *root_inode;
uint64_t recordsize;
int error;

error = zfs_sb_create(osname, &zsb);
error = zfs_sb_create(osname, zmo, &zsb);
if (error)
return (error);

Expand Down Expand Up @@ -1462,13 +1513,15 @@ zfs_umount(struct super_block *sb)
EXPORT_SYMBOL(zfs_umount);

int
zfs_remount(struct super_block *sb, int *flags, char *data)
zfs_remount(struct super_block *sb, int *flags, zfs_mntopts_t *zmo)
{
/*
* All namespace flags (MNT_*) and super block flags (MS_*) will
* be handled by the Linux VFS. Only handle custom options here.
*/
return (0);
zfs_sb_t *zsb = sb->s_fs_info;
int error;

zfs_unregister_callbacks(zsb);
error = zfs_register_callbacks(zsb);

return (error);
}
EXPORT_SYMBOL(zfs_remount);

Expand Down
Loading

0 comments on commit 0282c41

Please sign in to comment.