aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/md.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2005-11-09 00:39:24 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-09 10:56:37 -0500
commit86e6ffdd243a06663713e637ee683fb27dce8e0c (patch)
treed6bc5f26aff6b1a506ad04d8d605d92cfd19162f /drivers/md/md.c
parenteae1701fbd264cfc7efbaf7cd4cd999760070e27 (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/md.c')
-rw-r--r--drivers/md/md.c168
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
1221static void kick_rdev_from_array(mdk_rdev_t * rdev) 1258static void kick_rdev_from_array(mdk_rdev_t * rdev)
@@ -1414,6 +1451,94 @@ repeat:
1414 1451
1415} 1452}
1416 1453
1454struct 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
1460static ssize_t
1461rdev_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
1481static struct rdev_sysfs_entry rdev_state = {
1482 .attr = {.name = "state", .mode = S_IRUGO },
1483 .show = rdev_show_state,
1484};
1485
1486static ssize_t
1487rdev_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}
1495static struct rdev_sysfs_entry rdev_super = {
1496 .attr = {.name = "super", .mode = S_IRUGO },
1497 .show = rdev_show_super,
1498};
1499static struct attribute *rdev_default_attrs[] = {
1500 &rdev_state.attr,
1501 &rdev_super.attr,
1502 NULL,
1503};
1504static ssize_t
1505rdev_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
1515static ssize_t
1516rdev_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
1527static void rdev_free(struct kobject *ko)
1528{
1529 mdk_rdev_t *rdev = container_of(ko, mdk_rdev_t, kobj);
1530 kfree(rdev);
1531}
1532static struct sysfs_ops rdev_sysfs_ops = {
1533 .show = rdev_attr_show,
1534 .store = rdev_attr_store,
1535};
1536static 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 }