diff options
Diffstat (limited to 'fs/file_table.c')
| -rw-r--r-- | fs/file_table.c | 124 |
1 files changed, 95 insertions, 29 deletions
diff --git a/fs/file_table.c b/fs/file_table.c index edecd36fed9b..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! */ | 37 | DECLARE_LGLOCK(files_lglock); |
| 36 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); | 38 | DEFINE_LGLOCK(files_lglock); |
| 37 | 39 | ||
| 38 | /* SLAB cache for file structures */ | 40 | /* SLAB cache for file structures */ |
| 39 | static struct kmem_cache *filp_cachep __read_mostly; | 41 | static struct kmem_cache *filp_cachep __read_mostly; |
| @@ -249,7 +251,7 @@ static void __fput(struct file *file) | |||
| 249 | cdev_put(inode->i_cdev); | 251 | cdev_put(inode->i_cdev); |
| 250 | fops_put(file->f_op); | 252 | fops_put(file->f_op); |
| 251 | put_pid(file->f_owner.pid); | 253 | put_pid(file->f_owner.pid); |
| 252 | file_kill(file); | 254 | file_sb_list_del(file); |
| 253 | if (file->f_mode & FMODE_WRITE) | 255 | if (file->f_mode & FMODE_WRITE) |
| 254 | drop_file_write_access(file); | 256 | drop_file_write_access(file); |
| 255 | file->f_path.dentry = NULL; | 257 | file->f_path.dentry = NULL; |
| @@ -328,41 +330,107 @@ struct file *fget_light(unsigned int fd, int *fput_needed) | |||
| 328 | return file; | 330 | return file; |
| 329 | } | 331 | } |
| 330 | 332 | ||
| 331 | |||
| 332 | void put_filp(struct file *file) | 333 | void put_filp(struct file *file) |
| 333 | { | 334 | { |
| 334 | if (atomic_long_dec_and_test(&file->f_count)) { | 335 | if (atomic_long_dec_and_test(&file->f_count)) { |
| 335 | security_file_free(file); | 336 | security_file_free(file); |
| 336 | file_kill(file); | 337 | file_sb_list_del(file); |
| 337 | file_free(file); | 338 | file_free(file); |
| 338 | } | 339 | } |
| 339 | } | 340 | } |
| 340 | 341 | ||
| 341 | void file_move(struct file *file, struct list_head *list) | 342 | static inline int file_list_cpu(struct file *file) |
| 342 | { | 343 | { |
| 343 | if (!list) | 344 | #ifdef CONFIG_SMP |
| 344 | return; | 345 | return file->f_sb_list_cpu; |
| 345 | file_list_lock(); | 346 | #else |
| 346 | list_move(&file->f_u.fu_list, list); | 347 | return smp_processor_id(); |
| 347 | file_list_unlock(); | 348 | #endif |
| 349 | } | ||
| 350 | |||
| 351 | /* helper for file_sb_list_add to reduce ifdefs */ | ||
| 352 | static 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); | ||
| 348 | } | 364 | } |
| 349 | 365 | ||
| 350 | void 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 | */ | ||
| 374 | void 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 | */ | ||
| 388 | void file_sb_list_del(struct file *file) | ||
| 351 | { | 389 | { |
| 352 | if (!list_empty(&file->f_u.fu_list)) { | 390 | if (!list_empty(&file->f_u.fu_list)) { |
| 353 | file_list_lock(); | 391 | lg_local_lock_cpu(files_lglock, file_list_cpu(file)); |
| 354 | list_del_init(&file->f_u.fu_list); | 392 | list_del_init(&file->f_u.fu_list); |
| 355 | file_list_unlock(); | 393 | lg_local_unlock_cpu(files_lglock, file_list_cpu(file)); |
| 356 | } | 394 | } |
| 357 | } | 395 | } |
| 358 | 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 | |||
| 359 | int fs_may_remount_ro(struct super_block *sb) | 428 | int fs_may_remount_ro(struct super_block *sb) |
| 360 | { | 429 | { |
| 361 | struct file *file; | 430 | struct file *file; |
| 362 | |||
| 363 | /* Check that no files are currently opened for writing. */ | 431 | /* Check that no files are currently opened for writing. */ |
| 364 | file_list_lock(); | 432 | lg_global_lock(files_lglock); |
| 365 | list_for_each_entry(file, &sb->s_files, f_u.fu_list) { | 433 | do_file_list_for_each_entry(sb, file) { |
| 366 | struct inode *inode = file->f_path.dentry->d_inode; | 434 | struct inode *inode = file->f_path.dentry->d_inode; |
| 367 | 435 | ||
| 368 | /* File with pending delete? */ | 436 | /* File with pending delete? */ |
| @@ -372,11 +440,11 @@ int fs_may_remount_ro(struct super_block *sb) | |||
| 372 | /* Writeable file? */ | 440 | /* Writeable file? */ |
| 373 | if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) | 441 | if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) |
| 374 | goto too_bad; | 442 | goto too_bad; |
| 375 | } | 443 | } while_file_list_for_each_entry; |
| 376 | file_list_unlock(); | 444 | lg_global_unlock(files_lglock); |
| 377 | return 1; /* Tis' cool bro. */ | 445 | return 1; /* Tis' cool bro. */ |
| 378 | too_bad: | 446 | too_bad: |
| 379 | file_list_unlock(); | 447 | lg_global_unlock(files_lglock); |
| 380 | return 0; | 448 | return 0; |
| 381 | } | 449 | } |
| 382 | 450 | ||
| @@ -392,8 +460,8 @@ void mark_files_ro(struct super_block *sb) | |||
| 392 | struct file *f; | 460 | struct file *f; |
| 393 | 461 | ||
| 394 | retry: | 462 | retry: |
| 395 | file_list_lock(); | 463 | lg_global_lock(files_lglock); |
| 396 | list_for_each_entry(f, &sb->s_files, f_u.fu_list) { | 464 | do_file_list_for_each_entry(sb, f) { |
| 397 | struct vfsmount *mnt; | 465 | struct vfsmount *mnt; |
| 398 | if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) | 466 | if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) |
| 399 | continue; | 467 | continue; |
| @@ -408,16 +476,13 @@ retry: | |||
| 408 | continue; | 476 | continue; |
| 409 | file_release_write(f); | 477 | file_release_write(f); |
| 410 | mnt = mntget(f->f_path.mnt); | 478 | mnt = mntget(f->f_path.mnt); |
| 411 | file_list_unlock(); | 479 | /* This can sleep, so we can't hold the spinlock. */ |
| 412 | /* | 480 | lg_global_unlock(files_lglock); |
| 413 | * This can sleep, so we can't hold | ||
| 414 | * the file_list_lock() spinlock. | ||
| 415 | */ | ||
| 416 | mnt_drop_write(mnt); | 481 | mnt_drop_write(mnt); |
| 417 | mntput(mnt); | 482 | mntput(mnt); |
| 418 | goto retry; | 483 | goto retry; |
| 419 | } | 484 | } while_file_list_for_each_entry; |
| 420 | file_list_unlock(); | 485 | lg_global_unlock(files_lglock); |
| 421 | } | 486 | } |
| 422 | 487 | ||
| 423 | void __init files_init(unsigned long mempages) | 488 | void __init files_init(unsigned long mempages) |
| @@ -437,5 +502,6 @@ void __init files_init(unsigned long mempages) | |||
| 437 | if (files_stat.max_files < NR_FILE) | 502 | if (files_stat.max_files < NR_FILE) |
| 438 | files_stat.max_files = NR_FILE; | 503 | files_stat.max_files = NR_FILE; |
| 439 | files_defer_init(); | 504 | files_defer_init(); |
| 505 | lg_lock_init(files_lglock); | ||
| 440 | percpu_counter_init(&nr_files, 0); | 506 | percpu_counter_init(&nr_files, 0); |
| 441 | } | 507 | } |
