1212#include <linux/module.h>
1313#include <linux/init.h>
1414#include <linux/fs.h>
15+ #include <linux/fs_context.h>
16+ #include <linux/fs_parser.h>
1517#include <linux/sched.h>
1618#include <linux/namei.h>
1719#include <linux/slab.h>
2123#include <linux/magic.h>
2224#include <linux/idr.h>
2325#include <linux/devpts_fs.h>
24- #include <linux/parser.h>
2526#include <linux/fsnotify.h>
2627#include <linux/seq_file.h>
2728
@@ -87,14 +88,14 @@ enum {
8788 Opt_err
8889};
8990
90- static const match_table_t tokens = {
91- { Opt_uid , "uid=%u" } ,
92- { Opt_gid , "gid=%u" } ,
93- { Opt_mode , "mode=%o" } ,
94- { Opt_ptmxmode , "ptmxmode=%o" } ,
95- { Opt_newinstance , "newinstance" } ,
96- { Opt_max , "max=%d" } ,
97- {Opt_err , NULL }
91+ static const struct fs_parameter_spec devpts_param_specs [] = {
92+ fsparam_u32 ( "gid" , Opt_gid ) ,
93+ fsparam_s32 ( "max" , Opt_max ) ,
94+ fsparam_u32oct ( "mode" , Opt_mode ) ,
95+ fsparam_flag ( "newinstance" , Opt_newinstance ) ,
96+ fsparam_u32oct ( "ptmxmode" , Opt_ptmxmode ) ,
97+ fsparam_u32 ( "uid" , Opt_uid ) ,
98+ {}
9899};
99100
100101struct pts_fs_info {
@@ -214,93 +215,48 @@ void devpts_release(struct pts_fs_info *fsi)
214215 deactivate_super (fsi -> sb );
215216}
216217
217- #define PARSE_MOUNT 0
218- #define PARSE_REMOUNT 1
219-
220218/*
221- * parse_mount_options():
222- * Set @opts to mount options specified in @data. If an option is not
223- * specified in @data, set it to its default value.
224- *
225- * Note: @data may be NULL (in which case all options are set to default).
219+ * devpts_parse_param - Parse mount parameters
226220 */
227- static int parse_mount_options ( char * data , int op , struct pts_mount_opts * opts )
221+ static int devpts_parse_param ( struct fs_context * fc , struct fs_parameter * param )
228222{
229- char * p ;
230- kuid_t uid ;
231- kgid_t gid ;
232-
233- opts -> setuid = 0 ;
234- opts -> setgid = 0 ;
235- opts -> uid = GLOBAL_ROOT_UID ;
236- opts -> gid = GLOBAL_ROOT_GID ;
237- opts -> mode = DEVPTS_DEFAULT_MODE ;
238- opts -> ptmxmode = DEVPTS_DEFAULT_PTMX_MODE ;
239- opts -> max = NR_UNIX98_PTY_MAX ;
240-
241- /* Only allow instances mounted from the initial mount
242- * namespace to tap the reserve pool of ptys.
243- */
244- if (op == PARSE_MOUNT )
245- opts -> reserve =
246- (current -> nsproxy -> mnt_ns == init_task .nsproxy -> mnt_ns );
247-
248- while ((p = strsep (& data , "," )) != NULL ) {
249- substring_t args [MAX_OPT_ARGS ];
250- int token ;
251- int option ;
252-
253- if (!* p )
254- continue ;
255-
256- token = match_token (p , tokens , args );
257- switch (token ) {
258- case Opt_uid :
259- if (match_int (& args [0 ], & option ))
260- return - EINVAL ;
261- uid = make_kuid (current_user_ns (), option );
262- if (!uid_valid (uid ))
263- return - EINVAL ;
264- opts -> uid = uid ;
265- opts -> setuid = 1 ;
266- break ;
267- case Opt_gid :
268- if (match_int (& args [0 ], & option ))
269- return - EINVAL ;
270- gid = make_kgid (current_user_ns (), option );
271- if (!gid_valid (gid ))
272- return - EINVAL ;
273- opts -> gid = gid ;
274- opts -> setgid = 1 ;
275- break ;
276- case Opt_mode :
277- if (match_octal (& args [0 ], & option ))
278- return - EINVAL ;
279- opts -> mode = option & S_IALLUGO ;
280- break ;
281- case Opt_ptmxmode :
282- if (match_octal (& args [0 ], & option ))
283- return - EINVAL ;
284- opts -> ptmxmode = option & S_IALLUGO ;
285- break ;
286- case Opt_newinstance :
287- break ;
288- case Opt_max :
289- if (match_int (& args [0 ], & option ) ||
290- option < 0 || option > NR_UNIX98_PTY_MAX )
291- return - EINVAL ;
292- opts -> max = option ;
293- break ;
294- default :
295- pr_err ("called with bogus options\n" );
296- return - EINVAL ;
297- }
223+ struct pts_fs_info * fsi = fc -> s_fs_info ;
224+ struct pts_mount_opts * opts = & fsi -> mount_opts ;
225+ struct fs_parse_result result ;
226+ int opt ;
227+
228+ opt = fs_parse (fc , devpts_param_specs , param , & result );
229+ if (opt < 0 )
230+ return opt ;
231+
232+ switch (opt ) {
233+ case Opt_uid :
234+ opts -> uid = result .uid ;
235+ opts -> setuid = 1 ;
236+ break ;
237+ case Opt_gid :
238+ opts -> gid = result .gid ;
239+ opts -> setgid = 1 ;
240+ break ;
241+ case Opt_mode :
242+ opts -> mode = result .uint_32 & S_IALLUGO ;
243+ break ;
244+ case Opt_ptmxmode :
245+ opts -> ptmxmode = result .uint_32 & S_IALLUGO ;
246+ break ;
247+ case Opt_newinstance :
248+ break ;
249+ case Opt_max :
250+ if (result .uint_32 > NR_UNIX98_PTY_MAX )
251+ return invalf (fc , "max out of range" );
252+ opts -> max = result .uint_32 ;
253+ break ;
298254 }
299255
300256 return 0 ;
301257}
302258
303- static int mknod_ptmx (struct super_block * sb )
259+ static int mknod_ptmx (struct super_block * sb , struct fs_context * fc )
304260{
305261 int mode ;
306262 int rc = - ENOMEM ;
@@ -362,13 +318,23 @@ static void update_ptmx_mode(struct pts_fs_info *fsi)
362318 }
363319}
364320
365- static int devpts_remount (struct super_block * sb , int * flags , char * data )
321+ static int devpts_reconfigure (struct fs_context * fc )
366322{
367- int err ;
368- struct pts_fs_info * fsi = DEVPTS_SB (sb );
369- struct pts_mount_opts * opts = & fsi -> mount_opts ;
323+ struct pts_fs_info * fsi = DEVPTS_SB (fc -> root -> d_sb );
324+ struct pts_fs_info * new = fc -> s_fs_info ;
370325
371- err = parse_mount_options (data , PARSE_REMOUNT , opts );
326+ /* Apply the revised options. We don't want to change ->reserve.
327+ * Ideally, we'd update each option conditionally on it having been
328+ * explicitly changed, but the default is to reset everything so that
329+ * would break UAPI...
330+ */
331+ fsi -> mount_opts .setuid = new -> mount_opts .setuid ;
332+ fsi -> mount_opts .setgid = new -> mount_opts .setgid ;
333+ fsi -> mount_opts .uid = new -> mount_opts .uid ;
334+ fsi -> mount_opts .gid = new -> mount_opts .gid ;
335+ fsi -> mount_opts .mode = new -> mount_opts .mode ;
336+ fsi -> mount_opts .ptmxmode = new -> mount_opts .ptmxmode ;
337+ fsi -> mount_opts .max = new -> mount_opts .max ;
372338
373339 /*
374340 * parse_mount_options() restores options to default values
@@ -378,7 +344,7 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data)
378344 */
379345 update_ptmx_mode (fsi );
380346
381- return err ;
347+ return 0 ;
382348}
383349
384350static int devpts_show_options (struct seq_file * seq , struct dentry * root )
@@ -402,31 +368,13 @@ static int devpts_show_options(struct seq_file *seq, struct dentry *root)
402368
403369static const struct super_operations devpts_sops = {
404370 .statfs = simple_statfs ,
405- .remount_fs = devpts_remount ,
406371 .show_options = devpts_show_options ,
407372};
408373
409- static void * new_pts_fs_info (struct super_block * sb )
410- {
411- struct pts_fs_info * fsi ;
412-
413- fsi = kzalloc (sizeof (struct pts_fs_info ), GFP_KERNEL );
414- if (!fsi )
415- return NULL ;
416-
417- ida_init (& fsi -> allocated_ptys );
418- fsi -> mount_opts .mode = DEVPTS_DEFAULT_MODE ;
419- fsi -> mount_opts .ptmxmode = DEVPTS_DEFAULT_PTMX_MODE ;
420- fsi -> sb = sb ;
421-
422- return fsi ;
423- }
424-
425- static int
426- devpts_fill_super (struct super_block * s , void * data , int silent )
374+ static int devpts_fill_super (struct super_block * s , struct fs_context * fc )
427375{
376+ struct pts_fs_info * fsi = DEVPTS_SB (s );
428377 struct inode * inode ;
429- int error ;
430378
431379 s -> s_iflags &= ~SB_I_NODEV ;
432380 s -> s_blocksize = 1024 ;
@@ -435,20 +383,11 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
435383 s -> s_op = & devpts_sops ;
436384 s -> s_d_op = & simple_dentry_operations ;
437385 s -> s_time_gran = 1 ;
386+ fsi -> sb = s ;
438387
439- error = - ENOMEM ;
440- s -> s_fs_info = new_pts_fs_info (s );
441- if (!s -> s_fs_info )
442- goto fail ;
443-
444- error = parse_mount_options (data , PARSE_MOUNT , & DEVPTS_SB (s )-> mount_opts );
445- if (error )
446- goto fail ;
447-
448- error = - ENOMEM ;
449388 inode = new_inode (s );
450389 if (!inode )
451- goto fail ;
390+ return - ENOMEM ;
452391 inode -> i_ino = 1 ;
453392 simple_inode_init_ts (inode );
454393 inode -> i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR ;
@@ -459,31 +398,60 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
459398 s -> s_root = d_make_root (inode );
460399 if (!s -> s_root ) {
461400 pr_err ("get root dentry failed\n" );
462- goto fail ;
401+ return - ENOMEM ;
463402 }
464403
465- error = mknod_ptmx (s );
466- if (error )
467- goto fail_dput ;
468-
469- return 0 ;
470- fail_dput :
471- dput (s -> s_root );
472- s -> s_root = NULL ;
473- fail :
474- return error ;
404+ return mknod_ptmx (s , fc );
475405}
476406
477407/*
478- * devpts_mount ()
408+ * devpts_get_tree ()
479409 *
480410 * Mount a new (private) instance of devpts. PTYs created in this
481411 * instance are independent of the PTYs in other devpts instances.
482412 */
483- static struct dentry * devpts_mount (struct file_system_type * fs_type ,
484- int flags , const char * dev_name , void * data )
413+ static int devpts_get_tree (struct fs_context * fc )
414+ {
415+ return get_tree_nodev (fc , devpts_fill_super );
416+ }
417+
418+ static void devpts_free_fc (struct fs_context * fc )
419+ {
420+ kfree (fc -> s_fs_info );
421+ }
422+
423+ static const struct fs_context_operations devpts_context_ops = {
424+ .free = devpts_free_fc ,
425+ .parse_param = devpts_parse_param ,
426+ .get_tree = devpts_get_tree ,
427+ .reconfigure = devpts_reconfigure ,
428+ };
429+
430+ /*
431+ * Set up the filesystem mount context.
432+ */
433+ static int devpts_init_fs_context (struct fs_context * fc )
485434{
486- return mount_nodev (fs_type , flags , data , devpts_fill_super );
435+ struct pts_fs_info * fsi ;
436+
437+ fsi = kzalloc (sizeof (struct pts_fs_info ), GFP_KERNEL );
438+ if (!fsi )
439+ return - ENOMEM ;
440+
441+ ida_init (& fsi -> allocated_ptys );
442+ fsi -> mount_opts .uid = GLOBAL_ROOT_UID ;
443+ fsi -> mount_opts .gid = GLOBAL_ROOT_GID ;
444+ fsi -> mount_opts .mode = DEVPTS_DEFAULT_MODE ;
445+ fsi -> mount_opts .ptmxmode = DEVPTS_DEFAULT_PTMX_MODE ;
446+ fsi -> mount_opts .max = NR_UNIX98_PTY_MAX ;
447+
448+ if (fc -> purpose == FS_CONTEXT_FOR_MOUNT &&
449+ current -> nsproxy -> mnt_ns == init_task .nsproxy -> mnt_ns )
450+ fsi -> mount_opts .reserve = true;
451+
452+ fc -> s_fs_info = fsi ;
453+ fc -> ops = & devpts_context_ops ;
454+ return 0 ;
487455}
488456
489457static void devpts_kill_sb (struct super_block * sb )
@@ -498,7 +466,8 @@ static void devpts_kill_sb(struct super_block *sb)
498466
499467static struct file_system_type devpts_fs_type = {
500468 .name = "devpts" ,
501- .mount = devpts_mount ,
469+ .init_fs_context = devpts_init_fs_context ,
470+ .parameters = devpts_param_specs ,
502471 .kill_sb = devpts_kill_sb ,
503472 .fs_flags = FS_USERNS_MOUNT ,
504473};
0 commit comments