Diff markup
1 /* -*- linux-c -*- --------------------------- 1 /* -*- linux-c -*- --------------------------------------------------------- *
2 * 2 *
3 * linux/fs/devpts/inode.c 3 * linux/fs/devpts/inode.c
4 * 4 *
5 * Copyright 1998-2004 H. Peter Anvin -- All 5 * Copyright 1998-2004 H. Peter Anvin -- All Rights Reserved
6 * 6 *
7 * This file is part of the Linux kernel and i 7 * This file is part of the Linux kernel and is made available under
8 * the terms of the GNU General Public License 8 * the terms of the GNU General Public License, version 2, or at your
9 * option, any later version, incorporated her 9 * option, any later version, incorporated herein by reference.
10 * 10 *
11 * ------------------------------------------- 11 * ------------------------------------------------------------------------- */
12 12
13 #include <linux/module.h> 13 #include <linux/module.h>
14 #include <linux/init.h> 14 #include <linux/init.h>
15 #include <linux/fs.h> 15 #include <linux/fs.h>
16 #include <linux/sched.h> 16 #include <linux/sched.h>
17 #include <linux/namei.h> 17 #include <linux/namei.h>
18 #include <linux/mount.h> 18 #include <linux/mount.h>
19 #include <linux/tty.h> 19 #include <linux/tty.h>
20 #include <linux/mutex.h> <<
21 #include <linux/idr.h> <<
22 #include <linux/devpts_fs.h> 20 #include <linux/devpts_fs.h>
23 #include <linux/parser.h> !! 21 #include <linux/xattr.h>
24 #include <linux/fsnotify.h> <<
25 #include <linux/seq_file.h> <<
26 22
27 #define DEVPTS_SUPER_MAGIC 0x1cd1 23 #define DEVPTS_SUPER_MAGIC 0x1cd1
28 24
29 #define DEVPTS_DEFAULT_MODE 0600 !! 25 extern struct xattr_handler devpts_xattr_security_handler;
30 /* <<
31 * ptmx is a new node in /dev/pts and will be <<
32 * instance) mode. To prevent surprises in use <<
33 * ptmx to 0. Use 'chmod' or remount with '-o <<
34 * permissions. <<
35 */ <<
36 #define DEVPTS_DEFAULT_PTMX_MODE 0000 <<
37 #define PTMX_MINOR 2 <<
38 26
39 extern int pty_limit; /* Con !! 27 static struct xattr_handler *devpts_xattr_handlers[] = {
40 static DEFINE_MUTEX(allocated_ptys_lock); !! 28 #ifdef CONFIG_DEVPTS_FS_SECURITY
>> 29 &devpts_xattr_security_handler,
>> 30 #endif
>> 31 NULL
>> 32 };
>> 33
>> 34 static struct inode_operations devpts_file_inode_operations = {
>> 35 #ifdef CONFIG_DEVPTS_FS_XATTR
>> 36 .setxattr = generic_setxattr,
>> 37 .getxattr = generic_getxattr,
>> 38 .listxattr = generic_listxattr,
>> 39 .removexattr = generic_removexattr,
>> 40 #endif
>> 41 };
41 42
42 static struct vfsmount *devpts_mnt; 43 static struct vfsmount *devpts_mnt;
>> 44 static struct dentry *devpts_root;
43 45
44 struct pts_mount_opts { !! 46 static struct {
45 int setuid; 47 int setuid;
46 int setgid; 48 int setgid;
47 uid_t uid; 49 uid_t uid;
48 gid_t gid; 50 gid_t gid;
49 umode_t mode; 51 umode_t mode;
50 umode_t ptmxmode; !! 52 } config = {.mode = 0600};
51 int newinstance; <<
52 }; <<
53 <<
54 enum { <<
55 Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmo <<
56 Opt_err <<
57 }; <<
58 <<
59 static const match_table_t tokens = { <<
60 {Opt_uid, "uid=%u"}, <<
61 {Opt_gid, "gid=%u"}, <<
62 {Opt_mode, "mode=%o"}, <<
63 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES <<
64 {Opt_ptmxmode, "ptmxmode=%o"}, <<
65 {Opt_newinstance, "newinstance"}, <<
66 #endif <<
67 {Opt_err, NULL} <<
68 }; <<
69 <<
70 struct pts_fs_info { <<
71 struct ida allocated_ptys; <<
72 struct pts_mount_opts mount_opts; <<
73 struct dentry *ptmx_dentry; <<
74 }; <<
75 <<
76 static inline struct pts_fs_info *DEVPTS_SB(st <<
77 { <<
78 return sb->s_fs_info; <<
79 } <<
80 <<
81 static inline struct super_block *pts_sb_from_ <<
82 { <<
83 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES <<
84 if (inode->i_sb->s_magic == DEVPTS_SUP <<
85 return inode->i_sb; <<
86 #endif <<
87 return devpts_mnt->mnt_sb; <<
88 } <<
89 53
90 #define PARSE_MOUNT 0 !! 54 static int devpts_remount(struct super_block *sb, int *flags, char *data)
91 #define PARSE_REMOUNT 1 <<
92 <<
93 /* <<
94 * parse_mount_options(): <<
95 * Set @opts to mount options specified i <<
96 * specified in @data, set it to its defa <<
97 * 'newinstance' option which can only be <<
98 * cannot be changed during remount). <<
99 * <<
100 * Note: @data may be NULL (in which case all <<
101 */ <<
102 static int parse_mount_options(char *data, int <<
103 { 55 {
104 char *p; !! 56 int setuid = 0;
105 !! 57 int setgid = 0;
106 opts->setuid = 0; !! 58 uid_t uid = 0;
107 opts->setgid = 0; !! 59 gid_t gid = 0;
108 opts->uid = 0; !! 60 umode_t mode = 0600;
109 opts->gid = 0; !! 61 char *this_char;
110 opts->mode = DEVPTS_DEFAULT_MODE; !! 62
111 opts->ptmxmode = DEVPTS_DEFAULT_PTMX_M !! 63 this_char = NULL;
112 !! 64 while ((this_char = strsep(&data, ",")) != NULL) {
113 /* newinstance makes sense only on ini !! 65 int n;
114 if (op == PARSE_MOUNT) !! 66 char dummy;
115 opts->newinstance = 0; !! 67 if (!*this_char)
116 <<
117 while ((p = strsep(&data, ",")) != NUL <<
118 substring_t args[MAX_OPT_ARGS] <<
119 int token; <<
120 int option; <<
121 <<
122 if (!*p) <<
123 continue; 68 continue;
124 !! 69 if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) {
125 token = match_token(p, tokens, !! 70 setuid = 1;
126 switch (token) { !! 71 uid = n;
127 case Opt_uid: !! 72 } else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) {
128 if (match_int(&args[0] !! 73 setgid = 1;
129 return -EINVAL !! 74 gid = n;
130 opts->uid = option; !! 75 } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1)
131 opts->setuid = 1; !! 76 mode = n & ~S_IFMT;
132 break; !! 77 else {
133 case Opt_gid: !! 78 printk("devpts: called with bogus options\n");
134 if (match_int(&args[0] <<
135 return -EINVAL <<
136 opts->gid = option; <<
137 opts->setgid = 1; <<
138 break; <<
139 case Opt_mode: <<
140 if (match_octal(&args[ <<
141 return -EINVAL <<
142 opts->mode = option & <<
143 break; <<
144 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES <<
145 case Opt_ptmxmode: <<
146 if (match_octal(&args[ <<
147 return -EINVAL <<
148 opts->ptmxmode = optio <<
149 break; <<
150 case Opt_newinstance: <<
151 /* newinstance makes s <<
152 if (op == PARSE_MOUNT) <<
153 opts->newinsta <<
154 break; <<
155 #endif <<
156 default: <<
157 printk(KERN_ERR "devpt <<
158 return -EINVAL; 79 return -EINVAL;
159 } 80 }
160 } 81 }
>> 82 config.setuid = setuid;
>> 83 config.setgid = setgid;
>> 84 config.uid = uid;
>> 85 config.gid = gid;
>> 86 config.mode = mode;
161 87
162 return 0; 88 return 0;
163 } 89 }
164 90
165 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES !! 91 static struct super_operations devpts_sops = {
166 static int mknod_ptmx(struct super_block *sb) <<
167 { <<
168 int mode; <<
169 int rc = -ENOMEM; <<
170 struct dentry *dentry; <<
171 struct inode *inode; <<
172 struct dentry *root = sb->s_root; <<
173 struct pts_fs_info *fsi = DEVPTS_SB(sb <<
174 struct pts_mount_opts *opts = &fsi->mo <<
175 <<
176 mutex_lock(&root->d_inode->i_mutex); <<
177 <<
178 /* If we have already created ptmx nod <<
179 if (fsi->ptmx_dentry) { <<
180 rc = 0; <<
181 goto out; <<
182 } <<
183 <<
184 dentry = d_alloc_name(root, "ptmx"); <<
185 if (!dentry) { <<
186 printk(KERN_NOTICE "Unable to <<
187 goto out; <<
188 } <<
189 <<
190 /* <<
191 * Create a new 'ptmx' node in this mo <<
192 */ <<
193 inode = new_inode(sb); <<
194 if (!inode) { <<
195 printk(KERN_ERR "Unable to all <<
196 dput(dentry); <<
197 goto out; <<
198 } <<
199 <<
200 inode->i_ino = 2; <<
201 inode->i_mtime = inode->i_atime = inod <<
202 <<
203 mode = S_IFCHR|opts->ptmxmode; <<
204 init_special_inode(inode, mode, MKDEV( <<
205 <<
206 d_add(dentry, inode); <<
207 <<
208 fsi->ptmx_dentry = dentry; <<
209 rc = 0; <<
210 out: <<
211 mutex_unlock(&root->d_inode->i_mutex); <<
212 return rc; <<
213 } <<
214 <<
215 static void update_ptmx_mode(struct pts_fs_inf <<
216 { <<
217 struct inode *inode; <<
218 if (fsi->ptmx_dentry) { <<
219 inode = fsi->ptmx_dentry->d_in <<
220 inode->i_mode = S_IFCHR|fsi->m <<
221 } <<
222 } <<
223 #else <<
224 static inline void update_ptmx_mode(struct pts <<
225 { <<
226 return; <<
227 } <<
228 #endif <<
229 <<
230 static int devpts_remount(struct super_block * <<
231 { <<
232 int err; <<
233 struct pts_fs_info *fsi = DEVPTS_SB(sb <<
234 struct pts_mount_opts *opts = &fsi->mo <<
235 <<
236 err = parse_mount_options(data, PARSE_ <<
237 <<
238 /* <<
239 * parse_mount_options() restores opti <<
240 * before parsing and may have changed <<
241 * mode in the inode too. Bogus option <<
242 * so do this even on error return. <<
243 */ <<
244 update_ptmx_mode(fsi); <<
245 <<
246 return err; <<
247 } <<
248 <<
249 static int devpts_show_options(struct seq_file <<
250 { <<
251 struct pts_fs_info *fsi = DEVPTS_SB(vf <<
252 struct pts_mount_opts *opts = &fsi->mo <<
253 <<
254 if (opts->setuid) <<
255 seq_printf(seq, ",uid=%u", opt <<
256 if (opts->setgid) <<
257 seq_printf(seq, ",gid=%u", opt <<
258 seq_printf(seq, ",mode=%03o", opts->mo <<
259 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES <<
260 seq_printf(seq, ",ptmxmode=%03o", opts <<
261 #endif <<
262 <<
263 return 0; <<
264 } <<
265 <<
266 static const struct super_operations devpts_so <<
267 .statfs = simple_statfs, 92 .statfs = simple_statfs,
268 .remount_fs = devpts_remount, 93 .remount_fs = devpts_remount,
269 .show_options = devpts_show_options, <<
270 }; 94 };
271 95
272 static void *new_pts_fs_info(void) <<
273 { <<
274 struct pts_fs_info *fsi; <<
275 <<
276 fsi = kzalloc(sizeof(struct pts_fs_inf <<
277 if (!fsi) <<
278 return NULL; <<
279 <<
280 ida_init(&fsi->allocated_ptys); <<
281 fsi->mount_opts.mode = DEVPTS_DEFAULT_ <<
282 fsi->mount_opts.ptmxmode = DEVPTS_DEFA <<
283 <<
284 return fsi; <<
285 } <<
286 <<
287 static int 96 static int
288 devpts_fill_super(struct super_block *s, void 97 devpts_fill_super(struct super_block *s, void *data, int silent)
289 { 98 {
290 struct inode *inode; !! 99 struct inode * inode;
291 100
292 s->s_blocksize = 1024; 101 s->s_blocksize = 1024;
293 s->s_blocksize_bits = 10; 102 s->s_blocksize_bits = 10;
294 s->s_magic = DEVPTS_SUPER_MAGIC; 103 s->s_magic = DEVPTS_SUPER_MAGIC;
295 s->s_op = &devpts_sops; 104 s->s_op = &devpts_sops;
>> 105 s->s_xattr = devpts_xattr_handlers;
296 s->s_time_gran = 1; 106 s->s_time_gran = 1;
297 107
298 s->s_fs_info = new_pts_fs_info(); <<
299 if (!s->s_fs_info) <<
300 goto fail; <<
301 <<
302 inode = new_inode(s); 108 inode = new_inode(s);
303 if (!inode) 109 if (!inode)
304 goto free_fsi; !! 110 goto fail;
305 inode->i_ino = 1; 111 inode->i_ino = 1;
306 inode->i_mtime = inode->i_atime = inod 112 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
>> 113 inode->i_blocks = 0;
>> 114 inode->i_blksize = 1024;
>> 115 inode->i_uid = inode->i_gid = 0;
307 inode->i_mode = S_IFDIR | S_IRUGO | S_ 116 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
308 inode->i_op = &simple_dir_inode_operat 117 inode->i_op = &simple_dir_inode_operations;
309 inode->i_fop = &simple_dir_operations; 118 inode->i_fop = &simple_dir_operations;
310 inode->i_nlink = 2; 119 inode->i_nlink = 2;
311 120
312 s->s_root = d_alloc_root(inode); !! 121 devpts_root = s->s_root = d_alloc_root(inode);
313 if (s->s_root) 122 if (s->s_root)
314 return 0; 123 return 0;
315 !! 124
316 printk(KERN_ERR "devpts: get root dent !! 125 printk("devpts: get root dentry failed\n");
317 iput(inode); 126 iput(inode);
318 <<
319 free_fsi: <<
320 kfree(s->s_fs_info); <<
321 fail: 127 fail:
322 return -ENOMEM; 128 return -ENOMEM;
323 } 129 }
324 130
325 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES !! 131 static struct super_block *devpts_get_sb(struct file_system_type *fs_type,
326 static int compare_init_pts_sb(struct super_bl !! 132 int flags, const char *dev_name, void *data)
327 { <<
328 if (devpts_mnt) <<
329 return devpts_mnt->mnt_sb == s <<
330 return 0; <<
331 } <<
332 <<
333 /* <<
334 * devpts_get_sb() <<
335 * <<
336 * If the '-o newinstance' mount option wa <<
337 * (private) instance of devpts. PTYs cre <<
338 * independent of the PTYs in other devpts <<
339 * <<
340 * If the '-o newinstance' option was not <<
341 * initial kernel mount of devpts. This t <<
342 * legacy, single-instance semantics. <<
343 * <<
344 * The 'newinstance' option is needed to s <<
345 * semantics in devpts while preserving ba <<
346 * current 'single-namespace' semantics. i <<
347 * without the 'newinstance' mount option <<
348 * kernel mount, like get_sb_single(). <<
349 * <<
350 * Mounts with 'newinstance' option create <<
351 * <<
352 * NOTE: <<
353 * <<
354 * For single-mount semantics, devpts cann <<
355 * because get_sb_single()/sget() find and <<
356 * the most recent mount of devpts. But th <<
357 * 'newinstance' mount and get_sb_single() <<
358 * super-block instead of the initial supe <<
359 */ <<
360 static int devpts_get_sb(struct file_system_ty <<
361 int flags, const char *dev_name, void <<
362 { <<
363 int error; <<
364 struct pts_mount_opts opts; <<
365 struct super_block *s; <<
366 <<
367 error = parse_mount_options(data, PARS <<
368 if (error) <<
369 return error; <<
370 <<
371 if (opts.newinstance) <<
372 s = sget(fs_type, NULL, set_an <<
373 else <<
374 s = sget(fs_type, compare_init <<
375 <<
376 if (IS_ERR(s)) <<
377 return PTR_ERR(s); <<
378 <<
379 if (!s->s_root) { <<
380 s->s_flags = flags; <<
381 error = devpts_fill_super(s, d <<
382 if (error) <<
383 goto out_undo_sget; <<
384 s->s_flags |= MS_ACTIVE; <<
385 } <<
386 <<
387 simple_set_mnt(mnt, s); <<
388 <<
389 memcpy(&(DEVPTS_SB(s))->mount_opts, &o <<
390 <<
391 error = mknod_ptmx(s); <<
392 if (error) <<
393 goto out_dput; <<
394 <<
395 return 0; <<
396 <<
397 out_dput: <<
398 dput(s->s_root); /* undo dget() in sim <<
399 <<
400 out_undo_sget: <<
401 deactivate_locked_super(s); <<
402 return error; <<
403 } <<
404 <<
405 #else <<
406 /* <<
407 * This supports only the legacy single-instan <<
408 * multiple-instance semantics) <<
409 */ <<
410 static int devpts_get_sb(struct file_system_ty <<
411 const char *dev_name, void *da <<
412 { <<
413 return get_sb_single(fs_type, flags, d <<
414 } <<
415 #endif <<
416 <<
417 static void devpts_kill_sb(struct super_block <<
418 { 133 {
419 struct pts_fs_info *fsi = DEVPTS_SB(sb !! 134 return get_sb_single(fs_type, flags, data, devpts_fill_super);
420 <<
421 kfree(fsi); <<
422 kill_litter_super(sb); <<
423 } 135 }
424 136
425 static struct file_system_type devpts_fs_type 137 static struct file_system_type devpts_fs_type = {
>> 138 .owner = THIS_MODULE,
426 .name = "devpts", 139 .name = "devpts",
427 .get_sb = devpts_get_sb, 140 .get_sb = devpts_get_sb,
428 .kill_sb = devpts_kill_sb, !! 141 .kill_sb = kill_anon_super,
429 }; 142 };
430 143
431 /* 144 /*
432 * The normal naming convention is simply /dev 145 * The normal naming convention is simply /dev/pts/<number>; this conforms
433 * to the System V naming convention 146 * to the System V naming convention
434 */ 147 */
435 148
436 int devpts_new_index(struct inode *ptmx_inode) !! 149 static struct dentry *get_node(int num)
437 { 150 {
438 struct super_block *sb = pts_sb_from_i !! 151 char s[12];
439 struct pts_fs_info *fsi = DEVPTS_SB(sb !! 152 struct dentry *root = devpts_root;
440 int index; !! 153 down(&root->d_inode->i_sem);
441 int ida_ret; !! 154 return lookup_one_len(s, root, sprintf(s, "%d", num));
442 <<
443 retry: <<
444 if (!ida_pre_get(&fsi->allocated_ptys, <<
445 return -ENOMEM; <<
446 <<
447 mutex_lock(&allocated_ptys_lock); <<
448 ida_ret = ida_get_new(&fsi->allocated_ <<
449 if (ida_ret < 0) { <<
450 mutex_unlock(&allocated_ptys_l <<
451 if (ida_ret == -EAGAIN) <<
452 goto retry; <<
453 return -EIO; <<
454 } <<
455 <<
456 if (index >= pty_limit) { <<
457 ida_remove(&fsi->allocated_pty <<
458 mutex_unlock(&allocated_ptys_l <<
459 return -EIO; <<
460 } <<
461 mutex_unlock(&allocated_ptys_lock); <<
462 return index; <<
463 } <<
464 <<
465 void devpts_kill_index(struct inode *ptmx_inod <<
466 { <<
467 struct super_block *sb = pts_sb_from_i <<
468 struct pts_fs_info *fsi = DEVPTS_SB(sb <<
469 <<
470 mutex_lock(&allocated_ptys_lock); <<
471 ida_remove(&fsi->allocated_ptys, idx); <<
472 mutex_unlock(&allocated_ptys_lock); <<
473 } 155 }
474 156
475 int devpts_pty_new(struct inode *ptmx_inode, s !! 157 int devpts_pty_new(struct tty_struct *tty)
476 { 158 {
477 /* tty layer puts index from devpts_ne <<
478 int number = tty->index; 159 int number = tty->index;
479 struct tty_driver *driver = tty->drive 160 struct tty_driver *driver = tty->driver;
480 dev_t device = MKDEV(driver->major, dr 161 dev_t device = MKDEV(driver->major, driver->minor_start+number);
481 struct dentry *dentry; 162 struct dentry *dentry;
482 struct super_block *sb = pts_sb_from_i !! 163 struct inode *inode = new_inode(devpts_mnt->mnt_sb);
483 struct inode *inode = new_inode(sb); <<
484 struct dentry *root = sb->s_root; <<
485 struct pts_fs_info *fsi = DEVPTS_SB(sb <<
486 struct pts_mount_opts *opts = &fsi->mo <<
487 char s[12]; <<
488 164
489 /* We're supposed to be given the slav 165 /* We're supposed to be given the slave end of a pty */
490 BUG_ON(driver->type != TTY_DRIVER_TYPE 166 BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY);
491 BUG_ON(driver->subtype != PTY_TYPE_SLA 167 BUG_ON(driver->subtype != PTY_TYPE_SLAVE);
492 168
493 if (!inode) 169 if (!inode)
494 return -ENOMEM; 170 return -ENOMEM;
495 171
496 inode->i_ino = number + 3; !! 172 inode->i_ino = number+2;
497 inode->i_uid = opts->setuid ? opts->ui !! 173 inode->i_blksize = 1024;
498 inode->i_gid = opts->setgid ? opts->gi !! 174 inode->i_uid = config.setuid ? config.uid : current->fsuid;
>> 175 inode->i_gid = config.setgid ? config.gid : current->fsgid;
499 inode->i_mtime = inode->i_atime = inod 176 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
500 init_special_inode(inode, S_IFCHR|opts !! 177 init_special_inode(inode, S_IFCHR|config.mode, device);
501 inode->i_private = tty; !! 178 inode->i_op = &devpts_file_inode_operations;
502 tty->driver_data = inode; !! 179 inode->u.generic_ip = tty;
503 !! 180
504 sprintf(s, "%d", number); !! 181 dentry = get_node(number);
505 !! 182 if (!IS_ERR(dentry) && !dentry->d_inode)
506 mutex_lock(&root->d_inode->i_mutex); !! 183 d_instantiate(dentry, inode);
507 <<
508 dentry = d_alloc_name(root, s); <<
509 if (!IS_ERR(dentry)) { <<
510 d_add(dentry, inode); <<
511 fsnotify_create(root->d_inode, <<
512 } <<
513 184
514 mutex_unlock(&root->d_inode->i_mutex); !! 185 up(&devpts_root->d_inode->i_sem);
515 186
516 return 0; 187 return 0;
517 } 188 }
518 189
519 struct tty_struct *devpts_get_tty(struct inode !! 190 struct tty_struct *devpts_get_tty(int number)
520 { 191 {
521 struct dentry *dentry; !! 192 struct dentry *dentry = get_node(number);
522 struct tty_struct *tty; 193 struct tty_struct *tty;
523 194
524 BUG_ON(pts_inode->i_rdev == MKDEV(TTYA <<
525 <<
526 /* Ensure dentry has not been deleted <<
527 dentry = d_find_alias(pts_inode); <<
528 if (!dentry) <<
529 return NULL; <<
530 <<
531 tty = NULL; 195 tty = NULL;
532 if (pts_inode->i_sb->s_magic == DEVPTS !! 196 if (!IS_ERR(dentry)) {
533 tty = (struct tty_struct *)pts !! 197 if (dentry->d_inode)
>> 198 tty = dentry->d_inode->u.generic_ip;
>> 199 dput(dentry);
>> 200 }
534 201
535 dput(dentry); !! 202 up(&devpts_root->d_inode->i_sem);
536 203
537 return tty; 204 return tty;
538 } 205 }
539 206
540 void devpts_pty_kill(struct tty_struct *tty) !! 207 void devpts_pty_kill(int number)
541 { 208 {
542 struct inode *inode = tty->driver_data !! 209 struct dentry *dentry = get_node(number);
543 struct super_block *sb = pts_sb_from_i <<
544 struct dentry *root = sb->s_root; <<
545 struct dentry *dentry; <<
546 <<
547 BUG_ON(inode->i_rdev == MKDEV(TTYAUX_M <<
548 210
549 mutex_lock(&root->d_inode->i_mutex); !! 211 if (!IS_ERR(dentry)) {
550 !! 212 struct inode *inode = dentry->d_inode;
551 dentry = d_find_alias(inode); !! 213 if (inode) {
552 if (IS_ERR(dentry)) !! 214 inode->i_nlink--;
553 goto out; !! 215 d_delete(dentry);
554 !! 216 dput(dentry);
555 if (dentry) { !! 217 }
556 inode->i_nlink--; !! 218 dput(dentry);
557 d_delete(dentry); <<
558 dput(dentry); /* d_alloc_nam <<
559 } 219 }
560 !! 220 up(&devpts_root->d_inode->i_sem);
561 dput(dentry); /* d_find_alia <<
562 out: <<
563 mutex_unlock(&root->d_inode->i_mutex); <<
564 } 221 }
565 222
566 static int __init init_devpts_fs(void) 223 static int __init init_devpts_fs(void)
567 { 224 {
568 int err = register_filesystem(&devpts_ 225 int err = register_filesystem(&devpts_fs_type);
569 if (!err) { 226 if (!err) {
570 devpts_mnt = kern_mount(&devpt 227 devpts_mnt = kern_mount(&devpts_fs_type);
571 if (IS_ERR(devpts_mnt)) { !! 228 if (IS_ERR(devpts_mnt))
572 err = PTR_ERR(devpts_m 229 err = PTR_ERR(devpts_mnt);
573 unregister_filesystem( <<
574 } <<
575 } 230 }
576 return err; 231 return err;
577 } 232 }
>> 233
>> 234 static void __exit exit_devpts_fs(void)
>> 235 {
>> 236 unregister_filesystem(&devpts_fs_type);
>> 237 mntput(devpts_mnt);
>> 238 }
>> 239
578 module_init(init_devpts_fs) 240 module_init(init_devpts_fs)
>> 241 module_exit(exit_devpts_fs)
>> 242 MODULE_LICENSE("GPL");
579 243
|
This page was automatically generated by the
LXR engine.
|