[PATCH] md: support adding new devices to md arrays via sysfs
[pandora-kernel.git] / drivers / md / md.c
index 742a82a..825e235 100644 (file)
@@ -1667,7 +1667,7 @@ __ATTR(slot, 0644, slot_show, slot_store);
 static ssize_t
 offset_show(mdk_rdev_t *rdev, char *page)
 {
-       return sprintf(page, "%llu\n", rdev->data_offset);
+       return sprintf(page, "%llu\n", (unsigned long long)rdev->data_offset);
 }
 
 static ssize_t
@@ -1686,12 +1686,37 @@ offset_store(mdk_rdev_t *rdev, const char *buf, size_t len)
 static struct rdev_sysfs_entry rdev_offset =
 __ATTR(offset, 0644, offset_show, offset_store);
 
+static ssize_t
+rdev_size_show(mdk_rdev_t *rdev, char *page)
+{
+       return sprintf(page, "%llu\n", (unsigned long long)rdev->size);
+}
+
+static ssize_t
+rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
+{
+       char *e;
+       unsigned long long size = simple_strtoull(buf, &e, 10);
+       if (e==buf || (*e && *e != '\n'))
+               return -EINVAL;
+       if (rdev->mddev->pers)
+               return -EBUSY;
+       rdev->size = size;
+       if (size < rdev->mddev->size || rdev->mddev->size == 0)
+               rdev->mddev->size = size;
+       return len;
+}
+
+static struct rdev_sysfs_entry rdev_size =
+__ATTR(size, 0644, rdev_size_show, rdev_size_store);
+
 static struct attribute *rdev_default_attrs[] = {
        &rdev_state.attr,
        &rdev_super.attr,
        &rdev_errors.attr,
        &rdev_slot.attr,
        &rdev_offset.attr,
+       &rdev_size.attr,
        NULL,
 };
 static ssize_t
@@ -1962,6 +1987,65 @@ chunk_size_store(mddev_t *mddev, const char *buf, size_t len)
 static struct md_sysfs_entry md_chunk_size =
 __ATTR(chunk_size, 0644, chunk_size_show, chunk_size_store);
 
+static ssize_t
+null_show(mddev_t *mddev, char *page)
+{
+       return -EINVAL;
+}
+
+static ssize_t
+new_dev_store(mddev_t *mddev, const char *buf, size_t len)
+{
+       /* buf must be %d:%d\n? giving major and minor numbers */
+       /* The new device is added to the array.
+        * If the array has a persistent superblock, we read the
+        * superblock to initialise info and check validity.
+        * Otherwise, only checking done is that in bind_rdev_to_array,
+        * which mainly checks size.
+        */
+       char *e;
+       int major = simple_strtoul(buf, &e, 10);
+       int minor;
+       dev_t dev;
+       mdk_rdev_t *rdev;
+       int err;
+
+       if (!*buf || *e != ':' || !e[1] || e[1] == '\n')
+               return -EINVAL;
+       minor = simple_strtoul(e+1, &e, 10);
+       if (*e && *e != '\n')
+               return -EINVAL;
+       dev = MKDEV(major, minor);
+       if (major != MAJOR(dev) ||
+           minor != MINOR(dev))
+               return -EOVERFLOW;
+
+
+       if (mddev->persistent) {
+               rdev = md_import_device(dev, mddev->major_version,
+                                       mddev->minor_version);
+               if (!IS_ERR(rdev) && !list_empty(&mddev->disks)) {
+                       mdk_rdev_t *rdev0 = list_entry(mddev->disks.next,
+                                                      mdk_rdev_t, same_set);
+                       err = super_types[mddev->major_version]
+                               .load_super(rdev, rdev0, mddev->minor_version);
+                       if (err < 0)
+                               goto out;
+               }
+       } else
+               rdev = md_import_device(dev, -1, -1);
+
+       if (IS_ERR(rdev))
+               return PTR_ERR(rdev);
+       err = bind_rdev_to_array(rdev, mddev);
+ out:
+       if (err)
+               export_rdev(rdev);
+       return err ? err : len;
+}
+
+static struct md_sysfs_entry md_new_device =
+__ATTR(new_dev, 0200, null_show, new_dev_store);
 
 static ssize_t
 size_show(mddev_t *mddev, char *page)
@@ -2119,6 +2203,7 @@ static struct attribute *md_default_attrs[] = {
        &md_chunk_size.attr,
        &md_size.attr,
        &md_metadata.attr,
+       &md_new_device.attr,
        NULL,
 };