--- a/fs/aufs/branch.c +++ b/fs/aufs/branch.c @@ -571,22 +571,25 @@ { unsigned long long n; struct file **p, *f; + struct au_sphlhead *files; + struct au_finfo *finfo; struct super_block *sb = arg; n = 0; p = a; - lg_global_lock(&files_lglock); - do_file_list_for_each_entry(sb, f) { - if (au_fi(f) - && file_count(f) + files = &au_sbi(sb)->si_files; + spin_lock(&files->spin); + hlist_for_each_entry(finfo, &files->head, fi_hlist) { + f = finfo->fi_file; + if (file_count(f) && !special_file(file_inode(f)->i_mode)) { get_file(f); *p++ = f; n++; AuDebugOn(n > max); } - } while_file_list_for_each_entry; - lg_global_unlock(&files_lglock); + } + spin_unlock(&files->spin); return n; } @@ -1240,7 +1243,13 @@ continue; /* todo: already flushed? */ - /* cf. fs/super.c:mark_files_ro() */ + /* + * fs/super.c:mark_files_ro() is gone, but aufs keeps its + * approach which resets f_mode and calls mnt_drop_write() and + * file_release_write() for each file, because the branch + * attribute in aufs world is totally different from the native + * fs rw/ro mode. + */ /* fi_read_lock(file); */ hfile = &au_fi(file)->fi_htop; hf = hfile->hf_file; --- a/fs/aufs/file.h +++ b/fs/aufs/file.h @@ -61,6 +61,9 @@ atomic_t fi_mmapped; }; struct au_fidir *fi_hdir; /* for dir only */ + + struct hlist_node fi_hlist; + struct file *fi_file; /* very ugly */ } ____cacheline_aligned_in_smp; /* ---------------------------------------------------------------------- */ --- a/fs/aufs/sbinfo.c +++ b/fs/aufs/sbinfo.c @@ -118,6 +118,8 @@ init_waitqueue_head(&sbinfo->si_plink_wq); spin_lock_init(&sbinfo->si_plink_maint_lock); + au_sphl_init(&sbinfo->si_files); + /* leave other members for sysaufs and si_mnt. */ sbinfo->si_sb = sb; sb->s_fs_info = sbinfo; --- a/fs/aufs/super.h +++ b/fs/aufs/super.h @@ -108,7 +108,8 @@ } au_si_pid; /* - * dirty approach to protect sb->sb_inodes and ->s_files from remount. + * dirty approach to protect sb->sb_inodes and ->s_files (gone) from + * remount. */ atomic_long_t si_ninodes, si_nfiles; @@ -188,6 +189,9 @@ wait_queue_head_t si_plink_wq; spinlock_t si_plink_maint_lock; pid_t si_plink_maint_pid; + + /* file list */ + struct au_sphlhead si_files; /* * sysfs and lifetime management. --- a/fs/aufs/sysrq.c +++ b/fs/aufs/sysrq.c @@ -30,6 +30,8 @@ char *plevel; struct au_sbinfo *sbinfo; struct file *file; + struct au_sphlhead *files; + struct au_finfo *finfo; plevel = au_plevel; au_plevel = KERN_WARNING; @@ -86,15 +88,17 @@ } #endif pr("files\n"); - lg_global_lock(&files_lglock); - do_file_list_for_each_entry(sb, file) { + files = &au_sbi(sb)->si_files; + spin_lock(&files->spin); + hlist_for_each_entry(finfo, &files->head, fi_hlist) { umode_t mode; + file = finfo->fi_file; mode = file_inode(file)->i_mode; if (!special_file(mode)) au_dpri_file(file); - } while_file_list_for_each_entry; - lg_global_unlock(&files_lglock); + } + spin_unlock(&files->spin); pr("done\n"); #undef pr --- a/fs/aufs/vfsub.h +++ b/fs/aufs/vfsub.h @@ -32,7 +32,6 @@ /* copied from linux/fs/internal.h */ /* todo: BAD approach!! */ -extern struct lglock vfsmount_lock; extern void __mnt_drop_write(struct vfsmount *); extern spinlock_t inode_sb_list_lock; -/* copied from linux/fs/file_table.c */ -extern struct lglock files_lglock; -#ifdef CONFIG_SMP -/* - * These macros iterate all files on all CPUs for a given superblock. - * files_lglock must be held globally. - */ -#define do_file_list_for_each_entry(__sb, __file) \ -{ \ - int i; \ - for_each_possible_cpu(i) { \ - struct list_head *list; \ - list = per_cpu_ptr((__sb)->s_files, i); \ - list_for_each_entry((__file), list, f_u.fu_list) - -#define while_file_list_for_each_entry \ - } \ -} - -#else - -#define do_file_list_for_each_entry(__sb, __file) \ -{ \ - struct list_head *list; \ - list = &(sb)->s_files; \ - list_for_each_entry((__file), list, f_u.fu_list) - -#define while_file_list_for_each_entry \ -} -#endif - -/* ---------------------------------------------------------------------- */ - /* lock subclass for lower inode */ /* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ /* reduce? gave up. */ --- a/fs/aufs/export.c +++ b/fs/aufs/export.c @@ -301,9 +301,9 @@ }; get_fs_root(current->fs, &root); - br_read_lock(&vfsmount_lock); + rcu_read_lock(); err = iterate_mounts(au_compare_mnt, &args, root.mnt); - br_read_unlock(&vfsmount_lock); + rcu_read_unlock(); path_put(&root); AuDebugOn(!err); AuDebugOn(!args.mnt); --- a/fs/aufs/dcsub.c +++ b/fs/aufs/dcsub.c @@ -197,7 +197,7 @@ goto out; /* - * vfsmount_lock is unnecessary since this is a traverse in a single + * RCU for vfsmount is unnecessary since this is a traverse in a single * mount */ while (!IS_ROOT(dentry)) {