diff options
-rw-r--r-- | drivers/char/pty.c | 6 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 27 | ||||
-rw-r--r-- | fs/file_table.c | 42 | ||||
-rw-r--r-- | fs/open.c | 4 | ||||
-rw-r--r-- | include/linux/fs.h | 9 | ||||
-rw-r--r-- | include/linux/tty.h | 1 | ||||
-rw-r--r-- | security/selinux/hooks.c | 4 |
7 files changed, 50 insertions, 43 deletions
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 385c44b3034f..8fa273e76bb3 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
@@ -649,7 +649,11 @@ static int __ptmx_open(struct inode *inode, struct file *filp) | |||
649 | 649 | ||
650 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ | 650 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ |
651 | filp->private_data = tty; | 651 | filp->private_data = tty; |
652 | file_move(filp, &tty->tty_files); | 652 | |
653 | file_sb_list_del(filp); /* __dentry_open has put it on the sb list */ | ||
654 | spin_lock(&tty_files_lock); | ||
655 | list_add(&filp->f_u.fu_list, &tty->tty_files); | ||
656 | spin_unlock(&tty_files_lock); | ||
653 | 657 | ||
654 | retval = devpts_pty_new(inode, tty->link); | 658 | retval = devpts_pty_new(inode, tty->link); |
655 | if (retval) | 659 | if (retval) |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 76253cf27028..38ddfa404fb1 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -136,6 +136,9 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ | |||
136 | DEFINE_MUTEX(tty_mutex); | 136 | DEFINE_MUTEX(tty_mutex); |
137 | EXPORT_SYMBOL(tty_mutex); | 137 | EXPORT_SYMBOL(tty_mutex); |
138 | 138 | ||
139 | /* Spinlock to protect the tty->tty_files list */ | ||
140 | DEFINE_SPINLOCK(tty_files_lock); | ||
141 | |||
139 | static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); | 142 | static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); |
140 | static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); | 143 | static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); |
141 | ssize_t redirected_tty_write(struct file *, const char __user *, | 144 | ssize_t redirected_tty_write(struct file *, const char __user *, |
@@ -234,11 +237,11 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) | |||
234 | struct list_head *p; | 237 | struct list_head *p; |
235 | int count = 0; | 238 | int count = 0; |
236 | 239 | ||
237 | file_list_lock(); | 240 | spin_lock(&tty_files_lock); |
238 | list_for_each(p, &tty->tty_files) { | 241 | list_for_each(p, &tty->tty_files) { |
239 | count++; | 242 | count++; |
240 | } | 243 | } |
241 | file_list_unlock(); | 244 | spin_unlock(&tty_files_lock); |
242 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 245 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
243 | tty->driver->subtype == PTY_TYPE_SLAVE && | 246 | tty->driver->subtype == PTY_TYPE_SLAVE && |
244 | tty->link && tty->link->count) | 247 | tty->link && tty->link->count) |
@@ -516,8 +519,7 @@ static void do_tty_hangup(struct work_struct *work) | |||
516 | /* inuse_filps is protected by the single kernel lock */ | 519 | /* inuse_filps is protected by the single kernel lock */ |
517 | lock_kernel(); | 520 | lock_kernel(); |
518 | check_tty_count(tty, "do_tty_hangup"); | 521 | check_tty_count(tty, "do_tty_hangup"); |
519 | 522 | spin_lock(&tty_files_lock); | |
520 | file_list_lock(); | ||
521 | /* This breaks for file handles being sent over AF_UNIX sockets ? */ | 523 | /* This breaks for file handles being sent over AF_UNIX sockets ? */ |
522 | list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { | 524 | list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { |
523 | if (filp->f_op->write == redirected_tty_write) | 525 | if (filp->f_op->write == redirected_tty_write) |
@@ -528,7 +530,7 @@ static void do_tty_hangup(struct work_struct *work) | |||
528 | tty_fasync(-1, filp, 0); /* can't block */ | 530 | tty_fasync(-1, filp, 0); /* can't block */ |
529 | filp->f_op = &hung_up_tty_fops; | 531 | filp->f_op = &hung_up_tty_fops; |
530 | } | 532 | } |
531 | file_list_unlock(); | 533 | spin_unlock(&tty_files_lock); |
532 | 534 | ||
533 | tty_ldisc_hangup(tty); | 535 | tty_ldisc_hangup(tty); |
534 | 536 | ||
@@ -1419,9 +1421,9 @@ static void release_one_tty(struct work_struct *work) | |||
1419 | tty_driver_kref_put(driver); | 1421 | tty_driver_kref_put(driver); |
1420 | module_put(driver->owner); | 1422 | module_put(driver->owner); |
1421 | 1423 | ||
1422 | file_list_lock(); | 1424 | spin_lock(&tty_files_lock); |
1423 | list_del_init(&tty->tty_files); | 1425 | list_del_init(&tty->tty_files); |
1424 | file_list_unlock(); | 1426 | spin_unlock(&tty_files_lock); |
1425 | 1427 | ||
1426 | put_pid(tty->pgrp); | 1428 | put_pid(tty->pgrp); |
1427 | put_pid(tty->session); | 1429 | put_pid(tty->session); |
@@ -1666,7 +1668,10 @@ int tty_release(struct inode *inode, struct file *filp) | |||
1666 | * - do_tty_hangup no longer sees this file descriptor as | 1668 | * - do_tty_hangup no longer sees this file descriptor as |
1667 | * something that needs to be handled for hangups. | 1669 | * something that needs to be handled for hangups. |
1668 | */ | 1670 | */ |
1669 | file_kill(filp); | 1671 | spin_lock(&tty_files_lock); |
1672 | BUG_ON(list_empty(&filp->f_u.fu_list)); | ||
1673 | list_del_init(&filp->f_u.fu_list); | ||
1674 | spin_unlock(&tty_files_lock); | ||
1670 | filp->private_data = NULL; | 1675 | filp->private_data = NULL; |
1671 | 1676 | ||
1672 | /* | 1677 | /* |
@@ -1835,7 +1840,11 @@ got_driver: | |||
1835 | } | 1840 | } |
1836 | 1841 | ||
1837 | filp->private_data = tty; | 1842 | filp->private_data = tty; |
1838 | file_move(filp, &tty->tty_files); | 1843 | BUG_ON(list_empty(&filp->f_u.fu_list)); |
1844 | file_sb_list_del(filp); /* __dentry_open has put it on the sb list */ | ||
1845 | spin_lock(&tty_files_lock); | ||
1846 | list_add(&filp->f_u.fu_list, &tty->tty_files); | ||
1847 | spin_unlock(&tty_files_lock); | ||
1839 | check_tty_count(tty, "tty_open"); | 1848 | check_tty_count(tty, "tty_open"); |
1840 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 1849 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
1841 | tty->driver->subtype == PTY_TYPE_MASTER) | 1850 | tty->driver->subtype == PTY_TYPE_MASTER) |
diff --git a/fs/file_table.c b/fs/file_table.c index 32d12b78bac8..ce00b6e03a06 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
@@ -32,8 +32,7 @@ struct files_stat_struct files_stat = { | |||
32 | .max_files = NR_FILE | 32 | .max_files = NR_FILE |
33 | }; | 33 | }; |
34 | 34 | ||
35 | /* public. Not pretty! */ | 35 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); |
36 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); | ||
37 | 36 | ||
38 | /* SLAB cache for file structures */ | 37 | /* SLAB cache for file structures */ |
39 | static struct kmem_cache *filp_cachep __read_mostly; | 38 | static struct kmem_cache *filp_cachep __read_mostly; |
@@ -258,7 +257,7 @@ void __fput(struct file *file) | |||
258 | cdev_put(inode->i_cdev); | 257 | cdev_put(inode->i_cdev); |
259 | fops_put(file->f_op); | 258 | fops_put(file->f_op); |
260 | put_pid(file->f_owner.pid); | 259 | put_pid(file->f_owner.pid); |
261 | file_kill(file); | 260 | file_sb_list_del(file); |
262 | if (file->f_mode & FMODE_WRITE) | 261 | if (file->f_mode & FMODE_WRITE) |
263 | drop_file_write_access(file); | 262 | drop_file_write_access(file); |
264 | file->f_path.dentry = NULL; | 263 | file->f_path.dentry = NULL; |
@@ -320,31 +319,29 @@ struct file *fget_light(unsigned int fd, int *fput_needed) | |||
320 | return file; | 319 | return file; |
321 | } | 320 | } |
322 | 321 | ||
323 | |||
324 | void put_filp(struct file *file) | 322 | void put_filp(struct file *file) |
325 | { | 323 | { |
326 | if (atomic_long_dec_and_test(&file->f_count)) { | 324 | if (atomic_long_dec_and_test(&file->f_count)) { |
327 | security_file_free(file); | 325 | security_file_free(file); |
328 | file_kill(file); | 326 | file_sb_list_del(file); |
329 | file_free(file); | 327 | file_free(file); |
330 | } | 328 | } |
331 | } | 329 | } |
332 | 330 | ||
333 | void file_move(struct file *file, struct list_head *list) | 331 | void file_sb_list_add(struct file *file, struct super_block *sb) |
334 | { | 332 | { |
335 | if (!list) | 333 | spin_lock(&files_lock); |
336 | return; | 334 | BUG_ON(!list_empty(&file->f_u.fu_list)); |
337 | file_list_lock(); | 335 | list_add(&file->f_u.fu_list, &sb->s_files); |
338 | list_move(&file->f_u.fu_list, list); | 336 | spin_unlock(&files_lock); |
339 | file_list_unlock(); | ||
340 | } | 337 | } |
341 | 338 | ||
342 | void file_kill(struct file *file) | 339 | void file_sb_list_del(struct file *file) |
343 | { | 340 | { |
344 | if (!list_empty(&file->f_u.fu_list)) { | 341 | if (!list_empty(&file->f_u.fu_list)) { |
345 | file_list_lock(); | 342 | spin_lock(&files_lock); |
346 | list_del_init(&file->f_u.fu_list); | 343 | list_del_init(&file->f_u.fu_list); |
347 | file_list_unlock(); | 344 | spin_unlock(&files_lock); |
348 | } | 345 | } |
349 | } | 346 | } |
350 | 347 | ||
@@ -353,7 +350,7 @@ int fs_may_remount_ro(struct super_block *sb) | |||
353 | struct file *file; | 350 | struct file *file; |
354 | 351 | ||
355 | /* Check that no files are currently opened for writing. */ | 352 | /* Check that no files are currently opened for writing. */ |
356 | file_list_lock(); | 353 | spin_lock(&files_lock); |
357 | list_for_each_entry(file, &sb->s_files, f_u.fu_list) { | 354 | list_for_each_entry(file, &sb->s_files, f_u.fu_list) { |
358 | struct inode *inode = file->f_path.dentry->d_inode; | 355 | struct inode *inode = file->f_path.dentry->d_inode; |
359 | 356 | ||
@@ -365,10 +362,10 @@ int fs_may_remount_ro(struct super_block *sb) | |||
365 | if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) | 362 | if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) |
366 | goto too_bad; | 363 | goto too_bad; |
367 | } | 364 | } |
368 | file_list_unlock(); | 365 | spin_unlock(&files_lock); |
369 | return 1; /* Tis' cool bro. */ | 366 | return 1; /* Tis' cool bro. */ |
370 | too_bad: | 367 | too_bad: |
371 | file_list_unlock(); | 368 | spin_unlock(&files_lock); |
372 | return 0; | 369 | return 0; |
373 | } | 370 | } |
374 | 371 | ||
@@ -384,7 +381,7 @@ void mark_files_ro(struct super_block *sb) | |||
384 | struct file *f; | 381 | struct file *f; |
385 | 382 | ||
386 | retry: | 383 | retry: |
387 | file_list_lock(); | 384 | spin_lock(&files_lock); |
388 | list_for_each_entry(f, &sb->s_files, f_u.fu_list) { | 385 | list_for_each_entry(f, &sb->s_files, f_u.fu_list) { |
389 | struct vfsmount *mnt; | 386 | struct vfsmount *mnt; |
390 | if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) | 387 | if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) |
@@ -400,16 +397,13 @@ retry: | |||
400 | continue; | 397 | continue; |
401 | file_release_write(f); | 398 | file_release_write(f); |
402 | mnt = mntget(f->f_path.mnt); | 399 | mnt = mntget(f->f_path.mnt); |
403 | file_list_unlock(); | 400 | /* This can sleep, so we can't hold the spinlock. */ |
404 | /* | 401 | spin_unlock(&files_lock); |
405 | * This can sleep, so we can't hold | ||
406 | * the file_list_lock() spinlock. | ||
407 | */ | ||
408 | mnt_drop_write(mnt); | 402 | mnt_drop_write(mnt); |
409 | mntput(mnt); | 403 | mntput(mnt); |
410 | goto retry; | 404 | goto retry; |
411 | } | 405 | } |
412 | file_list_unlock(); | 406 | spin_unlock(&files_lock); |
413 | } | 407 | } |
414 | 408 | ||
415 | void __init files_init(unsigned long mempages) | 409 | void __init files_init(unsigned long mempages) |
@@ -844,7 +844,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
844 | f->f_path.mnt = mnt; | 844 | f->f_path.mnt = mnt; |
845 | f->f_pos = 0; | 845 | f->f_pos = 0; |
846 | f->f_op = fops_get(inode->i_fop); | 846 | f->f_op = fops_get(inode->i_fop); |
847 | file_move(f, &inode->i_sb->s_files); | 847 | file_sb_list_add(f, inode->i_sb); |
848 | 848 | ||
849 | error = security_dentry_open(f, cred); | 849 | error = security_dentry_open(f, cred); |
850 | if (error) | 850 | if (error) |
@@ -890,7 +890,7 @@ cleanup_all: | |||
890 | mnt_drop_write(mnt); | 890 | mnt_drop_write(mnt); |
891 | } | 891 | } |
892 | } | 892 | } |
893 | file_kill(f); | 893 | file_sb_list_del(f); |
894 | f->f_path.dentry = NULL; | 894 | f->f_path.dentry = NULL; |
895 | f->f_path.mnt = NULL; | 895 | f->f_path.mnt = NULL; |
896 | cleanup_file: | 896 | cleanup_file: |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 5191f49c2fec..fc515b423fae 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -948,9 +948,6 @@ struct file { | |||
948 | unsigned long f_mnt_write_state; | 948 | unsigned long f_mnt_write_state; |
949 | #endif | 949 | #endif |
950 | }; | 950 | }; |
951 | extern spinlock_t files_lock; | ||
952 | #define file_list_lock() spin_lock(&files_lock); | ||
953 | #define file_list_unlock() spin_unlock(&files_lock); | ||
954 | 951 | ||
955 | #define get_file(x) atomic_long_inc(&(x)->f_count) | 952 | #define get_file(x) atomic_long_inc(&(x)->f_count) |
956 | #define file_count(x) atomic_long_read(&(x)->f_count) | 953 | #define file_count(x) atomic_long_read(&(x)->f_count) |
@@ -2037,6 +2034,7 @@ extern const struct file_operations read_pipefifo_fops; | |||
2037 | extern const struct file_operations write_pipefifo_fops; | 2034 | extern const struct file_operations write_pipefifo_fops; |
2038 | extern const struct file_operations rdwr_pipefifo_fops; | 2035 | extern const struct file_operations rdwr_pipefifo_fops; |
2039 | 2036 | ||
2037 | extern void mark_files_ro(struct super_block *sb); | ||
2040 | extern int fs_may_remount_ro(struct super_block *); | 2038 | extern int fs_may_remount_ro(struct super_block *); |
2041 | 2039 | ||
2042 | #ifdef CONFIG_BLOCK | 2040 | #ifdef CONFIG_BLOCK |
@@ -2183,8 +2181,9 @@ static inline void insert_inode_hash(struct inode *inode) { | |||
2183 | __insert_inode_hash(inode, inode->i_ino); | 2181 | __insert_inode_hash(inode, inode->i_ino); |
2184 | } | 2182 | } |
2185 | 2183 | ||
2186 | extern void file_move(struct file *f, struct list_head *list); | 2184 | extern struct file * get_empty_filp(void); |
2187 | extern void file_kill(struct file *f); | 2185 | extern void file_sb_list_add(struct file *f, struct super_block *sb); |
2186 | extern void file_sb_list_del(struct file *f); | ||
2188 | #ifdef CONFIG_BLOCK | 2187 | #ifdef CONFIG_BLOCK |
2189 | struct bio; | 2188 | struct bio; |
2190 | extern void submit_bio(int, struct bio *); | 2189 | extern void submit_bio(int, struct bio *); |
diff --git a/include/linux/tty.h b/include/linux/tty.h index 42f207676016..e5c5ba2327f1 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h | |||
@@ -465,6 +465,7 @@ extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty); | |||
465 | extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty); | 465 | extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty); |
466 | 466 | ||
467 | extern struct mutex tty_mutex; | 467 | extern struct mutex tty_mutex; |
468 | extern spinlock_t tty_files_lock; | ||
468 | 469 | ||
469 | extern void tty_write_unlock(struct tty_struct *tty); | 470 | extern void tty_write_unlock(struct tty_struct *tty); |
470 | extern int tty_write_lock(struct tty_struct *tty, int ndelay); | 471 | extern int tty_write_lock(struct tty_struct *tty, int ndelay); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9a2ee845e9d4..f013de205ea8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -2246,7 +2246,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2246 | 2246 | ||
2247 | tty = get_current_tty(); | 2247 | tty = get_current_tty(); |
2248 | if (tty) { | 2248 | if (tty) { |
2249 | file_list_lock(); | 2249 | spin_lock(&tty_files_lock); |
2250 | if (!list_empty(&tty->tty_files)) { | 2250 | if (!list_empty(&tty->tty_files)) { |
2251 | struct inode *inode; | 2251 | struct inode *inode; |
2252 | 2252 | ||
@@ -2262,7 +2262,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2262 | drop_tty = 1; | 2262 | drop_tty = 1; |
2263 | } | 2263 | } |
2264 | } | 2264 | } |
2265 | file_list_unlock(); | 2265 | spin_unlock(&tty_files_lock); |
2266 | tty_kref_put(tty); | 2266 | tty_kref_put(tty); |
2267 | } | 2267 | } |
2268 | /* Reset controlling tty. */ | 2268 | /* Reset controlling tty. */ |