forked from opnsense/src
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
4 changed files
with
162 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
{ | ||
|
@@ -58,6 +67,105 @@ be_mountcheck_cb(zfs_handle_t *zfs_hdl, void *data) | |
return (0); | ||
} | ||
|
||
/* | ||
* 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 | ||
*/ | ||
|
@@ -108,8 +216,10 @@ be_mount(libbe_handle_t *lbh, char *bootenv, char *mountpoint, int flags, | |
{ | ||
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 *mountpoint, int flags, | |
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 *mountpoint, int flags, | |
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,44 +262,34 @@ be_mount(libbe_handle_t *lbh, char *bootenv, char *mountpoint, int flags, | |
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)); | ||
|
||
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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters