Date: Mon, 21 Jan 2019 02:57:58 +0000 (UTC) From: Kyle Evans <kevans@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r343241 - in stable/12: lib/libbe sbin/bectl sbin/bectl/tests Message-ID: <201901210257.x0L2vwv0019892@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kevans Date: Mon Jan 21 02:57:57 2019 New Revision: 343241 URL: https://svnweb.freebsd.org/changeset/base/343241 Log: MFC r342903, r342911: libbe(3)/bectl(8) refactor and fix mount for deep BEs r342903: libbe(3): move altroot augmentation bits around a little bit We could perhaps have a method that does this given a dataset, but it's yet clear that we'll always want to bypass the altroot when we grab the mountpoint. For now, we'll refactor things a bit so we grab the altroot length when libbe is initialized and have a common method that does the necessary augmentation (replace with / if it's the root, return a pointer to later in the string if not). This will be used in some upcoming work to make be_mount work properly for deep BEs. r342911: 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 Modified: stable/12/lib/libbe/be.c stable/12/lib/libbe/be_access.c stable/12/lib/libbe/be_impl.h stable/12/sbin/bectl/bectl.c stable/12/sbin/bectl/bectl_jail.c stable/12/sbin/bectl/tests/bectl_test.sh Directory Properties: stable/12/ (props changed) Modified: stable/12/lib/libbe/be.c ============================================================================== --- stable/12/lib/libbe/be.c Mon Jan 21 01:45:35 2019 (r343240) +++ stable/12/lib/libbe/be.c Mon Jan 21 02:57:57 2019 (r343241) @@ -90,6 +90,7 @@ be_locate_rootfs(libbe_handle_t *lbh) libbe_handle_t * libbe_init(const char *root) { + char altroot[MAXPATHLEN]; libbe_handle_t *lbh; char *poolname, *pos; int pnamelen; @@ -140,6 +141,11 @@ libbe_init(const char *root) sizeof(lbh->bootfs), NULL, true) != 0) goto err; + if (zpool_get_prop(lbh->active_phandle, ZPOOL_PROP_ALTROOT, + altroot, sizeof(altroot), NULL, true) == 0 && + strcmp(altroot, "-") != 0) + lbh->altroot_len = strlen(altroot); + return (lbh); err: if (lbh != NULL) { @@ -314,7 +320,6 @@ be_create(libbe_handle_t *lbh, const char *name) return (set_error(lbh, err)); } - static int be_deep_clone_prop(int prop, void *cb) { @@ -345,12 +350,9 @@ be_deep_clone_prop(int prop, void *cb) /* Augment mountpoint with altroot, if needed */ val = pval; - if (prop == ZFS_PROP_MOUNTPOINT && *dccb->altroot != '\0') { - if (pval[strlen(dccb->altroot)] == '\0') - strlcpy(pval, "/", sizeof(pval)); - else - val = pval + strlen(dccb->altroot); - } + if (prop == ZFS_PROP_MOUNTPOINT) + val = be_mountpoint_augmented(dccb->lbh, val); + nvlist_add_string(dccb->props, zfs_prop_to_name(prop), val); return (ZPROP_CONT); @@ -392,12 +394,9 @@ be_deep_clone(zfs_handle_t *ds, void *data) nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); nvlist_add_string(props, "canmount", "noauto"); + dccb.lbh = isdc->lbh; dccb.zhp = ds; dccb.props = props; - if (zpool_get_prop(isdc->lbh->active_phandle, ZPOOL_PROP_ALTROOT, - dccb.altroot, sizeof(dccb.altroot), NULL, true) != 0 || - strcmp(dccb.altroot, "-") == 0) - *dccb.altroot = '\0'; if (zprop_iter(be_deep_clone_prop, &dccb, B_FALSE, B_FALSE, ZFS_TYPE_FILESYSTEM) == ZPROP_INVAL) return (-1); Modified: stable/12/lib/libbe/be_access.c ============================================================================== --- stable/12/lib/libbe/be_access.c Mon Jan 21 01:45:35 2019 (r343240) +++ stable/12/lib/libbe/be_access.c Mon Jan 21 02:57:57 2019 (r343241) @@ -3,6 +3,7 @@ * * Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in> * Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org> + * Copyright (c) 2019 Wes Maag <wes@jwmaag.org> * 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,26 +279,38 @@ 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); +} + +/* + * This function will blow away the input buffer as needed if we're discovered + * to be looking at a root-mount. If the mountpoint is naturally beyond the + * root, however, the buffer may be left intact and a pointer to the section + * past altroot will be returned instead for the caller's perusal. + */ +char * +be_mountpoint_augmented(libbe_handle_t *lbh, char *mountpoint) +{ + + if (lbh->altroot_len == 0) + return (mountpoint); + if (mountpoint == NULL || *mountpoint == '\0') + return (mountpoint); + + if (mountpoint[lbh->altroot_len] == '\0') { + *(mountpoint + 1) = '\0'; + return (mountpoint); + } else + return (mountpoint + lbh->altroot_len); } Modified: stable/12/lib/libbe/be_impl.h ============================================================================== --- stable/12/lib/libbe/be_impl.h Mon Jan 21 01:45:35 2019 (r343240) +++ stable/12/lib/libbe/be_impl.h Mon Jan 21 02:57:57 2019 (r343241) @@ -36,11 +36,12 @@ #include "be.h" struct libbe_handle { - libzfs_handle_t *lzh; - zpool_handle_t *active_phandle; char root[BE_MAXPATHLEN]; char rootfs[BE_MAXPATHLEN]; char bootfs[BE_MAXPATHLEN]; + size_t altroot_len; + zpool_handle_t *active_phandle; + libzfs_handle_t *lzh; be_error_t error; bool print_on_err; }; @@ -53,9 +54,9 @@ struct libbe_deep_clone { }; struct libbe_dccb { + libbe_handle_t *lbh; zfs_handle_t *zhp; nvlist_t *props; - char altroot[MAXPATHLEN]; }; typedef struct prop_data { @@ -66,6 +67,8 @@ typedef struct prop_data { int prop_list_builder_cb(zfs_handle_t *, void *); int be_proplist_update(prop_data_t *); + +char *be_mountpoint_augmented(libbe_handle_t *lbh, char *mountpoint); /* Clobbers any previous errors */ int set_error(libbe_handle_t *, be_error_t); Modified: stable/12/sbin/bectl/bectl.c ============================================================================== --- stable/12/sbin/bectl/bectl.c Mon Jan 21 01:45:35 2019 (r343240) +++ stable/12/sbin/bectl/bectl.c Mon Jan 21 02:57:57 2019 (r343241) @@ -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: stable/12/sbin/bectl/bectl_jail.c ============================================================================== --- stable/12/sbin/bectl/bectl_jail.c Mon Jan 21 01:45:35 2019 (r343240) +++ stable/12/sbin/bectl/bectl_jail.c Mon Jan 21 02:57:57 2019 (r343241) @@ -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: stable/12/sbin/bectl/tests/bectl_test.sh ============================================================================== --- stable/12/sbin/bectl/tests/bectl_test.sh Mon Jan 21 01:45:35 2019 (r343240) +++ stable/12/sbin/bectl/tests/bectl_test.sh Mon Jan 21 02:57:57 2019 (r343241) @@ -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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201901210257.x0L2vwv0019892>