diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c index 5cff8a92a1bc65..28b6e9e340732a 100644 --- a/fs/aufs/branch.c +++ b/fs/aufs/branch.c @@ -568,23 +568,25 @@ static unsigned long long au_farray_cb(void *a, { 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; } @@ -1273,7 +1275,13 @@ static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) 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; diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c index 24150a8de3dde2..35d4c54d24c101 100644 --- a/fs/aufs/f_op.c +++ b/fs/aufs/f_op.c @@ -35,6 +35,8 @@ int au_do_open_nondir(struct file *file, int flags) au_set_fbstart(file, bindex); au_set_h_fptr(file, bindex, h_file); au_update_figen(file); + finfo->fi_file = file; + au_sphl_add(&finfo->fi_hlist, &au_sbi(dentry->d_sb)->si_files); /* todo: necessary? */ /* file->f_ra = h_file->f_ra; */ } @@ -65,6 +67,7 @@ int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) aufs_bindex_t bindex; finfo = au_fi(file); + au_sphl_del(&finfo->fi_hlist, &au_sbi(file->f_dentry->d_sb)->si_files); bindex = finfo->fi_btop; if (bindex >= 0) au_set_h_fptr(file, bindex, NULL); diff --git a/fs/aufs/file.h b/fs/aufs/file.h index fe4df42966dd5e..2f174140cd386b 100644 --- a/fs/aufs/file.h +++ b/fs/aufs/file.h @@ -48,6 +48,8 @@ struct au_finfo { 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; /* ---------------------------------------------------------------------- */ diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c index 76df5bfdb7131c..f9126b7773c16b 100644 --- a/fs/aufs/sbinfo.c +++ b/fs/aufs/sbinfo.c @@ -105,6 +105,8 @@ int au_si_alloc(struct super_block *sb) 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; diff --git a/fs/aufs/super.h b/fs/aufs/super.h index 310797556a8227..5d696e49b1273d 100644 --- a/fs/aufs/super.h +++ b/fs/aufs/super.h @@ -96,7 +96,8 @@ struct au_sbinfo { } 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; @@ -177,6 +178,9 @@ struct au_sbinfo { spinlock_t si_plink_maint_lock; pid_t si_plink_maint_pid; + /* file list */ + struct au_sphlhead si_files; + /* * sysfs and lifetime management. * this is not a small structure and it may be a waste of memory in case diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c index 95f4c7bed6b0ef..2fe72fc98243c7 100644 --- a/fs/aufs/sysrq.c +++ b/fs/aufs/sysrq.c @@ -17,6 +17,8 @@ static void sysrq_sb(struct super_block *sb) char *plevel; struct au_sbinfo *sbinfo; struct file *file; + struct au_sphlhead *files; + struct au_finfo *finfo; plevel = au_plevel; au_plevel = KERN_WARNING; @@ -73,15 +75,16 @@ static void sysrq_sb(struct super_block *sb) } #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 diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h index 6fc8454a972bc8..1951a36c418c6a 100644 --- a/fs/aufs/vfsub.h +++ b/fs/aufs/vfsub.h @@ -23,37 +23,6 @@ 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 */