inode.c 14.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* -*- linux-c -*- --------------------------------------------------------- *
 *
 * linux/fs/devpts/inode.c
 *
 *  Copyright 1998-2004 H. Peter Anvin -- All Rights Reserved
 *
 * This file is part of the Linux kernel and is made available under
 * the terms of the GNU General Public License, version 2, or at your
 * option, any later version, incorporated herein by reference.
 *
 * ------------------------------------------------------------------------- */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/namei.h>
18
#include <linux/slab.h>
L
Linus Torvalds 已提交
19 20
#include <linux/mount.h>
#include <linux/tty.h>
21
#include <linux/mutex.h>
N
Nick Black 已提交
22
#include <linux/magic.h>
23
#include <linux/idr.h>
L
Linus Torvalds 已提交
24
#include <linux/devpts_fs.h>
25
#include <linux/parser.h>
26
#include <linux/fsnotify.h>
M
Miklos Szeredi 已提交
27
#include <linux/seq_file.h>
L
Linus Torvalds 已提交
28

M
Miklos Szeredi 已提交
29
#define DEVPTS_DEFAULT_MODE 0600
S
Sukadev Bhattiprolu 已提交
30 31 32 33 34 35 36
/*
 * ptmx is a new node in /dev/pts and will be unused in legacy (single-
 * instance) mode. To prevent surprises in user space, set permissions of
 * ptmx to 0. Use 'chmod' or remount with '-o ptmxmode' to set meaningful
 * permissions.
 */
#define DEVPTS_DEFAULT_PTMX_MODE 0000
S
Sukadev Bhattiprolu 已提交
37
#define PTMX_MINOR	2
M
Miklos Szeredi 已提交
38

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
/*
 * sysctl support for setting limits on the number of Unix98 ptys allocated.
 * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
 */
static int pty_limit = NR_UNIX98_PTY_DEFAULT;
static int pty_limit_min;
static int pty_limit_max = NR_UNIX98_PTY_MAX;
static int pty_count;

static struct ctl_table pty_table[] = {
	{
		.procname	= "max",
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.data		= &pty_limit,
		.proc_handler	= proc_dointvec_minmax,
		.extra1		= &pty_limit_min,
		.extra2		= &pty_limit_max,
	}, {
		.procname	= "nr",
		.maxlen		= sizeof(int),
		.mode		= 0444,
		.data		= &pty_count,
		.proc_handler	= proc_dointvec,
	},
	{}
};

static struct ctl_table pty_kern_table[] = {
	{
		.procname	= "pty",
		.mode		= 0555,
		.child		= pty_table,
	},
	{}
};

static struct ctl_table pty_root_table[] = {
	{
		.procname	= "kernel",
		.mode		= 0555,
		.child		= pty_kern_table,
	},
	{}
};

85 86
static DEFINE_MUTEX(allocated_ptys_lock);

L
Linus Torvalds 已提交
87 88
static struct vfsmount *devpts_mnt;

S
Sukadev Bhattiprolu 已提交
89
struct pts_mount_opts {
L
Linus Torvalds 已提交
90 91 92 93 94
	int setuid;
	int setgid;
	uid_t   uid;
	gid_t   gid;
	umode_t mode;
S
Sukadev Bhattiprolu 已提交
95
	umode_t ptmxmode;
96
	int newinstance;
S
Sukadev Bhattiprolu 已提交
97
};
L
Linus Torvalds 已提交
98

99
enum {
100
	Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance,
101 102 103
	Opt_err
};

104
static const match_table_t tokens = {
105 106 107
	{Opt_uid, "uid=%u"},
	{Opt_gid, "gid=%u"},
	{Opt_mode, "mode=%o"},
S
Sukadev Bhattiprolu 已提交
108 109
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
	{Opt_ptmxmode, "ptmxmode=%o"},
110
	{Opt_newinstance, "newinstance"},
S
Sukadev Bhattiprolu 已提交
111
#endif
112 113 114
	{Opt_err, NULL}
};

S
Sukadev Bhattiprolu 已提交
115 116
struct pts_fs_info {
	struct ida allocated_ptys;
S
Sukadev Bhattiprolu 已提交
117
	struct pts_mount_opts mount_opts;
S
Sukadev Bhattiprolu 已提交
118
	struct dentry *ptmx_dentry;
S
Sukadev Bhattiprolu 已提交
119 120 121 122 123 124 125
};

static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
{
	return sb->s_fs_info;
}

S
Sukadev Bhattiprolu 已提交
126 127
static inline struct super_block *pts_sb_from_inode(struct inode *inode)
{
128
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
S
Sukadev Bhattiprolu 已提交
129 130
	if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
		return inode->i_sb;
131
#endif
S
Sukadev Bhattiprolu 已提交
132 133 134
	return devpts_mnt->mnt_sb;
}

135 136 137
#define PARSE_MOUNT	0
#define PARSE_REMOUNT	1

138 139 140 141 142 143 144 145 146
/*
 * parse_mount_options():
 * 	Set @opts to mount options specified in @data. If an option is not
 * 	specified in @data, set it to its default value. The exception is
 * 	'newinstance' option which can only be set/cleared on a mount (i.e.
 * 	cannot be changed during remount).
 *
 * Note: @data may be NULL (in which case all options are set to default).
 */
147
static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
L
Linus Torvalds 已提交
148
{
149 150
	char *p;

S
Sukadev Bhattiprolu 已提交
151 152 153 154 155
	opts->setuid  = 0;
	opts->setgid  = 0;
	opts->uid     = 0;
	opts->gid     = 0;
	opts->mode    = DEVPTS_DEFAULT_MODE;
S
Sukadev Bhattiprolu 已提交
156
	opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
157

158 159 160 161
	/* newinstance makes sense only on initial mount */
	if (op == PARSE_MOUNT)
		opts->newinstance = 0;

162 163 164 165 166 167
	while ((p = strsep(&data, ",")) != NULL) {
		substring_t args[MAX_OPT_ARGS];
		int token;
		int option;

		if (!*p)
L
Linus Torvalds 已提交
168
			continue;
169 170 171 172 173 174

		token = match_token(p, tokens, args);
		switch (token) {
		case Opt_uid:
			if (match_int(&args[0], &option))
				return -EINVAL;
S
Sukadev Bhattiprolu 已提交
175 176
			opts->uid = option;
			opts->setuid = 1;
177 178 179 180
			break;
		case Opt_gid:
			if (match_int(&args[0], &option))
				return -EINVAL;
S
Sukadev Bhattiprolu 已提交
181 182
			opts->gid = option;
			opts->setgid = 1;
183 184 185 186
			break;
		case Opt_mode:
			if (match_octal(&args[0], &option))
				return -EINVAL;
S
Sukadev Bhattiprolu 已提交
187
			opts->mode = option & S_IALLUGO;
188
			break;
S
Sukadev Bhattiprolu 已提交
189 190 191 192 193 194
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
		case Opt_ptmxmode:
			if (match_octal(&args[0], &option))
				return -EINVAL;
			opts->ptmxmode = option & S_IALLUGO;
			break;
195 196 197 198 199
		case Opt_newinstance:
			/* newinstance makes sense only on initial mount */
			if (op == PARSE_MOUNT)
				opts->newinstance = 1;
			break;
S
Sukadev Bhattiprolu 已提交
200
#endif
201 202
		default:
			printk(KERN_ERR "devpts: called with bogus options\n");
L
Linus Torvalds 已提交
203 204 205 206 207 208 209
			return -EINVAL;
		}
	}

	return 0;
}

S
Sukadev Bhattiprolu 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
static int mknod_ptmx(struct super_block *sb)
{
	int mode;
	int rc = -ENOMEM;
	struct dentry *dentry;
	struct inode *inode;
	struct dentry *root = sb->s_root;
	struct pts_fs_info *fsi = DEVPTS_SB(sb);
	struct pts_mount_opts *opts = &fsi->mount_opts;

	mutex_lock(&root->d_inode->i_mutex);

	/* If we have already created ptmx node, return */
	if (fsi->ptmx_dentry) {
		rc = 0;
		goto out;
	}

	dentry = d_alloc_name(root, "ptmx");
	if (!dentry) {
		printk(KERN_NOTICE "Unable to alloc dentry for ptmx node\n");
		goto out;
	}

	/*
	 * Create a new 'ptmx' node in this mount of devpts.
	 */
	inode = new_inode(sb);
	if (!inode) {
		printk(KERN_ERR "Unable to alloc inode for ptmx node\n");
		dput(dentry);
		goto out;
	}

	inode->i_ino = 2;
	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;

	mode = S_IFCHR|opts->ptmxmode;
	init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2));

	d_add(dentry, inode);

	fsi->ptmx_dentry = dentry;
	rc = 0;
out:
	mutex_unlock(&root->d_inode->i_mutex);
	return rc;
}

static void update_ptmx_mode(struct pts_fs_info *fsi)
{
	struct inode *inode;
	if (fsi->ptmx_dentry) {
		inode = fsi->ptmx_dentry->d_inode;
		inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode;
	}
}
#else
static inline void update_ptmx_mode(struct pts_fs_info *fsi)
{
       return;
}
#endif

275 276
static int devpts_remount(struct super_block *sb, int *flags, char *data)
{
S
Sukadev Bhattiprolu 已提交
277
	int err;
278 279 280
	struct pts_fs_info *fsi = DEVPTS_SB(sb);
	struct pts_mount_opts *opts = &fsi->mount_opts;

281
	err = parse_mount_options(data, PARSE_REMOUNT, opts);
S
Sukadev Bhattiprolu 已提交
282 283 284 285 286 287 288 289 290 291

	/*
	 * parse_mount_options() restores options to default values
	 * before parsing and may have changed ptmxmode. So, update the
	 * mode in the inode too. Bogus options don't fail the remount,
	 * so do this even on error return.
	 */
	update_ptmx_mode(fsi);

	return err;
292 293
}

294
static int devpts_show_options(struct seq_file *seq, struct dentry *root)
M
Miklos Szeredi 已提交
295
{
296
	struct pts_fs_info *fsi = DEVPTS_SB(root->d_sb);
S
Sukadev Bhattiprolu 已提交
297 298 299 300 301 302 303
	struct pts_mount_opts *opts = &fsi->mount_opts;

	if (opts->setuid)
		seq_printf(seq, ",uid=%u", opts->uid);
	if (opts->setgid)
		seq_printf(seq, ",gid=%u", opts->gid);
	seq_printf(seq, ",mode=%03o", opts->mode);
S
Sukadev Bhattiprolu 已提交
304 305 306
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
	seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
#endif
M
Miklos Szeredi 已提交
307 308 309 310

	return 0;
}

311
static const struct super_operations devpts_sops = {
L
Linus Torvalds 已提交
312 313
	.statfs		= simple_statfs,
	.remount_fs	= devpts_remount,
M
Miklos Szeredi 已提交
314
	.show_options	= devpts_show_options,
L
Linus Torvalds 已提交
315 316
};

S
Sukadev Bhattiprolu 已提交
317 318 319 320 321 322 323 324 325
static void *new_pts_fs_info(void)
{
	struct pts_fs_info *fsi;

	fsi = kzalloc(sizeof(struct pts_fs_info), GFP_KERNEL);
	if (!fsi)
		return NULL;

	ida_init(&fsi->allocated_ptys);
S
Sukadev Bhattiprolu 已提交
326
	fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
S
Sukadev Bhattiprolu 已提交
327
	fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
S
Sukadev Bhattiprolu 已提交
328 329 330 331

	return fsi;
}

L
Linus Torvalds 已提交
332 333 334
static int
devpts_fill_super(struct super_block *s, void *data, int silent)
{
S
Sukadev Bhattiprolu 已提交
335
	struct inode *inode;
L
Linus Torvalds 已提交
336 337 338 339 340 341 342

	s->s_blocksize = 1024;
	s->s_blocksize_bits = 10;
	s->s_magic = DEVPTS_SUPER_MAGIC;
	s->s_op = &devpts_sops;
	s->s_time_gran = 1;

S
Sukadev Bhattiprolu 已提交
343 344 345 346
	s->s_fs_info = new_pts_fs_info();
	if (!s->s_fs_info)
		goto fail;

L
Linus Torvalds 已提交
347 348
	inode = new_inode(s);
	if (!inode)
349
		goto fail;
L
Linus Torvalds 已提交
350 351 352 353 354
	inode->i_ino = 1;
	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
	inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
	inode->i_op = &simple_dir_inode_operations;
	inode->i_fop = &simple_dir_operations;
M
Miklos Szeredi 已提交
355
	set_nlink(inode, 2);
L
Linus Torvalds 已提交
356

S
Sukadev Bhattiprolu 已提交
357
	s->s_root = d_alloc_root(inode);
L
Linus Torvalds 已提交
358 359
	if (s->s_root)
		return 0;
S
Sukadev Bhattiprolu 已提交
360

A
Alan Cox 已提交
361
	printk(KERN_ERR "devpts: get root dentry failed\n");
L
Linus Torvalds 已提交
362
	iput(inode);
S
Sukadev Bhattiprolu 已提交
363

L
Linus Torvalds 已提交
364 365 366 367
fail:
	return -ENOMEM;
}

368
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
S
Sukadev Bhattiprolu 已提交
369 370 371 372
static int compare_init_pts_sb(struct super_block *s, void *p)
{
	if (devpts_mnt)
		return devpts_mnt->mnt_sb == s;
373 374 375 376
	return 0;
}

/*
A
Al Viro 已提交
377
 * devpts_mount()
378 379 380 381 382 383 384 385
 *
 *     If the '-o newinstance' mount option was specified, mount a new
 *     (private) instance of devpts.  PTYs created in this instance are
 *     independent of the PTYs in other devpts instances.
 *
 *     If the '-o newinstance' option was not specified, mount/remount the
 *     initial kernel mount of devpts.  This type of mount gives the
 *     legacy, single-instance semantics.
S
Sukadev Bhattiprolu 已提交
386
 *
387 388 389 390
 *     The 'newinstance' option is needed to support multiple namespace
 *     semantics in devpts while preserving backward compatibility of the
 *     current 'single-namespace' semantics. i.e all mounts of devpts
 *     without the 'newinstance' mount option should bind to the initial
A
Al Viro 已提交
391
 *     kernel mount, like mount_single().
S
Sukadev Bhattiprolu 已提交
392
 *
393
 *     Mounts with 'newinstance' option create a new, private namespace.
S
Sukadev Bhattiprolu 已提交
394
 *
395
 *     NOTE:
S
Sukadev Bhattiprolu 已提交
396
 *
A
Al Viro 已提交
397 398
 *     For single-mount semantics, devpts cannot use mount_single(),
 *     because mount_single()/sget() find and use the super-block from
S
Sukadev Bhattiprolu 已提交
399
 *     the most recent mount of devpts. But that recent mount may be a
A
Al Viro 已提交
400
 *     'newinstance' mount and mount_single() would pick the newinstance
S
Sukadev Bhattiprolu 已提交
401 402
 *     super-block instead of the initial super-block.
 */
A
Al Viro 已提交
403 404
static struct dentry *devpts_mount(struct file_system_type *fs_type,
	int flags, const char *dev_name, void *data)
L
Linus Torvalds 已提交
405
{
406 407
	int error;
	struct pts_mount_opts opts;
408
	struct super_block *s;
409

410 411
	error = parse_mount_options(data, PARSE_MOUNT, &opts);
	if (error)
A
Al Viro 已提交
412
		return ERR_PTR(error);
413

414
	if (opts.newinstance)
415
		s = sget(fs_type, NULL, set_anon_super, NULL);
416
	else
417
		s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL);
418

419
	if (IS_ERR(s))
A
Al Viro 已提交
420
		return ERR_CAST(s);
421 422 423 424 425 426 427 428 429 430

	if (!s->s_root) {
		s->s_flags = flags;
		error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
		if (error)
			goto out_undo_sget;
		s->s_flags |= MS_ACTIVE;
	}

	memcpy(&(DEVPTS_SB(s))->mount_opts, &opts, sizeof(opts));
431

432
	error = mknod_ptmx(s);
433
	if (error)
A
Al Viro 已提交
434
		goto out_undo_sget;
435

A
Al Viro 已提交
436
	return dget(s->s_root);
437 438

out_undo_sget:
439
	deactivate_locked_super(s);
A
Al Viro 已提交
440
	return ERR_PTR(error);
L
Linus Torvalds 已提交
441
}
442

443 444 445 446 447
#else
/*
 * This supports only the legacy single-instance semantics (no
 * multiple-instance semantics)
 */
A
Al Viro 已提交
448 449
static struct dentry *devpts_mount(struct file_system_type *fs_type, int flags,
		const char *dev_name, void *data)
450
{
A
Al Viro 已提交
451
	return mount_single(fs_type, flags, data, devpts_fill_super);
452 453
}
#endif
L
Linus Torvalds 已提交
454

S
Sukadev Bhattiprolu 已提交
455 456 457 458 459
static void devpts_kill_sb(struct super_block *sb)
{
	struct pts_fs_info *fsi = DEVPTS_SB(sb);

	kfree(fsi);
S
Sukadev Bhattiprolu 已提交
460
	kill_litter_super(sb);
S
Sukadev Bhattiprolu 已提交
461 462
}

L
Linus Torvalds 已提交
463 464
static struct file_system_type devpts_fs_type = {
	.name		= "devpts",
A
Al Viro 已提交
465
	.mount		= devpts_mount,
S
Sukadev Bhattiprolu 已提交
466
	.kill_sb	= devpts_kill_sb,
L
Linus Torvalds 已提交
467 468 469 470 471 472 473
};

/*
 * The normal naming convention is simply /dev/pts/<number>; this conforms
 * to the System V naming convention
 */

474
int devpts_new_index(struct inode *ptmx_inode)
475
{
S
Sukadev Bhattiprolu 已提交
476 477
	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
	struct pts_fs_info *fsi = DEVPTS_SB(sb);
478
	int index;
A
Alexey Dobriyan 已提交
479
	int ida_ret;
480 481

retry:
A
Alan Cox 已提交
482
	if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
483 484 485
		return -ENOMEM;

	mutex_lock(&allocated_ptys_lock);
S
Sukadev Bhattiprolu 已提交
486
	ida_ret = ida_get_new(&fsi->allocated_ptys, &index);
A
Alexey Dobriyan 已提交
487
	if (ida_ret < 0) {
488
		mutex_unlock(&allocated_ptys_lock);
A
Alexey Dobriyan 已提交
489
		if (ida_ret == -EAGAIN)
490 491 492 493 494
			goto retry;
		return -EIO;
	}

	if (index >= pty_limit) {
S
Sukadev Bhattiprolu 已提交
495
		ida_remove(&fsi->allocated_ptys, index);
496 497 498
		mutex_unlock(&allocated_ptys_lock);
		return -EIO;
	}
499
	pty_count++;
500 501 502 503
	mutex_unlock(&allocated_ptys_lock);
	return index;
}

504
void devpts_kill_index(struct inode *ptmx_inode, int idx)
505
{
S
Sukadev Bhattiprolu 已提交
506 507 508
	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
	struct pts_fs_info *fsi = DEVPTS_SB(sb);

509
	mutex_lock(&allocated_ptys_lock);
S
Sukadev Bhattiprolu 已提交
510
	ida_remove(&fsi->allocated_ptys, idx);
511
	pty_count--;
512 513 514
	mutex_unlock(&allocated_ptys_lock);
}

515
int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
L
Linus Torvalds 已提交
516
{
A
Alan Cox 已提交
517 518
	/* tty layer puts index from devpts_new_index() in here */
	int number = tty->index;
L
Linus Torvalds 已提交
519 520 521
	struct tty_driver *driver = tty->driver;
	dev_t device = MKDEV(driver->major, driver->minor_start+number);
	struct dentry *dentry;
S
Sukadev Bhattiprolu 已提交
522 523 524
	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
	struct inode *inode = new_inode(sb);
	struct dentry *root = sb->s_root;
S
Sukadev Bhattiprolu 已提交
525 526
	struct pts_fs_info *fsi = DEVPTS_SB(sb);
	struct pts_mount_opts *opts = &fsi->mount_opts;
527
	int ret = 0;
S
Sukadev Bhattiprolu 已提交
528
	char s[12];
L
Linus Torvalds 已提交
529 530 531 532 533 534 535 536

	/* We're supposed to be given the slave end of a pty */
	BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY);
	BUG_ON(driver->subtype != PTY_TYPE_SLAVE);

	if (!inode)
		return -ENOMEM;

537 538 539
	inode->i_ino = number + 3;
	inode->i_uid = opts->setuid ? opts->uid : current_fsuid();
	inode->i_gid = opts->setgid ? opts->gid : current_fsgid();
L
Linus Torvalds 已提交
540
	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
S
Sukadev Bhattiprolu 已提交
541
	init_special_inode(inode, S_IFCHR|opts->mode, device);
542
	inode->i_private = tty;
S
Sukadev Bhattiprolu 已提交
543
	tty->driver_data = inode;
L
Linus Torvalds 已提交
544

S
Sukadev Bhattiprolu 已提交
545 546
	sprintf(s, "%d", number);

S
Sukadev Bhattiprolu 已提交
547
	mutex_lock(&root->d_inode->i_mutex);
S
Sukadev Bhattiprolu 已提交
548

S
Sukadev Bhattiprolu 已提交
549
	dentry = d_alloc_name(root, s);
550
	if (dentry) {
S
Sukadev Bhattiprolu 已提交
551
		d_add(dentry, inode);
S
Sukadev Bhattiprolu 已提交
552
		fsnotify_create(root->d_inode, dentry);
553 554 555
	} else {
		iput(inode);
		ret = -ENOMEM;
556
	}
L
Linus Torvalds 已提交
557

S
Sukadev Bhattiprolu 已提交
558
	mutex_unlock(&root->d_inode->i_mutex);
L
Linus Torvalds 已提交
559

560
	return ret;
L
Linus Torvalds 已提交
561 562
}

563
struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
L
Linus Torvalds 已提交
564
{
565 566 567
	struct dentry *dentry;
	struct tty_struct *tty;

S
Sukadev Bhattiprolu 已提交
568
	BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
L
Linus Torvalds 已提交
569

570 571 572 573 574 575
	/* Ensure dentry has not been deleted by devpts_pty_kill() */
	dentry = d_find_alias(pts_inode);
	if (!dentry)
		return NULL;

	tty = NULL;
S
Sukadev Bhattiprolu 已提交
576
	if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
577 578 579 580 581
		tty = (struct tty_struct *)pts_inode->i_private;

	dput(dentry);

	return tty;
L
Linus Torvalds 已提交
582 583
}

584
void devpts_pty_kill(struct tty_struct *tty)
L
Linus Torvalds 已提交
585
{
S
Sukadev Bhattiprolu 已提交
586
	struct inode *inode = tty->driver_data;
S
Sukadev Bhattiprolu 已提交
587 588
	struct super_block *sb = pts_sb_from_inode(inode);
	struct dentry *root = sb->s_root;
S
Sukadev Bhattiprolu 已提交
589
	struct dentry *dentry;
L
Linus Torvalds 已提交
590

S
Sukadev Bhattiprolu 已提交
591 592
	BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));

S
Sukadev Bhattiprolu 已提交
593
	mutex_lock(&root->d_inode->i_mutex);
S
Sukadev Bhattiprolu 已提交
594 595 596

	dentry = d_find_alias(inode);

597
	drop_nlink(inode);
598 599
	d_delete(dentry);
	dput(dentry);	/* d_alloc_name() in devpts_pty_new() */
A
Alan Cox 已提交
600
	dput(dentry);		/* d_find_alias above */
601

S
Sukadev Bhattiprolu 已提交
602
	mutex_unlock(&root->d_inode->i_mutex);
L
Linus Torvalds 已提交
603 604 605 606 607
}

static int __init init_devpts_fs(void)
{
	int err = register_filesystem(&devpts_fs_type);
608 609
	struct ctl_table_header *table;

L
Linus Torvalds 已提交
610
	if (!err) {
611
		table = register_sysctl_table(pty_root_table);
L
Linus Torvalds 已提交
612
		devpts_mnt = kern_mount(&devpts_fs_type);
613
		if (IS_ERR(devpts_mnt)) {
L
Linus Torvalds 已提交
614
			err = PTR_ERR(devpts_mnt);
615
			unregister_filesystem(&devpts_fs_type);
616
			unregister_sysctl_table(table);
617
		}
L
Linus Torvalds 已提交
618 619 620 621
	}
	return err;
}
module_init(init_devpts_fs)