From 8033426e6bdb2690d302872ac1e1fadaec1a5581 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 26 Jul 2013 06:23:25 -0400 Subject: vfs: allow umount to handle mountpoints without revalidating them Christopher reported a regression where he was unable to unmount a NFS filesystem where the root had gone stale. The problem is that d_revalidate handles the root of the filesystem differently from other dentries, but d_weak_revalidate does not. We could simply fix this by making d_weak_revalidate return success on IS_ROOT dentries, but there are cases where we do want to revalidate the root of the fs. A umount is really a special case. We generally aren't interested in anything but the dentry and vfsmount that's attached at that point. If the inode turns out to be stale we just don't care since the intent is to stop using it anyway. Try to handle this situation better by treating umount as a special case in the lookup code. Have it resolve the parent using normal means, and then do a lookup of the final dentry without revalidating it. In most cases, the final lookup will come out of the dcache, but the case where there's a trailing symlink or !LAST_NORM entry on the end complicates things a bit. Cc: Neil Brown Reported-by: Christopher T Vogan Signed-off-by: Jeff Layton Signed-off-by: Al Viro --- include/linux/namei.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/namei.h b/include/linux/namei.h index 5a5ff57ceed4..cd09751c71a0 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -58,6 +58,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; extern int user_path_at(int, const char __user *, unsigned, struct path *); extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty); +extern int user_path_umountat(int, const char __user *, unsigned int, struct path *); #define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path) #define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path) -- cgit v1.2.3 From badcf2b7b816130a60152d9f5a06705176596925 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Jul 2013 18:15:46 +0400 Subject: constify touch_atime() Signed-off-by: Al Viro --- fs/inode.c | 2 +- include/linux/fs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/fs/inode.c b/fs/inode.c index d6dfb09c8280..93a0625b46e4 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1525,7 +1525,7 @@ static int update_time(struct inode *inode, struct timespec *time, int flags) * This function automatically handles read only file systems and media, * as well as the "noatime" flag and inode specific "noatime" markers. */ -void touch_atime(struct path *path) +void touch_atime(const struct path *path) { struct vfsmount *mnt = path->mnt; struct inode *inode = path->dentry->d_inode; diff --git a/include/linux/fs.h b/include/linux/fs.h index 981874773e85..65c9929cd340 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1804,7 +1804,7 @@ enum file_time_flags { S_VERSION = 8, }; -extern void touch_atime(struct path *); +extern void touch_atime(const struct path *); static inline void file_accessed(struct file *file) { if (!(file->f_flags & O_NOATIME)) -- cgit v1.2.3 From ef7bca1456e7f65e66b9466c3b149601fe32eec0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jul 2013 15:52:42 +0400 Subject: oprofile: don't bother with passing superblock to ->create_files() Signed-off-by: Al Viro --- arch/alpha/oprofile/common.c | 22 +++++++++++----------- arch/avr32/oprofile/op_model_avr32.c | 17 ++++++++--------- arch/mips/oprofile/common.c | 20 ++++++++++---------- arch/powerpc/oprofile/common.c | 28 ++++++++++++++-------------- arch/s390/oprofile/init.c | 35 +++++++++++++++++------------------ arch/x86/oprofile/nmi_int.c | 18 +++++++++--------- arch/x86/oprofile/op_model_amd.c | 24 ++++++++++++------------ drivers/oprofile/oprofile_files.c | 2 +- drivers/oprofile/oprofile_perf.c | 16 ++++++++-------- include/linux/oprofile.h | 2 +- 10 files changed, 91 insertions(+), 93 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/oprofile/common.c b/arch/alpha/oprofile/common.c index b8ce18f485d3..d79bf68caee2 100644 --- a/arch/alpha/oprofile/common.c +++ b/arch/alpha/oprofile/common.c @@ -106,7 +106,7 @@ op_axp_stop(void) } static int -op_axp_create_files(struct super_block *sb, struct dentry *root) +op_axp_create_files(struct dentry *root) { int i; @@ -115,23 +115,23 @@ op_axp_create_files(struct super_block *sb, struct dentry *root) char buf[4]; snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(sb, root, buf); + dir = oprofilefs_mkdir(root->d_sb, root, buf); - oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); - oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); - oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); + oprofilefs_create_ulong(root->d_sb, dir, "enabled", &ctr[i].enabled); + oprofilefs_create_ulong(root->d_sb, dir, "event", &ctr[i].event); + oprofilefs_create_ulong(root->d_sb, dir, "count", &ctr[i].count); /* Dummies. */ - oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); - oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); - oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); + oprofilefs_create_ulong(root->d_sb, dir, "kernel", &ctr[i].kernel); + oprofilefs_create_ulong(root->d_sb, dir, "user", &ctr[i].user); + oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", &ctr[i].unit_mask); } if (model->can_set_proc_mode) { - oprofilefs_create_ulong(sb, root, "enable_pal", + oprofilefs_create_ulong(root->d_sb, root, "enable_pal", &sys.enable_pal); - oprofilefs_create_ulong(sb, root, "enable_kernel", + oprofilefs_create_ulong(root->d_sb, root, "enable_kernel", &sys.enable_kernel); - oprofilefs_create_ulong(sb, root, "enable_user", + oprofilefs_create_ulong(root->d_sb, root, "enable_user", &sys.enable_user); } diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c index f74b7809e089..80a06158da82 100644 --- a/arch/avr32/oprofile/op_model_avr32.c +++ b/arch/avr32/oprofile/op_model_avr32.c @@ -97,8 +97,7 @@ static irqreturn_t avr32_perf_counter_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int avr32_perf_counter_create_files(struct super_block *sb, - struct dentry *root) +static int avr32_perf_counter_create_files(struct dentry *root) { struct dentry *dir; unsigned int i; @@ -106,21 +105,21 @@ static int avr32_perf_counter_create_files(struct super_block *sb, for (i = 0; i < NR_counter; i++) { snprintf(filename, sizeof(filename), "%u", i); - dir = oprofilefs_mkdir(sb, root, filename); + dir = oprofilefs_mkdir(root->d_sb, root, filename); - oprofilefs_create_ulong(sb, dir, "enabled", + oprofilefs_create_ulong(root->d_sb, dir, "enabled", &counter[i].enabled); - oprofilefs_create_ulong(sb, dir, "event", + oprofilefs_create_ulong(root->d_sb, dir, "event", &counter[i].event); - oprofilefs_create_ulong(sb, dir, "count", + oprofilefs_create_ulong(root->d_sb, dir, "count", &counter[i].count); /* Dummy entries */ - oprofilefs_create_ulong(sb, dir, "kernel", + oprofilefs_create_ulong(root->d_sb, dir, "kernel", &counter[i].kernel); - oprofilefs_create_ulong(sb, dir, "user", + oprofilefs_create_ulong(root->d_sb, dir, "user", &counter[i].user); - oprofilefs_create_ulong(sb, dir, "unit_mask", + oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", &counter[i].unit_mask); } diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index af763e838fdd..7439ae2df05c 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -33,7 +33,7 @@ static int op_mips_setup(void) return 0; } -static int op_mips_create_files(struct super_block *sb, struct dentry *root) +static int op_mips_create_files(struct dentry *root) { int i; @@ -42,16 +42,16 @@ static int op_mips_create_files(struct super_block *sb, struct dentry *root) char buf[4]; snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(sb, root, buf); - - oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); - oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); - oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); - oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); - oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); - oprofilefs_create_ulong(sb, dir, "exl", &ctr[i].exl); + dir = oprofilefs_mkdir(root->d_sb, root, buf); + + oprofilefs_create_ulong(root->d_sb, dir, "enabled", &ctr[i].enabled); + oprofilefs_create_ulong(root->d_sb, dir, "event", &ctr[i].event); + oprofilefs_create_ulong(root->d_sb, dir, "count", &ctr[i].count); + oprofilefs_create_ulong(root->d_sb, dir, "kernel", &ctr[i].kernel); + oprofilefs_create_ulong(root->d_sb, dir, "user", &ctr[i].user); + oprofilefs_create_ulong(root->d_sb, dir, "exl", &ctr[i].exl); /* Dummy. */ - oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); + oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", &ctr[i].unit_mask); } return 0; diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index 4f51025f5b00..addc62317f45 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -119,7 +119,7 @@ static void op_powerpc_stop(void) model->global_stop(); } -static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) +static int op_powerpc_create_files(struct dentry *root) { int i; @@ -128,9 +128,9 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) * There is one mmcr0, mmcr1 and mmcra for setting the events for * all of the counters. */ - oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0); - oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1); - oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra); + oprofilefs_create_ulong(root->d_sb, root, "mmcr0", &sys.mmcr0); + oprofilefs_create_ulong(root->d_sb, root, "mmcr1", &sys.mmcr1); + oprofilefs_create_ulong(root->d_sb, root, "mmcra", &sys.mmcra); #ifdef CONFIG_OPROFILE_CELL /* create a file the user tool can check to see what level of profiling * support exits with this kernel. Initialize bit mask to indicate @@ -142,7 +142,7 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) * If the file does not exist, then the kernel only supports SPU * cycle profiling, PPU event and cycle profiling. */ - oprofilefs_create_ulong(sb, root, "cell_support", &sys.cell_support); + oprofilefs_create_ulong(root->d_sb, root, "cell_support", &sys.cell_support); sys.cell_support = 0x1; /* Note, the user OProfile tool must check * that this bit is set before attempting to * user SPU event profiling. Older kernels @@ -160,11 +160,11 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) char buf[4]; snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(sb, root, buf); + dir = oprofilefs_mkdir(root->d_sb, root, buf); - oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); - oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); - oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); + oprofilefs_create_ulong(root->d_sb, dir, "enabled", &ctr[i].enabled); + oprofilefs_create_ulong(root->d_sb, dir, "event", &ctr[i].event); + oprofilefs_create_ulong(root->d_sb, dir, "count", &ctr[i].count); /* * Classic PowerPC doesn't support per-counter @@ -173,14 +173,14 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) * Book-E style performance monitors, we do * support them. */ - oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); - oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); + oprofilefs_create_ulong(root->d_sb, dir, "kernel", &ctr[i].kernel); + oprofilefs_create_ulong(root->d_sb, dir, "user", &ctr[i].user); - oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); + oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", &ctr[i].unit_mask); } - oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel); - oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user); + oprofilefs_create_ulong(root->d_sb, root, "enable_kernel", &sys.enable_kernel); + oprofilefs_create_ulong(root->d_sb, root, "enable_user", &sys.enable_user); /* Default to tracing both kernel and user */ sys.enable_kernel = 1; diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index 930783d2c99b..712d57bb783a 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c @@ -346,16 +346,15 @@ static const struct file_operations timer_enabled_fops = { }; -static int oprofile_create_hwsampling_files(struct super_block *sb, - struct dentry *root) +static int oprofile_create_hwsampling_files(struct dentry *root) { struct dentry *dir; - dir = oprofilefs_mkdir(sb, root, "timer"); + dir = oprofilefs_mkdir(root->d_sb, root, "timer"); if (!dir) return -EINVAL; - oprofilefs_create_file(sb, dir, "enabled", &timer_enabled_fops); + oprofilefs_create_file(root->d_sb, dir, "enabled", &timer_enabled_fops); if (!hwsampler_available) return 0; @@ -376,17 +375,17 @@ static int oprofile_create_hwsampling_files(struct super_block *sb, * and can only be set to 0. */ - dir = oprofilefs_mkdir(sb, root, "0"); + dir = oprofilefs_mkdir(root->d_sb, root, "0"); if (!dir) return -EINVAL; - oprofilefs_create_file(sb, dir, "enabled", &hwsampler_fops); - oprofilefs_create_file(sb, dir, "event", &zero_fops); - oprofilefs_create_file(sb, dir, "count", &hw_interval_fops); - oprofilefs_create_file(sb, dir, "unit_mask", &zero_fops); - oprofilefs_create_file(sb, dir, "kernel", &kernel_fops); - oprofilefs_create_file(sb, dir, "user", &user_fops); - oprofilefs_create_ulong(sb, dir, "hw_sdbt_blocks", + oprofilefs_create_file(root->d_sb, dir, "enabled", &hwsampler_fops); + oprofilefs_create_file(root->d_sb, dir, "event", &zero_fops); + oprofilefs_create_file(root->d_sb, dir, "count", &hw_interval_fops); + oprofilefs_create_file(root->d_sb, dir, "unit_mask", &zero_fops); + oprofilefs_create_file(root->d_sb, dir, "kernel", &kernel_fops); + oprofilefs_create_file(root->d_sb, dir, "user", &user_fops); + oprofilefs_create_ulong(root->d_sb, dir, "hw_sdbt_blocks", &oprofile_sdbt_blocks); } else { @@ -396,19 +395,19 @@ static int oprofile_create_hwsampling_files(struct super_block *sb, * space tools. The /dev/oprofile/hwsampling fs is * provided in that case. */ - dir = oprofilefs_mkdir(sb, root, "hwsampling"); + dir = oprofilefs_mkdir(root->d_sb, root, "hwsampling"); if (!dir) return -EINVAL; - oprofilefs_create_file(sb, dir, "hwsampler", + oprofilefs_create_file(root->d_sb, dir, "hwsampler", &hwsampler_fops); - oprofilefs_create_file(sb, dir, "hw_interval", + oprofilefs_create_file(root->d_sb, dir, "hw_interval", &hw_interval_fops); - oprofilefs_create_ro_ulong(sb, dir, "hw_min_interval", + oprofilefs_create_ro_ulong(root->d_sb, dir, "hw_min_interval", &oprofile_min_interval); - oprofilefs_create_ro_ulong(sb, dir, "hw_max_interval", + oprofilefs_create_ro_ulong(root->d_sb, dir, "hw_max_interval", &oprofile_max_interval); - oprofilefs_create_ulong(sb, dir, "hw_sdbt_blocks", + oprofilefs_create_ulong(root->d_sb, dir, "hw_sdbt_blocks", &oprofile_sdbt_blocks); } return 0; diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 48768df2471a..483f02b8c1a8 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -403,7 +403,7 @@ static void nmi_cpu_down(void *dummy) nmi_cpu_shutdown(dummy); } -static int nmi_create_files(struct super_block *sb, struct dentry *root) +static int nmi_create_files(struct dentry *root) { unsigned int i; @@ -420,14 +420,14 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) continue; snprintf(buf, sizeof(buf), "%d", i); - dir = oprofilefs_mkdir(sb, root, buf); - oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); - oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event); - oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count); - oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask); - oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel); - oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user); - oprofilefs_create_ulong(sb, dir, "extra", &counter_config[i].extra); + dir = oprofilefs_mkdir(root->d_sb, root, buf); + oprofilefs_create_ulong(root->d_sb, dir, "enabled", &counter_config[i].enabled); + oprofilefs_create_ulong(root->d_sb, dir, "event", &counter_config[i].event); + oprofilefs_create_ulong(root->d_sb, dir, "count", &counter_config[i].count); + oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", &counter_config[i].unit_mask); + oprofilefs_create_ulong(root->d_sb, dir, "kernel", &counter_config[i].kernel); + oprofilefs_create_ulong(root->d_sb, dir, "user", &counter_config[i].user); + oprofilefs_create_ulong(root->d_sb, dir, "extra", &counter_config[i].extra); } return 0; diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index b2b94438ff05..34e16c2fe357 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -454,16 +454,16 @@ static void init_ibs(void) printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps); } -static int (*create_arch_files)(struct super_block *sb, struct dentry *root); +static int (*create_arch_files)(struct dentry *root); -static int setup_ibs_files(struct super_block *sb, struct dentry *root) +static int setup_ibs_files(struct dentry *root) { struct dentry *dir; int ret = 0; /* architecture specific files */ if (create_arch_files) - ret = create_arch_files(sb, root); + ret = create_arch_files(root); if (ret) return ret; @@ -479,26 +479,26 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root) ibs_config.max_cnt_op = 250000; if (ibs_caps & IBS_CAPS_FETCHSAM) { - dir = oprofilefs_mkdir(sb, root, "ibs_fetch"); - oprofilefs_create_ulong(sb, dir, "enable", + dir = oprofilefs_mkdir(root->d_sb, root, "ibs_fetch"); + oprofilefs_create_ulong(root->d_sb, dir, "enable", &ibs_config.fetch_enabled); - oprofilefs_create_ulong(sb, dir, "max_count", + oprofilefs_create_ulong(root->d_sb, dir, "max_count", &ibs_config.max_cnt_fetch); - oprofilefs_create_ulong(sb, dir, "rand_enable", + oprofilefs_create_ulong(root->d_sb, dir, "rand_enable", &ibs_config.rand_en); } if (ibs_caps & IBS_CAPS_OPSAM) { - dir = oprofilefs_mkdir(sb, root, "ibs_op"); - oprofilefs_create_ulong(sb, dir, "enable", + dir = oprofilefs_mkdir(root->d_sb, root, "ibs_op"); + oprofilefs_create_ulong(root->d_sb, dir, "enable", &ibs_config.op_enabled); - oprofilefs_create_ulong(sb, dir, "max_count", + oprofilefs_create_ulong(root->d_sb, dir, "max_count", &ibs_config.max_cnt_op); if (ibs_caps & IBS_CAPS_OPCNT) - oprofilefs_create_ulong(sb, dir, "dispatched_ops", + oprofilefs_create_ulong(root->d_sb, dir, "dispatched_ops", &ibs_config.dispatched_ops); if (ibs_caps & IBS_CAPS_BRNTRGT) - oprofilefs_create_ulong(sb, dir, "branch_target", + oprofilefs_create_ulong(root->d_sb, dir, "branch_target", &ibs_config.branch_target); } diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 97c345ff62c4..ffc30ee641d4 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -197,5 +197,5 @@ void oprofile_create_files(struct dentry *root) #endif oprofile_create_stats_files(root->d_sb, root); if (oprofile_ops.create_files) - oprofile_ops.create_files(root->d_sb, root); + oprofile_ops.create_files(root); } diff --git a/drivers/oprofile/oprofile_perf.c b/drivers/oprofile/oprofile_perf.c index f3cfa0b9adfa..52ad942df04e 100644 --- a/drivers/oprofile/oprofile_perf.c +++ b/drivers/oprofile/oprofile_perf.c @@ -138,7 +138,7 @@ static void op_perf_stop(void) op_destroy_counter(cpu, event); } -static int oprofile_perf_create_files(struct super_block *sb, struct dentry *root) +static int oprofile_perf_create_files(struct dentry *root) { unsigned int i; @@ -147,13 +147,13 @@ static int oprofile_perf_create_files(struct super_block *sb, struct dentry *roo char buf[4]; snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(sb, root, buf); - oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); - oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event); - oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count); - oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask); - oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel); - oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user); + dir = oprofilefs_mkdir(root->d_sb, root, buf); + oprofilefs_create_ulong(root->d_sb, dir, "enabled", &counter_config[i].enabled); + oprofilefs_create_ulong(root->d_sb, dir, "event", &counter_config[i].event); + oprofilefs_create_ulong(root->d_sb, dir, "count", &counter_config[i].count); + oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", &counter_config[i].unit_mask); + oprofilefs_create_ulong(root->d_sb, dir, "kernel", &counter_config[i].kernel); + oprofilefs_create_ulong(root->d_sb, dir, "user", &counter_config[i].user); } return 0; diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index a4c562453f6b..8a906b4034a7 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -51,7 +51,7 @@ struct pt_regs; struct oprofile_operations { /* create any necessary configuration files in the oprofile fs. * Optional. */ - int (*create_files)(struct super_block * sb, struct dentry * root); + int (*create_files)(struct dentry * root); /* Do any necessary interrupt setup. Optional. */ int (*setup)(void); /* Do any necessary interrupt shutdown. Optional. */ -- cgit v1.2.3 From ecde28237e10de3750a97579f42bc2ec65b8a0e1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jul 2013 15:58:27 +0400 Subject: oprofilefs_mkdir() doesn't need superblock argument it's always equal to ->d_sb of the second argument (parent dentry), due to either being literally that, or ->d_sb of parent's parent. Signed-off-by: Al Viro --- arch/alpha/oprofile/common.c | 2 +- arch/avr32/oprofile/op_model_avr32.c | 2 +- arch/mips/oprofile/common.c | 2 +- arch/powerpc/oprofile/common.c | 2 +- arch/s390/oprofile/init.c | 6 +++--- arch/x86/oprofile/nmi_int.c | 2 +- arch/x86/oprofile/op_model_amd.c | 4 ++-- drivers/oprofile/oprofile_perf.c | 2 +- drivers/oprofile/oprofile_stats.c | 4 ++-- drivers/oprofile/oprofilefs.c | 15 +++++++-------- include/linux/oprofile.h | 3 +-- 11 files changed, 21 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/oprofile/common.c b/arch/alpha/oprofile/common.c index d79bf68caee2..a44608b697ac 100644 --- a/arch/alpha/oprofile/common.c +++ b/arch/alpha/oprofile/common.c @@ -115,7 +115,7 @@ op_axp_create_files(struct dentry *root) char buf[4]; snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(root->d_sb, root, buf); + dir = oprofilefs_mkdir(root, buf); oprofilefs_create_ulong(root->d_sb, dir, "enabled", &ctr[i].enabled); oprofilefs_create_ulong(root->d_sb, dir, "event", &ctr[i].event); diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c index 80a06158da82..7d920a41b441 100644 --- a/arch/avr32/oprofile/op_model_avr32.c +++ b/arch/avr32/oprofile/op_model_avr32.c @@ -105,7 +105,7 @@ static int avr32_perf_counter_create_files(struct dentry *root) for (i = 0; i < NR_counter; i++) { snprintf(filename, sizeof(filename), "%u", i); - dir = oprofilefs_mkdir(root->d_sb, root, filename); + dir = oprofilefs_mkdir(root, filename); oprofilefs_create_ulong(root->d_sb, dir, "enabled", &counter[i].enabled); diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index 7439ae2df05c..755caf04656e 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -42,7 +42,7 @@ static int op_mips_create_files(struct dentry *root) char buf[4]; snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(root->d_sb, root, buf); + dir = oprofilefs_mkdir(root, buf); oprofilefs_create_ulong(root->d_sb, dir, "enabled", &ctr[i].enabled); oprofilefs_create_ulong(root->d_sb, dir, "event", &ctr[i].event); diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index addc62317f45..60a286b367fc 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -160,7 +160,7 @@ static int op_powerpc_create_files(struct dentry *root) char buf[4]; snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(root->d_sb, root, buf); + dir = oprofilefs_mkdir(root, buf); oprofilefs_create_ulong(root->d_sb, dir, "enabled", &ctr[i].enabled); oprofilefs_create_ulong(root->d_sb, dir, "event", &ctr[i].event); diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index 712d57bb783a..5ae06db7ec58 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c @@ -350,7 +350,7 @@ static int oprofile_create_hwsampling_files(struct dentry *root) { struct dentry *dir; - dir = oprofilefs_mkdir(root->d_sb, root, "timer"); + dir = oprofilefs_mkdir(root, "timer"); if (!dir) return -EINVAL; @@ -375,7 +375,7 @@ static int oprofile_create_hwsampling_files(struct dentry *root) * and can only be set to 0. */ - dir = oprofilefs_mkdir(root->d_sb, root, "0"); + dir = oprofilefs_mkdir(root, "0"); if (!dir) return -EINVAL; @@ -395,7 +395,7 @@ static int oprofile_create_hwsampling_files(struct dentry *root) * space tools. The /dev/oprofile/hwsampling fs is * provided in that case. */ - dir = oprofilefs_mkdir(root->d_sb, root, "hwsampling"); + dir = oprofilefs_mkdir(root, "hwsampling"); if (!dir) return -EINVAL; diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 483f02b8c1a8..8bb2de6e103c 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -420,7 +420,7 @@ static int nmi_create_files(struct dentry *root) continue; snprintf(buf, sizeof(buf), "%d", i); - dir = oprofilefs_mkdir(root->d_sb, root, buf); + dir = oprofilefs_mkdir(root, buf); oprofilefs_create_ulong(root->d_sb, dir, "enabled", &counter_config[i].enabled); oprofilefs_create_ulong(root->d_sb, dir, "event", &counter_config[i].event); oprofilefs_create_ulong(root->d_sb, dir, "count", &counter_config[i].count); diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 34e16c2fe357..99131435ea32 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -479,7 +479,7 @@ static int setup_ibs_files(struct dentry *root) ibs_config.max_cnt_op = 250000; if (ibs_caps & IBS_CAPS_FETCHSAM) { - dir = oprofilefs_mkdir(root->d_sb, root, "ibs_fetch"); + dir = oprofilefs_mkdir(root, "ibs_fetch"); oprofilefs_create_ulong(root->d_sb, dir, "enable", &ibs_config.fetch_enabled); oprofilefs_create_ulong(root->d_sb, dir, "max_count", @@ -489,7 +489,7 @@ static int setup_ibs_files(struct dentry *root) } if (ibs_caps & IBS_CAPS_OPSAM) { - dir = oprofilefs_mkdir(root->d_sb, root, "ibs_op"); + dir = oprofilefs_mkdir(root, "ibs_op"); oprofilefs_create_ulong(root->d_sb, dir, "enable", &ibs_config.op_enabled); oprofilefs_create_ulong(root->d_sb, dir, "max_count", diff --git a/drivers/oprofile/oprofile_perf.c b/drivers/oprofile/oprofile_perf.c index 52ad942df04e..923a245774fa 100644 --- a/drivers/oprofile/oprofile_perf.c +++ b/drivers/oprofile/oprofile_perf.c @@ -147,7 +147,7 @@ static int oprofile_perf_create_files(struct dentry *root) char buf[4]; snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(root->d_sb, root, buf); + dir = oprofilefs_mkdir(root, buf); oprofilefs_create_ulong(root->d_sb, dir, "enabled", &counter_config[i].enabled); oprofilefs_create_ulong(root->d_sb, dir, "event", &counter_config[i].event); oprofilefs_create_ulong(root->d_sb, dir, "count", &counter_config[i].count); diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 627dce478311..8cf2fa9710a4 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -46,14 +46,14 @@ void oprofile_create_stats_files(struct dentry *root) char buf[10]; int i; - dir = oprofilefs_mkdir(root->d_sb, root, "stats"); + dir = oprofilefs_mkdir(root, "stats"); if (!dir) return; for_each_possible_cpu(i) { cpu_buf = &per_cpu(op_cpu_buffer, i); snprintf(buf, 10, "cpu%d", i); - cpudir = oprofilefs_mkdir(root->d_sb, dir, buf); + cpudir = oprofilefs_mkdir(dir, buf); /* Strictly speaking access to these ulongs is racy, * but we can't simply lock them, and they are diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 2e2dd5ca7211..6a345724637f 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -211,28 +211,27 @@ int oprofilefs_create_file_perm(struct super_block *sb, struct dentry *root, } -struct dentry *oprofilefs_mkdir(struct super_block *sb, - struct dentry *root, char const *name) +struct dentry *oprofilefs_mkdir(struct dentry *parent, char const *name) { struct dentry *dentry; struct inode *inode; - mutex_lock(&root->d_inode->i_mutex); - dentry = d_alloc_name(root, name); + mutex_lock(&parent->d_inode->i_mutex); + dentry = d_alloc_name(parent, name); if (!dentry) { - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&parent->d_inode->i_mutex); return NULL; } - inode = oprofilefs_get_inode(sb, S_IFDIR | 0755); + inode = oprofilefs_get_inode(parent->d_sb, S_IFDIR | 0755); if (!inode) { dput(dentry); - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&parent->d_inode->i_mutex); return NULL; } inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; d_add(dentry, inode); - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&parent->d_inode->i_mutex); return dentry; } diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index 8a906b4034a7..957877e7a408 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -144,8 +144,7 @@ int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root, char const * name, atomic_t * val); /** create a directory */ -struct dentry * oprofilefs_mkdir(struct super_block * sb, struct dentry * root, - char const * name); +struct dentry *oprofilefs_mkdir(struct dentry *parent, char const *name); /** * Write the given asciz string to the given user buffer @buf, updating *offset -- cgit v1.2.3 From 6af4ea0ba708172be8caf1ba5047b2b8a9d2fea3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jul 2013 16:10:36 +0400 Subject: oprofilefs_create_...() do not need superblock argument same story as with oprofilefs_mkdir() Signed-off-by: Al Viro --- arch/alpha/oprofile/common.c | 18 +++++++++--------- arch/avr32/oprofile/op_model_avr32.c | 12 ++++++------ arch/mips/oprofile/common.c | 14 +++++++------- arch/powerpc/oprofile/common.c | 24 ++++++++++++------------ arch/s390/oprofile/init.c | 26 +++++++++++++------------- arch/x86/oprofile/nmi_int.c | 14 +++++++------- arch/x86/oprofile/op_model_amd.c | 14 +++++++------- drivers/oprofile/oprofile_files.c | 20 ++++++++++---------- drivers/oprofile/oprofile_perf.c | 12 ++++++------ drivers/oprofile/oprofile_stats.c | 18 +++++++++--------- drivers/oprofile/oprofilefs.c | 27 +++++++++++++-------------- include/linux/oprofile.h | 10 +++++----- 12 files changed, 104 insertions(+), 105 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/oprofile/common.c b/arch/alpha/oprofile/common.c index a44608b697ac..310a4ce1dccc 100644 --- a/arch/alpha/oprofile/common.c +++ b/arch/alpha/oprofile/common.c @@ -117,21 +117,21 @@ op_axp_create_files(struct dentry *root) snprintf(buf, sizeof buf, "%d", i); dir = oprofilefs_mkdir(root, buf); - oprofilefs_create_ulong(root->d_sb, dir, "enabled", &ctr[i].enabled); - oprofilefs_create_ulong(root->d_sb, dir, "event", &ctr[i].event); - oprofilefs_create_ulong(root->d_sb, dir, "count", &ctr[i].count); + oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled); + oprofilefs_create_ulong(dir, "event", &ctr[i].event); + oprofilefs_create_ulong(dir, "count", &ctr[i].count); /* Dummies. */ - oprofilefs_create_ulong(root->d_sb, dir, "kernel", &ctr[i].kernel); - oprofilefs_create_ulong(root->d_sb, dir, "user", &ctr[i].user); - oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", &ctr[i].unit_mask); + oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel); + oprofilefs_create_ulong(dir, "user", &ctr[i].user); + oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask); } if (model->can_set_proc_mode) { - oprofilefs_create_ulong(root->d_sb, root, "enable_pal", + oprofilefs_create_ulong(root, "enable_pal", &sys.enable_pal); - oprofilefs_create_ulong(root->d_sb, root, "enable_kernel", + oprofilefs_create_ulong(root, "enable_kernel", &sys.enable_kernel); - oprofilefs_create_ulong(root->d_sb, root, "enable_user", + oprofilefs_create_ulong(root, "enable_user", &sys.enable_user); } diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c index 7d920a41b441..08308be2c02c 100644 --- a/arch/avr32/oprofile/op_model_avr32.c +++ b/arch/avr32/oprofile/op_model_avr32.c @@ -107,19 +107,19 @@ static int avr32_perf_counter_create_files(struct dentry *root) snprintf(filename, sizeof(filename), "%u", i); dir = oprofilefs_mkdir(root, filename); - oprofilefs_create_ulong(root->d_sb, dir, "enabled", + oprofilefs_create_ulong(dir, "enabled", &counter[i].enabled); - oprofilefs_create_ulong(root->d_sb, dir, "event", + oprofilefs_create_ulong(dir, "event", &counter[i].event); - oprofilefs_create_ulong(root->d_sb, dir, "count", + oprofilefs_create_ulong(dir, "count", &counter[i].count); /* Dummy entries */ - oprofilefs_create_ulong(root->d_sb, dir, "kernel", + oprofilefs_create_ulong(dir, "kernel", &counter[i].kernel); - oprofilefs_create_ulong(root->d_sb, dir, "user", + oprofilefs_create_ulong(dir, "user", &counter[i].user); - oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", + oprofilefs_create_ulong(dir, "unit_mask", &counter[i].unit_mask); } diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index 755caf04656e..5e5424753b56 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -44,14 +44,14 @@ static int op_mips_create_files(struct dentry *root) snprintf(buf, sizeof buf, "%d", i); dir = oprofilefs_mkdir(root, buf); - oprofilefs_create_ulong(root->d_sb, dir, "enabled", &ctr[i].enabled); - oprofilefs_create_ulong(root->d_sb, dir, "event", &ctr[i].event); - oprofilefs_create_ulong(root->d_sb, dir, "count", &ctr[i].count); - oprofilefs_create_ulong(root->d_sb, dir, "kernel", &ctr[i].kernel); - oprofilefs_create_ulong(root->d_sb, dir, "user", &ctr[i].user); - oprofilefs_create_ulong(root->d_sb, dir, "exl", &ctr[i].exl); + oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled); + oprofilefs_create_ulong(dir, "event", &ctr[i].event); + oprofilefs_create_ulong(dir, "count", &ctr[i].count); + oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel); + oprofilefs_create_ulong(dir, "user", &ctr[i].user); + oprofilefs_create_ulong(dir, "exl", &ctr[i].exl); /* Dummy. */ - oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", &ctr[i].unit_mask); + oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask); } return 0; diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index 60a286b367fc..c77348c5d463 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -128,9 +128,9 @@ static int op_powerpc_create_files(struct dentry *root) * There is one mmcr0, mmcr1 and mmcra for setting the events for * all of the counters. */ - oprofilefs_create_ulong(root->d_sb, root, "mmcr0", &sys.mmcr0); - oprofilefs_create_ulong(root->d_sb, root, "mmcr1", &sys.mmcr1); - oprofilefs_create_ulong(root->d_sb, root, "mmcra", &sys.mmcra); + oprofilefs_create_ulong(root, "mmcr0", &sys.mmcr0); + oprofilefs_create_ulong(root, "mmcr1", &sys.mmcr1); + oprofilefs_create_ulong(root, "mmcra", &sys.mmcra); #ifdef CONFIG_OPROFILE_CELL /* create a file the user tool can check to see what level of profiling * support exits with this kernel. Initialize bit mask to indicate @@ -142,7 +142,7 @@ static int op_powerpc_create_files(struct dentry *root) * If the file does not exist, then the kernel only supports SPU * cycle profiling, PPU event and cycle profiling. */ - oprofilefs_create_ulong(root->d_sb, root, "cell_support", &sys.cell_support); + oprofilefs_create_ulong(root, "cell_support", &sys.cell_support); sys.cell_support = 0x1; /* Note, the user OProfile tool must check * that this bit is set before attempting to * user SPU event profiling. Older kernels @@ -162,9 +162,9 @@ static int op_powerpc_create_files(struct dentry *root) snprintf(buf, sizeof buf, "%d", i); dir = oprofilefs_mkdir(root, buf); - oprofilefs_create_ulong(root->d_sb, dir, "enabled", &ctr[i].enabled); - oprofilefs_create_ulong(root->d_sb, dir, "event", &ctr[i].event); - oprofilefs_create_ulong(root->d_sb, dir, "count", &ctr[i].count); + oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled); + oprofilefs_create_ulong(dir, "event", &ctr[i].event); + oprofilefs_create_ulong(dir, "count", &ctr[i].count); /* * Classic PowerPC doesn't support per-counter @@ -173,14 +173,14 @@ static int op_powerpc_create_files(struct dentry *root) * Book-E style performance monitors, we do * support them. */ - oprofilefs_create_ulong(root->d_sb, dir, "kernel", &ctr[i].kernel); - oprofilefs_create_ulong(root->d_sb, dir, "user", &ctr[i].user); + oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel); + oprofilefs_create_ulong(dir, "user", &ctr[i].user); - oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", &ctr[i].unit_mask); + oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask); } - oprofilefs_create_ulong(root->d_sb, root, "enable_kernel", &sys.enable_kernel); - oprofilefs_create_ulong(root->d_sb, root, "enable_user", &sys.enable_user); + oprofilefs_create_ulong(root, "enable_kernel", &sys.enable_kernel); + oprofilefs_create_ulong(root, "enable_user", &sys.enable_user); /* Default to tracing both kernel and user */ sys.enable_kernel = 1; diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index 5ae06db7ec58..04e1b6a85362 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c @@ -354,7 +354,7 @@ static int oprofile_create_hwsampling_files(struct dentry *root) if (!dir) return -EINVAL; - oprofilefs_create_file(root->d_sb, dir, "enabled", &timer_enabled_fops); + oprofilefs_create_file(dir, "enabled", &timer_enabled_fops); if (!hwsampler_available) return 0; @@ -379,13 +379,13 @@ static int oprofile_create_hwsampling_files(struct dentry *root) if (!dir) return -EINVAL; - oprofilefs_create_file(root->d_sb, dir, "enabled", &hwsampler_fops); - oprofilefs_create_file(root->d_sb, dir, "event", &zero_fops); - oprofilefs_create_file(root->d_sb, dir, "count", &hw_interval_fops); - oprofilefs_create_file(root->d_sb, dir, "unit_mask", &zero_fops); - oprofilefs_create_file(root->d_sb, dir, "kernel", &kernel_fops); - oprofilefs_create_file(root->d_sb, dir, "user", &user_fops); - oprofilefs_create_ulong(root->d_sb, dir, "hw_sdbt_blocks", + oprofilefs_create_file(dir, "enabled", &hwsampler_fops); + oprofilefs_create_file(dir, "event", &zero_fops); + oprofilefs_create_file(dir, "count", &hw_interval_fops); + oprofilefs_create_file(dir, "unit_mask", &zero_fops); + oprofilefs_create_file(dir, "kernel", &kernel_fops); + oprofilefs_create_file(dir, "user", &user_fops); + oprofilefs_create_ulong(dir, "hw_sdbt_blocks", &oprofile_sdbt_blocks); } else { @@ -399,15 +399,15 @@ static int oprofile_create_hwsampling_files(struct dentry *root) if (!dir) return -EINVAL; - oprofilefs_create_file(root->d_sb, dir, "hwsampler", + oprofilefs_create_file(dir, "hwsampler", &hwsampler_fops); - oprofilefs_create_file(root->d_sb, dir, "hw_interval", + oprofilefs_create_file(dir, "hw_interval", &hw_interval_fops); - oprofilefs_create_ro_ulong(root->d_sb, dir, "hw_min_interval", + oprofilefs_create_ro_ulong(dir, "hw_min_interval", &oprofile_min_interval); - oprofilefs_create_ro_ulong(root->d_sb, dir, "hw_max_interval", + oprofilefs_create_ro_ulong(dir, "hw_max_interval", &oprofile_max_interval); - oprofilefs_create_ulong(root->d_sb, dir, "hw_sdbt_blocks", + oprofilefs_create_ulong(dir, "hw_sdbt_blocks", &oprofile_sdbt_blocks); } return 0; diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 8bb2de6e103c..6890d8498e0b 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -421,13 +421,13 @@ static int nmi_create_files(struct dentry *root) snprintf(buf, sizeof(buf), "%d", i); dir = oprofilefs_mkdir(root, buf); - oprofilefs_create_ulong(root->d_sb, dir, "enabled", &counter_config[i].enabled); - oprofilefs_create_ulong(root->d_sb, dir, "event", &counter_config[i].event); - oprofilefs_create_ulong(root->d_sb, dir, "count", &counter_config[i].count); - oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", &counter_config[i].unit_mask); - oprofilefs_create_ulong(root->d_sb, dir, "kernel", &counter_config[i].kernel); - oprofilefs_create_ulong(root->d_sb, dir, "user", &counter_config[i].user); - oprofilefs_create_ulong(root->d_sb, dir, "extra", &counter_config[i].extra); + oprofilefs_create_ulong(dir, "enabled", &counter_config[i].enabled); + oprofilefs_create_ulong(dir, "event", &counter_config[i].event); + oprofilefs_create_ulong(dir, "count", &counter_config[i].count); + oprofilefs_create_ulong(dir, "unit_mask", &counter_config[i].unit_mask); + oprofilefs_create_ulong(dir, "kernel", &counter_config[i].kernel); + oprofilefs_create_ulong(dir, "user", &counter_config[i].user); + oprofilefs_create_ulong(dir, "extra", &counter_config[i].extra); } return 0; diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 99131435ea32..50d86c0e9ba4 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -480,25 +480,25 @@ static int setup_ibs_files(struct dentry *root) if (ibs_caps & IBS_CAPS_FETCHSAM) { dir = oprofilefs_mkdir(root, "ibs_fetch"); - oprofilefs_create_ulong(root->d_sb, dir, "enable", + oprofilefs_create_ulong(dir, "enable", &ibs_config.fetch_enabled); - oprofilefs_create_ulong(root->d_sb, dir, "max_count", + oprofilefs_create_ulong(dir, "max_count", &ibs_config.max_cnt_fetch); - oprofilefs_create_ulong(root->d_sb, dir, "rand_enable", + oprofilefs_create_ulong(dir, "rand_enable", &ibs_config.rand_en); } if (ibs_caps & IBS_CAPS_OPSAM) { dir = oprofilefs_mkdir(root, "ibs_op"); - oprofilefs_create_ulong(root->d_sb, dir, "enable", + oprofilefs_create_ulong(dir, "enable", &ibs_config.op_enabled); - oprofilefs_create_ulong(root->d_sb, dir, "max_count", + oprofilefs_create_ulong(dir, "max_count", &ibs_config.max_cnt_op); if (ibs_caps & IBS_CAPS_OPCNT) - oprofilefs_create_ulong(root->d_sb, dir, "dispatched_ops", + oprofilefs_create_ulong(dir, "dispatched_ops", &ibs_config.dispatched_ops); if (ibs_caps & IBS_CAPS_BRNTRGT) - oprofilefs_create_ulong(root->d_sb, dir, "branch_target", + oprofilefs_create_ulong(dir, "branch_target", &ibs_config.branch_target); } diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 07462a9af615..ee2cfce358b9 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -183,17 +183,17 @@ void oprofile_create_files(struct dentry *root) oprofile_buffer_watershed = BUFFER_WATERSHED_DEFAULT; oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT); - oprofilefs_create_file(root->d_sb, root, "enable", &enable_fops); - oprofilefs_create_file_perm(root->d_sb, root, "dump", &dump_fops, 0666); - oprofilefs_create_file(root->d_sb, root, "buffer", &event_buffer_fops); - oprofilefs_create_ulong(root->d_sb, root, "buffer_size", &oprofile_buffer_size); - oprofilefs_create_ulong(root->d_sb, root, "buffer_watershed", &oprofile_buffer_watershed); - oprofilefs_create_ulong(root->d_sb, root, "cpu_buffer_size", &oprofile_cpu_buffer_size); - oprofilefs_create_file(root->d_sb, root, "cpu_type", &cpu_type_fops); - oprofilefs_create_file(root->d_sb, root, "backtrace_depth", &depth_fops); - oprofilefs_create_file(root->d_sb, root, "pointer_size", &pointer_size_fops); + oprofilefs_create_file(root, "enable", &enable_fops); + oprofilefs_create_file_perm(root, "dump", &dump_fops, 0666); + oprofilefs_create_file(root, "buffer", &event_buffer_fops); + oprofilefs_create_ulong(root, "buffer_size", &oprofile_buffer_size); + oprofilefs_create_ulong(root, "buffer_watershed", &oprofile_buffer_watershed); + oprofilefs_create_ulong(root, "cpu_buffer_size", &oprofile_cpu_buffer_size); + oprofilefs_create_file(root, "cpu_type", &cpu_type_fops); + oprofilefs_create_file(root, "backtrace_depth", &depth_fops); + oprofilefs_create_file(root, "pointer_size", &pointer_size_fops); #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - oprofilefs_create_file(root->d_sb, root, "time_slice", &timeout_fops); + oprofilefs_create_file(root, "time_slice", &timeout_fops); #endif oprofile_create_stats_files(root); if (oprofile_ops.create_files) diff --git a/drivers/oprofile/oprofile_perf.c b/drivers/oprofile/oprofile_perf.c index 923a245774fa..d5b2732b1b81 100644 --- a/drivers/oprofile/oprofile_perf.c +++ b/drivers/oprofile/oprofile_perf.c @@ -148,12 +148,12 @@ static int oprofile_perf_create_files(struct dentry *root) snprintf(buf, sizeof buf, "%d", i); dir = oprofilefs_mkdir(root, buf); - oprofilefs_create_ulong(root->d_sb, dir, "enabled", &counter_config[i].enabled); - oprofilefs_create_ulong(root->d_sb, dir, "event", &counter_config[i].event); - oprofilefs_create_ulong(root->d_sb, dir, "count", &counter_config[i].count); - oprofilefs_create_ulong(root->d_sb, dir, "unit_mask", &counter_config[i].unit_mask); - oprofilefs_create_ulong(root->d_sb, dir, "kernel", &counter_config[i].kernel); - oprofilefs_create_ulong(root->d_sb, dir, "user", &counter_config[i].user); + oprofilefs_create_ulong(dir, "enabled", &counter_config[i].enabled); + oprofilefs_create_ulong(dir, "event", &counter_config[i].event); + oprofilefs_create_ulong(dir, "count", &counter_config[i].count); + oprofilefs_create_ulong(dir, "unit_mask", &counter_config[i].unit_mask); + oprofilefs_create_ulong(dir, "kernel", &counter_config[i].kernel); + oprofilefs_create_ulong(dir, "user", &counter_config[i].user); } return 0; diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 8cf2fa9710a4..59659cea4582 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -59,26 +59,26 @@ void oprofile_create_stats_files(struct dentry *root) * but we can't simply lock them, and they are * informational only. */ - oprofilefs_create_ro_ulong(root->d_sb, cpudir, "sample_received", + oprofilefs_create_ro_ulong(cpudir, "sample_received", &cpu_buf->sample_received); - oprofilefs_create_ro_ulong(root->d_sb, cpudir, "sample_lost_overflow", + oprofilefs_create_ro_ulong(cpudir, "sample_lost_overflow", &cpu_buf->sample_lost_overflow); - oprofilefs_create_ro_ulong(root->d_sb, cpudir, "backtrace_aborted", + oprofilefs_create_ro_ulong(cpudir, "backtrace_aborted", &cpu_buf->backtrace_aborted); - oprofilefs_create_ro_ulong(root->d_sb, cpudir, "sample_invalid_eip", + oprofilefs_create_ro_ulong(cpudir, "sample_invalid_eip", &cpu_buf->sample_invalid_eip); } - oprofilefs_create_ro_atomic(root->d_sb, dir, "sample_lost_no_mm", + oprofilefs_create_ro_atomic(dir, "sample_lost_no_mm", &oprofile_stats.sample_lost_no_mm); - oprofilefs_create_ro_atomic(root->d_sb, dir, "sample_lost_no_mapping", + oprofilefs_create_ro_atomic(dir, "sample_lost_no_mapping", &oprofile_stats.sample_lost_no_mapping); - oprofilefs_create_ro_atomic(root->d_sb, dir, "event_lost_overflow", + oprofilefs_create_ro_atomic(dir, "event_lost_overflow", &oprofile_stats.event_lost_overflow); - oprofilefs_create_ro_atomic(root->d_sb, dir, "bt_lost_no_mapping", + oprofilefs_create_ro_atomic(dir, "bt_lost_no_mapping", &oprofile_stats.bt_lost_no_mapping); #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX - oprofilefs_create_ro_atomic(root->d_sb, dir, "multiplex_counter", + oprofilefs_create_ro_atomic(dir, "multiplex_counter", &oprofile_stats.multiplex_counter); #endif } diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 6a345724637f..3f493459378f 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -132,9 +132,8 @@ static const struct file_operations ulong_ro_fops = { }; -static int __oprofilefs_create_file(struct super_block *sb, - struct dentry *root, char const *name, const struct file_operations *fops, - int perm, void *priv) +static int __oprofilefs_create_file(struct dentry *root, char const *name, + const struct file_operations *fops, int perm, void *priv) { struct dentry *dentry; struct inode *inode; @@ -145,7 +144,7 @@ static int __oprofilefs_create_file(struct super_block *sb, mutex_unlock(&root->d_inode->i_mutex); return -ENOMEM; } - inode = oprofilefs_get_inode(sb, S_IFREG | perm); + inode = oprofilefs_get_inode(root->d_sb, S_IFREG | perm); if (!inode) { dput(dentry); mutex_unlock(&root->d_inode->i_mutex); @@ -159,18 +158,18 @@ static int __oprofilefs_create_file(struct super_block *sb, } -int oprofilefs_create_ulong(struct super_block *sb, struct dentry *root, +int oprofilefs_create_ulong(struct dentry *root, char const *name, unsigned long *val) { - return __oprofilefs_create_file(sb, root, name, + return __oprofilefs_create_file(root, name, &ulong_fops, 0644, val); } -int oprofilefs_create_ro_ulong(struct super_block *sb, struct dentry *root, +int oprofilefs_create_ro_ulong(struct dentry *root, char const *name, unsigned long *val) { - return __oprofilefs_create_file(sb, root, name, + return __oprofilefs_create_file(root, name, &ulong_ro_fops, 0444, val); } @@ -189,25 +188,25 @@ static const struct file_operations atomic_ro_fops = { }; -int oprofilefs_create_ro_atomic(struct super_block *sb, struct dentry *root, +int oprofilefs_create_ro_atomic(struct dentry *root, char const *name, atomic_t *val) { - return __oprofilefs_create_file(sb, root, name, + return __oprofilefs_create_file(root, name, &atomic_ro_fops, 0444, val); } -int oprofilefs_create_file(struct super_block *sb, struct dentry *root, +int oprofilefs_create_file(struct dentry *root, char const *name, const struct file_operations *fops) { - return __oprofilefs_create_file(sb, root, name, fops, 0644, NULL); + return __oprofilefs_create_file(root, name, fops, 0644, NULL); } -int oprofilefs_create_file_perm(struct super_block *sb, struct dentry *root, +int oprofilefs_create_file_perm(struct dentry *root, char const *name, const struct file_operations *fops, int perm) { - return __oprofilefs_create_file(sb, root, name, fops, perm, NULL); + return __oprofilefs_create_file(root, name, fops, perm, NULL); } diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index 957877e7a408..166ef4fb4b5c 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -125,22 +125,22 @@ void oprofile_add_trace(unsigned long eip); * Create a file of the given name as a child of the given root, with * the specified file operations. */ -int oprofilefs_create_file(struct super_block * sb, struct dentry * root, +int oprofilefs_create_file(struct dentry * root, char const * name, const struct file_operations * fops); -int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root, +int oprofilefs_create_file_perm(struct dentry * root, char const * name, const struct file_operations * fops, int perm); /** Create a file for read/write access to an unsigned long. */ -int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root, +int oprofilefs_create_ulong(struct dentry * root, char const * name, ulong * val); /** Create a file for read-only access to an unsigned long. */ -int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root, +int oprofilefs_create_ro_ulong(struct dentry * root, char const * name, ulong * val); /** Create a file for read-only access to an atomic_t. */ -int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root, +int oprofilefs_create_ro_atomic(struct dentry * root, char const * name, atomic_t * val); /** create a directory */ -- cgit v1.2.3 From 2b2fee80a7058959a6a9ba8706b3af5589b286d3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jul 2013 16:13:30 +0400 Subject: oprofile: get rid of pointless forward declarations of struct super_block Signed-off-by: Al Viro --- drivers/oprofile/oprof.h | 1 - drivers/oprofile/oprofile_stats.h | 1 - include/linux/oprofile.h | 1 - 3 files changed, 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index 8c43f20ab5fa..d5412060ab0f 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -30,7 +30,6 @@ extern struct oprofile_operations oprofile_ops; extern unsigned long oprofile_started; extern unsigned long oprofile_backtrace_depth; -struct super_block; struct dentry; void oprofile_create_files(struct dentry *root); diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h index 13e8e3f1e356..1fc622bd1834 100644 --- a/drivers/oprofile/oprofile_stats.h +++ b/drivers/oprofile/oprofile_stats.h @@ -25,7 +25,6 @@ extern struct oprofile_stat_struct oprofile_stats; /* reset all stats to zero */ void oprofile_reset_stats(void); -struct super_block; struct dentry; /* create the stats/ dir */ diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index 166ef4fb4b5c..b2a0f15f11fe 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -42,7 +42,6 @@ #define IBS_FETCH_CODE 13 #define IBS_OP_CODE 14 -struct super_block; struct dentry; struct file_operations; struct pt_regs; -- cgit v1.2.3 From 7b7a8665edd8db733980389b098530f9e4f630b2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 4 Sep 2013 15:04:39 +0200 Subject: direct-io: Implement generic deferred AIO completions Add support to the core direct-io code to defer AIO completions to user context using a workqueue. This replaces opencoded and less efficient code in XFS and ext4 (we save a memory allocation for each direct IO) and will be needed to properly support O_(D)SYNC for AIO. The communication between the filesystem and the direct I/O code requires a new buffer head flag, which is a bit ugly but not avoidable until the direct I/O code stops abusing the buffer_head structure for communicating with the filesystems. Currently this creates a per-superblock unbound workqueue for these completions, which is taken from an earlier patch by Jan Kara. I'm not really convinced about this use and would prefer a "normal" global workqueue with a high concurrency limit, but this needs further discussion. JK: Fixed ext4 part, dynamic allocation of the workqueue. Signed-off-by: Christoph Hellwig Signed-off-by: Jan Kara Signed-off-by: Al Viro --- fs/direct-io.c | 85 ++++++++++++++++++++++++++++++++++++--------- fs/ext4/ext4.h | 11 ------ fs/ext4/inode.c | 28 ++++----------- fs/ext4/page-io.c | 30 ++++------------ fs/ext4/super.c | 16 --------- fs/ocfs2/aops.c | 8 +---- fs/super.c | 18 +++++----- fs/xfs/xfs_aops.c | 28 +++------------ fs/xfs/xfs_aops.h | 3 -- include/linux/buffer_head.h | 2 ++ include/linux/fs.h | 7 ++-- 11 files changed, 105 insertions(+), 131 deletions(-) (limited to 'include/linux') diff --git a/fs/direct-io.c b/fs/direct-io.c index 7ab90f5081ee..8b31b9f449f4 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -127,6 +127,7 @@ struct dio { spinlock_t bio_lock; /* protects BIO fields below */ int page_errors; /* errno from get_user_pages() */ int is_async; /* is IO async ? */ + bool defer_completion; /* defer AIO completion to workqueue? */ int io_error; /* IO error in completion path */ unsigned long refcount; /* direct_io_worker() and bios */ struct bio *bio_list; /* singly linked via bi_private */ @@ -141,7 +142,10 @@ struct dio { * allocation time. Don't add new fields after pages[] unless you * wish that they not be zeroed. */ - struct page *pages[DIO_PAGES]; /* page buffer */ + union { + struct page *pages[DIO_PAGES]; /* page buffer */ + struct work_struct complete_work;/* deferred AIO completion */ + }; } ____cacheline_aligned_in_smp; static struct kmem_cache *dio_cache __read_mostly; @@ -221,16 +225,16 @@ static inline struct page *dio_get_page(struct dio *dio, * dio_complete() - called when all DIO BIO I/O has been completed * @offset: the byte offset in the file of the completed operation * - * This releases locks as dictated by the locking type, lets interested parties - * know that a DIO operation has completed, and calculates the resulting return - * code for the operation. + * This drops i_dio_count, lets interested parties know that a DIO operation + * has completed, and calculates the resulting return code for the operation. * * It lets the filesystem know if it registered an interest earlier via * get_block. Pass the private field of the map buffer_head so that * filesystems can use it to hold additional state between get_block calls and * dio_complete. */ -static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, bool is_async) +static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, + bool is_async) { ssize_t transferred = 0; @@ -258,19 +262,26 @@ static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, bool is if (ret == 0) ret = transferred; - if (dio->end_io && dio->result) { - dio->end_io(dio->iocb, offset, transferred, - dio->private, ret, is_async); - } else { - inode_dio_done(dio->inode); - if (is_async) - aio_complete(dio->iocb, ret, 0); - } + if (dio->end_io && dio->result) + dio->end_io(dio->iocb, offset, transferred, dio->private); + + inode_dio_done(dio->inode); + if (is_async) + aio_complete(dio->iocb, ret, 0); + kmem_cache_free(dio_cache, dio); return ret; } +static void dio_aio_complete_work(struct work_struct *work) +{ + struct dio *dio = container_of(work, struct dio, complete_work); + + dio_complete(dio, dio->iocb->ki_pos, 0, true); +} + static int dio_bio_complete(struct dio *dio, struct bio *bio); + /* * Asynchronous IO callback. */ @@ -290,8 +301,13 @@ static void dio_bio_end_aio(struct bio *bio, int error) spin_unlock_irqrestore(&dio->bio_lock, flags); if (remaining == 0) { - dio_complete(dio, dio->iocb->ki_pos, 0, true); - kmem_cache_free(dio_cache, dio); + if (dio->result && dio->defer_completion) { + INIT_WORK(&dio->complete_work, dio_aio_complete_work); + queue_work(dio->inode->i_sb->s_dio_done_wq, + &dio->complete_work); + } else { + dio_complete(dio, dio->iocb->ki_pos, 0, true); + } } } @@ -510,6 +526,41 @@ static inline int dio_bio_reap(struct dio *dio, struct dio_submit *sdio) return ret; } +/* + * Create workqueue for deferred direct IO completions. We allocate the + * workqueue when it's first needed. This avoids creating workqueue for + * filesystems that don't need it and also allows us to create the workqueue + * late enough so the we can include s_id in the name of the workqueue. + */ +static int sb_init_dio_done_wq(struct super_block *sb) +{ + struct workqueue_struct *wq = alloc_workqueue("dio/%s", + WQ_MEM_RECLAIM, 0, + sb->s_id); + if (!wq) + return -ENOMEM; + /* + * This has to be atomic as more DIOs can race to create the workqueue + */ + cmpxchg(&sb->s_dio_done_wq, NULL, wq); + /* Someone created workqueue before us? Free ours... */ + if (wq != sb->s_dio_done_wq) + destroy_workqueue(wq); + return 0; +} + +static int dio_set_defer_completion(struct dio *dio) +{ + struct super_block *sb = dio->inode->i_sb; + + if (dio->defer_completion) + return 0; + dio->defer_completion = true; + if (!sb->s_dio_done_wq) + return sb_init_dio_done_wq(sb); + return 0; +} + /* * Call into the fs to map some more disk blocks. We record the current number * of available blocks at sdio->blocks_available. These are in units of the @@ -581,6 +632,9 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio, /* Store for completion */ dio->private = map_bh->b_private; + + if (ret == 0 && buffer_defer_completion(map_bh)) + ret = dio_set_defer_completion(dio); } return ret; } @@ -1269,7 +1323,6 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, if (drop_refcount(dio) == 0) { retval = dio_complete(dio, offset, retval, false); - kmem_cache_free(dio_cache, dio); } else BUG_ON(retval != -EIOCBQUEUED); diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 0ab26fbf3380..b247fbbed99c 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -180,7 +180,6 @@ struct ext4_map_blocks { * Flags for ext4_io_end->flags */ #define EXT4_IO_END_UNWRITTEN 0x0001 -#define EXT4_IO_END_DIRECT 0x0002 /* * For converting uninitialized extents on a work queue. 'handle' is used for @@ -196,8 +195,6 @@ typedef struct ext4_io_end { unsigned int flag; /* unwritten or not */ loff_t offset; /* offset in the file */ ssize_t size; /* size of the extent */ - struct kiocb *iocb; /* iocb struct for AIO */ - int result; /* error value for AIO */ atomic_t count; /* reference counter */ } ext4_io_end_t; @@ -900,11 +897,9 @@ struct ext4_inode_info { * Completed IOs that need unwritten extents handling and don't have * transaction reserved */ - struct list_head i_unrsv_conversion_list; atomic_t i_ioend_count; /* Number of outstanding io_end structs */ atomic_t i_unwritten; /* Nr. of inflight conversions pending */ struct work_struct i_rsv_conversion_work; - struct work_struct i_unrsv_conversion_work; spinlock_t i_block_reservation_lock; @@ -1276,8 +1271,6 @@ struct ext4_sb_info { struct flex_groups *s_flex_groups; ext4_group_t s_flex_groups_allocated; - /* workqueue for unreserved extent convertions (dio) */ - struct workqueue_struct *unrsv_conversion_wq; /* workqueue for reserved extent conversions (buffered io) */ struct workqueue_struct *rsv_conversion_wq; @@ -1340,9 +1333,6 @@ static inline void ext4_set_io_unwritten_flag(struct inode *inode, struct ext4_io_end *io_end) { if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) { - /* Writeback has to have coversion transaction reserved */ - WARN_ON(EXT4_SB(inode->i_sb)->s_journal && !io_end->handle && - !(io_end->flag & EXT4_IO_END_DIRECT)); io_end->flag |= EXT4_IO_END_UNWRITTEN; atomic_inc(&EXT4_I(inode)->i_unwritten); } @@ -2716,7 +2706,6 @@ extern void ext4_put_io_end_defer(ext4_io_end_t *io_end); extern void ext4_io_submit_init(struct ext4_io_submit *io, struct writeback_control *wbc); extern void ext4_end_io_rsv_work(struct work_struct *work); -extern void ext4_end_io_unrsv_work(struct work_struct *work); extern void ext4_io_submit(struct ext4_io_submit *io); extern int ext4_bio_write_page(struct ext4_io_submit *io, struct page *page, diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c2ca04e67a4f..123bd81692d1 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -727,8 +727,12 @@ static int _ext4_get_block(struct inode *inode, sector_t iblock, ret = ext4_map_blocks(handle, inode, &map, flags); if (ret > 0) { + ext4_io_end_t *io_end = ext4_inode_aio(inode); + map_bh(bh, inode->i_sb, map.m_pblk); bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags; + if (io_end && io_end->flag & EXT4_IO_END_UNWRITTEN) + set_buffer_defer_completion(bh); bh->b_size = inode->i_sb->s_blocksize * map.m_len; ret = 0; } @@ -2991,19 +2995,13 @@ static int ext4_get_block_write_nolock(struct inode *inode, sector_t iblock, } static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, - ssize_t size, void *private, int ret, - bool is_async) + ssize_t size, void *private) { - struct inode *inode = file_inode(iocb->ki_filp); ext4_io_end_t *io_end = iocb->private; /* if not async direct IO just return */ - if (!io_end) { - inode_dio_done(inode); - if (is_async) - aio_complete(iocb, ret, 0); + if (!io_end) return; - } ext_debug("ext4_end_io_dio(): io_end 0x%p " "for inode %lu, iocb 0x%p, offset %llu, size %zd\n", @@ -3013,11 +3011,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, iocb->private = NULL; io_end->offset = offset; io_end->size = size; - if (is_async) { - io_end->iocb = iocb; - io_end->result = ret; - } - ext4_put_io_end_defer(io_end); + ext4_put_io_end(io_end); } /* @@ -3102,7 +3096,6 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, ret = -ENOMEM; goto retake_lock; } - io_end->flag |= EXT4_IO_END_DIRECT; /* * Grab reference for DIO. Will be dropped in ext4_end_io_dio() */ @@ -3147,13 +3140,6 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, if (ret <= 0 && ret != -EIOCBQUEUED && iocb->private) { WARN_ON(iocb->private != io_end); WARN_ON(io_end->flag & EXT4_IO_END_UNWRITTEN); - WARN_ON(io_end->iocb); - /* - * Generic code already did inode_dio_done() so we - * have to clear EXT4_IO_END_DIRECT to not do it for - * the second time. - */ - io_end->flag = 0; ext4_put_io_end(io_end); iocb->private = NULL; } diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 6625d210fb45..d7d0c7b46ed4 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -123,10 +123,6 @@ static void ext4_release_io_end(ext4_io_end_t *io_end) ext4_finish_bio(bio); bio_put(bio); } - if (io_end->flag & EXT4_IO_END_DIRECT) - inode_dio_done(io_end->inode); - if (io_end->iocb) - aio_complete(io_end->iocb, io_end->result, 0); kmem_cache_free(io_end_cachep, io_end); } @@ -204,19 +200,14 @@ static void ext4_add_complete_io(ext4_io_end_t *io_end) struct workqueue_struct *wq; unsigned long flags; - BUG_ON(!(io_end->flag & EXT4_IO_END_UNWRITTEN)); + /* Only reserved conversions from writeback should enter here */ + WARN_ON(!(io_end->flag & EXT4_IO_END_UNWRITTEN)); + WARN_ON(!io_end->handle); spin_lock_irqsave(&ei->i_completed_io_lock, flags); - if (io_end->handle) { - wq = EXT4_SB(io_end->inode->i_sb)->rsv_conversion_wq; - if (list_empty(&ei->i_rsv_conversion_list)) - queue_work(wq, &ei->i_rsv_conversion_work); - list_add_tail(&io_end->list, &ei->i_rsv_conversion_list); - } else { - wq = EXT4_SB(io_end->inode->i_sb)->unrsv_conversion_wq; - if (list_empty(&ei->i_unrsv_conversion_list)) - queue_work(wq, &ei->i_unrsv_conversion_work); - list_add_tail(&io_end->list, &ei->i_unrsv_conversion_list); - } + wq = EXT4_SB(io_end->inode->i_sb)->rsv_conversion_wq; + if (list_empty(&ei->i_rsv_conversion_list)) + queue_work(wq, &ei->i_rsv_conversion_work); + list_add_tail(&io_end->list, &ei->i_rsv_conversion_list); spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); } @@ -256,13 +247,6 @@ void ext4_end_io_rsv_work(struct work_struct *work) ext4_do_flush_completed_IO(&ei->vfs_inode, &ei->i_rsv_conversion_list); } -void ext4_end_io_unrsv_work(struct work_struct *work) -{ - struct ext4_inode_info *ei = container_of(work, struct ext4_inode_info, - i_unrsv_conversion_work); - ext4_do_flush_completed_IO(&ei->vfs_inode, &ei->i_unrsv_conversion_list); -} - ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags) { ext4_io_end_t *io = kmem_cache_zalloc(io_end_cachep, flags); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index b59373b625e9..5db4f0df8174 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -762,9 +762,7 @@ static void ext4_put_super(struct super_block *sb) ext4_unregister_li_request(sb); dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); - flush_workqueue(sbi->unrsv_conversion_wq); flush_workqueue(sbi->rsv_conversion_wq); - destroy_workqueue(sbi->unrsv_conversion_wq); destroy_workqueue(sbi->rsv_conversion_wq); if (sbi->s_journal) { @@ -875,14 +873,12 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) #endif ei->jinode = NULL; INIT_LIST_HEAD(&ei->i_rsv_conversion_list); - INIT_LIST_HEAD(&ei->i_unrsv_conversion_list); spin_lock_init(&ei->i_completed_io_lock); ei->i_sync_tid = 0; ei->i_datasync_tid = 0; atomic_set(&ei->i_ioend_count, 0); atomic_set(&ei->i_unwritten, 0); INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work); - INIT_WORK(&ei->i_unrsv_conversion_work, ext4_end_io_unrsv_work); return &ei->vfs_inode; } @@ -3954,14 +3950,6 @@ no_journal: goto failed_mount4; } - EXT4_SB(sb)->unrsv_conversion_wq = - alloc_workqueue("ext4-unrsv-conversion", WQ_MEM_RECLAIM | WQ_UNBOUND, 1); - if (!EXT4_SB(sb)->unrsv_conversion_wq) { - printk(KERN_ERR "EXT4-fs: failed to create workqueue\n"); - ret = -ENOMEM; - goto failed_mount4; - } - /* * The jbd2_journal_load will have done any necessary log recovery, * so we can safely mount the rest of the filesystem now. @@ -4115,8 +4103,6 @@ failed_mount4: ext4_msg(sb, KERN_ERR, "mount failed"); if (EXT4_SB(sb)->rsv_conversion_wq) destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq); - if (EXT4_SB(sb)->unrsv_conversion_wq) - destroy_workqueue(EXT4_SB(sb)->unrsv_conversion_wq); failed_mount_wq: if (sbi->s_journal) { jbd2_journal_destroy(sbi->s_journal); @@ -4564,7 +4550,6 @@ static int ext4_sync_fs(struct super_block *sb, int wait) trace_ext4_sync_fs(sb, wait); flush_workqueue(sbi->rsv_conversion_wq); - flush_workqueue(sbi->unrsv_conversion_wq); /* * Writeback quota in non-journalled quota case - journalled quota has * no dirty dquots @@ -4600,7 +4585,6 @@ static int ext4_sync_fs_nojournal(struct super_block *sb, int wait) trace_ext4_sync_fs(sb, wait); flush_workqueue(EXT4_SB(sb)->rsv_conversion_wq); - flush_workqueue(EXT4_SB(sb)->unrsv_conversion_wq); dquot_writeback_dquots(sb, -1); if (wait && test_opt(sb, BARRIER)) ret = blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL); diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 2abf97b2a592..94417a85ce6e 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -565,9 +565,7 @@ bail: static void ocfs2_dio_end_io(struct kiocb *iocb, loff_t offset, ssize_t bytes, - void *private, - int ret, - bool is_async) + void *private) { struct inode *inode = file_inode(iocb->ki_filp); int level; @@ -592,10 +590,6 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, level = ocfs2_iocb_rw_locked_level(iocb); ocfs2_rw_unlock(inode, level); - - inode_dio_done(inode); - if (is_async) - aio_complete(iocb, ret, 0); } /* diff --git a/fs/super.c b/fs/super.c index 68307c029228..5536a95186e2 100644 --- a/fs/super.c +++ b/fs/super.c @@ -152,15 +152,9 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) static const struct super_operations default_op; if (s) { - if (security_sb_alloc(s)) { - /* - * We cannot call security_sb_free() without - * security_sb_alloc() succeeding. So bail out manually - */ - kfree(s); - s = NULL; - goto out; - } + if (security_sb_alloc(s)) + goto out_free_sb; + #ifdef CONFIG_SMP s->s_files = alloc_percpu(struct list_head); if (!s->s_files) @@ -228,6 +222,7 @@ err_out: free_percpu(s->s_files); #endif destroy_sb_writers(s); +out_free_sb: kfree(s); s = NULL; goto out; @@ -414,6 +409,11 @@ void generic_shutdown_super(struct super_block *sb) evict_inodes(sb); + if (sb->s_dio_done_wq) { + destroy_workqueue(sb->s_dio_done_wq); + sb->s_dio_done_wq = NULL; + } + if (sop->put_super) sop->put_super(sb); diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 596ec71da00e..e11d654af786 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -86,14 +86,6 @@ xfs_destroy_ioend( bh->b_end_io(bh, !ioend->io_error); } - if (ioend->io_iocb) { - inode_dio_done(ioend->io_inode); - if (ioend->io_isasync) { - aio_complete(ioend->io_iocb, ioend->io_error ? - ioend->io_error : ioend->io_result, 0); - } - } - mempool_free(ioend, xfs_ioend_pool); } @@ -281,7 +273,6 @@ xfs_alloc_ioend( * all the I/O from calling the completion routine too early. */ atomic_set(&ioend->io_remaining, 1); - ioend->io_isasync = 0; ioend->io_isdirect = 0; ioend->io_error = 0; ioend->io_list = NULL; @@ -291,8 +282,6 @@ xfs_alloc_ioend( ioend->io_buffer_tail = NULL; ioend->io_offset = 0; ioend->io_size = 0; - ioend->io_iocb = NULL; - ioend->io_result = 0; ioend->io_append_trans = NULL; INIT_WORK(&ioend->io_work, xfs_end_io); @@ -1292,8 +1281,10 @@ __xfs_get_blocks( if (create || !ISUNWRITTEN(&imap)) xfs_map_buffer(inode, bh_result, &imap, offset); if (create && ISUNWRITTEN(&imap)) { - if (direct) + if (direct) { bh_result->b_private = inode; + set_buffer_defer_completion(bh_result); + } set_buffer_unwritten(bh_result); } } @@ -1390,9 +1381,7 @@ xfs_end_io_direct_write( struct kiocb *iocb, loff_t offset, ssize_t size, - void *private, - int ret, - bool is_async) + void *private) { struct xfs_ioend *ioend = iocb->private; @@ -1414,17 +1403,10 @@ xfs_end_io_direct_write( ioend->io_offset = offset; ioend->io_size = size; - ioend->io_iocb = iocb; - ioend->io_result = ret; if (private && size > 0) ioend->io_type = XFS_IO_UNWRITTEN; - if (is_async) { - ioend->io_isasync = 1; - xfs_finish_ioend(ioend); - } else { - xfs_finish_ioend_sync(ioend); - } + xfs_finish_ioend_sync(ioend); } STATIC ssize_t diff --git a/fs/xfs/xfs_aops.h b/fs/xfs/xfs_aops.h index c325abb8d61a..f94dd459dff9 100644 --- a/fs/xfs/xfs_aops.h +++ b/fs/xfs/xfs_aops.h @@ -45,7 +45,6 @@ typedef struct xfs_ioend { unsigned int io_type; /* delalloc / unwritten */ int io_error; /* I/O error code */ atomic_t io_remaining; /* hold count */ - unsigned int io_isasync : 1; /* needs aio_complete */ unsigned int io_isdirect : 1;/* direct I/O */ struct inode *io_inode; /* file being written to */ struct buffer_head *io_buffer_head;/* buffer linked list head */ @@ -54,8 +53,6 @@ typedef struct xfs_ioend { xfs_off_t io_offset; /* offset in the file */ struct work_struct io_work; /* xfsdatad work queue */ struct xfs_trans *io_append_trans;/* xact. for size update */ - struct kiocb *io_iocb; - int io_result; } xfs_ioend_t; extern const struct address_space_operations xfs_address_space_operations; diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 91fa9a94ae92..d77797a52b7b 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -36,6 +36,7 @@ enum bh_state_bits { BH_Quiet, /* Buffer Error Prinks to be quiet */ BH_Meta, /* Buffer contains metadata */ BH_Prio, /* Buffer should be submitted with REQ_PRIO */ + BH_Defer_Completion, /* Defer AIO completion to workqueue */ BH_PrivateStart,/* not a state bit, but the first bit available * for private allocation by other entities @@ -128,6 +129,7 @@ BUFFER_FNS(Write_EIO, write_io_error) BUFFER_FNS(Unwritten, unwritten) BUFFER_FNS(Meta, meta) BUFFER_FNS(Prio, prio) +BUFFER_FNS(Defer_Completion, defer_completion) #define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) diff --git a/include/linux/fs.h b/include/linux/fs.h index 65c9929cd340..c9013876eb29 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -46,6 +46,7 @@ struct vfsmount; struct cred; struct swap_info_struct; struct seq_file; +struct workqueue_struct; extern void __init inode_init(void); extern void __init inode_init_early(void); @@ -63,8 +64,7 @@ struct buffer_head; typedef int (get_block_t)(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create); typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, - ssize_t bytes, void *private, int ret, - bool is_async); + ssize_t bytes, void *private); #define MAY_EXEC 0x00000001 #define MAY_WRITE 0x00000002 @@ -1328,6 +1328,9 @@ struct super_block { /* Being remounted read-only */ int s_readonly_remount; + + /* AIO completions deferred from interrupt context */ + struct workqueue_struct *s_dio_done_wq; }; /* superblock cache pruning functions */ -- cgit v1.2.3