aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2010-08-17 14:37:35 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-08-18 08:35:47 -0400
commitee2ffa0dfdd2db19705f2ba1c6a4c0bfe8122dd8 (patch)
treee48400d1a33f8d2e68589ccfd61637aa64462f08
parentb04f784e5d19ed58892833dae845738972cea260 (diff)
fs: cleanup files_lock locking
fs: cleanup files_lock locking Lock tty_files with a new spinlock, tty_files_lock; provide helpers to manipulate the per-sb files list; unexport the files_lock spinlock. Cc: linux-kernel@vger.kernel.org Cc: Christoph Hellwig <hch@infradead.org> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Acked-by: Andi Kleen <ak@linux.intel.com> Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Nick Piggin <npiggin@kernel.dk> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--drivers/char/pty.c6
-rw-r--r--drivers/char/tty_io.c26
-rw-r--r--fs/file_table.c42
-rw-r--r--fs/open.c4
-rw-r--r--include/linux/fs.h7
-rw-r--r--include/linux/tty.h1
-rw-r--r--security/selinux/hooks.c4
7 files changed, 48 insertions, 42 deletions
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index ad46eae1f9bb..2c64faa8efa4 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -676,7 +676,11 @@ static int ptmx_open(struct inode *inode, struct file *filp)
676 676
677 set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ 677 set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
678 filp->private_data = tty; 678 filp->private_data = tty;
679 file_move(filp, &tty->tty_files); 679
680 file_sb_list_del(filp); /* __dentry_open has put it on the sb list */
681 spin_lock(&tty_files_lock);
682 list_add(&filp->f_u.fu_list, &tty->tty_files);
683 spin_unlock(&tty_files_lock);
680 684
681 retval = devpts_pty_new(inode, tty->link); 685 retval = devpts_pty_new(inode, tty->link);
682 if (retval) 686 if (retval)
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 0350c42375a2..cd5b829634ea 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 */
136DEFINE_MUTEX(tty_mutex); 136DEFINE_MUTEX(tty_mutex);
137EXPORT_SYMBOL(tty_mutex); 137EXPORT_SYMBOL(tty_mutex);
138 138
139/* Spinlock to protect the tty->tty_files list */
140DEFINE_SPINLOCK(tty_files_lock);
141
139static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); 142static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
140static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); 143static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
141ssize_t redirected_tty_write(struct file *, const char __user *, 144ssize_t redirected_tty_write(struct file *, const char __user *,
@@ -235,11 +238,11 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
235 struct list_head *p; 238 struct list_head *p;
236 int count = 0; 239 int count = 0;
237 240
238 file_list_lock(); 241 spin_lock(&tty_files_lock);
239 list_for_each(p, &tty->tty_files) { 242 list_for_each(p, &tty->tty_files) {
240 count++; 243 count++;
241 } 244 }
242 file_list_unlock(); 245 spin_unlock(&tty_files_lock);
243 if (tty->driver->type == TTY_DRIVER_TYPE_PTY && 246 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
244 tty->driver->subtype == PTY_TYPE_SLAVE && 247 tty->driver->subtype == PTY_TYPE_SLAVE &&
245 tty->link && tty->link->count) 248 tty->link && tty->link->count)
@@ -519,7 +522,7 @@ void __tty_hangup(struct tty_struct *tty)
519 workqueue with the lock held */ 522 workqueue with the lock held */
520 check_tty_count(tty, "tty_hangup"); 523 check_tty_count(tty, "tty_hangup");
521 524
522 file_list_lock(); 525 spin_lock(&tty_files_lock);
523 /* This breaks for file handles being sent over AF_UNIX sockets ? */ 526 /* This breaks for file handles being sent over AF_UNIX sockets ? */
524 list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { 527 list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) {
525 if (filp->f_op->write == redirected_tty_write) 528 if (filp->f_op->write == redirected_tty_write)
@@ -530,7 +533,7 @@ void __tty_hangup(struct tty_struct *tty)
530 __tty_fasync(-1, filp, 0); /* can't block */ 533 __tty_fasync(-1, filp, 0); /* can't block */
531 filp->f_op = &hung_up_tty_fops; 534 filp->f_op = &hung_up_tty_fops;
532 } 535 }
533 file_list_unlock(); 536 spin_unlock(&tty_files_lock);
534 537
535 tty_ldisc_hangup(tty); 538 tty_ldisc_hangup(tty);
536 539
@@ -1424,9 +1427,9 @@ static void release_one_tty(struct work_struct *work)
1424 tty_driver_kref_put(driver); 1427 tty_driver_kref_put(driver);
1425 module_put(driver->owner); 1428 module_put(driver->owner);
1426 1429
1427 file_list_lock(); 1430 spin_lock(&tty_files_lock);
1428 list_del_init(&tty->tty_files); 1431 list_del_init(&tty->tty_files);
1429 file_list_unlock(); 1432 spin_unlock(&tty_files_lock);
1430 1433
1431 put_pid(tty->pgrp); 1434 put_pid(tty->pgrp);
1432 put_pid(tty->session); 1435 put_pid(tty->session);
@@ -1671,7 +1674,10 @@ int tty_release(struct inode *inode, struct file *filp)
1671 * - do_tty_hangup no longer sees this file descriptor as 1674 * - do_tty_hangup no longer sees this file descriptor as
1672 * something that needs to be handled for hangups. 1675 * something that needs to be handled for hangups.
1673 */ 1676 */
1674 file_kill(filp); 1677 spin_lock(&tty_files_lock);
1678 BUG_ON(list_empty(&filp->f_u.fu_list));
1679 list_del_init(&filp->f_u.fu_list);
1680 spin_unlock(&tty_files_lock);
1675 filp->private_data = NULL; 1681 filp->private_data = NULL;
1676 1682
1677 /* 1683 /*
@@ -1840,7 +1846,11 @@ got_driver:
1840 } 1846 }
1841 1847
1842 filp->private_data = tty; 1848 filp->private_data = tty;
1843 file_move(filp, &tty->tty_files); 1849 BUG_ON(list_empty(&filp->f_u.fu_list));
1850 file_sb_list_del(filp); /* __dentry_open has put it on the sb list */
1851 spin_lock(&tty_files_lock);
1852 list_add(&filp->f_u.fu_list, &tty->tty_files);
1853 spin_unlock(&tty_files_lock);
1844 check_tty_count(tty, "tty_open"); 1854 check_tty_count(tty, "tty_open");
1845 if (tty->driver->type == TTY_DRIVER_TYPE_PTY && 1855 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
1846 tty->driver->subtype == PTY_TYPE_MASTER) 1856 tty->driver->subtype == PTY_TYPE_MASTER)
diff --git a/fs/file_table.c b/fs/file_table.c
index edecd36fed9b..6f0e62ecfddd 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! */ 35static __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 */
39static struct kmem_cache *filp_cachep __read_mostly; 38static struct kmem_cache *filp_cachep __read_mostly;
@@ -249,7 +248,7 @@ static void __fput(struct file *file)
249 cdev_put(inode->i_cdev); 248 cdev_put(inode->i_cdev);
250 fops_put(file->f_op); 249 fops_put(file->f_op);
251 put_pid(file->f_owner.pid); 250 put_pid(file->f_owner.pid);
252 file_kill(file); 251 file_sb_list_del(file);
253 if (file->f_mode & FMODE_WRITE) 252 if (file->f_mode & FMODE_WRITE)
254 drop_file_write_access(file); 253 drop_file_write_access(file);
255 file->f_path.dentry = NULL; 254 file->f_path.dentry = NULL;
@@ -328,31 +327,29 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
328 return file; 327 return file;
329} 328}
330 329
331
332void put_filp(struct file *file) 330void put_filp(struct file *file)
333{ 331{
334 if (atomic_long_dec_and_test(&file->f_count)) { 332 if (atomic_long_dec_and_test(&file->f_count)) {
335 security_file_free(file); 333 security_file_free(file);
336 file_kill(file); 334 file_sb_list_del(file);
337 file_free(file); 335 file_free(file);
338 } 336 }
339} 337}
340 338
341void file_move(struct file *file, struct list_head *list) 339void file_sb_list_add(struct file *file, struct super_block *sb)
342{ 340{
343 if (!list) 341 spin_lock(&files_lock);
344 return; 342 BUG_ON(!list_empty(&file->f_u.fu_list));
345 file_list_lock(); 343 list_add(&file->f_u.fu_list, &sb->s_files);
346 list_move(&file->f_u.fu_list, list); 344 spin_unlock(&files_lock);
347 file_list_unlock();
348} 345}
349 346
350void file_kill(struct file *file) 347void file_sb_list_del(struct file *file)
351{ 348{
352 if (!list_empty(&file->f_u.fu_list)) { 349 if (!list_empty(&file->f_u.fu_list)) {
353 file_list_lock(); 350 spin_lock(&files_lock);
354 list_del_init(&file->f_u.fu_list); 351 list_del_init(&file->f_u.fu_list);
355 file_list_unlock(); 352 spin_unlock(&files_lock);
356 } 353 }
357} 354}
358 355
@@ -361,7 +358,7 @@ int fs_may_remount_ro(struct super_block *sb)
361 struct file *file; 358 struct file *file;
362 359
363 /* Check that no files are currently opened for writing. */ 360 /* Check that no files are currently opened for writing. */
364 file_list_lock(); 361 spin_lock(&files_lock);
365 list_for_each_entry(file, &sb->s_files, f_u.fu_list) { 362 list_for_each_entry(file, &sb->s_files, f_u.fu_list) {
366 struct inode *inode = file->f_path.dentry->d_inode; 363 struct inode *inode = file->f_path.dentry->d_inode;
367 364
@@ -373,10 +370,10 @@ int fs_may_remount_ro(struct super_block *sb)
373 if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) 370 if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
374 goto too_bad; 371 goto too_bad;
375 } 372 }
376 file_list_unlock(); 373 spin_unlock(&files_lock);
377 return 1; /* Tis' cool bro. */ 374 return 1; /* Tis' cool bro. */
378too_bad: 375too_bad:
379 file_list_unlock(); 376 spin_unlock(&files_lock);
380 return 0; 377 return 0;
381} 378}
382 379
@@ -392,7 +389,7 @@ void mark_files_ro(struct super_block *sb)
392 struct file *f; 389 struct file *f;
393 390
394retry: 391retry:
395 file_list_lock(); 392 spin_lock(&files_lock);
396 list_for_each_entry(f, &sb->s_files, f_u.fu_list) { 393 list_for_each_entry(f, &sb->s_files, f_u.fu_list) {
397 struct vfsmount *mnt; 394 struct vfsmount *mnt;
398 if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) 395 if (!S_ISREG(f->f_path.dentry->d_inode->i_mode))
@@ -408,16 +405,13 @@ retry:
408 continue; 405 continue;
409 file_release_write(f); 406 file_release_write(f);
410 mnt = mntget(f->f_path.mnt); 407 mnt = mntget(f->f_path.mnt);
411 file_list_unlock(); 408 /* This can sleep, so we can't hold the spinlock. */
412 /* 409 spin_unlock(&files_lock);
413 * This can sleep, so we can't hold
414 * the file_list_lock() spinlock.
415 */
416 mnt_drop_write(mnt); 410 mnt_drop_write(mnt);
417 mntput(mnt); 411 mntput(mnt);
418 goto retry; 412 goto retry;
419 } 413 }
420 file_list_unlock(); 414 spin_unlock(&files_lock);
421} 415}
422 416
423void __init files_init(unsigned long mempages) 417void __init files_init(unsigned long mempages)
diff --git a/fs/open.c b/fs/open.c
index 630715f9f73d..d74e1983e8dc 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -675,7 +675,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
675 f->f_path.mnt = mnt; 675 f->f_path.mnt = mnt;
676 f->f_pos = 0; 676 f->f_pos = 0;
677 f->f_op = fops_get(inode->i_fop); 677 f->f_op = fops_get(inode->i_fop);
678 file_move(f, &inode->i_sb->s_files); 678 file_sb_list_add(f, inode->i_sb);
679 679
680 error = security_dentry_open(f, cred); 680 error = security_dentry_open(f, cred);
681 if (error) 681 if (error)
@@ -721,7 +721,7 @@ cleanup_all:
721 mnt_drop_write(mnt); 721 mnt_drop_write(mnt);
722 } 722 }
723 } 723 }
724 file_kill(f); 724 file_sb_list_del(f);
725 f->f_path.dentry = NULL; 725 f->f_path.dentry = NULL;
726 f->f_path.mnt = NULL; 726 f->f_path.mnt = NULL;
727cleanup_file: 727cleanup_file:
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 29f7c975304c..5a9a9e5a3705 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -944,9 +944,6 @@ struct file {
944 unsigned long f_mnt_write_state; 944 unsigned long f_mnt_write_state;
945#endif 945#endif
946}; 946};
947extern spinlock_t files_lock;
948#define file_list_lock() spin_lock(&files_lock);
949#define file_list_unlock() spin_unlock(&files_lock);
950 947
951#define get_file(x) atomic_long_inc(&(x)->f_count) 948#define get_file(x) atomic_long_inc(&(x)->f_count)
952#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1) 949#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1)
@@ -2188,8 +2185,8 @@ static inline void insert_inode_hash(struct inode *inode) {
2188 __insert_inode_hash(inode, inode->i_ino); 2185 __insert_inode_hash(inode, inode->i_ino);
2189} 2186}
2190 2187
2191extern void file_move(struct file *f, struct list_head *list); 2188extern void file_sb_list_add(struct file *f, struct super_block *sb);
2192extern void file_kill(struct file *f); 2189extern void file_sb_list_del(struct file *f);
2193#ifdef CONFIG_BLOCK 2190#ifdef CONFIG_BLOCK
2194extern void submit_bio(int, struct bio *); 2191extern void submit_bio(int, struct bio *);
2195extern int bdev_read_only(struct block_device *); 2192extern int bdev_read_only(struct block_device *);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 1437da3ddc62..f6b371a2514e 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -470,6 +470,7 @@ extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
470extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty); 470extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty);
471 471
472extern struct mutex tty_mutex; 472extern struct mutex tty_mutex;
473extern spinlock_t tty_files_lock;
473 474
474extern void tty_write_unlock(struct tty_struct *tty); 475extern void tty_write_unlock(struct tty_struct *tty);
475extern int tty_write_lock(struct tty_struct *tty, int ndelay); 476extern int tty_write_lock(struct tty_struct *tty, int ndelay);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 42043f96e54f..bd7da0f0ccf3 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2170,7 +2170,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
2170 2170
2171 tty = get_current_tty(); 2171 tty = get_current_tty();
2172 if (tty) { 2172 if (tty) {
2173 file_list_lock(); 2173 spin_lock(&tty_files_lock);
2174 if (!list_empty(&tty->tty_files)) { 2174 if (!list_empty(&tty->tty_files)) {
2175 struct inode *inode; 2175 struct inode *inode;
2176 2176
@@ -2186,7 +2186,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
2186 drop_tty = 1; 2186 drop_tty = 1;
2187 } 2187 }
2188 } 2188 }
2189 file_list_unlock(); 2189 spin_unlock(&tty_files_lock);
2190 tty_kref_put(tty); 2190 tty_kref_put(tty);
2191 } 2191 }
2192 /* Reset controlling tty. */ 2192 /* Reset controlling tty. */