Blame view

fs/devpts/inode.c 13.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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>
5a0e3ad6a   Tejun Heo   include cleanup: ...
18
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  #include <linux/mount.h>
  #include <linux/tty.h>
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
21
  #include <linux/mutex.h>
1fd7317d0   Nick Black   Move magic number...
22
  #include <linux/magic.h>
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
23
  #include <linux/idr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include <linux/devpts_fs.h>
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
25
  #include <linux/parser.h>
3972b7f67   Florin Malita   devpts: add fsnot...
26
  #include <linux/fsnotify.h>
b87a267eb   Miklos Szeredi   mount options: fi...
27
  #include <linux/seq_file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28

b87a267eb   Miklos Szeredi   mount options: fi...
29
  #define DEVPTS_DEFAULT_MODE 0600
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
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
527b3e477   Sukadev Bhattiprolu   Simplify devpts_g...
37
  #define PTMX_MINOR	2
b87a267eb   Miklos Szeredi   mount options: fi...
38

718a91633   Sukadev Bhattiprolu   devpts: factor ou...
39
  extern int pty_limit;			/* Config limit on Unix98 ptys */
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
40
  static DEFINE_MUTEX(allocated_ptys_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  static struct vfsmount *devpts_mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

31af0abbd   Sukadev Bhattiprolu   Per-mount 'config...
43
  struct pts_mount_opts {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
  	int setuid;
  	int setgid;
  	uid_t   uid;
  	gid_t   gid;
  	umode_t mode;
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
49
  	umode_t ptmxmode;
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
50
  	int newinstance;
31af0abbd   Sukadev Bhattiprolu   Per-mount 'config...
51
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

7a673c6b8   Domen Puncer   [PATCH] devpts: u...
53
  enum {
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
54
  	Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance,
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
55
56
  	Opt_err
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
57
  static const match_table_t tokens = {
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
58
59
60
  	{Opt_uid, "uid=%u"},
  	{Opt_gid, "gid=%u"},
  	{Opt_mode, "mode=%o"},
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
61
62
  #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
  	{Opt_ptmxmode, "ptmxmode=%o"},
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
63
  	{Opt_newinstance, "newinstance"},
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
64
  #endif
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
65
66
  	{Opt_err, NULL}
  };
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
67
68
  struct pts_fs_info {
  	struct ida allocated_ptys;
31af0abbd   Sukadev Bhattiprolu   Per-mount 'config...
69
  	struct pts_mount_opts mount_opts;
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
70
  	struct dentry *ptmx_dentry;
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
71
72
73
74
75
76
  };
  
  static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
  {
  	return sb->s_fs_info;
  }
59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
77
78
  static inline struct super_block *pts_sb_from_inode(struct inode *inode)
  {
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
79
  #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
80
81
  	if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
  		return inode->i_sb;
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
82
  #endif
59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
83
84
  	return devpts_mnt->mnt_sb;
  }
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
85
86
  #define PARSE_MOUNT	0
  #define PARSE_REMOUNT	1
1f71ebedb   Sukadev Bhattiprolu   devpts: correctly...
87
88
89
90
91
92
93
94
95
  /*
   * 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).
   */
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
96
  static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  {
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
98
  	char *p;
31af0abbd   Sukadev Bhattiprolu   Per-mount 'config...
99
100
101
102
103
  	opts->setuid  = 0;
  	opts->setgid  = 0;
  	opts->uid     = 0;
  	opts->gid     = 0;
  	opts->mode    = DEVPTS_DEFAULT_MODE;
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
104
  	opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
105

2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
106
107
108
  	/* newinstance makes sense only on initial mount */
  	if (op == PARSE_MOUNT)
  		opts->newinstance = 0;
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
109
110
111
112
113
114
  	while ((p = strsep(&data, ",")) != NULL) {
  		substring_t args[MAX_OPT_ARGS];
  		int token;
  		int option;
  
  		if (!*p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  			continue;
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
116
117
118
119
120
121
  
  		token = match_token(p, tokens, args);
  		switch (token) {
  		case Opt_uid:
  			if (match_int(&args[0], &option))
  				return -EINVAL;
31af0abbd   Sukadev Bhattiprolu   Per-mount 'config...
122
123
  			opts->uid = option;
  			opts->setuid = 1;
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
124
125
126
127
  			break;
  		case Opt_gid:
  			if (match_int(&args[0], &option))
  				return -EINVAL;
31af0abbd   Sukadev Bhattiprolu   Per-mount 'config...
128
129
  			opts->gid = option;
  			opts->setgid = 1;
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
130
131
132
133
  			break;
  		case Opt_mode:
  			if (match_octal(&args[0], &option))
  				return -EINVAL;
31af0abbd   Sukadev Bhattiprolu   Per-mount 'config...
134
  			opts->mode = option & S_IALLUGO;
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
135
  			break;
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
136
137
138
139
140
141
  #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
  		case Opt_ptmxmode:
  			if (match_octal(&args[0], &option))
  				return -EINVAL;
  			opts->ptmxmode = option & S_IALLUGO;
  			break;
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
142
143
144
145
146
  		case Opt_newinstance:
  			/* newinstance makes sense only on initial mount */
  			if (op == PARSE_MOUNT)
  				opts->newinstance = 1;
  			break;
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
147
  #endif
7a673c6b8   Domen Puncer   [PATCH] devpts: u...
148
149
150
  		default:
  			printk(KERN_ERR "devpts: called with bogus options
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
  			return -EINVAL;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
  
  	return 0;
  }
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  #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
  ");
  		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
  ");
  		dput(dentry);
  		goto out;
  	}
  
  	inode->i_ino = 2;
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
195
196
197
198
199
200
201
202
203
  	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;
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  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
53af8ee40   Sukadev Bhattiprolu   Extract option pa...
223
224
  static int devpts_remount(struct super_block *sb, int *flags, char *data)
  {
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
225
  	int err;
53af8ee40   Sukadev Bhattiprolu   Extract option pa...
226
227
  	struct pts_fs_info *fsi = DEVPTS_SB(sb);
  	struct pts_mount_opts *opts = &fsi->mount_opts;
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
228
  	err = parse_mount_options(data, PARSE_REMOUNT, opts);
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
229
230
231
232
233
234
235
236
237
238
  
  	/*
  	 * 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;
53af8ee40   Sukadev Bhattiprolu   Extract option pa...
239
  }
34c80b1d9   Al Viro   vfs: switch ->sho...
240
  static int devpts_show_options(struct seq_file *seq, struct dentry *root)
b87a267eb   Miklos Szeredi   mount options: fi...
241
  {
34c80b1d9   Al Viro   vfs: switch ->sho...
242
  	struct pts_fs_info *fsi = DEVPTS_SB(root->d_sb);
31af0abbd   Sukadev Bhattiprolu   Per-mount 'config...
243
244
245
246
247
248
249
  	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);
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
250
251
252
  #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
  	seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
  #endif
b87a267eb   Miklos Szeredi   mount options: fi...
253
254
255
  
  	return 0;
  }
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
256
  static const struct super_operations devpts_sops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
  	.statfs		= simple_statfs,
  	.remount_fs	= devpts_remount,
b87a267eb   Miklos Szeredi   mount options: fi...
259
  	.show_options	= devpts_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
  };
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
261
262
263
264
265
266
267
268
269
  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);
31af0abbd   Sukadev Bhattiprolu   Per-mount 'config...
270
  	fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
271
  	fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
272
273
274
  
  	return fsi;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
277
  static int
  devpts_fill_super(struct super_block *s, void *data, int silent)
  {
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
278
  	struct inode *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
283
  
  	s->s_blocksize = 1024;
  	s->s_blocksize_bits = 10;
  	s->s_magic = DEVPTS_SUPER_MAGIC;
  	s->s_op = &devpts_sops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  	s->s_time_gran = 1;
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
285
286
287
  	s->s_fs_info = new_pts_fs_info();
  	if (!s->s_fs_info)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
  	inode = new_inode(s);
  	if (!inode)
3850aba74   Al Viro   devpts: fix doubl...
290
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
  	inode->i_ino = 1;
  	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
  	inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
  	inode->i_op = &simple_dir_inode_operations;
  	inode->i_fop = &simple_dir_operations;
bfe868486   Miklos Szeredi   filesystems: add ...
296
  	set_nlink(inode, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297

59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
298
  	s->s_root = d_alloc_root(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
  	if (s->s_root)
  		return 0;
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
301

835aa440f   Alan Cox   devpts: Coding st...
302
303
  	printk(KERN_ERR "devpts: get root dentry failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  	iput(inode);
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
305

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
  fail:
  	return -ENOMEM;
  }
8c056e5b1   Andrew Morton   devpts: fix unuse...
309
  #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
d4076ac55   Sukadev Bhattiprolu   Define get_init_p...
310
311
312
313
  static int compare_init_pts_sb(struct super_block *s, void *p)
  {
  	if (devpts_mnt)
  		return devpts_mnt->mnt_sb == s;
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
314
315
  	return 0;
  }
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
316
  /*
fc14f2fef   Al Viro   convert get_sb_si...
317
   * devpts_mount()
1bd790356   Sukadev Bhattiprolu   Merge code for si...
318
319
320
321
322
323
324
325
   *
   *     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.
289f00e22   Sukadev Bhattiprolu   Remove get_init_p...
326
   *
1bd790356   Sukadev Bhattiprolu   Merge code for si...
327
328
329
330
   *     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
fc14f2fef   Al Viro   convert get_sb_si...
331
   *     kernel mount, like mount_single().
d4076ac55   Sukadev Bhattiprolu   Define get_init_p...
332
   *
1bd790356   Sukadev Bhattiprolu   Merge code for si...
333
   *     Mounts with 'newinstance' option create a new, private namespace.
d4076ac55   Sukadev Bhattiprolu   Define get_init_p...
334
   *
1bd790356   Sukadev Bhattiprolu   Merge code for si...
335
   *     NOTE:
d4076ac55   Sukadev Bhattiprolu   Define get_init_p...
336
   *
fc14f2fef   Al Viro   convert get_sb_si...
337
338
   *     For single-mount semantics, devpts cannot use mount_single(),
   *     because mount_single()/sget() find and use the super-block from
d4076ac55   Sukadev Bhattiprolu   Define get_init_p...
339
   *     the most recent mount of devpts. But that recent mount may be a
fc14f2fef   Al Viro   convert get_sb_si...
340
   *     'newinstance' mount and mount_single() would pick the newinstance
d4076ac55   Sukadev Bhattiprolu   Define get_init_p...
341
   *     super-block instead of the initial super-block.
d4076ac55   Sukadev Bhattiprolu   Define get_init_p...
342
   */
fc14f2fef   Al Viro   convert get_sb_si...
343
344
  static struct dentry *devpts_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  {
482984f06   Sukadev Bhattiprolu   Parse mount optio...
346
347
  	int error;
  	struct pts_mount_opts opts;
1bd790356   Sukadev Bhattiprolu   Merge code for si...
348
  	struct super_block *s;
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
349

1f71ebedb   Sukadev Bhattiprolu   devpts: correctly...
350
351
  	error = parse_mount_options(data, PARSE_MOUNT, &opts);
  	if (error)
fc14f2fef   Al Viro   convert get_sb_si...
352
  		return ERR_PTR(error);
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
353

482984f06   Sukadev Bhattiprolu   Parse mount optio...
354
  	if (opts.newinstance)
1bd790356   Sukadev Bhattiprolu   Merge code for si...
355
  		s = sget(fs_type, NULL, set_anon_super, NULL);
482984f06   Sukadev Bhattiprolu   Parse mount optio...
356
  	else
1bd790356   Sukadev Bhattiprolu   Merge code for si...
357
  		s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL);
945cf2c79   Sukadev Bhattiprolu   Move common mknod...
358

1bd790356   Sukadev Bhattiprolu   Merge code for si...
359
  	if (IS_ERR(s))
fc14f2fef   Al Viro   convert get_sb_si...
360
  		return ERR_CAST(s);
1bd790356   Sukadev Bhattiprolu   Merge code for si...
361
362
363
364
365
366
367
368
  
  	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;
  	}
1bd790356   Sukadev Bhattiprolu   Merge code for si...
369
  	memcpy(&(DEVPTS_SB(s))->mount_opts, &opts, sizeof(opts));
945cf2c79   Sukadev Bhattiprolu   Move common mknod...
370

1bd790356   Sukadev Bhattiprolu   Merge code for si...
371
  	error = mknod_ptmx(s);
945cf2c79   Sukadev Bhattiprolu   Move common mknod...
372
  	if (error)
894680710   Al Viro   Simplify devpts_g...
373
  		goto out_undo_sget;
945cf2c79   Sukadev Bhattiprolu   Move common mknod...
374

fc14f2fef   Al Viro   convert get_sb_si...
375
  	return dget(s->s_root);
1bd790356   Sukadev Bhattiprolu   Merge code for si...
376
377
  
  out_undo_sget:
6f5bbff9a   Al Viro   Convert obvious p...
378
  	deactivate_locked_super(s);
fc14f2fef   Al Viro   convert get_sb_si...
379
  	return ERR_PTR(error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  }
482984f06   Sukadev Bhattiprolu   Parse mount optio...
381

2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
382
383
384
385
386
  #else
  /*
   * This supports only the legacy single-instance semantics (no
   * multiple-instance semantics)
   */
fc14f2fef   Al Viro   convert get_sb_si...
387
388
  static struct dentry *devpts_mount(struct file_system_type *fs_type, int flags,
  		const char *dev_name, void *data)
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
389
  {
fc14f2fef   Al Viro   convert get_sb_si...
390
  	return mount_single(fs_type, flags, data, devpts_fill_super);
2a1b2dc0c   Sukadev Bhattiprolu   Enable multiple i...
391
392
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393

e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
394
395
396
397
398
  static void devpts_kill_sb(struct super_block *sb)
  {
  	struct pts_fs_info *fsi = DEVPTS_SB(sb);
  
  	kfree(fsi);
1f8f1e296   Sukadev Bhattiprolu   Define mknod_ptmx()
399
  	kill_litter_super(sb);
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
400
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  static struct file_system_type devpts_fs_type = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  	.name		= "devpts",
fc14f2fef   Al Viro   convert get_sb_si...
403
  	.mount		= devpts_mount,
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
404
  	.kill_sb	= devpts_kill_sb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
407
408
409
410
  };
  
  /*
   * The normal naming convention is simply /dev/pts/<number>; this conforms
   * to the System V naming convention
   */
15f1a6338   Sukadev Bhattiprolu   Add an instance p...
411
  int devpts_new_index(struct inode *ptmx_inode)
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
412
  {
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
413
414
  	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
  	struct pts_fs_info *fsi = DEVPTS_SB(sb);
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
415
  	int index;
7ee7c12b7   Alexey Dobriyan   [PATCH] devpts: s...
416
  	int ida_ret;
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
417
418
  
  retry:
835aa440f   Alan Cox   devpts: Coding st...
419
  	if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
420
  		return -ENOMEM;
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
421
422
  
  	mutex_lock(&allocated_ptys_lock);
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
423
  	ida_ret = ida_get_new(&fsi->allocated_ptys, &index);
7ee7c12b7   Alexey Dobriyan   [PATCH] devpts: s...
424
  	if (ida_ret < 0) {
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
425
  		mutex_unlock(&allocated_ptys_lock);
7ee7c12b7   Alexey Dobriyan   [PATCH] devpts: s...
426
  		if (ida_ret == -EAGAIN)
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
427
428
429
430
431
  			goto retry;
  		return -EIO;
  	}
  
  	if (index >= pty_limit) {
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
432
  		ida_remove(&fsi->allocated_ptys, index);
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
433
434
435
436
437
438
  		mutex_unlock(&allocated_ptys_lock);
  		return -EIO;
  	}
  	mutex_unlock(&allocated_ptys_lock);
  	return index;
  }
15f1a6338   Sukadev Bhattiprolu   Add an instance p...
439
  void devpts_kill_index(struct inode *ptmx_inode, int idx)
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
440
  {
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
441
442
  	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
  	struct pts_fs_info *fsi = DEVPTS_SB(sb);
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
443
  	mutex_lock(&allocated_ptys_lock);
e76b7c01e   Sukadev Bhattiprolu   Per-mount allocat...
444
  	ida_remove(&fsi->allocated_ptys, idx);
718a91633   Sukadev Bhattiprolu   devpts: factor ou...
445
446
  	mutex_unlock(&allocated_ptys_lock);
  }
15f1a6338   Sukadev Bhattiprolu   Add an instance p...
447
  int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  {
835aa440f   Alan Cox   devpts: Coding st...
449
450
  	/* tty layer puts index from devpts_new_index() in here */
  	int number = tty->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
  	struct tty_driver *driver = tty->driver;
  	dev_t device = MKDEV(driver->major, driver->minor_start+number);
  	struct dentry *dentry;
59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
454
455
456
  	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
  	struct inode *inode = new_inode(sb);
  	struct dentry *root = sb->s_root;
31af0abbd   Sukadev Bhattiprolu   Per-mount 'config...
457
458
  	struct pts_fs_info *fsi = DEVPTS_SB(sb);
  	struct pts_mount_opts *opts = &fsi->mount_opts;
aa597bc1f   Andrey Vagin   fs: devpts_pty_ne...
459
  	int ret = 0;
89a52e109   Sukadev Bhattiprolu   Simplify devpts_p...
460
  	char s[12];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
467
  
  	/* 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;
d0eafc7db   David Howells   CRED: Wrap task c...
468
469
470
  	inode->i_ino = number + 3;
  	inode->i_uid = opts->setuid ? opts->uid : current_fsuid();
  	inode->i_gid = opts->setgid ? opts->gid : current_fsgid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
31af0abbd   Sukadev Bhattiprolu   Per-mount 'config...
472
  	init_special_inode(inode, S_IFCHR|opts->mode, device);
8e18e2941   Theodore Ts'o   [PATCH] inode_die...
473
  	inode->i_private = tty;
a6f37daa8   Sukadev Bhattiprolu   Simplify devpts_p...
474
  	tty->driver_data = inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475

89a52e109   Sukadev Bhattiprolu   Simplify devpts_p...
476
  	sprintf(s, "%d", number);
59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
477
  	mutex_lock(&root->d_inode->i_mutex);
89a52e109   Sukadev Bhattiprolu   Simplify devpts_p...
478

59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
479
  	dentry = d_alloc_name(root, s);
b12d12596   Andrey Vagin   fs/devpts/inode.c...
480
  	if (dentry) {
89a52e109   Sukadev Bhattiprolu   Simplify devpts_p...
481
  		d_add(dentry, inode);
59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
482
  		fsnotify_create(root->d_inode, dentry);
aa597bc1f   Andrey Vagin   fs: devpts_pty_ne...
483
484
485
  	} else {
  		iput(inode);
  		ret = -ENOMEM;
3972b7f67   Florin Malita   devpts: add fsnot...
486
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487

59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
488
  	mutex_unlock(&root->d_inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489

aa597bc1f   Andrey Vagin   fs: devpts_pty_ne...
490
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  }
15f1a6338   Sukadev Bhattiprolu   Add an instance p...
492
  struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
  {
edfacdd6f   Sukadev Bhattiprolu   devpts_get_tty() ...
494
495
  	struct dentry *dentry;
  	struct tty_struct *tty;
527b3e477   Sukadev Bhattiprolu   Simplify devpts_g...
496
  	BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497

edfacdd6f   Sukadev Bhattiprolu   devpts_get_tty() ...
498
499
500
501
502
503
  	/* Ensure dentry has not been deleted by devpts_pty_kill() */
  	dentry = d_find_alias(pts_inode);
  	if (!dentry)
  		return NULL;
  
  	tty = NULL;
527b3e477   Sukadev Bhattiprolu   Simplify devpts_g...
504
  	if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
edfacdd6f   Sukadev Bhattiprolu   devpts_get_tty() ...
505
506
507
508
509
  		tty = (struct tty_struct *)pts_inode->i_private;
  
  	dput(dentry);
  
  	return tty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
  }
15f1a6338   Sukadev Bhattiprolu   Add an instance p...
511
  void devpts_pty_kill(struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  {
a6f37daa8   Sukadev Bhattiprolu   Simplify devpts_p...
513
  	struct inode *inode = tty->driver_data;
59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
514
515
  	struct super_block *sb = pts_sb_from_inode(inode);
  	struct dentry *root = sb->s_root;
a6f37daa8   Sukadev Bhattiprolu   Simplify devpts_p...
516
  	struct dentry *dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517

a6f37daa8   Sukadev Bhattiprolu   Simplify devpts_p...
518
  	BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
519
  	mutex_lock(&root->d_inode->i_mutex);
a6f37daa8   Sukadev Bhattiprolu   Simplify devpts_p...
520
521
  
  	dentry = d_find_alias(inode);
a6f37daa8   Sukadev Bhattiprolu   Simplify devpts_p...
522

6d6b77f16   Miklos Szeredi   filesystems: add ...
523
  	drop_nlink(inode);
aa597bc1f   Andrey Vagin   fs: devpts_pty_ne...
524
525
  	d_delete(dentry);
  	dput(dentry);	/* d_alloc_name() in devpts_pty_new() */
835aa440f   Alan Cox   devpts: Coding st...
526
  	dput(dentry);		/* d_find_alias above */
aa597bc1f   Andrey Vagin   fs: devpts_pty_ne...
527

59e55e6cf   Sukadev Bhattiprolu   Remove devpts_roo...
528
  	mutex_unlock(&root->d_inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
532
533
534
535
  }
  
  static int __init init_devpts_fs(void)
  {
  	int err = register_filesystem(&devpts_fs_type);
  	if (!err) {
  		devpts_mnt = kern_mount(&devpts_fs_type);
93d5581e2   Alan Cox   devpts: unregiste...
536
  		if (IS_ERR(devpts_mnt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  			err = PTR_ERR(devpts_mnt);
93d5581e2   Alan Cox   devpts: unregiste...
538
539
  			unregister_filesystem(&devpts_fs_type);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
  	}
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  module_init(init_devpts_fs)