diff options
author | NeilBrown <neilb@suse.de> | 2006-01-06 03:21:16 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:34:10 -0500 |
commit | 6d7ff7380b2e28c2807da3bf9fa614d91d15bacf (patch) | |
tree | 1f995a4f047a041c86b52efe0db221c76c7d0327 /drivers/md/md.c | |
parent | 83303b613d00718b07ec0a4dee7c99aa66629d96 (diff) |
[PATCH] md: support adding new devices to md arrays via sysfs
Writing major:minor to md/new_dev will bind that device to the array.
Signed-off-by: Neil Brown <neilb@suse.de>
Acked-by: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r-- | drivers/md/md.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 40ac7fbab61f..825e235b791b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -1987,6 +1987,65 @@ chunk_size_store(mddev_t *mddev, const char *buf, size_t len) | |||
1987 | static struct md_sysfs_entry md_chunk_size = | 1987 | static struct md_sysfs_entry md_chunk_size = |
1988 | __ATTR(chunk_size, 0644, chunk_size_show, chunk_size_store); | 1988 | __ATTR(chunk_size, 0644, chunk_size_show, chunk_size_store); |
1989 | 1989 | ||
1990 | static ssize_t | ||
1991 | null_show(mddev_t *mddev, char *page) | ||
1992 | { | ||
1993 | return -EINVAL; | ||
1994 | } | ||
1995 | |||
1996 | static ssize_t | ||
1997 | new_dev_store(mddev_t *mddev, const char *buf, size_t len) | ||
1998 | { | ||
1999 | /* buf must be %d:%d\n? giving major and minor numbers */ | ||
2000 | /* The new device is added to the array. | ||
2001 | * If the array has a persistent superblock, we read the | ||
2002 | * superblock to initialise info and check validity. | ||
2003 | * Otherwise, only checking done is that in bind_rdev_to_array, | ||
2004 | * which mainly checks size. | ||
2005 | */ | ||
2006 | char *e; | ||
2007 | int major = simple_strtoul(buf, &e, 10); | ||
2008 | int minor; | ||
2009 | dev_t dev; | ||
2010 | mdk_rdev_t *rdev; | ||
2011 | int err; | ||
2012 | |||
2013 | if (!*buf || *e != ':' || !e[1] || e[1] == '\n') | ||
2014 | return -EINVAL; | ||
2015 | minor = simple_strtoul(e+1, &e, 10); | ||
2016 | if (*e && *e != '\n') | ||
2017 | return -EINVAL; | ||
2018 | dev = MKDEV(major, minor); | ||
2019 | if (major != MAJOR(dev) || | ||
2020 | minor != MINOR(dev)) | ||
2021 | return -EOVERFLOW; | ||
2022 | |||
2023 | |||
2024 | if (mddev->persistent) { | ||
2025 | rdev = md_import_device(dev, mddev->major_version, | ||
2026 | mddev->minor_version); | ||
2027 | if (!IS_ERR(rdev) && !list_empty(&mddev->disks)) { | ||
2028 | mdk_rdev_t *rdev0 = list_entry(mddev->disks.next, | ||
2029 | mdk_rdev_t, same_set); | ||
2030 | err = super_types[mddev->major_version] | ||
2031 | .load_super(rdev, rdev0, mddev->minor_version); | ||
2032 | if (err < 0) | ||
2033 | goto out; | ||
2034 | } | ||
2035 | } else | ||
2036 | rdev = md_import_device(dev, -1, -1); | ||
2037 | |||
2038 | if (IS_ERR(rdev)) | ||
2039 | return PTR_ERR(rdev); | ||
2040 | err = bind_rdev_to_array(rdev, mddev); | ||
2041 | out: | ||
2042 | if (err) | ||
2043 | export_rdev(rdev); | ||
2044 | return err ? err : len; | ||
2045 | } | ||
2046 | |||
2047 | static struct md_sysfs_entry md_new_device = | ||
2048 | __ATTR(new_dev, 0200, null_show, new_dev_store); | ||
1990 | 2049 | ||
1991 | static ssize_t | 2050 | static ssize_t |
1992 | size_show(mddev_t *mddev, char *page) | 2051 | size_show(mddev_t *mddev, char *page) |
@@ -2144,6 +2203,7 @@ static struct attribute *md_default_attrs[] = { | |||
2144 | &md_chunk_size.attr, | 2203 | &md_chunk_size.attr, |
2145 | &md_size.attr, | 2204 | &md_size.attr, |
2146 | &md_metadata.attr, | 2205 | &md_metadata.attr, |
2206 | &md_new_device.attr, | ||
2147 | NULL, | 2207 | NULL, |
2148 | }; | 2208 | }; |
2149 | 2209 | ||