aboutsummaryrefslogtreecommitdiffstats
path: root/fs/file_table.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/file_table.c')
-rw-r--r--fs/file_table.c133
1 files changed, 95 insertions, 38 deletions
diff --git a/fs/file_table.c b/fs/file_table.c
index 2fc3b3c08911..a04bdd81c11c 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -20,7 +20,9 @@
20#include <linux/cdev.h> 20#include <linux/cdev.h>
21#include <linux/fsnotify.h> 21#include <linux/fsnotify.h>
22#include <linux/sysctl.h> 22#include <linux/sysctl.h>
23#include <linux/lglock.h>
23#include <linux/percpu_counter.h> 24#include <linux/percpu_counter.h>
25#include <linux/percpu.h>
24#include <linux/ima.h> 26#include <linux/ima.h>
25 27
26#include <asm/atomic.h> 28#include <asm/atomic.h>
@@ -32,8 +34,8 @@ struct files_stat_struct files_stat = {
32 .max_files = NR_FILE 34 .max_files = NR_FILE
33}; 35};
34 36
35/* public. Not pretty! */ 37DECLARE_LGLOCK(files_lglock);
36__cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); 38DEFINE_LGLOCK(files_lglock);
37 39
38/* SLAB cache for file structures */ 40/* SLAB cache for file structures */
39static struct kmem_cache *filp_cachep __read_mostly; 41static struct kmem_cache *filp_cachep __read_mostly;
@@ -230,15 +232,6 @@ static void __fput(struct file *file)
230 might_sleep(); 232 might_sleep();
231 233
232 fsnotify_close(file); 234 fsnotify_close(file);
233
234 /*
235 * fsnotify_create_event may have taken one or more references on this
236 * file. If it did so it left one reference for us to drop to make sure
237 * its calls to fput could not prematurely destroy the file.
238 */
239 if (atomic_long_read(&file->f_count))
240 return fput(file);
241
242 /* 235 /*
243 * The function eventpoll_release() should be the first called 236 * The function eventpoll_release() should be the first called
244 * in the file cleanup chain. 237 * in the file cleanup chain.
@@ -258,7 +251,7 @@ static void __fput(struct file *file)
258 cdev_put(inode->i_cdev); 251 cdev_put(inode->i_cdev);
259 fops_put(file->f_op); 252 fops_put(file->f_op);
260 put_pid(file->f_owner.pid); 253 put_pid(file->f_owner.pid);
261 file_kill(file); 254 file_sb_list_del(file);
262 if (file->f_mode & FMODE_WRITE) 255 if (file->f_mode & FMODE_WRITE)
263 drop_file_write_access(file); 256 drop_file_write_access(file);
264 file->f_path.dentry = NULL; 257 file->f_path.dentry = NULL;
@@ -337,41 +330,107 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
337 return file; 330 return file;
338} 331}
339 332
340
341void put_filp(struct file *file) 333void put_filp(struct file *file)
342{ 334{
343 if (atomic_long_dec_and_test(&file->f_count)) { 335 if (atomic_long_dec_and_test(&file->f_count)) {
344 security_file_free(file); 336 security_file_free(file);
345 file_kill(file); 337 file_sb_list_del(file);
346 file_free(file); 338 file_free(file);
347 } 339 }
348} 340}
349 341
350void file_move(struct file *file, struct list_head *list) 342static inline int file_list_cpu(struct file *file)
351{ 343{
352 if (!list) 344#ifdef CONFIG_SMP
353 return; 345 return file->f_sb_list_cpu;
354 file_list_lock(); 346#else
355 list_move(&file->f_u.fu_list, list); 347 return smp_processor_id();
356 file_list_unlock(); 348#endif
349}
350
351/* helper for file_sb_list_add to reduce ifdefs */
352static inline void __file_sb_list_add(struct file *file, struct super_block *sb)
353{
354 struct list_head *list;
355#ifdef CONFIG_SMP
356 int cpu;
357 cpu = smp_processor_id();
358 file->f_sb_list_cpu = cpu;
359 list = per_cpu_ptr(sb->s_files, cpu);
360#else
361 list = &sb->s_files;
362#endif
363 list_add(&file->f_u.fu_list, list);
357} 364}
358 365
359void file_kill(struct file *file) 366/**
367 * file_sb_list_add - add a file to the sb's file list
368 * @file: file to add
369 * @sb: sb to add it to
370 *
371 * Use this function to associate a file with the superblock of the inode it
372 * refers to.
373 */
374void file_sb_list_add(struct file *file, struct super_block *sb)
375{
376 lg_local_lock(files_lglock);
377 __file_sb_list_add(file, sb);
378 lg_local_unlock(files_lglock);
379}
380
381/**
382 * file_sb_list_del - remove a file from the sb's file list
383 * @file: file to remove
384 * @sb: sb to remove it from
385 *
386 * Use this function to remove a file from its superblock.
387 */
388void file_sb_list_del(struct file *file)
360{ 389{
361 if (!list_empty(&file->f_u.fu_list)) { 390 if (!list_empty(&file->f_u.fu_list)) {
362 file_list_lock(); 391 lg_local_lock_cpu(files_lglock, file_list_cpu(file));
363 list_del_init(&file->f_u.fu_list); 392 list_del_init(&file->f_u.fu_list);
364 file_list_unlock(); 393 lg_local_unlock_cpu(files_lglock, file_list_cpu(file));
365 } 394 }
366} 395}
367 396
397#ifdef CONFIG_SMP
398
399/*
400 * These macros iterate all files on all CPUs for a given superblock.
401 * files_lglock must be held globally.
402 */
403#define do_file_list_for_each_entry(__sb, __file) \
404{ \
405 int i; \
406 for_each_possible_cpu(i) { \
407 struct list_head *list; \
408 list = per_cpu_ptr((__sb)->s_files, i); \
409 list_for_each_entry((__file), list, f_u.fu_list)
410
411#define while_file_list_for_each_entry \
412 } \
413}
414
415#else
416
417#define do_file_list_for_each_entry(__sb, __file) \
418{ \
419 struct list_head *list; \
420 list = &(sb)->s_files; \
421 list_for_each_entry((__file), list, f_u.fu_list)
422
423#define while_file_list_for_each_entry \
424}
425
426#endif
427
368int fs_may_remount_ro(struct super_block *sb) 428int fs_may_remount_ro(struct super_block *sb)
369{ 429{
370 struct file *file; 430 struct file *file;
371
372 /* Check that no files are currently opened for writing. */ 431 /* Check that no files are currently opened for writing. */
373 file_list_lock(); 432 lg_global_lock(files_lglock);
374 list_for_each_entry(file, &sb->s_files, f_u.fu_list) { 433 do_file_list_for_each_entry(sb, file) {
375 struct inode *inode = file->f_path.dentry->d_inode; 434 struct inode *inode = file->f_path.dentry->d_inode;
376 435
377 /* File with pending delete? */ 436 /* File with pending delete? */
@@ -381,11 +440,11 @@ int fs_may_remount_ro(struct super_block *sb)
381 /* Writeable file? */ 440 /* Writeable file? */
382 if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) 441 if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
383 goto too_bad; 442 goto too_bad;
384 } 443 } while_file_list_for_each_entry;
385 file_list_unlock(); 444 lg_global_unlock(files_lglock);
386 return 1; /* Tis' cool bro. */ 445 return 1; /* Tis' cool bro. */
387too_bad: 446too_bad:
388 file_list_unlock(); 447 lg_global_unlock(files_lglock);
389 return 0; 448 return 0;
390} 449}
391 450
@@ -401,8 +460,8 @@ void mark_files_ro(struct super_block *sb)
401 struct file *f; 460 struct file *f;
402 461
403retry: 462retry:
404 file_list_lock(); 463 lg_global_lock(files_lglock);
405 list_for_each_entry(f, &sb->s_files, f_u.fu_list) { 464 do_file_list_for_each_entry(sb, f) {
406 struct vfsmount *mnt; 465 struct vfsmount *mnt;
407 if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) 466 if (!S_ISREG(f->f_path.dentry->d_inode->i_mode))
408 continue; 467 continue;
@@ -417,16 +476,13 @@ retry:
417 continue; 476 continue;
418 file_release_write(f); 477 file_release_write(f);
419 mnt = mntget(f->f_path.mnt); 478 mnt = mntget(f->f_path.mnt);
420 file_list_unlock(); 479 /* This can sleep, so we can't hold the spinlock. */
421 /* 480 lg_global_unlock(files_lglock);
422 * This can sleep, so we can't hold
423 * the file_list_lock() spinlock.
424 */
425 mnt_drop_write(mnt); 481 mnt_drop_write(mnt);
426 mntput(mnt); 482 mntput(mnt);
427 goto retry; 483 goto retry;
428 } 484 } while_file_list_for_each_entry;
429 file_list_unlock(); 485 lg_global_unlock(files_lglock);
430} 486}
431 487
432void __init files_init(unsigned long mempages) 488void __init files_init(unsigned long mempages)
@@ -446,5 +502,6 @@ void __init files_init(unsigned long mempages)
446 if (files_stat.max_files < NR_FILE) 502 if (files_stat.max_files < NR_FILE)
447 files_stat.max_files = NR_FILE; 503 files_stat.max_files = NR_FILE;
448 files_defer_init(); 504 files_defer_init();
505 lg_lock_init(files_lglock);
449 percpu_counter_init(&nr_files, 0); 506 percpu_counter_init(&nr_files, 0);
450} 507}