diff options
| author | NeilBrown <neilb@suse.de> | 2005-11-09 00:39:24 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-09 10:56:37 -0500 |
| commit | 86e6ffdd243a06663713e637ee683fb27dce8e0c (patch) | |
| tree | d6bc5f26aff6b1a506ad04d8d605d92cfd19162f | |
| parent | eae1701fbd264cfc7efbaf7cd4cd999760070e27 (diff) | |
[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>
| -rw-r--r-- | drivers/md/md.c | 168 | ||||
| -rw-r--r-- | include/linux/raid/md_k.h | 2 |
2 files changed, 162 insertions, 8 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index a68ad8547325..74520b50c307 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
| @@ -711,6 +711,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
| 711 | */ | 711 | */ |
| 712 | int i; | 712 | int i; |
| 713 | int active=0, working=0,failed=0,spare=0,nr_disks=0; | 713 | int active=0, working=0,failed=0,spare=0,nr_disks=0; |
| 714 | unsigned int fixdesc=0; | ||
| 714 | 715 | ||
| 715 | rdev->sb_size = MD_SB_BYTES; | 716 | rdev->sb_size = MD_SB_BYTES; |
| 716 | 717 | ||
| @@ -758,16 +759,28 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
| 758 | sb->disks[0].state = (1<<MD_DISK_REMOVED); | 759 | sb->disks[0].state = (1<<MD_DISK_REMOVED); |
| 759 | ITERATE_RDEV(mddev,rdev2,tmp) { | 760 | ITERATE_RDEV(mddev,rdev2,tmp) { |
| 760 | mdp_disk_t *d; | 761 | mdp_disk_t *d; |
| 762 | int desc_nr; | ||
| 761 | if (rdev2->raid_disk >= 0 && rdev2->in_sync && !rdev2->faulty) | 763 | if (rdev2->raid_disk >= 0 && rdev2->in_sync && !rdev2->faulty) |
| 762 | rdev2->desc_nr = rdev2->raid_disk; | 764 | desc_nr = rdev2->raid_disk; |
| 763 | else | 765 | 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 | } | ||
| 765 | d = &sb->disks[rdev2->desc_nr]; | 778 | d = &sb->disks[rdev2->desc_nr]; |
| 766 | nr_disks++; | 779 | nr_disks++; |
| 767 | d->number = rdev2->desc_nr; | 780 | d->number = rdev2->desc_nr; |
| 768 | d->major = MAJOR(rdev2->bdev->bd_dev); | 781 | d->major = MAJOR(rdev2->bdev->bd_dev); |
| 769 | d->minor = MINOR(rdev2->bdev->bd_dev); | 782 | 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) |
| 771 | d->raid_disk = rdev2->raid_disk; | 784 | d->raid_disk = rdev2->raid_disk; |
| 772 | else | 785 | else |
| 773 | d->raid_disk = rdev2->desc_nr; /* compatibility */ | 786 | d->raid_disk = rdev2->desc_nr; /* compatibility */ |
| @@ -787,7 +800,22 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
| 787 | if (test_bit(WriteMostly, &rdev2->flags)) | 800 | if (test_bit(WriteMostly, &rdev2->flags)) |
| 788 | d->state |= (1<<MD_DISK_WRITEMOSTLY); | 801 | d->state |= (1<<MD_DISK_WRITEMOSTLY); |
| 789 | } | 802 | } |
| 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 | } | ||
| 791 | /* now set the "removed" and "faulty" bits on any missing devices */ | 819 | /* now set the "removed" and "faulty" bits on any missing devices */ |
| 792 | for (i=0 ; i < mddev->raid_disks ; i++) { | 820 | for (i=0 ; i < mddev->raid_disks ; i++) { |
| 793 | mdp_disk_t *d = &sb->disks[i]; | 821 | mdp_disk_t *d = &sb->disks[i]; |
| @@ -1147,6 +1175,13 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) | |||
| 1147 | list_add(&rdev->same_set, &mddev->disks); | 1175 | list_add(&rdev->same_set, &mddev->disks); |
| 1148 | rdev->mddev = mddev; | 1176 | rdev->mddev = mddev; |
| 1149 | printk(KERN_INFO "md: bind<%s>\n", bdevname(rdev->bdev,b)); | 1177 | 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"); | ||
| 1150 | return 0; | 1185 | return 0; |
| 1151 | } | 1186 | } |
| 1152 | 1187 | ||
| @@ -1160,6 +1195,8 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) | |||
| 1160 | list_del_init(&rdev->same_set); | 1195 | list_del_init(&rdev->same_set); |
| 1161 | printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); | 1196 | printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); |
| 1162 | rdev->mddev = NULL; | 1197 | rdev->mddev = NULL; |
| 1198 | sysfs_remove_link(&rdev->kobj, "block"); | ||
| 1199 | kobject_del(&rdev->kobj); | ||
| 1163 | } | 1200 | } |
| 1164 | 1201 | ||
| 1165 | /* | 1202 | /* |
| @@ -1215,7 +1252,7 @@ static void export_rdev(mdk_rdev_t * rdev) | |||
| 1215 | md_autodetect_dev(rdev->bdev->bd_dev); | 1252 | md_autodetect_dev(rdev->bdev->bd_dev); |
| 1216 | #endif | 1253 | #endif |
| 1217 | unlock_rdev(rdev); | 1254 | unlock_rdev(rdev); |
| 1218 | kfree(rdev); | 1255 | kobject_put(&rdev->kobj); |
| 1219 | } | 1256 | } |
| 1220 | 1257 | ||
| 1221 | static void kick_rdev_from_array(mdk_rdev_t * rdev) | 1258 | static void kick_rdev_from_array(mdk_rdev_t * rdev) |
| @@ -1414,6 +1451,94 @@ repeat: | |||
| 1414 | 1451 | ||
| 1415 | } | 1452 | } |
| 1416 | 1453 | ||
| 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); | ||
