Skip to content

Commit 86e6ffd

Browse files
neilbrownLinus Torvalds
authored andcommitted
[PATCH] md: extend md sysfs support to component devices.
Each device in an md array how has a corresponding /sys/block/mdX/md/devNN/ directory which can contain attributes. Currently there is only 'state' which summarises the state, nd 'super' which has a copy of the superblock, and 'block' which is a symlink to the block device. Also, /sys/block/mdX/md/rdNN represents slot 'NN' in the array, and is a symlink to the relevant 'devNN'. Obviously spare devices do not have a slot in the array, and so don't have such a symlink. Signed-off-by: Neil Brown <neilb@suse.de> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
1 parent eae1701 commit 86e6ffd

File tree

2 files changed

+162
-8
lines changed

2 files changed

+162
-8
lines changed

drivers/md/md.c

Lines changed: 160 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
711711
*/
712712
int i;
713713
int active=0, working=0,failed=0,spare=0,nr_disks=0;
714+
unsigned int fixdesc=0;
714715

715716
rdev->sb_size = MD_SB_BYTES;
716717

@@ -758,16 +759,28 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
758759
sb->disks[0].state = (1<<MD_DISK_REMOVED);
759760
ITERATE_RDEV(mddev,rdev2,tmp) {
760761
mdp_disk_t *d;
762+
int desc_nr;
761763
if (rdev2->raid_disk >= 0 && rdev2->in_sync && !rdev2->faulty)
762-
rdev2->desc_nr = rdev2->raid_disk;
764+
desc_nr = rdev2->raid_disk;
763765
else
764-
rdev2->desc_nr = next_spare++;
766+
desc_nr = next_spare++;
767+
if (desc_nr != rdev2->desc_nr) {
768+
fixdesc |= (1 << desc_nr);
769+
rdev2->desc_nr = desc_nr;
770+
if (rdev2->raid_disk >= 0) {
771+
char nm[20];
772+
sprintf(nm, "rd%d", rdev2->raid_disk);
773+
sysfs_remove_link(&mddev->kobj, nm);
774+
}
775+
sysfs_remove_link(&rdev2->kobj, "block");
776+
kobject_del(&rdev2->kobj);
777+
}
765778
d = &sb->disks[rdev2->desc_nr];
766779
nr_disks++;
767780
d->number = rdev2->desc_nr;
768781
d->major = MAJOR(rdev2->bdev->bd_dev);
769782
d->minor = MINOR(rdev2->bdev->bd_dev);
770-
if (rdev2->raid_disk >= 0 && rdev->in_sync && !rdev2->faulty)
783+
if (rdev2->raid_disk >= 0 && rdev2->in_sync && !rdev2->faulty)
771784
d->raid_disk = rdev2->raid_disk;
772785
else
773786
d->raid_disk = rdev2->desc_nr; /* compatibility */
@@ -787,7 +800,22 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
787800
if (test_bit(WriteMostly, &rdev2->flags))
788801
d->state |= (1<<MD_DISK_WRITEMOSTLY);
789802
}
790-
803+
if (fixdesc)
804+
ITERATE_RDEV(mddev,rdev2,tmp)
805+
if (fixdesc & (1<<rdev2->desc_nr)) {
806+
snprintf(rdev2->kobj.name, KOBJ_NAME_LEN, "dev%d",
807+
rdev2->desc_nr);
808+
kobject_add(&rdev2->kobj);
809+
sysfs_create_link(&rdev2->kobj,
810+
&rdev2->bdev->bd_disk->kobj,
811+
"block");
812+
if (rdev2->raid_disk >= 0) {
813+
char nm[20];
814+
sprintf(nm, "rd%d", rdev2->raid_disk);
815+
sysfs_create_link(&mddev->kobj,
816+
&rdev2->kobj, nm);
817+
}
818+
}
791819
/* now set the "removed" and "faulty" bits on any missing devices */
792820
for (i=0 ; i < mddev->raid_disks ; i++) {
793821
mdp_disk_t *d = &sb->disks[i];
@@ -1147,6 +1175,13 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
11471175
list_add(&rdev->same_set, &mddev->disks);
11481176
rdev->mddev = mddev;
11491177
printk(KERN_INFO "md: bind<%s>\n", bdevname(rdev->bdev,b));
1178+
1179+
rdev->kobj.k_name = NULL;
1180+
snprintf(rdev->kobj.name, KOBJ_NAME_LEN, "dev%d", rdev->desc_nr);
1181+
rdev->kobj.parent = kobject_get(&mddev->kobj);
1182+
kobject_add(&rdev->kobj);
1183+
1184+
sysfs_create_link(&rdev->kobj, &rdev->bdev->bd_disk->kobj, "block");
11501185
return 0;
11511186
}
11521187

@@ -1160,6 +1195,8 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
11601195
list_del_init(&rdev->same_set);
11611196
printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
11621197
rdev->mddev = NULL;
1198+
sysfs_remove_link(&rdev->kobj, "block");
1199+
kobject_del(&rdev->kobj);
11631200
}
11641201

11651202
/*
@@ -1215,7 +1252,7 @@ static void export_rdev(mdk_rdev_t * rdev)
12151252
md_autodetect_dev(rdev->bdev->bd_dev);
12161253
#endif
12171254
unlock_rdev(rdev);
1218-
kfree(rdev);
1255+
kobject_put(&rdev->kobj);
12191256
}
12201257

12211258
static void kick_rdev_from_array(mdk_rdev_t * rdev)
@@ -1414,6 +1451,94 @@ static void md_update_sb(mddev_t * mddev)
14141451

14151452
}
14161453

1454+
struct rdev_sysfs_entry {
1455+
struct attribute attr;
1456+
ssize_t (*show)(mdk_rdev_t *, char *);
1457+
ssize_t (*store)(mdk_rdev_t *, const char *, size_t);
1458+
};
1459+
1460+
static ssize_t
1461+
rdev_show_state(mdk_rdev_t *rdev, char *page)
1462+
{
1463+
char *sep = "";
1464+
int len=0;
1465+
1466+
if (rdev->faulty) {
1467+
len+= sprintf(page+len, "%sfaulty",sep);
1468+
sep = ",";
1469+
}
1470+
if (rdev->in_sync) {
1471+
len += sprintf(page+len, "%sin_sync",sep);
1472+
sep = ",";
1473+
}
1474+
if (!rdev->faulty && !rdev->in_sync) {
1475+
len += sprintf(page+len, "%sspare", sep);
1476+
sep = ",";
1477+
}
1478+
return len+sprintf(page+len, "\n");
1479+
}
1480+
1481+
static struct rdev_sysfs_entry rdev_state = {
1482+
.attr = {.name = "state", .mode = S_IRUGO },
1483+
.show = rdev_show_state,
1484+
};
1485+
1486+
static ssize_t
1487+
rdev_show_super(mdk_rdev_t *rdev, char *page)
1488+
{
1489+
if (rdev->sb_loaded && rdev->sb_size) {
1490+
memcpy(page, page_address(rdev->sb_page), rdev->sb_size);
1491+
return rdev->sb_size;
1492+
} else
1493+
return 0;
1494+
}
1495+
static struct rdev_sysfs_entry rdev_super = {
1496+
.attr = {.name = "super", .mode = S_IRUGO },
1497+
.show = rdev_show_super,
1498+
};
1499+
static struct attribute *rdev_default_attrs[] = {
1500+
&rdev_state.attr,
1501+
&rdev_super.attr,
1502+
NULL,
1503+
};
1504+
static ssize_t
1505+
rdev_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
1506+
{
1507+
struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
1508+
mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
1509+
1510+
if (!entry->show)
1511+
return -EIO;
1512+
return entry->show(rdev, page);
1513+
}
1514+
1515+
static ssize_t
1516+
rdev_attr_store(struct kobject *kobj, struct attribute *attr,
1517+
const char *page, size_t length)
1518+
{
1519+
struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
1520+
mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
1521+
1522+
if (!entry->store)
1523+
return -EIO;
1524+
return entry->store(rdev, page, length);
1525+
}
1526+
1527+
static void rdev_free(struct kobject *ko)
1528+
{
1529+
mdk_rdev_t *rdev = container_of(ko, mdk_rdev_t, kobj);
1530+
kfree(rdev);
1531+
}
1532+
static struct sysfs_ops rdev_sysfs_ops = {
1533+
.show = rdev_attr_show,
1534+
.store = rdev_attr_store,
1535+
};
1536+
static struct kobj_type rdev_ktype = {
1537+
.release = rdev_free,
1538+
.sysfs_ops = &rdev_sysfs_ops,
1539+
.default_attrs = rdev_default_attrs,
1540+
};
1541+
14171542
/*
14181543
* Import a device. If 'super_format' >= 0, then sanity check the superblock
14191544
*
@@ -1445,6 +1570,10 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
14451570
if (err)
14461571
goto abort_free;
14471572

1573+
rdev->kobj.parent = NULL;
1574+
rdev->kobj.ktype = &rdev_ktype;
1575+
kobject_init(&rdev->kobj);
1576+
14481577
rdev->desc_nr = -1;
14491578
rdev->faulty = 0;
14501579
rdev->in_sync = 0;
@@ -1820,6 +1949,13 @@ static int do_md_run(mddev_t * mddev)
18201949
mddev->safemode_timer.data = (unsigned long) mddev;
18211950
mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */
18221951
mddev->in_sync = 1;
1952+
1953+
ITERATE_RDEV(mddev,rdev,tmp)
1954+
if (rdev->raid_disk >= 0) {
1955+
char nm[20];
1956+
sprintf(nm, "rd%d", rdev->raid_disk);
1957+
sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
1958+
}
18231959

18241960
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
18251961
md_wakeup_thread(mddev->thread);
@@ -1941,9 +2077,18 @@ static int do_md_stop(mddev_t * mddev, int ro)
19412077
* Free resources if final stop
19422078
*/
19432079
if (!ro) {
2080+
mdk_rdev_t *rdev;
2081+
struct list_head *tmp;
19442082
struct gendisk *disk;
19452083
printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
19462084

2085+
ITERATE_RDEV(mddev,rdev,tmp)
2086+
if (rdev->raid_disk >= 0) {
2087+
char nm[20];
2088+
sprintf(nm, "rd%d", rdev->raid_disk);
2089+
sysfs_remove_link(&mddev->kobj, nm);
2090+
}
2091+
19472092
export_array(mddev);
19482093

19492094
mddev->array_size = 0;
@@ -3962,17 +4107,24 @@ void md_check_recovery(mddev_t *mddev)
39624107
if (rdev->raid_disk >= 0 &&
39634108
(rdev->faulty || ! rdev->in_sync) &&
39644109
atomic_read(&rdev->nr_pending)==0) {
3965-
if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0)
4110+
if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0) {
4111+
char nm[20];
4112+
sprintf(nm,"rd%d", rdev->raid_disk);
4113+
sysfs_remove_link(&mddev->kobj, nm);
39664114
rdev->raid_disk = -1;
4115+
}
39674116
}
39684117

39694118
if (mddev->degraded) {
39704119
ITERATE_RDEV(mddev,rdev,rtmp)
39714120
if (rdev->raid_disk < 0
39724121
&& !rdev->faulty) {
3973-
if (mddev->pers->hot_add_disk(mddev,rdev))
4122+
if (mddev->pers->hot_add_disk(mddev,rdev)) {
4123+
char nm[20];
4124+
sprintf(nm, "rd%d", rdev->raid_disk);
4125+
sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
39744126
spares++;
3975-
else
4127+
} else
39764128
break;
39774129
}
39784130
}

include/linux/raid/md_k.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ struct mdk_rdev_s
105105
int sb_size; /* bytes in the superblock */
106106
int preferred_minor; /* autorun support */
107107

108+
struct kobject kobj;
109+
108110
/* A device can be in one of three states based on two flags:
109111
* Not working: faulty==1 in_sync==0
110112
* Fully working: faulty==0 in_sync==1

0 commit comments

Comments
 (0)