From 8ea55c95c372a7a51fa50cb7c75240bfbe8bd337 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 28 Jan 2015 18:44:17 +0100 Subject: s390/dasd: add locking for global_profile access Access to DASDs global statistics is done without locking which can lead to inconsistent data. Add locking to fix this. Also move the relevant structs in a global dasd_profile struct. Signed-off-by: Sebastian Ott Reviewed-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 32 ++++++++++++++++++++------------ drivers/s390/block/dasd_int.h | 2 +- drivers/s390/block/dasd_proc.c | 4 +++- 3 files changed, 24 insertions(+), 14 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4abf1196..a67e8da 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -674,8 +674,12 @@ EXPORT_SYMBOL(dasd_enable_device); unsigned int dasd_global_profile_level = DASD_PROFILE_OFF; #ifdef CONFIG_DASD_PROFILE -struct dasd_profile_info dasd_global_profile_data; -static struct dentry *dasd_global_profile_dentry; +static struct dasd_profile_info dasd_global_profile_data; +struct dasd_profile dasd_global_profile = { + .dentry = NULL, + .data = &dasd_global_profile_data, + .lock = __SPIN_LOCK_UNLOCKED(dasd_global_profile.lock), +}; static struct dentry *dasd_debugfs_global_entry; /* @@ -696,11 +700,13 @@ static void dasd_profile_start(struct dasd_block *block, if (++counter >= 31) break; + spin_lock(&dasd_global_profile.lock); if (dasd_global_profile_level) { - dasd_global_profile_data.dasd_io_nr_req[counter]++; + dasd_global_profile.data->dasd_io_nr_req[counter]++; if (rq_data_dir(req) == READ) - dasd_global_profile_data.dasd_read_nr_req[counter]++; + dasd_global_profile.data->dasd_read_nr_req[counter]++; } + spin_unlock(&dasd_global_profile.lock); spin_lock(&block->profile.lock); if (block->profile.data) { @@ -825,8 +831,9 @@ static void dasd_profile_end(struct dasd_block *block, dasd_profile_counter(irqtime / sectors, irqtimeps_ind); dasd_profile_counter(endtime, endtime_ind); + spin_lock(&dasd_global_profile.lock); if (dasd_global_profile_level) { - dasd_profile_end_add_data(&dasd_global_profile_data, + dasd_profile_end_add_data(dasd_global_profile.data, cqr->startdev != block->base, cqr->cpmode == 1, rq_data_dir(req) == READ, @@ -835,6 +842,7 @@ static void dasd_profile_end(struct dasd_block *block, irqtime_ind, irqtimeps_ind, endtime_ind); } + spin_unlock(&dasd_global_profile.lock); spin_lock(&block->profile.lock); if (block->profile.data) @@ -878,8 +886,7 @@ void dasd_profile_reset(struct dasd_profile *profile) void dasd_global_profile_reset(void) { - memset(&dasd_global_profile_data, 0, sizeof(dasd_global_profile_data)); - getnstimeofday(&dasd_global_profile_data.starttod); + dasd_profile_reset(&dasd_global_profile); } int dasd_profile_on(struct dasd_profile *profile) @@ -1077,7 +1084,9 @@ static int dasd_stats_global_show(struct seq_file *m, void *v) seq_puts(m, "disabled\n"); return 0; } - dasd_stats_seq_print(m, &dasd_global_profile_data); + spin_lock_bh(&dasd_global_profile.lock); + dasd_stats_seq_print(m, dasd_global_profile.data); + spin_unlock_bh(&dasd_global_profile.lock); return 0; } @@ -1123,8 +1132,8 @@ static void dasd_profile_exit(struct dasd_profile *profile) static void dasd_statistics_removeroot(void) { dasd_global_profile_level = DASD_PROFILE_OFF; - debugfs_remove(dasd_global_profile_dentry); - dasd_global_profile_dentry = NULL; + debugfs_remove(dasd_global_profile.dentry); + dasd_global_profile.dentry = NULL; debugfs_remove(dasd_debugfs_global_entry); debugfs_remove(dasd_debugfs_root_entry); } @@ -1136,7 +1145,6 @@ static void dasd_statistics_createroot(void) dasd_debugfs_root_entry = NULL; dasd_debugfs_global_entry = NULL; - dasd_global_profile_dentry = NULL; pde = debugfs_create_dir("dasd", NULL); if (!pde || IS_ERR(pde)) goto error; @@ -1151,7 +1159,7 @@ static void dasd_statistics_createroot(void) NULL, &dasd_stats_global_fops); if (!pde || IS_ERR(pde)) goto error; - dasd_global_profile_dentry = pde; + dasd_global_profile.dentry = pde; return; error: diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 8b5d410..91731fa 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -651,7 +651,7 @@ dasd_check_blocksize(int bsize) #define DASD_PROFILE_GLOBAL_ONLY 2 extern debug_info_t *dasd_debug_area; -extern struct dasd_profile_info dasd_global_profile_data; +extern struct dasd_profile dasd_global_profile; extern unsigned int dasd_global_profile_level; extern const struct block_device_operations dasd_device_operations; diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 78ac905a..7641008 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -219,7 +219,8 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v) "/proc/dasd/statistics'\n"); return 0; } - prof = &dasd_global_profile_data; + spin_lock_bh(&dasd_global_profile.lock); + prof = dasd_global_profile.data; /* prevent counter 'overflow' on output */ for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999; @@ -255,6 +256,7 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v) dasd_statistics_array(m, prof->dasd_io_time3, factor); seq_printf(m, "# of req in chanq at enqueuing (1..32) \n"); dasd_statistics_array(m, prof->dasd_io_nr_req, factor); + spin_unlock_bh(&dasd_global_profile.lock); #else seq_printf(m, "Statistics are not activated in this kernel\n"); #endif -- cgit v1.1