Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

devpts: Make each mount of devpts an independent filesystem.

The /dev/ptmx device node is changed to lookup the directory entry "pts"
in the same directory as the /dev/ptmx device node was opened in. If
there is a "pts" entry and that entry is a devpts filesystem /dev/ptmx
uses that filesystem. Otherwise the open of /dev/ptmx fails.

The DEVPTS_MULTIPLE_INSTANCES configuration option is removed, so that
userspace can now safely depend on each mount of devpts creating a new
instance of the filesystem.

Each mount of devpts is now a separate and equal filesystem.

Reserved ttys are now available to all instances of devpts where the
mounter is in the initial mount namespace.

A new vfs helper path_pts is introduced that finds a directory entry
named "pts" in the directory of the passed in path, and changes the
passed in path to point to it. The helper path_pts uses a function
path_parent_directory that was factored out of follow_dotdot.

In the implementation of devpts:
- devpts_mnt is killed as it is no longer meaningful if all mounts of
devpts are equal.
- pts_sb_from_inode is replaced by just inode->i_sb as all cached
inodes in the tty layer are now from the devpts filesystem.
- devpts_add_ref is rolled into the new function devpts_ptmx. And the
unnecessary inode hold is removed.
- devpts_del_ref is renamed devpts_release and reduced to just a
deacrivate_super.
- The newinstance mount option continues to be accepted but is now
ignored.

In devpts_fs.h definitions for when !CONFIG_UNIX98_PTYS are removed as
they are never used.

Documentation/filesystems/devices.txt is updated to describe the current
situation.

This has been verified to work properly on openwrt-15.05, centos5,
centos6, centos7, debian-6.0.2, debian-7.9, debian-8.2, ubuntu-14.04.3,
ubuntu-15.10, fedora23, magia-5, mint-17.3, opensuse-42.1,
slackware-14.1, gentoo-20151225 (13.0?), archlinux-2015-12-01. With the
caveat that on centos6 and on slackware-14.1 that there wind up being
two instances of the devpts filesystem mounted on /dev/pts, the lower
copy does not end up getting used.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Greg KH <greg@kroah.com>
Cc: Peter Hurley <peter@hurleysoftware.com>
Cc: Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: One Thousand Gnomes <gnomes@lxorguk.ukuu.org.uk>
Cc: Jann Horn <jann@thejh.net>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Florian Weimer <fw@deneb.enyo.de>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Eric W. Biederman and committed by
Linus Torvalds
eedf265a 049ec1b5

+126 -296
+15 -130
Documentation/filesystems/devpts.txt
··· 1 + Each mount of the devpts filesystem is now distinct such that ptys 2 + and their indicies allocated in one mount are independent from ptys 3 + and their indicies in all other mounts. 1 4 2 - To support containers, we now allow multiple instances of devpts filesystem, 3 - such that indices of ptys allocated in one instance are independent of indices 4 - allocated in other instances of devpts. 5 + All mounts of the devpts filesystem now create a /dev/pts/ptmx node 6 + with permissions 0000. 5 7 6 - To preserve backward compatibility, this support for multiple instances is 7 - enabled only if: 8 + To retain backwards compatibility the a ptmx device node (aka any node 9 + created with "mknod name c 5 2") when opened will look for an instance 10 + of devpts under the name "pts" in the same directory as the ptmx device 11 + node. 8 12 9 - - CONFIG_DEVPTS_MULTIPLE_INSTANCES=y, and 10 - - '-o newinstance' mount option is specified while mounting devpts 11 - 12 - IOW, devpts now supports both single-instance and multi-instance semantics. 13 - 14 - If CONFIG_DEVPTS_MULTIPLE_INSTANCES=n, there is no change in behavior and 15 - this referred to as the "legacy" mode. In this mode, the new mount options 16 - (-o newinstance and -o ptmxmode) will be ignored with a 'bogus option' message 17 - on console. 18 - 19 - If CONFIG_DEVPTS_MULTIPLE_INSTANCES=y and devpts is mounted without the 20 - 'newinstance' option (as in current start-up scripts) the new mount binds 21 - to the initial kernel mount of devpts. This mode is referred to as the 22 - 'single-instance' mode and the current, single-instance semantics are 23 - preserved, i.e PTYs are common across the system. 24 - 25 - The only difference between this single-instance mode and the legacy mode 26 - is the presence of new, '/dev/pts/ptmx' node with permissions 0000, which 27 - can safely be ignored. 28 - 29 - If CONFIG_DEVPTS_MULTIPLE_INSTANCES=y and 'newinstance' option is specified, 30 - the mount is considered to be in the multi-instance mode and a new instance 31 - of the devpts fs is created. Any ptys created in this instance are independent 32 - of ptys in other instances of devpts. Like in the single-instance mode, the 33 - /dev/pts/ptmx node is present. To effectively use the multi-instance mode, 34 - open of /dev/ptmx must be a redirected to '/dev/pts/ptmx' using a symlink or 35 - bind-mount. 36 - 37 - Eg: A container startup script could do the following: 38 - 39 - $ chmod 0666 /dev/pts/ptmx 40 - $ rm /dev/ptmx 41 - $ ln -s pts/ptmx /dev/ptmx 42 - $ ns_exec -cm /bin/bash 43 - 44 - # We are now in new container 45 - 46 - $ umount /dev/pts 47 - $ mount -t devpts -o newinstance lxcpts /dev/pts 48 - $ sshd -p 1234 49 - 50 - where 'ns_exec -cm /bin/bash' calls clone() with CLONE_NEWNS flag and execs 51 - /bin/bash in the child process. A pty created by the sshd is not visible in 52 - the original mount of /dev/pts. 13 + As an option instead of placing a /dev/ptmx device node at /dev/ptmx 14 + it is possible to place a symlink to /dev/pts/ptmx at /dev/ptmx or 15 + to bind mount /dev/ptx/ptmx to /dev/ptmx. If you opt for using 16 + the devpts filesystem in this manner devpts should be mounted with 17 + the ptmxmode=0666, or chmod 0666 /dev/pts/ptmx should be called. 53 18 54 19 Total count of pty pairs in all instances is limited by sysctls: 55 20 kernel.pty.max = 4096 - global limit 56 - kernel.pty.reserve = 1024 - reserve for initial instance 21 + kernel.pty.reserve = 1024 - reserved for filesystems mounted from the initial mount namespace 57 22 kernel.pty.nr - current count of ptys 58 23 59 24 Per-instance limit could be set by adding mount option "max=<count>". 60 25 This feature was added in kernel 3.4 together with sysctl kernel.pty.reserve. 61 26 In kernels older than 3.4 sysctl kernel.pty.max works as per-instance limit. 62 - 63 - User-space changes 64 - ------------------ 65 - 66 - In multi-instance mode (i.e '-o newinstance' mount option is specified at least 67 - once), following user-space issues should be noted. 68 - 69 - 1. If -o newinstance mount option is never used, /dev/pts/ptmx can be ignored 70 - and no change is needed to system-startup scripts. 71 - 72 - 2. To effectively use multi-instance mode (i.e -o newinstance is specified) 73 - administrators or startup scripts should "redirect" open of /dev/ptmx to 74 - /dev/pts/ptmx using either a bind mount or symlink. 75 - 76 - $ mount -t devpts -o newinstance devpts /dev/pts 77 - 78 - followed by either 79 - 80 - $ rm /dev/ptmx 81 - $ ln -s pts/ptmx /dev/ptmx 82 - $ chmod 666 /dev/pts/ptmx 83 - or 84 - $ mount -o bind /dev/pts/ptmx /dev/ptmx 85 - 86 - 3. The '/dev/ptmx -> pts/ptmx' symlink is the preferred method since it 87 - enables better error-reporting and treats both single-instance and 88 - multi-instance mounts similarly. 89 - 90 - But this method requires that system-startup scripts set the mode of 91 - /dev/pts/ptmx correctly (default mode is 0000). The scripts can set the 92 - mode by, either 93 - 94 - - adding ptmxmode mount option to devpts entry in /etc/fstab, or 95 - - using 'chmod 0666 /dev/pts/ptmx' 96 - 97 - 4. If multi-instance mode mount is needed for containers, but the system 98 - startup scripts have not yet been updated, container-startup scripts 99 - should bind mount /dev/ptmx to /dev/pts/ptmx to avoid breaking single- 100 - instance mounts. 101 - 102 - Or, in general, container-startup scripts should use: 103 - 104 - mount -t devpts -o newinstance -o ptmxmode=0666 devpts /dev/pts 105 - if [ ! -L /dev/ptmx ]; then 106 - mount -o bind /dev/pts/ptmx /dev/ptmx 107 - fi 108 - 109 - When all devpts mounts are multi-instance, /dev/ptmx can permanently be 110 - a symlink to pts/ptmx and the bind mount can be ignored. 111 - 112 - 5. A multi-instance mount that is not accompanied by the /dev/ptmx to 113 - /dev/pts/ptmx redirection would result in an unusable/unreachable pty. 114 - 115 - mount -t devpts -o newinstance lxcpts /dev/pts 116 - 117 - immediately followed by: 118 - 119 - open("/dev/ptmx") 120 - 121 - would create a pty, say /dev/pts/7, in the initial kernel mount. 122 - But /dev/pts/7 would be invisible in the new mount. 123 - 124 - 6. The permissions for /dev/pts/ptmx node should be specified when mounting 125 - /dev/pts, using the '-o ptmxmode=%o' mount option (default is 0000). 126 - 127 - mount -t devpts -o newinstance -o ptmxmode=0644 devpts /dev/pts 128 - 129 - The permissions can be later be changed as usual with 'chmod'. 130 - 131 - chmod 666 /dev/pts/ptmx 132 - 133 - 7. A mount of devpts without the 'newinstance' option results in binding to 134 - initial kernel mount. This behavior while preserving legacy semantics, 135 - does not provide strict isolation in a container environment. i.e by 136 - mounting devpts without the 'newinstance' option, a container could 137 - get visibility into the 'host' or root container's devpts. 138 - 139 - To workaround this and have strict isolation, all mounts of devpts, 140 - including the mount in the root container, should use the newinstance 141 - option.
-11
drivers/tty/Kconfig
··· 120 120 All modern Linux systems use the Unix98 ptys. Say Y unless 121 121 you're on an embedded system and want to conserve memory. 122 122 123 - config DEVPTS_MULTIPLE_INSTANCES 124 - bool "Support multiple instances of devpts" 125 - depends on UNIX98_PTYS 126 - default n 127 - ---help--- 128 - Enable support for multiple instances of devpts filesystem. 129 - If you want to have isolated PTY namespaces (eg: in containers), 130 - say Y here. Otherwise, say N. If enabled, each mount of devpts 131 - filesystem with the '-o newinstance' option will create an 132 - independent PTY namespace. 133 - 134 123 config LEGACY_PTYS 135 124 bool "Legacy (BSD) PTY support" 136 125 default y
+8 -7
drivers/tty/pty.c
··· 668 668 else 669 669 fsi = tty->link->driver_data; 670 670 devpts_kill_index(fsi, tty->index); 671 - devpts_put_ref(fsi); 671 + devpts_release(fsi); 672 672 } 673 673 674 674 static const struct tty_operations ptm_unix98_ops = { ··· 733 733 if (retval) 734 734 return retval; 735 735 736 - fsi = devpts_get_ref(inode, filp); 737 - retval = -ENODEV; 738 - if (!fsi) 736 + fsi = devpts_acquire(filp); 737 + if (IS_ERR(fsi)) { 738 + retval = PTR_ERR(fsi); 739 739 goto out_free_file; 740 + } 740 741 741 742 /* find a device that is not in use. */ 742 743 mutex_lock(&devpts_mutex); ··· 746 745 747 746 retval = index; 748 747 if (index < 0) 749 - goto out_put_ref; 748 + goto out_put_fsi; 750 749 751 750 752 751 mutex_lock(&tty_mutex); ··· 790 789 return retval; 791 790 out: 792 791 devpts_kill_index(fsi, index); 793 - out_put_ref: 794 - devpts_put_ref(fsi); 792 + out_put_fsi: 793 + devpts_release(fsi); 795 794 out_free_file: 796 795 tty_free_file(filp); 797 796 return retval;
+55 -136
fs/devpts/inode.c
··· 95 95 96 96 static DEFINE_MUTEX(allocated_ptys_lock); 97 97 98 - static struct vfsmount *devpts_mnt; 99 - 100 98 struct pts_mount_opts { 101 99 int setuid; 102 100 int setgid; ··· 102 104 kgid_t gid; 103 105 umode_t mode; 104 106 umode_t ptmxmode; 105 - int newinstance; 107 + int reserve; 106 108 int max; 107 109 }; 108 110 ··· 115 117 {Opt_uid, "uid=%u"}, 116 118 {Opt_gid, "gid=%u"}, 117 119 {Opt_mode, "mode=%o"}, 118 - #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES 119 120 {Opt_ptmxmode, "ptmxmode=%o"}, 120 121 {Opt_newinstance, "newinstance"}, 121 122 {Opt_max, "max=%d"}, 122 - #endif 123 123 {Opt_err, NULL} 124 124 }; 125 125 ··· 133 137 return sb->s_fs_info; 134 138 } 135 139 136 - static inline struct super_block *pts_sb_from_inode(struct inode *inode) 140 + struct pts_fs_info *devpts_acquire(struct file *filp) 137 141 { 138 - #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES 139 - if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) 140 - return inode->i_sb; 141 - #endif 142 - if (!devpts_mnt) 143 - return NULL; 144 - return devpts_mnt->mnt_sb; 142 + struct pts_fs_info *result; 143 + struct path path; 144 + struct super_block *sb; 145 + int err; 146 + 147 + path = filp->f_path; 148 + path_get(&path); 149 + 150 + /* Has the devpts filesystem already been found? */ 151 + sb = path.mnt->mnt_sb; 152 + if (sb->s_magic != DEVPTS_SUPER_MAGIC) { 153 + /* Is a devpts filesystem at "pts" in the same directory? */ 154 + err = path_pts(&path); 155 + if (err) { 156 + result = ERR_PTR(err); 157 + goto out; 158 + } 159 + 160 + /* Is the path the root of a devpts filesystem? */ 161 + result = ERR_PTR(-ENODEV); 162 + sb = path.mnt->mnt_sb; 163 + if ((sb->s_magic != DEVPTS_SUPER_MAGIC) || 164 + (path.mnt->mnt_root != sb->s_root)) 165 + goto out; 166 + } 167 + 168 + /* 169 + * pty code needs to hold extra references in case of last /dev/tty close 170 + */ 171 + atomic_inc(&sb->s_active); 172 + result = DEVPTS_SB(sb); 173 + 174 + out: 175 + path_put(&path); 176 + return result; 177 + } 178 + 179 + void devpts_release(struct pts_fs_info *fsi) 180 + { 181 + deactivate_super(fsi->sb); 145 182 } 146 183 147 184 #define PARSE_MOUNT 0 ··· 183 154 /* 184 155 * parse_mount_options(): 185 156 * Set @opts to mount options specified in @data. If an option is not 186 - * specified in @data, set it to its default value. The exception is 187 - * 'newinstance' option which can only be set/cleared on a mount (i.e. 188 - * cannot be changed during remount). 157 + * specified in @data, set it to its default value. 189 158 * 190 159 * Note: @data may be NULL (in which case all options are set to default). 191 160 */ ··· 201 174 opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; 202 175 opts->max = NR_UNIX98_PTY_MAX; 203 176 204 - /* newinstance makes sense only on initial mount */ 177 + /* Only allow instances mounted from the initial mount 178 + * namespace to tap the reserve pool of ptys. 179 + */ 205 180 if (op == PARSE_MOUNT) 206 - opts->newinstance = 0; 181 + opts->reserve = 182 + (current->nsproxy->mnt_ns == init_task.nsproxy->mnt_ns); 207 183 208 184 while ((p = strsep(&data, ",")) != NULL) { 209 185 substring_t args[MAX_OPT_ARGS]; ··· 241 211 return -EINVAL; 242 212 opts->mode = option & S_IALLUGO; 243 213 break; 244 - #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES 245 214 case Opt_ptmxmode: 246 215 if (match_octal(&args[0], &option)) 247 216 return -EINVAL; 248 217 opts->ptmxmode = option & S_IALLUGO; 249 218 break; 250 219 case Opt_newinstance: 251 - /* newinstance makes sense only on initial mount */ 252 - if (op == PARSE_MOUNT) 253 - opts->newinstance = 1; 254 220 break; 255 221 case Opt_max: 256 222 if (match_int(&args[0], &option) || ··· 254 228 return -EINVAL; 255 229 opts->max = option; 256 230 break; 257 - #endif 258 231 default: 259 232 pr_err("called with bogus options\n"); 260 233 return -EINVAL; ··· 263 238 return 0; 264 239 } 265 240 266 - #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES 267 241 static int mknod_ptmx(struct super_block *sb) 268 242 { 269 243 int mode; ··· 329 305 inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode; 330 306 } 331 307 } 332 - #else 333 - static inline void update_ptmx_mode(struct pts_fs_info *fsi) 334 - { 335 - return; 336 - } 337 - #endif 338 308 339 309 static int devpts_remount(struct super_block *sb, int *flags, char *data) 340 310 { ··· 362 344 seq_printf(seq, ",gid=%u", 363 345 from_kgid_munged(&init_user_ns, opts->gid)); 364 346 seq_printf(seq, ",mode=%03o", opts->mode); 365 - #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES 366 347 seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); 367 348 if (opts->max < NR_UNIX98_PTY_MAX) 368 349 seq_printf(seq, ",max=%d", opts->max); 369 - #endif 370 350 371 351 return 0; 372 352 } ··· 426 410 return -ENOMEM; 427 411 } 428 412 429 - #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES 430 - static int compare_init_pts_sb(struct super_block *s, void *p) 431 - { 432 - if (devpts_mnt) 433 - return devpts_mnt->mnt_sb == s; 434 - return 0; 435 - } 436 - 437 413 /* 438 414 * devpts_mount() 439 415 * 440 - * If the '-o newinstance' mount option was specified, mount a new 441 - * (private) instance of devpts. PTYs created in this instance are 442 - * independent of the PTYs in other devpts instances. 443 - * 444 - * If the '-o newinstance' option was not specified, mount/remount the 445 - * initial kernel mount of devpts. This type of mount gives the 446 - * legacy, single-instance semantics. 447 - * 448 - * The 'newinstance' option is needed to support multiple namespace 449 - * semantics in devpts while preserving backward compatibility of the 450 - * current 'single-namespace' semantics. i.e all mounts of devpts 451 - * without the 'newinstance' mount option should bind to the initial 452 - * kernel mount, like mount_single(). 453 - * 454 - * Mounts with 'newinstance' option create a new, private namespace. 455 - * 456 - * NOTE: 457 - * 458 - * For single-mount semantics, devpts cannot use mount_single(), 459 - * because mount_single()/sget() find and use the super-block from 460 - * the most recent mount of devpts. But that recent mount may be a 461 - * 'newinstance' mount and mount_single() would pick the newinstance 462 - * super-block instead of the initial super-block. 416 + * Mount a new (private) instance of devpts. PTYs created in this 417 + * instance are independent of the PTYs in other devpts instances. 463 418 */ 464 419 static struct dentry *devpts_mount(struct file_system_type *fs_type, 465 420 int flags, const char *dev_name, void *data) ··· 443 456 if (error) 444 457 return ERR_PTR(error); 445 458 446 - /* Require newinstance for all user namespace mounts to ensure 447 - * the mount options are not changed. 448 - */ 449 - if ((current_user_ns() != &init_user_ns) && !opts.newinstance) 450 - return ERR_PTR(-EINVAL); 451 - 452 - if (opts.newinstance) 453 - s = sget(fs_type, NULL, set_anon_super, flags, NULL); 454 - else 455 - s = sget(fs_type, compare_init_pts_sb, set_anon_super, flags, 456 - NULL); 457 - 459 + s = sget(fs_type, NULL, set_anon_super, flags, NULL); 458 460 if (IS_ERR(s)) 459 461 return ERR_CAST(s); 460 462 ··· 467 491 return ERR_PTR(error); 468 492 } 469 493 470 - #else 471 - /* 472 - * This supports only the legacy single-instance semantics (no 473 - * multiple-instance semantics) 474 - */ 475 - static struct dentry *devpts_mount(struct file_system_type *fs_type, int flags, 476 - const char *dev_name, void *data) 477 - { 478 - return mount_single(fs_type, flags, data, devpts_fill_super); 479 - } 480 - #endif 481 - 482 494 static void devpts_kill_sb(struct super_block *sb) 483 495 { 484 496 struct pts_fs_info *fsi = DEVPTS_SB(sb); ··· 480 516 .name = "devpts", 481 517 .mount = devpts_mount, 482 518 .kill_sb = devpts_kill_sb, 483 - #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES 484 519 .fs_flags = FS_USERNS_MOUNT | FS_USERNS_DEV_MOUNT, 485 - #endif 486 520 }; 487 521 488 522 /* ··· 493 531 int index; 494 532 int ida_ret; 495 533 496 - if (!fsi) 497 - return -ENODEV; 498 - 499 534 retry: 500 535 if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL)) 501 536 return -ENOMEM; 502 537 503 538 mutex_lock(&allocated_ptys_lock); 504 - if (pty_count >= pty_limit - 505 - (fsi->mount_opts.newinstance ? pty_reserve : 0)) { 539 + if (pty_count >= (pty_limit - 540 + (fsi->mount_opts.reserve ? 0 : pty_reserve))) { 506 541 mutex_unlock(&allocated_ptys_lock); 507 542 return -ENOSPC; 508 543 } ··· 530 571 mutex_unlock(&allocated_ptys_lock); 531 572 } 532 573 533 - /* 534 - * pty code needs to hold extra references in case of last /dev/tty close 535 - */ 536 - struct pts_fs_info *devpts_get_ref(struct inode *ptmx_inode, struct file *file) 537 - { 538 - struct super_block *sb; 539 - struct pts_fs_info *fsi; 540 - 541 - sb = pts_sb_from_inode(ptmx_inode); 542 - if (!sb) 543 - return NULL; 544 - fsi = DEVPTS_SB(sb); 545 - if (!fsi) 546 - return NULL; 547 - 548 - atomic_inc(&sb->s_active); 549 - return fsi; 550 - } 551 - 552 - void devpts_put_ref(struct pts_fs_info *fsi) 553 - { 554 - deactivate_super(fsi->sb); 555 - } 556 - 557 574 /** 558 575 * devpts_pty_new -- create a new inode in /dev/pts/ 559 576 * @ptmx_inode: inode of the master ··· 542 607 struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv) 543 608 { 544 609 struct dentry *dentry; 545 - struct super_block *sb; 610 + struct super_block *sb = fsi->sb; 546 611 struct inode *inode; 547 612 struct dentry *root; 548 613 struct pts_mount_opts *opts; 549 614 char s[12]; 550 615 551 - if (!fsi) 552 - return ERR_PTR(-ENODEV); 553 - 554 - sb = fsi->sb; 555 616 root = sb->s_root; 556 617 opts = &fsi->mount_opts; 557 618 ··· 607 676 static int __init init_devpts_fs(void) 608 677 { 609 678 int err = register_filesystem(&devpts_fs_type); 610 - struct ctl_table_header *table; 611 - 612 679 if (!err) { 613 - struct vfsmount *mnt; 614 - 615 - table = register_sysctl_table(pty_root_table); 616 - mnt = kern_mount(&devpts_fs_type); 617 - if (IS_ERR(mnt)) { 618 - err = PTR_ERR(mnt); 619 - unregister_filesystem(&devpts_fs_type); 620 - unregister_sysctl_table(table); 621 - } else { 622 - devpts_mnt = mnt; 623 - } 680 + register_sysctl_table(pty_root_table); 624 681 } 625 682 return err; 626 683 }
+42 -7
fs/namei.c
··· 1416 1416 } 1417 1417 } 1418 1418 1419 + static int path_parent_directory(struct path *path) 1420 + { 1421 + struct dentry *old = path->dentry; 1422 + /* rare case of legitimate dget_parent()... */ 1423 + path->dentry = dget_parent(path->dentry); 1424 + dput(old); 1425 + if (unlikely(!path_connected(path))) 1426 + return -ENOENT; 1427 + return 0; 1428 + } 1429 + 1419 1430 static int follow_dotdot(struct nameidata *nd) 1420 1431 { 1421 1432 while(1) { 1422 - struct dentry *old = nd->path.dentry; 1423 - 1424 1433 if (nd->path.dentry == nd->root.dentry && 1425 1434 nd->path.mnt == nd->root.mnt) { 1426 1435 break; 1427 1436 } 1428 1437 if (nd->path.dentry != nd->path.mnt->mnt_root) { 1429 - /* rare case of legitimate dget_parent()... */ 1430 - nd->path.dentry = dget_parent(nd->path.dentry); 1431 - dput(old); 1432 - if (unlikely(!path_connected(&nd->path))) 1433 - return -ENOENT; 1438 + int ret = path_parent_directory(&nd->path); 1439 + if (ret) 1440 + return ret; 1434 1441 break; 1435 1442 } 1436 1443 if (!follow_up(&nd->path)) ··· 2520 2513 return lookup_hash(&this, base); 2521 2514 } 2522 2515 EXPORT_SYMBOL(lookup_one_len_unlocked); 2516 + 2517 + #ifdef CONFIG_UNIX98_PTYS 2518 + int path_pts(struct path *path) 2519 + { 2520 + /* Find something mounted on "pts" in the same directory as 2521 + * the input path. 2522 + */ 2523 + struct dentry *child, *parent; 2524 + struct qstr this; 2525 + int ret; 2526 + 2527 + ret = path_parent_directory(path); 2528 + if (ret) 2529 + return ret; 2530 + 2531 + parent = path->dentry; 2532 + this.name = "pts"; 2533 + this.len = 3; 2534 + child = d_hash_and_lookup(parent, &this); 2535 + if (!child) 2536 + return -ENOENT; 2537 + 2538 + path->dentry = child; 2539 + dput(parent); 2540 + follow_mount(path); 2541 + return 0; 2542 + } 2543 + #endif 2523 2544 2524 2545 int user_path_at_empty(int dfd, const char __user *name, unsigned flags, 2525 2546 struct path *path, int *empty)
+4 -5
include/linux/devpts_fs.h
··· 15 15 16 16 #include <linux/errno.h> 17 17 18 - struct pts_fs_info; 19 - 20 18 #ifdef CONFIG_UNIX98_PTYS 21 19 22 - /* Look up a pts fs info and get a ref to it */ 23 - struct pts_fs_info *devpts_get_ref(struct inode *, struct file *); 24 - void devpts_put_ref(struct pts_fs_info *); 20 + struct pts_fs_info; 21 + 22 + struct pts_fs_info *devpts_acquire(struct file *); 23 + void devpts_release(struct pts_fs_info *); 25 24 26 25 int devpts_new_index(struct pts_fs_info *); 27 26 void devpts_kill_index(struct pts_fs_info *, int);
+2
include/linux/namei.h
··· 45 45 #define LOOKUP_ROOT 0x2000 46 46 #define LOOKUP_EMPTY 0x4000 47 47 48 + extern int path_pts(struct path *path); 49 + 48 50 extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty); 49 51 50 52 static inline int user_path_at(int dfd, const char __user *name, unsigned flags,