This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / s390 / block / dcssblk.c
index a66b17b..b7a764c 100644 (file)
@@ -139,57 +139,6 @@ 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)
@@ -218,50 +167,80 @@ 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);
-               rc = -EBUSY;
-               goto out;
+               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;
        }
        if (inbuf[0] == '1') {
                // reload segment in shared mode
-               rc = segment_modify_shared(dev_info->segment_name,
-                                          SEGMENT_SHARED);
+               segment_unload(dev_info->segment_name);
+               rc = segment_load(dev_info->segment_name, SEGMENT_SHARED_RO,
+                                       &dev_info->start, &dev_info->end);
                if (rc < 0) {
-                       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);
-                       }
+                       PRINT_ERR("Segment %s not reloaded, rc=%d\n",
+                                       dev_info->segment_name, rc);
+                       goto removeseg;
                }
+               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
-               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);
+               segment_unload(dev_info->segment_name);
+               rc = segment_load(dev_info->segment_name, SEGMENT_EXCLUSIVE_RW,
+                                       &dev_info->start, &dev_info->end);
                if (rc < 0) {
-                       BUG_ON(rc == -EINVAL);
-                       if (rc == -EIO || rc == -ENOENT)
-                               goto removeseg;
-               } else {
-                       dev_info->is_shared = 0;
-                       set_disk_ro(dev_info->gd, 0);
+                       PRINT_ERR("Segment %s not reloaded, rc=%d\n",
+                                       dev_info->segment_name, rc);
+                       goto removeseg;
                }
+               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");
-               rc = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
+       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:
@@ -275,8 +254,8 @@ removeseg:
        put_disk(dev_info->gd);
        device_unregister(dev);
        put_device(dev);
-out:
        up_write(&dcssblk_devices_sem);
+out:
        return rc;
 }
 
@@ -313,7 +292,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_save(dev_info->segment_name);
+                       segment_replace(dev_info->segment_name);
                }  else {
                        // device is busy => we save it when it becomes
                        // idle in dcssblk_release
@@ -411,17 +390,18 @@ dcssblk_add_store(struct device *dev, const char *buf, size_t count)
        /*
         * load the segment
         */
-       rc = segment_load(local_buf, SEGMENT_SHARED,
+       rc = segment_load(local_buf, SEGMENT_SHARED_RO,
                                &dev_info->start, &dev_info->end);
        if (rc < 0) {
-               dcssblk_segment_warn(rc, dev_info->segment_name);
+               PRINT_ERR("Segment %s not loaded, rc=%d\n", local_buf, rc);
                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, size = %lu Byte, "
-                  "capacity = %lu (512 Byte) sectors\n", local_buf,
-                  seg_byte_size, seg_byte_size >> 9);
+       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);
 
        dev_info->segment_type = rc;
        dev_info->save_pending = 0;
@@ -471,12 +451,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 SEG_TYPE_SR:
-               case SEG_TYPE_ER:
-               case SEG_TYPE_SC:
+               case SEGMENT_SHARED_RO:
+               case SEGMENT_EXCLUSIVE_RO:
                        set_disk_ro(dev_info->gd,1);
                        break;
-               default:
+               case SEGMENT_SHARED_RW:
+               case SEGMENT_EXCLUSIVE_RW:
                        set_disk_ro(dev_info->gd,0);
                        break;
        }
@@ -609,7 +589,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_save(dev_info->segment_name);
+               segment_replace(dev_info->segment_name);
                dev_info->save_pending = 0;
        }
        up_write(&dcssblk_devices_sem);