Author: kevans
Date: Thu Jan 10 03:27:20 2019
New Revision: 342911
URL: https://svnweb.freebsd.org/changeset/base/342911

Log:
  libbe(3): Change be_mount to mount/unmount child datasets
  
  This set of changes is geared towards making bectl respect deep boot
  environments when they exist and are mounted. The deep BE composition
  functionality (`bectl add`) remains disabled for the time being. This set of
  changes has no effect for the average user. but allows deep BE users to
  upgrade properly with their current setup.
  
  libbe(3): Open the target boot environment and get a zfs handle, then pass
  that with the target mountpoint to be_mount_iter; If the BE_MNT_DEEP flag is
  set call zfs_iter_filesystems and mount the child datasets.
  
  Similar logic is employed when unmounting the datasets, save for children
  are unmounted first.
  
  bectl(8): Change bectl_cmd_jail to pass the BE_MNT_DEEP flag when
  calling be_mount as well as call be_unmount when cleaning up after the
  jail has exited instead of umount(2) directly.
  
  PR:           234795
  Submitted by: Wes Maag <jwmaag_gmail.com> (test additions by kevans)
  MFC after:    1 week
  Differential Revision:        https://reviews.freebsd.org/D18796

Modified:
  head/lib/libbe/be_access.c
  head/sbin/bectl/bectl.c
  head/sbin/bectl/bectl_jail.c
  head/sbin/bectl/tests/bectl_test.sh

Modified: head/lib/libbe/be_access.c
==============================================================================
--- head/lib/libbe/be_access.c  Thu Jan 10 02:59:19 2019        (r342910)
+++ head/lib/libbe/be_access.c  Thu Jan 10 03:27:20 2019        (r342911)
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2017 Kyle J. Kneitinger <[email protected]>
  * Copyright (c) 2018 Kyle Evans <[email protected]>
+ * Copyright (c) 2019 Wes Maag <[email protected]>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,6 +39,14 @@ struct be_mountcheck_info {
        char *name;
 };
 
+struct be_mount_info {
+       libbe_handle_t *lbh;
+       const char *be;
+       const char *mountpoint;
+       int mntflags;
+       int deepmount;
+};
+
 static int
 be_mountcheck_cb(zfs_handle_t *zfs_hdl, void *data)
 {
@@ -59,6 +68,105 @@ be_mountcheck_cb(zfs_handle_t *zfs_hdl, void *data)
 }
 
 /*
+ * Called from be_mount, uses the given zfs_handle and attempts to
+ * mount it at the passed mountpoint. If the deepmount flag is set, continue
+ * calling the function for each child dataset.
+ */
+static int
+be_mount_iter(zfs_handle_t *zfs_hdl, void *data)
+{
+       int err;
+       char *mountpoint;
+       char tmp[BE_MAXPATHLEN], zfs_mnt[BE_MAXPATHLEN];
+       struct be_mount_info *info;
+
+       info = (struct be_mount_info *)data;
+
+       if (zfs_is_mounted(zfs_hdl, &mountpoint)) {
+               free(mountpoint);
+               return (0);
+       }
+
+       if (zfs_prop_get_int(zfs_hdl, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_OFF)
+               return (0);
+
+       if (zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, zfs_mnt, BE_MAXPATHLEN,
+           NULL, NULL, 0, 1))
+               return (1);
+
+       if (strcmp("none", zfs_mnt) != 0) {
+               char opt = '\0';
+
+               mountpoint = be_mountpoint_augmented(info->lbh, zfs_mnt);
+
+               snprintf(tmp, BE_MAXPATHLEN, "%s%s", info->mountpoint,
+                   mountpoint);
+
+               if ((err = zmount(zfs_get_name(zfs_hdl), tmp, info->mntflags,
+                __DECONST(char *, MNTTYPE_ZFS), NULL, 0, &opt, 1)) != 0) {
+                       switch (errno) {
+                       case ENAMETOOLONG:
+                               return (set_error(info->lbh, BE_ERR_PATHLEN));
+                       case ELOOP:
+                       case ENOENT:
+                       case ENOTDIR:
+                               return (set_error(info->lbh, BE_ERR_BADPATH));
+                       case EPERM:
+                               return (set_error(info->lbh, BE_ERR_PERMS));
+                       case EBUSY:
+                               return (set_error(info->lbh, BE_ERR_PATHBUSY));
+                       default:
+                               return (set_error(info->lbh, BE_ERR_UNKNOWN));
+                       }
+               }
+       }
+
+       if (!info->deepmount)
+               return (0);
+
+       return (zfs_iter_filesystems(zfs_hdl, be_mount_iter, info));
+}
+
+
+static int
+be_umount_iter(zfs_handle_t *zfs_hdl, void *data)
+{
+
+       int err;
+       char *mountpoint;
+       struct be_mount_info *info;
+
+       info = (struct be_mount_info *)data;
+
+       if((err = zfs_iter_filesystems(zfs_hdl, be_umount_iter, info)) != 0) {
+               return (err);
+       }
+
+       if (!zfs_is_mounted(zfs_hdl, &mountpoint)) {
+               return (0);
+       }
+       free(mountpoint);
+
+       if (zfs_unmount(zfs_hdl, NULL, info->mntflags) != 0) {
+               switch (errno) {
+               case ENAMETOOLONG:
+                       return (set_error(info->lbh, BE_ERR_PATHLEN));
+               case ELOOP:
+               case ENOENT:
+               case ENOTDIR:
+                       return (set_error(info->lbh, BE_ERR_BADPATH));
+               case EPERM:
+                       return (set_error(info->lbh, BE_ERR_PERMS));
+               case EBUSY:
+                       return (set_error(info->lbh, BE_ERR_PATHBUSY));
+               default:
+                       return (set_error(info->lbh, BE_ERR_UNKNOWN));
+               }
+       }
+       return (0);
+}
+
+/*
  * usage
  */
 int
@@ -108,8 +216,10 @@ be_mount(libbe_handle_t *lbh, char *bootenv, char *mou
 {
        char be[BE_MAXPATHLEN];
        char mnt_temp[BE_MAXPATHLEN];
-       int mntflags;
+       int mntflags, mntdeep;
        int err;
+       struct be_mount_info info;
+       zfs_handle_t *zhdl;
 
        if ((err = be_root_concat(lbh, bootenv, be)) != 0)
                return (set_error(lbh, err));
@@ -120,6 +230,7 @@ be_mount(libbe_handle_t *lbh, char *bootenv, char *mou
        if (is_mounted(lbh->lzh, be, NULL))
                return (set_error(lbh, BE_ERR_MOUNTED));
 
+       mntdeep = (flags & BE_MNT_DEEP) ? 1 : 0;
        mntflags = (flags & BE_MNT_FORCE) ? MNT_FORCE : 0;
 
        /* Create mountpoint if it is not specified */
@@ -129,24 +240,20 @@ be_mount(libbe_handle_t *lbh, char *bootenv, char *mou
                        return (set_error(lbh, BE_ERR_IO));
        }
 
-       char opt = '\0';
-       if ((err = zmount(be, (mountpoint == NULL) ? mnt_temp : mountpoint,
-           mntflags, __DECONST(char *, MNTTYPE_ZFS), NULL, 0, &opt, 1)) != 0) {
-               switch (errno) {
-               case ENAMETOOLONG:
-                       return (set_error(lbh, BE_ERR_PATHLEN));
-               case ELOOP:
-               case ENOENT:
-               case ENOTDIR:
-                       return (set_error(lbh, BE_ERR_BADPATH));
-               case EPERM:
-                       return (set_error(lbh, BE_ERR_PERMS));
-               case EBUSY:
-                       return (set_error(lbh, BE_ERR_PATHBUSY));
-               default:
-                       return (set_error(lbh, BE_ERR_UNKNOWN));
-               }
+       if ((zhdl = zfs_open(lbh->lzh, be, ZFS_TYPE_FILESYSTEM)) == NULL)
+               return (set_error(lbh, BE_ERR_ZFSOPEN));
+
+       info.lbh = lbh;
+       info.be = be;
+       info.mountpoint = (mountpoint == NULL) ? mnt_temp : mountpoint;
+       info.mntflags = mntflags;
+       info.deepmount = mntdeep;
+
+       if((err = be_mount_iter(zhdl, &info) != 0)) {
+               zfs_close(zhdl);
+               return (err);
        }
+       zfs_close(zhdl);
 
        if (result_loc != NULL)
                strlcpy(result_loc, mountpoint == NULL ? mnt_temp : mountpoint,
@@ -155,16 +262,16 @@ be_mount(libbe_handle_t *lbh, char *bootenv, char *mou
        return (BE_ERR_SUCCESS);
 }
 
-
 /*
  * usage
  */
 int
 be_unmount(libbe_handle_t *lbh, char *bootenv, int flags)
 {
-       int err, mntflags;
+       int err;
        char be[BE_MAXPATHLEN];
        zfs_handle_t *root_hdl;
+       struct be_mount_info info;
 
        if ((err = be_root_concat(lbh, bootenv, be)) != 0)
                return (set_error(lbh, err));
@@ -172,27 +279,17 @@ be_unmount(libbe_handle_t *lbh, char *bootenv, int fla
        if ((root_hdl = zfs_open(lbh->lzh, be, ZFS_TYPE_FILESYSTEM)) == NULL)
                return (set_error(lbh, BE_ERR_ZFSOPEN));
 
-       mntflags = (flags & BE_MNT_FORCE) ? MS_FORCE : 0;
+       info.lbh = lbh;
+       info.be = be;
+       info.mountpoint = NULL;
+       info.mntflags = (flags & BE_MNT_FORCE) ? MS_FORCE : 0;
 
-       if (zfs_unmount(root_hdl, NULL, mntflags) != 0) {
+       if ((err = be_umount_iter(root_hdl, &info)) != 0) {
                zfs_close(root_hdl);
-               switch (errno) {
-               case ENAMETOOLONG:
-                       return (set_error(lbh, BE_ERR_PATHLEN));
-               case ELOOP:
-               case ENOENT:
-               case ENOTDIR:
-                       return (set_error(lbh, BE_ERR_BADPATH));
-               case EPERM:
-                       return (set_error(lbh, BE_ERR_PERMS));
-               case EBUSY:
-                       return (set_error(lbh, BE_ERR_PATHBUSY));
-               default:
-                       return (set_error(lbh, BE_ERR_UNKNOWN));
-               }
+               return (err);
        }
-       zfs_close(root_hdl);
 
+       zfs_close(root_hdl);
        return (BE_ERR_SUCCESS);
 }
 

Modified: head/sbin/bectl/bectl.c
==============================================================================
--- head/sbin/bectl/bectl.c     Thu Jan 10 02:59:19 2019        (r342910)
+++ head/sbin/bectl/bectl.c     Thu Jan 10 03:27:20 2019        (r342911)
@@ -378,8 +378,10 @@ bectl_cmd_mount(int argc, char *argv[])
 {
        char result_loc[BE_MAXPATHLEN];
        char *bootenv, *mountpoint;
-       int err;
+       int err, mntflags;
 
+       /* XXX TODO: Allow shallow */
+       mntflags = BE_MNT_DEEP;
        if (argc < 2) {
                fprintf(stderr, "bectl mount: missing argument(s)\n");
                return (usage(false));
@@ -393,7 +395,7 @@ bectl_cmd_mount(int argc, char *argv[])
        bootenv = argv[1];
        mountpoint = ((argc == 3) ? argv[2] : NULL);
 
-       err = be_mount(be, bootenv, mountpoint, 0, result_loc);
+       err = be_mount(be, bootenv, mountpoint, mntflags, result_loc);
 
        switch (err) {
        case BE_ERR_SUCCESS:

Modified: head/sbin/bectl/bectl_jail.c
==============================================================================
--- head/sbin/bectl/bectl_jail.c        Thu Jan 10 02:59:19 2019        
(r342910)
+++ head/sbin/bectl/bectl_jail.c        Thu Jan 10 03:27:20 2019        
(r342911)
@@ -180,10 +180,12 @@ int
 bectl_cmd_jail(int argc, char *argv[])
 {
        char *bootenv, *mountpoint;
-       int jid, opt, ret;
+       int jid, mntflags, opt, ret;
        bool default_hostname, interactive, unjail;
        pid_t pid;
 
+       /* XXX TODO: Allow shallow */
+       mntflags = BE_MNT_DEEP;
        default_hostname = interactive = unjail = true;
        jpcnt = INIT_PARAMCOUNT;
        jp = malloc(jpcnt * sizeof(*jp));
@@ -250,7 +252,7 @@ bectl_cmd_jail(int argc, char *argv[])
                mountpoint = NULL;
        else
                mountpoint = mnt_loc;
-       if (be_mount(be, bootenv, mountpoint, 0, mnt_loc) != BE_ERR_SUCCESS) {
+       if (be_mount(be, bootenv, mountpoint, mntflags, mnt_loc) != 
BE_ERR_SUCCESS) {
                fprintf(stderr, "could not mount bootenv\n");
                return (1);
        }
@@ -301,7 +303,7 @@ bectl_cmd_jail(int argc, char *argv[])
 
        if (unjail) {
                jail_remove(jid);
-               unmount(mnt_loc, 0);
+               be_unmount(be, bootenv, 0);
        }
 
        return (0);
@@ -415,7 +417,7 @@ bectl_cmd_unjail(int argc, char *argv[])
        }
 
        jail_remove(jid);
-       unmount(path, 0);
+       be_unmount(be, target, 0);
 
        return (0);
 }

Modified: head/sbin/bectl/tests/bectl_test.sh
==============================================================================
--- head/sbin/bectl/tests/bectl_test.sh Thu Jan 10 02:59:19 2019        
(r342910)
+++ head/sbin/bectl/tests/bectl_test.sh Thu Jan 10 03:27:20 2019        
(r342911)
@@ -42,7 +42,21 @@ bectl_create_setup()
        atf_check zfs create -o mountpoint=/ -o canmount=noauto \
            ${zpool}/ROOT/default
 }
+bectl_create_deep_setup()
+{
+       zpool=$1
+       disk=$2
+       mnt=$3
 
+       bectl_create_setup ${zpool} ${disk} ${mnt}
+       atf_check mkdir -p ${root}
+       atf_check -o ignore bectl -r ${zpool}/ROOT mount default ${root}
+       atf_check mkdir -p ${root}/usr
+       atf_check zfs create -o mountpoint=/usr -o canmount=noauto \
+           ${zpool}/ROOT/default/usr
+       atf_check -o ignore bectl -r ${zpool}/ROOT umount default
+}
+
 bectl_cleanup()
 {
        zpool=$1
@@ -183,7 +197,7 @@ bectl_mount_body()
        mount=${cwd}/mnt
        root=${mount}/root
 
-       bectl_create_setup ${zpool} ${disk} ${mount}
+       bectl_create_deep_setup ${zpool} ${disk} ${mount}
        atf_check mkdir -p ${root}
        # Test unmount first...
        atf_check -o not-empty bectl -r ${zpool}/ROOT mount default ${root}
@@ -246,7 +260,7 @@ bectl_jail_body()
        if [ ! -f /rescue/rescue ]; then
                atf_skip "This test requires a rescue binary"
        fi
-       bectl_create_setup ${zpool} ${disk} ${mount}
+       bectl_create_deep_setup ${zpool} ${disk} ${mount}
        # Prepare our minimal BE... plop a rescue binary into it
        atf_check mkdir -p ${root}
        atf_check -o ignore bectl -r ${zpool}/ROOT mount default ${root}
@@ -263,9 +277,9 @@ bectl_jail_body()
        atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT unjail default
 
        # Basic command-mode tests, with and without jail cleanup
-       atf_check -o inline:"rescue\n" bectl -r ${zpool}/ROOT \
+       atf_check -o inline:"rescue\nusr\n" bectl -r ${zpool}/ROOT \
            jail default /rescue/rescue ls -1
-       atf_check -o inline:"rescue\n" bectl -r ${zpool}/ROOT \
+       atf_check -o inline:"rescue\nusr\n" bectl -r ${zpool}/ROOT \
            jail -Uo path=${root} default /rescue/rescue ls -1
        atf_check [ -f ${root}/rescue/rescue ]
        atf_check bectl -r ${zpool}/ROOT ujail default
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to