diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/file_table.c | 108 | ||||
-rw-r--r-- | fs/super.c | 18 |
2 files changed, 108 insertions, 18 deletions
diff --git a/fs/file_table.c b/fs/file_table.c index 6f0e62ecfddd..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,7 +34,8 @@ struct files_stat_struct files_stat = { | |||
32 | .max_files = NR_FILE | 34 | .max_files = NR_FILE |
33 | }; | 35 | }; |
34 | 36 | ||
35 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); | 37 | DECLARE_LGLOCK(files_lglock); |
38 | DEFINE_LGLOCK(files_lglock); | ||
36 | 39 | ||
37 | /* SLAB cache for file structures */ | 40 | /* SLAB cache for file structures */ |
38 | static struct kmem_cache *filp_cachep __read_mostly; | 41 | static struct kmem_cache *filp_cachep __read_mostly; |
@@ -336,30 +339,98 @@ void put_filp(struct file *file) | |||
336 | } | 339 | } |
337 | } | 340 | } |
338 | 341 | ||
342 | static inline int file_list_cpu(struct file *file) | ||
343 | { | ||
344 | #ifdef CONFIG_SMP | ||
345 | return file->f_sb_list_cpu; | ||
346 | #else | ||
347 | return smp_processor_id(); | ||
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); | ||
364 | } | ||
365 | |||
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 | */ | ||
339 | void file_sb_list_add(struct file *file, struct super_block *sb) | 374 | void file_sb_list_add(struct file *file, struct super_block *sb) |
340 | { | 375 | { |
341 | spin_lock(&files_lock); | 376 | lg_local_lock(files_lglock); |
342 | BUG_ON(!list_empty(&file->f_u.fu_list)); | 377 | __file_sb_list_add(file, sb); |
343 | list_add(&file->f_u.fu_list, &sb->s_files); | 378 | lg_local_unlock(files_lglock); |
344 | spin_unlock(&files_lock); | ||
345 | } | 379 | } |
346 | 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 | */ | ||
347 | void file_sb_list_del(struct file *file) | 388 | void file_sb_list_del(struct file *file) |
348 | { | 389 | { |
349 | if (!list_empty(&file->f_u.fu_list)) { | 390 | if (!list_empty(&file->f_u.fu_list)) { |
350 | spin_lock(&files_lock); | 391 | lg_local_lock_cpu(files_lglock, file_list_cpu(file)); |
351 | list_del_init(&file->f_u.fu_list); | 392 | list_del_init(&file->f_u.fu_list); |
352 | spin_unlock(&files_lock); | 393 | lg_local_unlock_cpu(files_lglock, file_list_cpu(file)); |
353 | } | 394 | } |
354 | } | 395 | } |
355 | 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 | |||
356 | int fs_may_remount_ro(struct super_block *sb) | 428 | int fs_may_remount_ro(struct super_block *sb) |
357 | { | 429 | { |
358 | struct file *file; | 430 | struct file *file; |
359 | |||
360 | /* Check that no files are currently opened for writing. */ | 431 | /* Check that no files are currently opened for writing. */ |
361 | spin_lock(&files_lock); | 432 | lg_global_lock(files_lglock); |
362 | list_for_each_entry(file, &sb->s_files, f_u.fu_list) { | 433 | do_file_list_for_each_entry(sb, file) { |
363 | struct inode *inode = file->f_path.dentry->d_inode; | 434 | struct inode *inode = file->f_path.dentry->d_inode; |
364 | 435 | ||
365 | /* File with pending delete? */ | 436 | /* File with pending delete? */ |
@@ -369,11 +440,11 @@ int fs_may_remount_ro(struct super_block *sb) | |||
369 | /* Writeable file? */ | 440 | /* Writeable file? */ |
370 | if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) | 441 | if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) |
371 | goto too_bad; | 442 | goto too_bad; |
372 | } | 443 | } while_file_list_for_each_entry; |
373 | spin_unlock(&files_lock); | 444 | lg_global_unlock(files_lglock); |
374 | return 1; /* Tis' cool bro. */ | 445 | return 1; /* Tis' cool bro. */ |
375 | too_bad: | 446 | too_bad: |
376 | spin_unlock(&files_lock); | 447 | lg_global_unlock(files_lglock); |
377 | return 0; | 448 | return 0; |
378 | } | 449 | } |
379 | 450 | ||
@@ -389,8 +460,8 @@ void mark_files_ro(struct super_block *sb) | |||
389 | struct file *f; | 460 | struct file *f; |
390 | 461 | ||
391 | retry: | 462 | retry: |
392 | spin_lock(&files_lock); | 463 | lg_global_lock(files_lglock); |
393 | list_for_each_entry(f, &sb->s_files, f_u.fu_list) { | 464 | do_file_list_for_each_entry(sb, f) { |
394 | struct vfsmount *mnt; | 465 | struct vfsmount *mnt; |
395 | if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) | 466 | if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) |
396 | continue; | 467 | continue; |
@@ -406,12 +477,12 @@ retry: | |||
406 | file_release_write(f); | 477 | file_release_write(f); |
407 | mnt = mntget(f->f_path.mnt); | 478 | mnt = mntget(f->f_path.mnt); |
408 | /* This can sleep, so we can't hold the spinlock. */ | 479 | /* This can sleep, so we can't hold the spinlock. */ |
409 | spin_unlock(&files_lock); | 480 | lg_global_unlock(files_lglock); |
410 | mnt_drop_write(mnt); | 481 | mnt_drop_write(mnt); |
411 | mntput(mnt); | 482 | mntput(mnt); |
412 | goto retry; | 483 | goto retry; |
413 | } | 484 | } while_file_list_for_each_entry; |
414 | spin_unlock(&files_lock); | 485 | lg_global_unlock(files_lglock); |
415 | } | 486 | } |
416 | 487 | ||
417 | void __init files_init(unsigned long mempages) | 488 | void __init files_init(unsigned long mempages) |
@@ -431,5 +502,6 @@ void __init files_init(unsigned long mempages) | |||
431 | if (files_stat.max_files < NR_FILE) | 502 | if (files_stat.max_files < NR_FILE) |
432 | files_stat.max_files = NR_FILE; | 503 | files_stat.max_files = NR_FILE; |
433 | files_defer_init(); | 504 | files_defer_init(); |
505 | lg_lock_init(files_lglock); | ||
434 | percpu_counter_init(&nr_files, 0); | 506 | percpu_counter_init(&nr_files, 0); |
435 | } | 507 | } |
diff --git a/fs/super.c b/fs/super.c index 9674ab2c8718..8819e3a7ff20 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -54,7 +54,22 @@ static struct super_block *alloc_super(struct file_system_type *type) | |||
54 | s = NULL; | 54 | s = NULL; |
55 | goto out; | 55 | goto out; |
56 | } | 56 | } |
57 | #ifdef CONFIG_SMP | ||
58 | s->s_files = alloc_percpu(struct list_head); | ||
59 | if (!s->s_files) { | ||
60 | security_sb_free(s); | ||
61 | kfree(s); | ||
62 | s = NULL; | ||
63 | goto out; | ||
64 | } else { | ||
65 | int i; | ||
66 | |||
67 | for_each_possible_cpu(i) | ||
68 | INIT_LIST_HEAD(per_cpu_ptr(s->s_files, i)); | ||
69 | } | ||
70 | #else | ||
57 | INIT_LIST_HEAD(&s->s_files); | 71 | INIT_LIST_HEAD(&s->s_files); |
72 | #endif | ||
58 | INIT_LIST_HEAD(&s->s_instances); | 73 | INIT_LIST_HEAD(&s->s_instances); |
59 | INIT_HLIST_HEAD(&s->s_anon); | 74 | INIT_HLIST_HEAD(&s->s_anon); |
60 | INIT_LIST_HEAD(&s->s_inodes); | 75 | INIT_LIST_HEAD(&s->s_inodes); |
@@ -108,6 +123,9 @@ out: | |||
108 | */ | 123 | */ |
109 | static inline void destroy_super(struct super_block *s) | 124 | static inline void destroy_super(struct super_block *s) |
110 | { | 125 | { |
126 | #ifdef CONFIG_SMP | ||
127 | free_percpu(s->s_files); | ||
128 | #endif | ||
111 | security_sb_free(s); | 129 | security_sb_free(s); |
112 | kfree(s->s_subtype); | 130 | kfree(s->s_subtype); |
113 | kfree(s->s_options); | 131 | kfree(s->s_options); |