Skip to content

Commit a6f99d4

Browse files
authored
Merge pull request #258 from truenas/NAS-127825-ee
NAS-127825 / 24.10.1 / Fix inconsistent mount options for ZFS root
2 parents 3b73b0e + bd9b874 commit a6f99d4

File tree

4 files changed

+111
-10
lines changed

4 files changed

+111
-10
lines changed

contrib/initramfs/scripts/zfs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ mount_fs()
345345

346346
# Need the _original_ datasets mountpoint!
347347
mountpoint=$(get_fs_value "$fs" mountpoint)
348-
ZFS_CMD="mount -o zfsutil -t zfs"
348+
ZFS_CMD="mount.zfs -o zfsutil"
349349
if [ "$mountpoint" = "legacy" ] || [ "$mountpoint" = "none" ]; then
350350
# Can't use the mountpoint property. Might be one of our
351351
# clones. Check the 'org.zol:mountpoint' property set in
@@ -360,9 +360,8 @@ mount_fs()
360360
# isn't the root fs.
361361
return 0
362362
fi
363-
# Don't use mount.zfs -o zfsutils for legacy mountpoint
364363
if [ "$mountpoint" = "legacy" ]; then
365-
ZFS_CMD="mount -t zfs"
364+
ZFS_CMD="mount.zfs"
366365
fi
367366
# Last hail-mary: Hope 'rootmnt' is set!
368367
mountpoint=""

include/os/linux/zfs/sys/zfs_vfsops_os.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ typedef struct vfs {
6969
boolean_t vfs_do_relatime;
7070
boolean_t vfs_nbmand;
7171
boolean_t vfs_do_nbmand;
72+
kmutex_t vfs_mntpt_lock;
7273
} vfs_t;
7374

7475
typedef struct zfs_mnt {

module/os/linux/zfs/zfs_ctldir.c

Lines changed: 104 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -769,9 +769,6 @@ zfsctl_snapshot_path_objset(zfsvfs_t *zfsvfs, uint64_t objsetid,
769769
uint64_t id, pos = 0;
770770
int error = 0;
771771

772-
if (zfsvfs->z_vfs->vfs_mntpoint == NULL)
773-
return (SET_ERROR(ENOENT));
774-
775772
cookie = spl_fstrans_mark();
776773
snapname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
777774

@@ -788,8 +785,14 @@ zfsctl_snapshot_path_objset(zfsvfs_t *zfsvfs, uint64_t objsetid,
788785
break;
789786
}
790787

791-
snprintf(full_path, path_len, "%s/.zfs/snapshot/%s",
792-
zfsvfs->z_vfs->vfs_mntpoint, snapname);
788+
mutex_enter(&zfsvfs->z_vfs->vfs_mntpt_lock);
789+
if (zfsvfs->z_vfs->vfs_mntpoint != NULL) {
790+
snprintf(full_path, path_len, "%s/.zfs/snapshot/%s",
791+
zfsvfs->z_vfs->vfs_mntpoint, snapname);
792+
} else
793+
error = SET_ERROR(ENOENT);
794+
mutex_exit(&zfsvfs->z_vfs->vfs_mntpt_lock);
795+
793796
out:
794797
kmem_free(snapname, ZFS_MAX_DATASET_NAME_LEN);
795798
spl_fstrans_unmark(cookie);
@@ -1049,6 +1052,66 @@ exportfs_flush(void)
10491052
(void) call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
10501053
}
10511054

1055+
/*
1056+
* Returns the path in char format for given struct path. Uses
1057+
* d_path exported by kernel to convert struct path to char
1058+
* format. Returns the correct path for mountpoints and chroot
1059+
* environments.
1060+
*
1061+
* If chroot environment has directories that are mounted with
1062+
* --bind or --rbind flag, d_path returns the complete path inside
1063+
* chroot environment but does not return the absolute path, i.e.
1064+
* the path to chroot environment is missing.
1065+
*/
1066+
static int
1067+
get_root_path(struct path *path, char *buff, int len)
1068+
{
1069+
char *path_buffer, *path_ptr;
1070+
int error = 0;
1071+
1072+
path_get(path);
1073+
path_buffer = kmem_zalloc(len, KM_SLEEP);
1074+
path_ptr = d_path(path, path_buffer, len);
1075+
if (IS_ERR(path_ptr))
1076+
error = SET_ERROR(-PTR_ERR(path_ptr));
1077+
else
1078+
strcpy(buff, path_ptr);
1079+
1080+
kmem_free(path_buffer, len);
1081+
path_put(path);
1082+
return (error);
1083+
}
1084+
1085+
/*
1086+
* Returns if the current process root is chrooted or not. Linux
1087+
* kernel exposes the task_struct for current process and init.
1088+
* Since init process root points to actual root filesystem when
1089+
* Linux runtime is reached, we can compare the current process
1090+
* root with init process root to determine if root of the current
1091+
* process is different from init, which can reliably determine if
1092+
* current process is in chroot context or not.
1093+
*/
1094+
static int
1095+
is_current_chrooted(void)
1096+
{
1097+
struct task_struct *curr = current, *global = &init_task;
1098+
struct path cr_root, gl_root;
1099+
1100+
task_lock(curr);
1101+
get_fs_root(curr->fs, &cr_root);
1102+
task_unlock(curr);
1103+
1104+
task_lock(global);
1105+
get_fs_root(global->fs, &gl_root);
1106+
task_unlock(global);
1107+
1108+
int chrooted = !path_equal(&cr_root, &gl_root);
1109+
path_put(&gl_root);
1110+
path_put(&cr_root);
1111+
1112+
return (chrooted);
1113+
}
1114+
10521115
/*
10531116
* Attempt to unmount a snapshot by making a call to user space.
10541117
* There is no assurance that this can or will succeed, is just a
@@ -1122,14 +1185,50 @@ zfsctl_snapshot_mount(struct path *path, int flags)
11221185
if (error)
11231186
goto error;
11241187

1188+
if (is_current_chrooted() == 0) {
1189+
/*
1190+
* Current process is not in chroot context
1191+
*/
1192+
1193+
char *m = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1194+
struct path mnt_path;
1195+
mnt_path.mnt = path->mnt;
1196+
mnt_path.dentry = path->mnt->mnt_root;
1197+
1198+
/*
1199+
* Get path to current mountpoint
1200+
*/
1201+
error = get_root_path(&mnt_path, m, MAXPATHLEN);
1202+
if (error != 0) {
1203+
kmem_free(m, MAXPATHLEN);
1204+
goto error;
1205+
}
1206+
mutex_enter(&zfsvfs->z_vfs->vfs_mntpt_lock);
1207+
if (zfsvfs->z_vfs->vfs_mntpoint != NULL) {
1208+
/*
1209+
* If current mnountpoint and vfs_mntpoint are not same,
1210+
* store current mountpoint in vfs_mntpoint.
1211+
*/
1212+
if (strcmp(zfsvfs->z_vfs->vfs_mntpoint, m) != 0) {
1213+
kmem_strfree(zfsvfs->z_vfs->vfs_mntpoint);
1214+
zfsvfs->z_vfs->vfs_mntpoint = kmem_strdup(m);
1215+
}
1216+
} else
1217+
zfsvfs->z_vfs->vfs_mntpoint = kmem_strdup(m);
1218+
mutex_exit(&zfsvfs->z_vfs->vfs_mntpt_lock);
1219+
kmem_free(m, MAXPATHLEN);
1220+
}
1221+
11251222
/*
11261223
* Construct a mount point path from sb of the ctldir inode and dirent
11271224
* name, instead of from d_path(), so that chroot'd process doesn't fail
11281225
* on mount.zfs(8).
11291226
*/
1227+
mutex_enter(&zfsvfs->z_vfs->vfs_mntpt_lock);
11301228
snprintf(full_path, MAXPATHLEN, "%s/.zfs/snapshot/%s",
11311229
zfsvfs->z_vfs->vfs_mntpoint ? zfsvfs->z_vfs->vfs_mntpoint : "",
11321230
dname(dentry));
1231+
mutex_exit(&zfsvfs->z_vfs->vfs_mntpt_lock);
11331232

11341233
/*
11351234
* Multiple concurrent automounts of a snapshot are never allowed.

module/os/linux/zfs/zfs_vfsops.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ zfsvfs_vfs_free(vfs_t *vfsp)
113113
if (vfsp != NULL) {
114114
if (vfsp->vfs_mntpoint != NULL)
115115
kmem_strfree(vfsp->vfs_mntpoint);
116-
116+
mutex_destroy(&vfsp->vfs_mntpt_lock);
117117
kmem_free(vfsp, sizeof (vfs_t));
118118
}
119119
}
@@ -195,10 +195,11 @@ zfsvfs_parse_option(char *option, int token, substring_t *args, vfs_t *vfsp)
195195
vfsp->vfs_do_nbmand = B_TRUE;
196196
break;
197197
case TOKEN_MNTPOINT:
198+
if (vfsp->vfs_mntpoint != NULL)
199+
kmem_strfree(vfsp->vfs_mntpoint);
198200
vfsp->vfs_mntpoint = match_strdup(&args[0]);
199201
if (vfsp->vfs_mntpoint == NULL)
200202
return (SET_ERROR(ENOMEM));
201-
202203
break;
203204
default:
204205
break;
@@ -217,6 +218,7 @@ zfsvfs_parse_options(char *mntopts, vfs_t **vfsp)
217218
int error;
218219

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

221223
if (mntopts != NULL) {
222224
substring_t args[MAX_OPT_ARGS];

0 commit comments

Comments
 (0)