Skip to content

Commit

Permalink
Merge pull request #258 from truenas/NAS-127825-ee
Browse files Browse the repository at this point in the history
NAS-127825 / 24.10.1 / Fix inconsistent mount options for ZFS root
  • Loading branch information
amotin authored Oct 21, 2024
2 parents 3b73b0e + bd9b874 commit a6f99d4
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 10 deletions.
5 changes: 2 additions & 3 deletions contrib/initramfs/scripts/zfs
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ mount_fs()

# Need the _original_ datasets mountpoint!
mountpoint=$(get_fs_value "$fs" mountpoint)
ZFS_CMD="mount -o zfsutil -t zfs"
ZFS_CMD="mount.zfs -o zfsutil"
if [ "$mountpoint" = "legacy" ] || [ "$mountpoint" = "none" ]; then
# Can't use the mountpoint property. Might be one of our
# clones. Check the 'org.zol:mountpoint' property set in
Expand All @@ -360,9 +360,8 @@ mount_fs()
# isn't the root fs.
return 0
fi
# Don't use mount.zfs -o zfsutils for legacy mountpoint
if [ "$mountpoint" = "legacy" ]; then
ZFS_CMD="mount -t zfs"
ZFS_CMD="mount.zfs"
fi
# Last hail-mary: Hope 'rootmnt' is set!
mountpoint=""
Expand Down
1 change: 1 addition & 0 deletions include/os/linux/zfs/sys/zfs_vfsops_os.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ typedef struct vfs {
boolean_t vfs_do_relatime;
boolean_t vfs_nbmand;
boolean_t vfs_do_nbmand;
kmutex_t vfs_mntpt_lock;
} vfs_t;

typedef struct zfs_mnt {
Expand Down
109 changes: 104 additions & 5 deletions module/os/linux/zfs/zfs_ctldir.c
Original file line number Diff line number Diff line change
Expand Up @@ -769,9 +769,6 @@ zfsctl_snapshot_path_objset(zfsvfs_t *zfsvfs, uint64_t objsetid,
uint64_t id, pos = 0;
int error = 0;

if (zfsvfs->z_vfs->vfs_mntpoint == NULL)
return (SET_ERROR(ENOENT));

cookie = spl_fstrans_mark();
snapname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);

Expand All @@ -788,8 +785,14 @@ zfsctl_snapshot_path_objset(zfsvfs_t *zfsvfs, uint64_t objsetid,
break;
}

snprintf(full_path, path_len, "%s/.zfs/snapshot/%s",
zfsvfs->z_vfs->vfs_mntpoint, snapname);
mutex_enter(&zfsvfs->z_vfs->vfs_mntpt_lock);
if (zfsvfs->z_vfs->vfs_mntpoint != NULL) {
snprintf(full_path, path_len, "%s/.zfs/snapshot/%s",
zfsvfs->z_vfs->vfs_mntpoint, snapname);
} else
error = SET_ERROR(ENOENT);
mutex_exit(&zfsvfs->z_vfs->vfs_mntpt_lock);

out:
kmem_free(snapname, ZFS_MAX_DATASET_NAME_LEN);
spl_fstrans_unmark(cookie);
Expand Down Expand Up @@ -1049,6 +1052,66 @@ exportfs_flush(void)
(void) call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
}

/*
* Returns the path in char format for given struct path. Uses
* d_path exported by kernel to convert struct path to char
* format. Returns the correct path for mountpoints and chroot
* environments.
*
* If chroot environment has directories that are mounted with
* --bind or --rbind flag, d_path returns the complete path inside
* chroot environment but does not return the absolute path, i.e.
* the path to chroot environment is missing.
*/
static int
get_root_path(struct path *path, char *buff, int len)
{
char *path_buffer, *path_ptr;
int error = 0;

path_get(path);
path_buffer = kmem_zalloc(len, KM_SLEEP);
path_ptr = d_path(path, path_buffer, len);
if (IS_ERR(path_ptr))
error = SET_ERROR(-PTR_ERR(path_ptr));
else
strcpy(buff, path_ptr);

kmem_free(path_buffer, len);
path_put(path);
return (error);
}

/*
* Returns if the current process root is chrooted or not. Linux
* kernel exposes the task_struct for current process and init.
* Since init process root points to actual root filesystem when
* Linux runtime is reached, we can compare the current process
* root with init process root to determine if root of the current
* process is different from init, which can reliably determine if
* current process is in chroot context or not.
*/
static int
is_current_chrooted(void)
{
struct task_struct *curr = current, *global = &init_task;
struct path cr_root, gl_root;

task_lock(curr);
get_fs_root(curr->fs, &cr_root);
task_unlock(curr);

task_lock(global);
get_fs_root(global->fs, &gl_root);
task_unlock(global);

int chrooted = !path_equal(&cr_root, &gl_root);
path_put(&gl_root);
path_put(&cr_root);

return (chrooted);
}

/*
* Attempt to unmount a snapshot by making a call to user space.
* There is no assurance that this can or will succeed, is just a
Expand Down Expand Up @@ -1122,14 +1185,50 @@ zfsctl_snapshot_mount(struct path *path, int flags)
if (error)
goto error;

if (is_current_chrooted() == 0) {
/*
* Current process is not in chroot context
*/

char *m = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
struct path mnt_path;
mnt_path.mnt = path->mnt;
mnt_path.dentry = path->mnt->mnt_root;

/*
* Get path to current mountpoint
*/
error = get_root_path(&mnt_path, m, MAXPATHLEN);
if (error != 0) {
kmem_free(m, MAXPATHLEN);
goto error;
}
mutex_enter(&zfsvfs->z_vfs->vfs_mntpt_lock);
if (zfsvfs->z_vfs->vfs_mntpoint != NULL) {
/*
* If current mnountpoint and vfs_mntpoint are not same,
* store current mountpoint in vfs_mntpoint.
*/
if (strcmp(zfsvfs->z_vfs->vfs_mntpoint, m) != 0) {
kmem_strfree(zfsvfs->z_vfs->vfs_mntpoint);
zfsvfs->z_vfs->vfs_mntpoint = kmem_strdup(m);
}
} else
zfsvfs->z_vfs->vfs_mntpoint = kmem_strdup(m);
mutex_exit(&zfsvfs->z_vfs->vfs_mntpt_lock);
kmem_free(m, MAXPATHLEN);
}

/*
* Construct a mount point path from sb of the ctldir inode and dirent
* name, instead of from d_path(), so that chroot'd process doesn't fail
* on mount.zfs(8).
*/
mutex_enter(&zfsvfs->z_vfs->vfs_mntpt_lock);
snprintf(full_path, MAXPATHLEN, "%s/.zfs/snapshot/%s",
zfsvfs->z_vfs->vfs_mntpoint ? zfsvfs->z_vfs->vfs_mntpoint : "",
dname(dentry));
mutex_exit(&zfsvfs->z_vfs->vfs_mntpt_lock);

/*
* Multiple concurrent automounts of a snapshot are never allowed.
Expand Down
6 changes: 4 additions & 2 deletions module/os/linux/zfs/zfs_vfsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ zfsvfs_vfs_free(vfs_t *vfsp)
if (vfsp != NULL) {
if (vfsp->vfs_mntpoint != NULL)
kmem_strfree(vfsp->vfs_mntpoint);

mutex_destroy(&vfsp->vfs_mntpt_lock);
kmem_free(vfsp, sizeof (vfs_t));
}
}
Expand Down Expand Up @@ -195,10 +195,11 @@ zfsvfs_parse_option(char *option, int token, substring_t *args, vfs_t *vfsp)
vfsp->vfs_do_nbmand = B_TRUE;
break;
case TOKEN_MNTPOINT:
if (vfsp->vfs_mntpoint != NULL)
kmem_strfree(vfsp->vfs_mntpoint);
vfsp->vfs_mntpoint = match_strdup(&args[0]);
if (vfsp->vfs_mntpoint == NULL)
return (SET_ERROR(ENOMEM));

break;
default:
break;
Expand All @@ -217,6 +218,7 @@ zfsvfs_parse_options(char *mntopts, vfs_t **vfsp)
int error;

tmp_vfsp = kmem_zalloc(sizeof (vfs_t), KM_SLEEP);
mutex_init(&tmp_vfsp->vfs_mntpt_lock, NULL, MUTEX_DEFAULT, NULL);

if (mntopts != NULL) {
substring_t args[MAX_OPT_ARGS];
Expand Down

0 comments on commit a6f99d4

Please sign in to comment.