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 /drivers/md | |
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>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/md.c | 168 |
1 files changed, 160 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); | ||
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 | |||
1417 | /* | 1542 | /* |
1418 | * Import a device. If 'super_format' >= 0, then sanity check the superblock | 1543 | * Import a device. If 'super_format' >= 0, then sanity check the superblock |
1419 | * | 1544 | * |
@@ -1445,6 +1570,10 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi | |||
1445 | if (err) | 1570 | if (err) |
1446 | goto abort_free; | 1571 | goto abort_free; |
1447 | 1572 | ||
1573 | rdev->kobj.parent = NULL; | ||
1574 | rdev->kobj.ktype = &rdev_ktype; | ||
1575 | kobject_init(&rdev->kobj); | ||
1576 | |||
1448 | rdev->desc_nr = -1; | 1577 | rdev->desc_nr = -1; |
1449 | rdev->faulty = 0; | 1578 | rdev->faulty = 0; |
1450 | rdev->in_sync = 0; | 1579 | rdev->in_sync = 0; |
@@ -1820,6 +1949,13 @@ static int do_md_run(mddev_t * mddev) | |||
1820 | mddev->safemode_timer.data = (unsigned long) mddev; | 1949 | mddev->safemode_timer.data = (unsigned long) mddev; |
1821 | mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */ | 1950 | mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */ |
1822 | mddev->in_sync = 1; | 1951 | 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 | } | ||
1823 | 1959 | ||
1824 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | 1960 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); |
1825 | md_wakeup_thread(mddev->thread); | 1961 | md_wakeup_thread(mddev->thread); |
@@ -1941,9 +2077,18 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
1941 | * Free resources if final stop | 2077 | * Free resources if final stop |
1942 | */ | 2078 | */ |
1943 | if (!ro) { | 2079 | if (!ro) { |
2080 | mdk_rdev_t *rdev; | ||
2081 | struct list_head *tmp; | ||
1944 | struct gendisk *disk; | 2082 | struct gendisk *disk; |
1945 | printk(KERN_INFO "md: %s stopped.\n", mdname(mddev)); | 2083 | printk(KERN_INFO "md: %s stopped.\n", mdname(mddev)); |
1946 | 2084 | ||
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 | |||
1947 | export_array(mddev); | 2092 | export_array(mddev); |
1948 | 2093 | ||
1949 | mddev->array_size = 0; | 2094 | mddev->array_size = 0; |
@@ -3962,17 +4107,24 @@ void md_check_recovery(mddev_t *mddev) | |||
3962 | if (rdev->raid_disk >= 0 && | 4107 | if (rdev->raid_disk >= 0 && |
3963 | (rdev->faulty || ! rdev->in_sync) && | 4108 | (rdev->faulty || ! rdev->in_sync) && |
3964 | atomic_read(&rdev->nr_pending)==0) { | 4109 | 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); | ||
3966 | rdev->raid_disk = -1; | 4114 | rdev->raid_disk = -1; |
4115 | } | ||
3967 | } | 4116 | } |
3968 | 4117 | ||
3969 | if (mddev->degraded) { | 4118 | if (mddev->degraded) { |
3970 | ITERATE_RDEV(mddev,rdev,rtmp) | 4119 | ITERATE_RDEV(mddev,rdev,rtmp) |
3971 | if (rdev->raid_disk < 0 | 4120 | if (rdev->raid_disk < 0 |
3972 | && !rdev->faulty) { | 4121 | && !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); | ||
3974 | spares++; | 4126 | spares++; |
3975 | else | 4127 | } else |
3976 | break; | 4128 | break; |
3977 | } | 4129 | } |
3978 | } | 4130 | } |