X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fs390%2Fblock%2Fdcssblk.c;h=a66b17b65296e7d73ddc6d8f0ecea6c5ac864b6f;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=b7a764ca36b345b3757be3395e88ecc32a46f968;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index b7a764ca3..a66b17b65 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -139,6 +139,57 @@ dcssblk_get_device_by_name(char *name) return NULL; } +/* + * print appropriate error message for segment_load()/segment_type() + * return code + */ +static void +dcssblk_segment_warn(int rc, char* seg_name) +{ + switch (rc) { + case -ENOENT: + PRINT_WARN("cannot load/query segment %s, does not exist\n", + seg_name); + break; + case -ENOSYS: + PRINT_WARN("cannot load/query segment %s, not running on VM\n", + seg_name); + break; + case -EIO: + PRINT_WARN("cannot load/query segment %s, hardware error\n", + seg_name); + break; + case -ENOTSUPP: + PRINT_WARN("cannot load/query segment %s, is a multi-part " + "segment\n", seg_name); + break; + case -ENOSPC: + PRINT_WARN("cannot load/query segment %s, overlaps with " + "storage\n", seg_name); + break; + case -EBUSY: + PRINT_WARN("cannot load/query segment %s, overlaps with " + "already loaded dcss\n", seg_name); + break; + case -EPERM: + PRINT_WARN("cannot load/query segment %s, already loaded in " + "incompatible mode\n", seg_name); + break; + case -ENOMEM: + PRINT_WARN("cannot load/query segment %s, out of memory\n", + seg_name); + break; + case -ERANGE: + PRINT_WARN("cannot load/query segment %s, exceeds kernel " + "mapping range\n", seg_name); + break; + default: + PRINT_WARN("cannot load/query segment %s, return value %i\n", + seg_name, rc); + break; + } +} + /* * device attribute for switching shared/nonshared (exclusive) * operation (show + store) @@ -167,80 +218,50 @@ dcssblk_shared_store(struct device *dev, const char *inbuf, size_t count) if (atomic_read(&dev_info->use_count)) { PRINT_ERR("share: segment %s is busy!\n", dev_info->segment_name); - up_write(&dcssblk_devices_sem); - return -EBUSY; - } - if ((inbuf[0] == '1') && (dev_info->is_shared == 1)) { - PRINT_WARN("Segment %s already loaded in shared mode!\n", - dev_info->segment_name); - up_write(&dcssblk_devices_sem); - return count; - } - if ((inbuf[0] == '0') && (dev_info->is_shared == 0)) { - PRINT_WARN("Segment %s already loaded in exclusive mode!\n", - dev_info->segment_name); - up_write(&dcssblk_devices_sem); - return count; + rc = -EBUSY; + goto out; } if (inbuf[0] == '1') { // reload segment in shared mode - segment_unload(dev_info->segment_name); - rc = segment_load(dev_info->segment_name, SEGMENT_SHARED_RO, - &dev_info->start, &dev_info->end); + rc = segment_modify_shared(dev_info->segment_name, + SEGMENT_SHARED); if (rc < 0) { - PRINT_ERR("Segment %s not reloaded, rc=%d\n", - dev_info->segment_name, rc); - goto removeseg; + BUG_ON(rc == -EINVAL); + if (rc == -EIO || rc == -ENOENT) + goto removeseg; + } else { + dev_info->is_shared = 1; + switch (dev_info->segment_type) { + case SEG_TYPE_SR: + case SEG_TYPE_ER: + case SEG_TYPE_SC: + set_disk_ro(dev_info->gd,1); + } } - dev_info->is_shared = 1; - PRINT_INFO("Segment %s reloaded, shared mode.\n", - dev_info->segment_name); } else if (inbuf[0] == '0') { // reload segment in exclusive mode - segment_unload(dev_info->segment_name); - rc = segment_load(dev_info->segment_name, SEGMENT_EXCLUSIVE_RW, - &dev_info->start, &dev_info->end); + if (dev_info->segment_type == SEG_TYPE_SC) { + PRINT_ERR("Segment type SC (%s) cannot be loaded in " + "non-shared mode\n", dev_info->segment_name); + rc = -EINVAL; + goto out; + } + rc = segment_modify_shared(dev_info->segment_name, + SEGMENT_EXCLUSIVE); if (rc < 0) { - PRINT_ERR("Segment %s not reloaded, rc=%d\n", - dev_info->segment_name, rc); - goto removeseg; + BUG_ON(rc == -EINVAL); + if (rc == -EIO || rc == -ENOENT) + goto removeseg; + } else { + dev_info->is_shared = 0; + set_disk_ro(dev_info->gd, 0); } - dev_info->is_shared = 0; - PRINT_INFO("Segment %s reloaded, exclusive (read-write) mode.\n", - dev_info->segment_name); } else { - up_write(&dcssblk_devices_sem); PRINT_WARN("Invalid value, must be 0 or 1\n"); - return -EINVAL; + rc = -EINVAL; + goto out; } - dev_info->segment_type = rc; rc = count; - - switch (dev_info->segment_type) { - case SEGMENT_SHARED_RO: - case SEGMENT_EXCLUSIVE_RO: - set_disk_ro(dev_info->gd, 1); - break; - case SEGMENT_SHARED_RW: - case SEGMENT_EXCLUSIVE_RW: - set_disk_ro(dev_info->gd, 0); - break; - } - if ((inbuf[0] == '1') && - ((dev_info->segment_type == SEGMENT_EXCLUSIVE_RO) || - (dev_info->segment_type == SEGMENT_EXCLUSIVE_RW))) { - PRINT_WARN("Could not get shared copy of segment %s\n", - dev_info->segment_name); - rc = -EPERM; - } - if ((inbuf[0] == '0') && - ((dev_info->segment_type == SEGMENT_SHARED_RO) || - (dev_info->segment_type == SEGMENT_SHARED_RW))) { - PRINT_WARN("Could not get exclusive copy of segment %s\n", - dev_info->segment_name); - rc = -EPERM; - } - up_write(&dcssblk_devices_sem); goto out; removeseg: @@ -254,8 +275,8 @@ removeseg: put_disk(dev_info->gd); device_unregister(dev); put_device(dev); - up_write(&dcssblk_devices_sem); out: + up_write(&dcssblk_devices_sem); return rc; } @@ -292,7 +313,7 @@ dcssblk_save_store(struct device *dev, const char *inbuf, size_t count) // device is idle => we save immediately PRINT_INFO("Saving segment %s\n", dev_info->segment_name); - segment_replace(dev_info->segment_name); + segment_save(dev_info->segment_name); } else { // device is busy => we save it when it becomes // idle in dcssblk_release @@ -390,18 +411,17 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count) /* * load the segment */ - rc = segment_load(local_buf, SEGMENT_SHARED_RO, + rc = segment_load(local_buf, SEGMENT_SHARED, &dev_info->start, &dev_info->end); if (rc < 0) { - PRINT_ERR("Segment %s not loaded, rc=%d\n", local_buf, rc); + dcssblk_segment_warn(rc, dev_info->segment_name); goto dealloc_gendisk; } seg_byte_size = (dev_info->end - dev_info->start + 1); set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors - PRINT_INFO("Loaded segment %s from %p to %p, size = %lu Byte, " - "capacity = %lu sectors (512 Byte)\n", local_buf, - (void *) dev_info->start, (void *) dev_info->end, - seg_byte_size, seg_byte_size >> 9); + PRINT_INFO("Loaded segment %s, size = %lu Byte, " + "capacity = %lu (512 Byte) sectors\n", local_buf, + seg_byte_size, seg_byte_size >> 9); dev_info->segment_type = rc; dev_info->save_pending = 0; @@ -451,12 +471,12 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count) blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); switch (dev_info->segment_type) { - case SEGMENT_SHARED_RO: - case SEGMENT_EXCLUSIVE_RO: + case SEG_TYPE_SR: + case SEG_TYPE_ER: + case SEG_TYPE_SC: set_disk_ro(dev_info->gd,1); break; - case SEGMENT_SHARED_RW: - case SEGMENT_EXCLUSIVE_RW: + default: set_disk_ro(dev_info->gd,0); break; } @@ -589,7 +609,7 @@ dcssblk_release(struct inode *inode, struct file *filp) && (dev_info->save_pending)) { PRINT_INFO("Segment %s became idle and is being saved now\n", dev_info->segment_name); - segment_replace(dev_info->segment_name); + segment_save(dev_info->segment_name); dev_info->save_pending = 0; } up_write(&dcssblk_devices_sem);