aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block')
-rw-r--r--drivers/s390/block/dasd.c102
-rw-r--r--drivers/s390/block/dasd_int.h3
-rw-r--r--drivers/s390/block/dasd_proc.c21
-rw-r--r--drivers/s390/block/dcssblk.c36
4 files changed, 61 insertions, 101 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 4abf11965484..be34ef41b7c7 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -674,8 +674,9 @@ 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;
+struct dasd_profile dasd_global_profile = {
+ .lock = __SPIN_LOCK_UNLOCKED(dasd_global_profile.lock),
+};
static struct dentry *dasd_debugfs_global_entry;
/*
@@ -696,11 +697,13 @@ static void dasd_profile_start(struct dasd_block *block,
if (++counter >= 31)
break;
- if (dasd_global_profile_level) {
- dasd_global_profile_data.dasd_io_nr_req[counter]++;
+ spin_lock(&dasd_global_profile.lock);
+ if (dasd_global_profile.data) {
+ 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 +828,9 @@ static void dasd_profile_end(struct dasd_block *block,
dasd_profile_counter(irqtime / sectors, irqtimeps_ind);
dasd_profile_counter(endtime, endtime_ind);
- if (dasd_global_profile_level) {
- dasd_profile_end_add_data(&dasd_global_profile_data,
+ spin_lock(&dasd_global_profile.lock);
+ if (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 +839,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)
@@ -876,12 +881,6 @@ void dasd_profile_reset(struct dasd_profile *profile)
spin_unlock_bh(&profile->lock);
}
-void dasd_global_profile_reset(void)
-{
- memset(&dasd_global_profile_data, 0, sizeof(dasd_global_profile_data));
- getnstimeofday(&dasd_global_profile_data.starttod);
-}
-
int dasd_profile_on(struct dasd_profile *profile)
{
struct dasd_profile_info *data;
@@ -949,12 +948,20 @@ static ssize_t dasd_stats_write(struct file *file,
dasd_profile_reset(prof);
} else if (strncmp(str, "on", 2) == 0) {
rc = dasd_profile_on(prof);
- if (!rc)
- rc = user_len;
+ if (rc)
+ goto out;
+ rc = user_len;
+ if (prof == &dasd_global_profile) {
+ dasd_profile_reset(prof);
+ dasd_global_profile_level = DASD_PROFILE_GLOBAL_ONLY;
+ }
} else if (strncmp(str, "off", 3) == 0) {
+ if (prof == &dasd_global_profile)
+ dasd_global_profile_level = DASD_PROFILE_OFF;
dasd_profile_off(prof);
} else
rc = -EINVAL;
+out:
vfree(buffer);
return rc;
}
@@ -1044,57 +1051,6 @@ static const struct file_operations dasd_stats_raw_fops = {
.write = dasd_stats_write,
};
-static ssize_t dasd_stats_global_write(struct file *file,
- const char __user *user_buf,
- size_t user_len, loff_t *pos)
-{
- char *buffer, *str;
- ssize_t rc;
-
- if (user_len > 65536)
- user_len = 65536;
- buffer = dasd_get_user_string(user_buf, user_len);
- if (IS_ERR(buffer))
- return PTR_ERR(buffer);
- str = skip_spaces(buffer);
- rc = user_len;
- if (strncmp(str, "reset", 5) == 0) {
- dasd_global_profile_reset();
- } else if (strncmp(str, "on", 2) == 0) {
- dasd_global_profile_reset();
- dasd_global_profile_level = DASD_PROFILE_GLOBAL_ONLY;
- } else if (strncmp(str, "off", 3) == 0) {
- dasd_global_profile_level = DASD_PROFILE_OFF;
- } else
- rc = -EINVAL;
- vfree(buffer);
- return rc;
-}
-
-static int dasd_stats_global_show(struct seq_file *m, void *v)
-{
- if (!dasd_global_profile_level) {
- seq_puts(m, "disabled\n");
- return 0;
- }
- dasd_stats_seq_print(m, &dasd_global_profile_data);
- return 0;
-}
-
-static int dasd_stats_global_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dasd_stats_global_show, NULL);
-}
-
-static const struct file_operations dasd_stats_global_fops = {
- .owner = THIS_MODULE,
- .open = dasd_stats_global_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = dasd_stats_global_write,
-};
-
static void dasd_profile_init(struct dasd_profile *profile,
struct dentry *base_dentry)
{
@@ -1123,20 +1079,16 @@ 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;
+ dasd_profile_exit(&dasd_global_profile);
debugfs_remove(dasd_debugfs_global_entry);
debugfs_remove(dasd_debugfs_root_entry);
}
static void dasd_statistics_createroot(void)
{
- umode_t mode;
struct dentry *pde;
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;
@@ -1145,13 +1097,7 @@ static void dasd_statistics_createroot(void)
if (!pde || IS_ERR(pde))
goto error;
dasd_debugfs_global_entry = pde;
-
- mode = (S_IRUSR | S_IWUSR | S_IFREG);
- pde = debugfs_create_file("statistics", mode, dasd_debugfs_global_entry,
- NULL, &dasd_stats_global_fops);
- if (!pde || IS_ERR(pde))
- goto error;
- dasd_global_profile_dentry = pde;
+ dasd_profile_init(&dasd_global_profile, dasd_debugfs_global_entry);
return;
error:
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 8b5d4100abf7..227e3dea3155 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;
@@ -728,7 +728,6 @@ int dasd_device_is_ro(struct dasd_device *);
void dasd_profile_reset(struct dasd_profile *);
int dasd_profile_on(struct dasd_profile *);
void dasd_profile_off(struct dasd_profile *);
-void dasd_global_profile_reset(void);
char *dasd_get_user_string(const char __user *, size_t);
/* externals in dasd_devmap.c */
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 78ac905a5b7f..aa7bb2d1da81 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -212,14 +212,15 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v)
struct dasd_profile_info *prof;
int factor;
- /* check for active profiling */
- if (!dasd_global_profile_level) {
+ spin_lock_bh(&dasd_global_profile.lock);
+ prof = dasd_global_profile.data;
+ if (!prof) {
+ spin_unlock_bh(&dasd_global_profile.lock);
seq_printf(m, "Statistics are off - they might be "
"switched on using 'echo set on > "
"/proc/dasd/statistics'\n");
return 0;
}
- 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
@@ -291,14 +293,19 @@ static ssize_t dasd_stats_proc_write(struct file *file,
dasd_stats_all_block_off();
goto out_error;
}
- dasd_global_profile_reset();
+ rc = dasd_profile_on(&dasd_global_profile);
+ if (rc) {
+ dasd_stats_all_block_off();
+ goto out_error;
+ }
+ dasd_profile_reset(&dasd_global_profile);
dasd_global_profile_level = DASD_PROFILE_ON;
pr_info("The statistics feature has been switched "
"on\n");
} else if (strcmp(str, "off") == 0) {
- /* switch off and reset statistics profiling */
+ /* switch off statistics profiling */
dasd_global_profile_level = DASD_PROFILE_OFF;
- dasd_global_profile_reset();
+ dasd_profile_off(&dasd_global_profile);
dasd_stats_all_block_off();
pr_info("The statistics feature has been switched "
"off\n");
@@ -306,7 +313,7 @@ static ssize_t dasd_stats_proc_write(struct file *file,
goto out_parse_error;
} else if (strncmp(str, "reset", 5) == 0) {
/* reset the statistics */
- dasd_global_profile_reset();
+ dasd_profile_reset(&dasd_global_profile);
dasd_stats_all_block_reset();
pr_info("The statistics have been reset\n");
} else
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index b550c8c8d010..96128cb009f3 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -28,8 +28,8 @@
static int dcssblk_open(struct block_device *bdev, fmode_t mode);
static void dcssblk_release(struct gendisk *disk, fmode_t mode);
static void dcssblk_make_request(struct request_queue *q, struct bio *bio);
-static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
- void **kaddr, unsigned long *pfn);
+static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
+ void **kaddr, unsigned long *pfn, long size);
static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
@@ -438,7 +438,13 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
pr_info("All DCSSs that map to device %s are "
"saved\n", dev_info->segment_name);
list_for_each_entry(entry, &dev_info->seg_list, lh) {
- segment_save(entry->segment_name);
+ if (entry->segment_type == SEG_TYPE_EN ||
+ entry->segment_type == SEG_TYPE_SN)
+ pr_warn("DCSS %s is of type SN or EN"
+ " and cannot be saved\n",
+ entry->segment_name);
+ else
+ segment_save(entry->segment_name);
}
} else {
// device is busy => we save it when it becomes
@@ -797,7 +803,12 @@ dcssblk_release(struct gendisk *disk, fmode_t mode)
pr_info("Device %s has become idle and is being saved "
"now\n", dev_info->segment_name);
list_for_each_entry(entry, &dev_info->seg_list, lh) {
- segment_save(entry->segment_name);
+ if (entry->segment_type == SEG_TYPE_EN ||
+ entry->segment_type == SEG_TYPE_SN)
+ pr_warn("DCSS %s is of type SN or EN and cannot"
+ " be saved\n", entry->segment_name);
+ else
+ segment_save(entry->segment_name);
}
dev_info->save_pending = 0;
}
@@ -866,25 +877,22 @@ fail:
bio_io_error(bio);
}
-static int
+static long
dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
- void **kaddr, unsigned long *pfn)
+ void **kaddr, unsigned long *pfn, long size)
{
struct dcssblk_dev_info *dev_info;
- unsigned long pgoff;
+ unsigned long offset, dev_sz;
dev_info = bdev->bd_disk->private_data;
if (!dev_info)
return -ENODEV;
- if (secnum % (PAGE_SIZE/512))
- return -EINVAL;
- pgoff = secnum / (PAGE_SIZE / 512);
- if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
- return -ERANGE;
- *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE);
+ dev_sz = dev_info->end - dev_info->start;
+ offset = secnum * 512;
+ *kaddr = (void *) (dev_info->start + offset);
*pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT;
- return 0;
+ return dev_sz - offset;
}
static void