diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-13 01:34:18 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-13 01:34:18 -0500 |
commit | 9bc9ccd7db1c9f043f75380b5a5b94912046a60e (patch) | |
tree | dd0a1b3396ae9414f668b0110cc39d11268ad3ed /fs/file_table.c | |
parent | f0230294271f511b41797305b685365a9e569a09 (diff) | |
parent | bdd3536618443809d18868563eeafa63b9d29603 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs updates from Al Viro:
"All kinds of stuff this time around; some more notable parts:
- RCU'd vfsmounts handling
- new primitives for coredump handling
- files_lock is gone
- Bruce's delegations handling series
- exportfs fixes
plus misc stuff all over the place"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (101 commits)
ecryptfs: ->f_op is never NULL
locks: break delegations on any attribute modification
locks: break delegations on link
locks: break delegations on rename
locks: helper functions for delegation breaking
locks: break delegations on unlink
namei: minor vfs_unlink cleanup
locks: implement delegations
locks: introduce new FL_DELEG lock flag
vfs: take i_mutex on renamed file
vfs: rename I_MUTEX_QUOTA now that it's not used for quotas
vfs: don't use PARENT/CHILD lock classes for non-directories
vfs: pull ext4's double-i_mutex-locking into common code
exportfs: fix quadratic behavior in filehandle lookup
exportfs: better variable name
exportfs: move most of reconnect_path to helper function
exportfs: eliminate unused "noprogress" counter
exportfs: stop retrying once we race with rename/remove
exportfs: clear DISCONNECTED on all parents sooner
exportfs: more detailed comment for path_reconnect
...
Diffstat (limited to 'fs/file_table.c')
-rw-r--r-- | fs/file_table.c | 129 |
1 files changed, 2 insertions, 127 deletions
diff --git a/fs/file_table.c b/fs/file_table.c index e900ca518635..5fff9030be34 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
@@ -36,8 +36,6 @@ struct files_stat_struct files_stat = { | |||
36 | .max_files = NR_FILE | 36 | .max_files = NR_FILE |
37 | }; | 37 | }; |
38 | 38 | ||
39 | DEFINE_STATIC_LGLOCK(files_lglock); | ||
40 | |||
41 | /* SLAB cache for file structures */ | 39 | /* SLAB cache for file structures */ |
42 | static struct kmem_cache *filp_cachep __read_mostly; | 40 | static struct kmem_cache *filp_cachep __read_mostly; |
43 | 41 | ||
@@ -134,7 +132,6 @@ struct file *get_empty_filp(void) | |||
134 | return ERR_PTR(error); | 132 | return ERR_PTR(error); |
135 | } | 133 | } |
136 | 134 | ||
137 | INIT_LIST_HEAD(&f->f_u.fu_list); | ||
138 | atomic_long_set(&f->f_count, 1); | 135 | atomic_long_set(&f->f_count, 1); |
139 | rwlock_init(&f->f_owner.lock); | 136 | rwlock_init(&f->f_owner.lock); |
140 | spin_lock_init(&f->f_lock); | 137 | spin_lock_init(&f->f_lock); |
@@ -240,11 +237,11 @@ static void __fput(struct file *file) | |||
240 | locks_remove_flock(file); | 237 | locks_remove_flock(file); |
241 | 238 | ||
242 | if (unlikely(file->f_flags & FASYNC)) { | 239 | if (unlikely(file->f_flags & FASYNC)) { |
243 | if (file->f_op && file->f_op->fasync) | 240 | if (file->f_op->fasync) |
244 | file->f_op->fasync(-1, file, 0); | 241 | file->f_op->fasync(-1, file, 0); |
245 | } | 242 | } |
246 | ima_file_free(file); | 243 | ima_file_free(file); |
247 | if (file->f_op && file->f_op->release) | 244 | if (file->f_op->release) |
248 | file->f_op->release(inode, file); | 245 | file->f_op->release(inode, file); |
249 | security_file_free(file); | 246 | security_file_free(file); |
250 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL && | 247 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL && |
@@ -304,7 +301,6 @@ void fput(struct file *file) | |||
304 | if (atomic_long_dec_and_test(&file->f_count)) { | 301 | if (atomic_long_dec_and_test(&file->f_count)) { |
305 | struct task_struct *task = current; | 302 | struct task_struct *task = current; |
306 | 303 | ||
307 | file_sb_list_del(file); | ||
308 | if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) { | 304 | if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) { |
309 | init_task_work(&file->f_u.fu_rcuhead, ____fput); | 305 | init_task_work(&file->f_u.fu_rcuhead, ____fput); |
310 | if (!task_work_add(task, &file->f_u.fu_rcuhead, true)) | 306 | if (!task_work_add(task, &file->f_u.fu_rcuhead, true)) |
@@ -333,7 +329,6 @@ void __fput_sync(struct file *file) | |||
333 | { | 329 | { |
334 | if (atomic_long_dec_and_test(&file->f_count)) { | 330 | if (atomic_long_dec_and_test(&file->f_count)) { |
335 | struct task_struct *task = current; | 331 | struct task_struct *task = current; |
336 | file_sb_list_del(file); | ||
337 | BUG_ON(!(task->flags & PF_KTHREAD)); | 332 | BUG_ON(!(task->flags & PF_KTHREAD)); |
338 | __fput(file); | 333 | __fput(file); |
339 | } | 334 | } |
@@ -345,129 +340,10 @@ void put_filp(struct file *file) | |||
345 | { | 340 | { |
346 | if (atomic_long_dec_and_test(&file->f_count)) { | 341 | if (atomic_long_dec_and_test(&file->f_count)) { |
347 | security_file_free(file); | 342 | security_file_free(file); |
348 | file_sb_list_del(file); | ||
349 | file_free(file); | 343 | file_free(file); |
350 | } | 344 | } |
351 | } | 345 | } |
352 | 346 | ||
353 | static inline int file_list_cpu(struct file *file) | ||
354 | { | ||
355 | #ifdef CONFIG_SMP | ||
356 | return file->f_sb_list_cpu; | ||
357 | #else | ||
358 | return smp_processor_id(); | ||
359 | #endif | ||
360 | } | ||
361 | |||
362 | /* helper for file_sb_list_add to reduce ifdefs */ | ||
363 | static inline void __file_sb_list_add(struct file *file, struct super_block *sb) | ||
364 | { | ||
365 | struct list_head *list; | ||
366 | #ifdef CONFIG_SMP | ||
367 | int cpu; | ||
368 | cpu = smp_processor_id(); | ||
369 | file->f_sb_list_cpu = cpu; | ||
370 | list = per_cpu_ptr(sb->s_files, cpu); | ||
371 | #else | ||
372 | list = &sb->s_files; | ||
373 | #endif | ||
374 | list_add(&file->f_u.fu_list, list); | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * file_sb_list_add - add a file to the sb's file list | ||
379 | * @file: file to add | ||
380 | * @sb: sb to add it to | ||
381 | * | ||
382 | * Use this function to associate a file with the superblock of the inode it | ||
383 | * refers to. | ||
384 | */ | ||
385 | void file_sb_list_add(struct file *file, struct super_block *sb) | ||
386 | { | ||
387 | if (likely(!(file->f_mode & FMODE_WRITE))) | ||
388 | return; | ||
389 | if (!S_ISREG(file_inode(file)->i_mode)) | ||
390 | return; | ||
391 | lg_local_lock(&files_lglock); | ||
392 | __file_sb_list_add(file, sb); | ||
393 | lg_local_unlock(&files_lglock); | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * file_sb_list_del - remove a file from the sb's file list | ||
398 | * @file: file to remove | ||
399 | * @sb: sb to remove it from | ||
400 | * | ||
401 | * Use this function to remove a file from its superblock. | ||
402 | */ | ||
403 | void file_sb_list_del(struct file *file) | ||
404 | { | ||
405 | if (!list_empty(&file->f_u.fu_list)) { | ||
406 | lg_local_lock_cpu(&files_lglock, file_list_cpu(file)); | ||
407 | list_del_init(&file->f_u.fu_list); | ||
408 | lg_local_unlock_cpu(&files_lglock, file_list_cpu(file)); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | #ifdef CONFIG_SMP | ||
413 | |||
414 | /* | ||
415 | * These macros iterate all files on all CPUs for a given superblock. | ||
416 | * files_lglock must be held globally. | ||
417 | */ | ||
418 | #define do_file_list_for_each_entry(__sb, __file) \ | ||
419 | { \ | ||
420 | int i; \ | ||
421 | for_each_possible_cpu(i) { \ | ||
422 | struct list_head *list; \ | ||
423 | list = per_cpu_ptr((__sb)->s_files, i); \ | ||
424 | list_for_each_entry((__file), list, f_u.fu_list) | ||
425 | |||
426 | #define while_file_list_for_each_entry \ | ||
427 | } \ | ||
428 | } | ||
429 | |||
430 | #else | ||
431 | |||
432 | #define do_file_list_for_each_entry(__sb, __file) \ | ||
433 | { \ | ||
434 | struct list_head *list; \ | ||
435 | list = &(sb)->s_files; \ | ||
436 | list_for_each_entry((__file), list, f_u.fu_list) | ||
437 | |||
438 | #define while_file_list_for_each_entry \ | ||
439 | } | ||
440 | |||
441 | #endif | ||
442 | |||
443 | /** | ||
444 | * mark_files_ro - mark all files read-only | ||
445 | * @sb: superblock in question | ||
446 | * | ||
447 | * All files are marked read-only. We don't care about pending | ||
448 | * delete files so this should be used in 'force' mode only. | ||
449 | */ | ||
450 | void mark_files_ro(struct super_block *sb) | ||
451 | { | ||
452 | struct file *f; | ||
453 | |||
454 | lg_global_lock(&files_lglock); | ||
455 | do_file_list_for_each_entry(sb, f) { | ||
456 | if (!file_count(f)) | ||
457 | continue; | ||
458 | if (!(f->f_mode & FMODE_WRITE)) | ||
459 | continue; | ||
460 | spin_lock(&f->f_lock); | ||
461 | f->f_mode &= ~FMODE_WRITE; | ||
462 | spin_unlock(&f->f_lock); | ||
463 | if (file_check_writeable(f) != 0) | ||
464 | continue; | ||
465 | __mnt_drop_write(f->f_path.mnt); | ||
466 | file_release_write(f); | ||
467 | } while_file_list_for_each_entry; | ||
468 | lg_global_unlock(&files_lglock); | ||
469 | } | ||
470 | |||
471 | void __init files_init(unsigned long mempages) | 347 | void __init files_init(unsigned long mempages) |
472 | { | 348 | { |
473 | unsigned long n; | 349 | unsigned long n; |
@@ -483,6 +359,5 @@ void __init files_init(unsigned long mempages) | |||
483 | n = (mempages * (PAGE_SIZE / 1024)) / 10; | 359 | n = (mempages * (PAGE_SIZE / 1024)) / 10; |
484 | files_stat.max_files = max_t(unsigned long, n, NR_FILE); | 360 | files_stat.max_files = max_t(unsigned long, n, NR_FILE); |
485 | files_defer_init(); | 361 | files_defer_init(); |
486 | lg_lock_init(&files_lglock, "files_lglock"); | ||
487 | percpu_counter_init(&nr_files, 0); | 362 | percpu_counter_init(&nr_files, 0); |
488 | } | 363 | } |