const int recursive = mnt_optlist_is_recursive(cxt->optlist);
const char *target = mnt_fs_get_target(cxt->fs);
int fd_tree = -1;
- int rc;
+ int rc, is_private = 1;
assert(hd);
assert(target);
* Once a mount has been attached to the filesystem it can't be
* idmapped anymore. So create a new detached mount.
*/
- fd_tree = open_tree(-1, target,
+#ifdef USE_LIBMOUNT_MOUNTFD_SUPPORT
+ {
+ struct libmnt_sysapi *api = mnt_context_get_sysapi(cxt);
+
+ if (api && api->fd_tree >= 0) {
+ fd_tree = api->fd_tree;
+ is_private = 0;
+ DBG(HOOK, ul_debugobj(hs, " reuse tree FD"));
+ }
+ }
+#endif
+ if (fd_tree < 0)
+ fd_tree = open_tree(-1, target,
OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC |
(recursive ? AT_RECURSIVE : 0));
if (fd_tree < 0) {
DBG(HOOK, ul_debugobj(hs, " failed to set attributes"));
goto done;
}
- /* Unmount the old, non-idmapped mount we just cloned and idmapped. */
- rc = umount(target);
- if (rc < 0) {
- DBG(HOOK, ul_debugobj(hs, " failed to set umount target"));
- goto done;
- }
/* Attach the idmapped mount. */
- rc = move_mount(fd_tree, "", -1, target, MOVE_MOUNT_F_EMPTY_PATH);
- if (rc)
- DBG(HOOK, ul_debugobj(hs, " failed to set move mount"));
+ if (is_private) {
+ /* Unmount the old, non-idmapped mount we just cloned and idmapped. */
+ umount2(target, MNT_DETACH);
+ rc = move_mount(fd_tree, "", -1, target, MOVE_MOUNT_F_EMPTY_PATH);
+ if (rc)
+ DBG(HOOK, ul_debugobj(hs, " failed to set move mount"));
+ }
done:
- close(fd_tree);
+ if (is_private)
+ close(fd_tree);
if (rc < 0)
return -MNT_ERR_IDMAP;
done:
/* define post-mount hook to enter the namespace */
DBG(HOOK, ul_debugobj(hs, " wanted new user namespace"));
+ cxt->force_clone = 1; /* require OPEN_TREE_CLONE */
rc = mnt_context_append_hook(cxt, hs,
MNT_STAGE_MOUNT_POST,
hd, hook_mount_post);
return 0;
}
-static int open_fs_configuration_context(struct libmnt_context *cxt, const char *type)
+static int open_fs_configuration_context(struct libmnt_context *cxt,
+ struct libmnt_sysapi *api,
+ const char *type)
{
- int fd;
-
DBG(HOOK, ul_debug(" new FS '%s'", type));
if (!type)
DBG(HOOK, ul_debug(" fsopen(%s)", type));
- fd = fsopen(type, FSOPEN_CLOEXEC);
- set_syscall_status(cxt, "fsopen", fd >= 0);
- if (fd < 0)
+ api->fd_fs = fsopen(type, FSOPEN_CLOEXEC);
+ set_syscall_status(cxt, "fsopen", api->fd_fs >= 0);
+ if (api->fd_fs < 0)
return -errno;
- return fd;
+ api->is_new_fs = 1;
+ return api->fd_fs;
}
static int open_mount_tree(struct libmnt_context *cxt, const char *path, unsigned long mflg)
oflg |= AT_RECURSIVE;
}
- DBG(HOOK, ul_debug("open_tree(path=%s, flgs=0x%08lx)", path, oflg));
+ if (cxt->force_clone)
+ oflg |= OPEN_TREE_CLONE;
+
+ DBG(HOOK, ul_debug("open_tree(path=%s%s%s)", path,
+ oflg & OPEN_TREE_CLONE ? " clone" : "",
+ oflg & AT_RECURSIVE ? " recursive" : ""));
fd = open_tree(AT_FDCWD, path, oflg);
set_syscall_status(cxt, "open_tree", fd >= 0);
if (api->fd_fs < 0) {
const char *type = mnt_fs_get_fstype(cxt->fs);
- api->fd_fs = open_fs_configuration_context(cxt, type);
- if (api->fd_fs < 0) {
+ rc = open_fs_configuration_context(cxt, api, type);
+ if (rc < 0) {
rc = api->fd_fs;
goto done;
}
assert(api);
assert(api->fd_tree >= 0);
- if (!rc) {
- DBG(HOOK, ul_debugobj(hs, "move_mount(to=%s)", target));
+ DBG(HOOK, ul_debugobj(hs, "move_mount(to=%s)", target));
+
+ /* umount old target if we created a clone */
+ if (cxt->force_clone
+ && !api->is_new_fs
+ && !mnt_optlist_is_bind(cxt->optlist)) {
- rc = move_mount(api->fd_tree, "", AT_FDCWD, target, MOVE_MOUNT_F_EMPTY_PATH);
- set_syscall_status(cxt, "move_mount", rc == 0);
+ DBG(HOOK, ul_debugobj(hs, "remove expired target"));
+ umount2(target, MNT_DETACH);
}
+
+ rc = move_mount(api->fd_tree, "", AT_FDCWD, target, MOVE_MOUNT_F_EMPTY_PATH);
+ set_syscall_status(cxt, "move_mount", rc == 0);
+
return rc == 0 ? 0 : -errno;
}
if (mnt_context_is_fake(cxt))
goto fake;
- if (cxt->helper == NULL && type && !strchr(type, ',')) {
- api->fd_fs = open_fs_configuration_context(cxt, type);
- if (api->fd_fs < 0)
- goto fail;
- }
+ if (cxt->helper == NULL
+ && type && !strchr(type, ',')
+ && open_fs_configuration_context(cxt, api, type) < 0)
+ goto fail;
}
return 0;
/* call move_mount() to attach target */
if (!rc
&& cxt->helper == NULL
- && !(flags & MS_REMOUNT)
- && !mnt_context_propagation_only(cxt))
+ && (cxt->force_clone ||
+ (!(flags & MS_REMOUNT) && !mnt_context_propagation_only(cxt))))
rc = mnt_context_append_hook(cxt, hs, MNT_STAGE_MOUNT_POST, NULL,
hook_attach_target);