diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2018-06-13 05:23:04 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2019-09-12 08:59:40 -0400 |
commit | 0cc2656cdb0b1f234e6d29378cb061e29d7522bc (patch) | |
tree | 131a397c92997fcfac727b37f1237b31b68c3f55 | |
parent | 4388c5aac4bae5c83a2c66882043942002ba09a2 (diff) |
fuse: extract fuse_fill_super_common()
fuse_fill_super() includes code to process the fd= option and link the
struct fuse_dev to the fd's struct file. In virtio-fs there is no file
descriptor because /dev/fuse is not used.
This patch extracts fuse_fill_super_common() so that both classic fuse and
virtio-fs can share the code to initialize a mount.
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r-- | fs/fuse/fuse_i.h | 27 | ||||
-rw-r--r-- | fs/fuse/inode.c | 112 |
2 files changed, 80 insertions, 59 deletions
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 5f910c99e8dd..1902148281cc 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -416,6 +416,26 @@ struct fuse_dev { | |||
416 | struct list_head entry; | 416 | struct list_head entry; |
417 | }; | 417 | }; |
418 | 418 | ||
419 | struct fuse_fs_context { | ||
420 | int fd; | ||
421 | unsigned int rootmode; | ||
422 | kuid_t user_id; | ||
423 | kgid_t group_id; | ||
424 | bool is_bdev:1; | ||
425 | bool fd_present:1; | ||
426 | bool rootmode_present:1; | ||
427 | bool user_id_present:1; | ||
428 | bool group_id_present:1; | ||
429 | bool default_permissions:1; | ||
430 | bool allow_other:1; | ||
431 | unsigned int max_read; | ||
432 | unsigned int blksize; | ||
433 | const char *subtype; | ||
434 | |||
435 | /* fuse_dev pointer to fill in, should contain NULL on entry */ | ||
436 | void **fudptr; | ||
437 | }; | ||
438 | |||
419 | /** | 439 | /** |
420 | * A Fuse connection. | 440 | * A Fuse connection. |
421 | * | 441 | * |
@@ -874,6 +894,13 @@ void fuse_dev_free(struct fuse_dev *fud); | |||
874 | void fuse_send_init(struct fuse_conn *fc); | 894 | void fuse_send_init(struct fuse_conn *fc); |
875 | 895 | ||
876 | /** | 896 | /** |
897 | * Fill in superblock and initialize fuse connection | ||
898 | * @sb: partially-initialized superblock to fill in | ||
899 | * @ctx: mount context | ||
900 | */ | ||
901 | int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx); | ||
902 | |||
903 | /** | ||
877 | * Add connection to control filesystem | 904 | * Add connection to control filesystem |
878 | */ | 905 | */ |
879 | int fuse_ctl_add_conn(struct fuse_conn *fc); | 906 | int fuse_ctl_add_conn(struct fuse_conn *fc); |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 5d455f4d6195..30d92e633ece 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -64,23 +64,6 @@ MODULE_PARM_DESC(max_user_congthresh, | |||
64 | static struct file_system_type fuseblk_fs_type; | 64 | static struct file_system_type fuseblk_fs_type; |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | struct fuse_fs_context { | ||
68 | const char *subtype; | ||
69 | bool is_bdev; | ||
70 | int fd; | ||
71 | unsigned rootmode; | ||
72 | kuid_t user_id; | ||
73 | kgid_t group_id; | ||
74 | unsigned fd_present:1; | ||
75 | unsigned rootmode_present:1; | ||
76 | unsigned user_id_present:1; | ||
77 | unsigned group_id_present:1; | ||
78 | unsigned default_permissions:1; | ||
79 | unsigned allow_other:1; | ||
80 | unsigned max_read; | ||
81 | unsigned blksize; | ||
82 | }; | ||
83 | |||
84 | struct fuse_forget_link *fuse_alloc_forget(void) | 67 | struct fuse_forget_link *fuse_alloc_forget(void) |
85 | { | 68 | { |
86 | return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL); | 69 | return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL); |
@@ -1100,16 +1083,13 @@ void fuse_dev_free(struct fuse_dev *fud) | |||
1100 | } | 1083 | } |
1101 | EXPORT_SYMBOL_GPL(fuse_dev_free); | 1084 | EXPORT_SYMBOL_GPL(fuse_dev_free); |
1102 | 1085 | ||
1103 | static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) | 1086 | int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) |
1104 | { | 1087 | { |
1105 | struct fuse_fs_context *ctx = fsc->fs_private; | ||
1106 | struct fuse_dev *fud; | 1088 | struct fuse_dev *fud; |
1107 | struct fuse_conn *fc; | 1089 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
1108 | struct inode *root; | 1090 | struct inode *root; |
1109 | struct file *file; | ||
1110 | struct dentry *root_dentry; | 1091 | struct dentry *root_dentry; |
1111 | int err; | 1092 | int err; |
1112 | int is_bdev = sb->s_bdev != NULL; | ||
1113 | 1093 | ||
1114 | err = -EINVAL; | 1094 | err = -EINVAL; |
1115 | if (sb->s_flags & SB_MANDLOCK) | 1095 | if (sb->s_flags & SB_MANDLOCK) |
@@ -1117,7 +1097,7 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) | |||
1117 | 1097 | ||
1118 | sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION); | 1098 | sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION); |
1119 | 1099 | ||
1120 | if (is_bdev) { | 1100 | if (ctx->is_bdev) { |
1121 | #ifdef CONFIG_BLOCK | 1101 | #ifdef CONFIG_BLOCK |
1122 | err = -EINVAL; | 1102 | err = -EINVAL; |
1123 | if (!sb_set_blocksize(sb, ctx->blksize)) | 1103 | if (!sb_set_blocksize(sb, ctx->blksize)) |
@@ -1140,19 +1120,6 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) | |||
1140 | if (sb->s_user_ns != &init_user_ns) | 1120 | if (sb->s_user_ns != &init_user_ns) |
1141 | sb->s_iflags |= SB_I_UNTRUSTED_MOUNTER; | 1121 | sb->s_iflags |= SB_I_UNTRUSTED_MOUNTER; |
1142 | 1122 | ||
1143 | file = fget(ctx->fd); | ||
1144 | err = -EINVAL; | ||
1145 | if (!file) | ||
1146 | goto err; | ||
1147 | |||
1148 | /* | ||
1149 | * Require mount to happen from the same user namespace which | ||
1150 | * opened /dev/fuse to prevent potential attacks. | ||
1151 | */ | ||
1152 | if (file->f_op != &fuse_dev_operations || | ||
1153 | file->f_cred->user_ns != sb->s_user_ns) | ||
1154 | goto err_fput; | ||
1155 | |||
1156 | /* | 1123 | /* |
1157 | * If we are not in the initial user namespace posix | 1124 | * If we are not in the initial user namespace posix |
1158 | * acls must be translated. | 1125 | * acls must be translated. |
@@ -1160,17 +1127,9 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) | |||
1160 | if (sb->s_user_ns != &init_user_ns) | 1127 | if (sb->s_user_ns != &init_user_ns) |
1161 | sb->s_xattr = fuse_no_acl_xattr_handlers; | 1128 | sb->s_xattr = fuse_no_acl_xattr_handlers; |
1162 | 1129 | ||
1163 | fc = kmalloc(sizeof(*fc), GFP_KERNEL); | ||
1164 | err = -ENOMEM; | ||
1165 | if (!fc) | ||
1166 | goto err_fput; | ||
1167 | |||
1168 | fuse_conn_init(fc, sb->s_user_ns); | ||
1169 | fc->release = fuse_free_conn; | ||
1170 | |||
1171 | fud = fuse_dev_alloc(fc); | 1130 | fud = fuse_dev_alloc(fc); |
1172 | if (!fud) | 1131 | if (!fud) |
1173 | goto err_put_conn; | 1132 | goto err; |
1174 | 1133 | ||
1175 | fc->dev = sb->s_dev; | 1134 | fc->dev = sb->s_dev; |
1176 | fc->sb = sb; | 1135 | fc->sb = sb; |
@@ -1188,10 +1147,7 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) | |||
1188 | fc->user_id = ctx->user_id; | 1147 | fc->user_id = ctx->user_id; |
1189 | fc->group_id = ctx->group_id; | 1148 | fc->group_id = ctx->group_id; |
1190 | fc->max_read = max_t(unsigned, 4096, ctx->max_read); | 1149 | fc->max_read = max_t(unsigned, 4096, ctx->max_read); |
1191 | fc->destroy = is_bdev; | 1150 | fc->destroy = ctx->is_bdev; |
1192 | |||
1193 | /* Used by get_root_inode() */ | ||
1194 | sb->s_fs_info = fc; | ||
1195 | 1151 | ||
1196 | err = -ENOMEM; | 1152 | err = -ENOMEM; |
1197 | root = fuse_get_root_inode(sb, ctx->rootmode); | 1153 | root = fuse_get_root_inode(sb, ctx->rootmode); |
@@ -1204,7 +1160,7 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) | |||
1204 | 1160 | ||
1205 | mutex_lock(&fuse_mutex); | 1161 | mutex_lock(&fuse_mutex); |
1206 | err = -EINVAL; | 1162 | err = -EINVAL; |
1207 | if (file->private_data) | 1163 | if (*ctx->fudptr) |
1208 | goto err_unlock; | 1164 | goto err_unlock; |
1209 | 1165 | ||
1210 | err = fuse_ctl_add_conn(fc); | 1166 | err = fuse_ctl_add_conn(fc); |
@@ -1213,24 +1169,62 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) | |||
1213 | 1169 | ||
1214 | list_add_tail(&fc->entry, &fuse_conn_list); | 1170 | list_add_tail(&fc->entry, &fuse_conn_list); |
1215 | sb->s_root = root_dentry; | 1171 | sb->s_root = root_dentry; |
1216 | file->private_data = fud; | 1172 | *ctx->fudptr = fud; |
1217 | mutex_unlock(&fuse_mutex); | 1173 | mutex_unlock(&fuse_mutex); |
1174 | return 0; | ||
1175 | |||
1176 | err_unlock: | ||
1177 | mutex_unlock(&fuse_mutex); | ||
1178 | dput(root_dentry); | ||
1179 | err_dev_free: | ||
1180 | fuse_dev_free(fud); | ||
1181 | err: | ||
1182 | return err; | ||
1183 | } | ||
1184 | EXPORT_SYMBOL_GPL(fuse_fill_super_common); | ||
1185 | |||
1186 | static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) | ||
1187 | { | ||
1188 | struct fuse_fs_context *ctx = fsc->fs_private; | ||
1189 | struct file *file; | ||
1190 | int err; | ||
1191 | struct fuse_conn *fc; | ||
1192 | |||
1193 | err = -EINVAL; | ||
1194 | file = fget(ctx->fd); | ||
1195 | if (!file) | ||
1196 | goto err; | ||
1197 | |||
1198 | /* | ||
1199 | * Require mount to happen from the same user namespace which | ||
1200 | * opened /dev/fuse to prevent potential attacks. | ||
1201 | */ | ||
1202 | if ((file->f_op != &fuse_dev_operations) || | ||
1203 | (file->f_cred->user_ns != sb->s_user_ns)) | ||
1204 | goto err_fput; | ||
1205 | ctx->fudptr = &file->private_data; | ||
1206 | |||
1207 | fc = kmalloc(sizeof(*fc), GFP_KERNEL); | ||
1208 | err = -ENOMEM; | ||
1209 | if (!fc) | ||
1210 | goto err_fput; | ||
1211 | |||
1212 | fuse_conn_init(fc, sb->s_user_ns); | ||
1213 | fc->release = fuse_free_conn; | ||
1214 | sb->s_fs_info = fc; | ||
1215 | |||
1216 | err = fuse_fill_super_common(sb, ctx); | ||
1217 | if (err) | ||
1218 | goto err_put_conn; | ||
1218 | /* | 1219 | /* |
1219 | * atomic_dec_and_test() in fput() provides the necessary | 1220 | * atomic_dec_and_test() in fput() provides the necessary |
1220 | * memory barrier for file->private_data to be visible on all | 1221 | * memory barrier for file->private_data to be visible on all |
1221 | * CPUs after this | 1222 | * CPUs after this |
1222 | */ | 1223 | */ |
1223 | fput(file); | 1224 | fput(file); |
1224 | 1225 | fuse_send_init(get_fuse_conn_super(sb)); | |
1225 | fuse_send_init(fc); | ||
1226 | |||
1227 | return 0; | 1226 | return 0; |
1228 | 1227 | ||
1229 | err_unlock: | ||
1230 | mutex_unlock(&fuse_mutex); | ||
1231 | dput(root_dentry); | ||
1232 | err_dev_free: | ||
1233 | fuse_dev_free(fud); | ||
1234 | err_put_conn: | 1228 | err_put_conn: |
1235 | fuse_conn_put(fc); | 1229 | fuse_conn_put(fc); |
1236 | sb->s_fs_info = NULL; | 1230 | sb->s_fs_info = NULL; |