diff options
Diffstat (limited to 'fs/devpts')
-rw-r--r-- | fs/devpts/inode.c | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 8ee9dc2f9e48..2d0eb2cf99e6 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c | |||
@@ -305,10 +305,63 @@ fail: | |||
305 | return -ENOMEM; | 305 | return -ENOMEM; |
306 | } | 306 | } |
307 | 307 | ||
308 | static int compare_init_pts_sb(struct super_block *s, void *p) | ||
309 | { | ||
310 | if (devpts_mnt) | ||
311 | return devpts_mnt->mnt_sb == s; | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | /* | ||
317 | * get_init_pts_sb() | ||
318 | * | ||
319 | * This interface is needed to support multiple namespace semantics in | ||
320 | * devpts while preserving backward compatibility of the current 'single- | ||
321 | * namespace' semantics. i.e all mounts of devpts without the 'newinstance' | ||
322 | * mount option should bind to the initial kernel mount, like | ||
323 | * get_sb_single(). | ||
324 | * | ||
325 | * Mounts with 'newinstance' option create a new private namespace. | ||
326 | * | ||
327 | * But for single-mount semantics, devpts cannot use get_sb_single(), | ||
328 | * because get_sb_single()/sget() find and use the super-block from | ||
329 | * the most recent mount of devpts. But that recent mount may be a | ||
330 | * 'newinstance' mount and get_sb_single() would pick the newinstance | ||
331 | * super-block instead of the initial super-block. | ||
332 | * | ||
333 | * This interface is identical to get_sb_single() except that it | ||
334 | * consistently selects the 'single-namespace' superblock even in the | ||
335 | * presence of the private namespace (i.e 'newinstance') super-blocks. | ||
336 | */ | ||
337 | static int get_init_pts_sb(struct file_system_type *fs_type, int flags, | ||
338 | void *data, struct vfsmount *mnt) | ||
339 | { | ||
340 | struct super_block *s; | ||
341 | int error; | ||
342 | |||
343 | s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL); | ||
344 | if (IS_ERR(s)) | ||
345 | return PTR_ERR(s); | ||
346 | |||
347 | if (!s->s_root) { | ||
348 | s->s_flags = flags; | ||
349 | error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0); | ||
350 | if (error) { | ||
351 | up_write(&s->s_umount); | ||
352 | deactivate_super(s); | ||
353 | return error; | ||
354 | } | ||
355 | s->s_flags |= MS_ACTIVE; | ||
356 | } | ||
357 | do_remount_sb(s, flags, data, 0); | ||
358 | return simple_set_mnt(mnt, s); | ||
359 | } | ||
360 | |||
308 | static int devpts_get_sb(struct file_system_type *fs_type, | 361 | static int devpts_get_sb(struct file_system_type *fs_type, |
309 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | 362 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) |
310 | { | 363 | { |
311 | return get_sb_single(fs_type, flags, data, devpts_fill_super, mnt); | 364 | return get_init_pts_sb(fs_type, flags, data, mnt); |
312 | } | 365 | } |
313 | 366 | ||
314 | static void devpts_kill_sb(struct super_block *sb) | 367 | static void devpts_kill_sb(struct super_block *sb) |