aboutsummaryrefslogtreecommitdiffstats
path: root/block/genhd.c
diff options
context:
space:
mode:
authorJens Axboe <jaxboe@fusionio.com>2011-01-13 08:47:54 -0500
committerJens Axboe <jaxboe@fusionio.com>2011-01-13 08:47:54 -0500
commit81c5e2ae33c4b19e53966b427e33646bf6811830 (patch)
treea602a6dd100165c8948bfa713e6f0b422dcba5d8 /block/genhd.c
parent797a455d2c682476c3797dbfecf5bf84c1e3b9d3 (diff)
parentfcc57045d53edc35bcce456e60ac4aa802712934 (diff)
Merge branch 'for-2.6.38/event-handling' into for-2.6.38/core
Diffstat (limited to 'block/genhd.c')
-rw-r--r--block/genhd.c544
1 files changed, 516 insertions, 28 deletions
diff --git a/block/genhd.c b/block/genhd.c
index 399d37ec7412..6a5b772aa201 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -18,6 +18,7 @@
18#include <linux/buffer_head.h> 18#include <linux/buffer_head.h>
19#include <linux/mutex.h> 19#include <linux/mutex.h>
20#include <linux/idr.h> 20#include <linux/idr.h>
21#include <linux/log2.h>
21 22
22#include "blk.h" 23#include "blk.h"
23 24
@@ -35,6 +36,10 @@ static DEFINE_IDR(ext_devt_idr);
35 36
36static struct device_type disk_type; 37static struct device_type disk_type;
37 38
39static void disk_add_events(struct gendisk *disk);
40static void disk_del_events(struct gendisk *disk);
41static void disk_release_events(struct gendisk *disk);
42
38/** 43/**
39 * disk_get_part - get partition 44 * disk_get_part - get partition
40 * @disk: disk to look partition from 45 * @disk: disk to look partition from
@@ -502,6 +507,64 @@ static int exact_lock(dev_t devt, void *data)
502 return 0; 507 return 0;
503} 508}
504 509
510void register_disk(struct gendisk *disk)
511{
512 struct device *ddev = disk_to_dev(disk);
513 struct block_device *bdev;
514 struct disk_part_iter piter;
515 struct hd_struct *part;
516 int err;
517
518 ddev->parent = disk->driverfs_dev;
519
520 dev_set_name(ddev, disk->disk_name);
521
522 /* delay uevents, until we scanned partition table */
523 dev_set_uevent_suppress(ddev, 1);
524
525 if (device_add(ddev))
526 return;
527 if (!sysfs_deprecated) {
528 err = sysfs_create_link(block_depr, &ddev->kobj,
529 kobject_name(&ddev->kobj));
530 if (err) {
531 device_del(ddev);
532 return;
533 }
534 }
535 disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
536 disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
537
538 /* No minors to use for partitions */
539 if (!disk_partitionable(disk))
540 goto exit;
541
542 /* No such device (e.g., media were just removed) */
543 if (!get_capacity(disk))
544 goto exit;
545
546 bdev = bdget_disk(disk, 0);
547 if (!bdev)
548 goto exit;
549
550 bdev->bd_invalidated = 1;
551 err = blkdev_get(bdev, FMODE_READ, NULL);
552 if (err < 0)
553 goto exit;
554 blkdev_put(bdev, FMODE_READ);
555
556exit:
557 /* announce disk after possible partitions are created */
558 dev_set_uevent_suppress(ddev, 0);
559 kobject_uevent(&ddev->kobj, KOBJ_ADD);
560
561 /* announce possible partitions */
562 disk_part_iter_init(&piter, disk, 0);
563 while ((part = disk_part_iter_next(&piter)))
564 kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD);
565 disk_part_iter_exit(&piter);
566}
567
505/** 568/**
506 * add_disk - add partitioning information to kernel list 569 * add_disk - add partitioning information to kernel list
507 * @disk: per-device partitioning information 570 * @disk: per-device partitioning information
@@ -551,18 +614,48 @@ void add_disk(struct gendisk *disk)
551 retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj, 614 retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
552 "bdi"); 615 "bdi");
553 WARN_ON(retval); 616 WARN_ON(retval);
554}
555 617
618 disk_add_events(disk);
619}
556EXPORT_SYMBOL(add_disk); 620EXPORT_SYMBOL(add_disk);
557EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */
558 621
559void unlink_gendisk(struct gendisk *disk) 622void del_gendisk(struct gendisk *disk)
560{ 623{
624 struct disk_part_iter piter;
625 struct hd_struct *part;
626
627 disk_del_events(disk);
628
629 /* invalidate stuff */
630 disk_part_iter_init(&piter, disk,
631 DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
632 while ((part = disk_part_iter_next(&piter))) {
633 invalidate_partition(disk, part->partno);
634 delete_partition(disk, part->partno);
635 }
636 disk_part_iter_exit(&piter);
637
638 invalidate_partition(disk, 0);
639 blk_free_devt(disk_to_dev(disk)->devt);
640 set_capacity(disk, 0);
641 disk->flags &= ~GENHD_FL_UP;
642
561 sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi"); 643 sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
562 bdi_unregister(&disk->queue->backing_dev_info); 644 bdi_unregister(&disk->queue->backing_dev_info);
563 blk_unregister_queue(disk); 645 blk_unregister_queue(disk);
564 blk_unregister_region(disk_devt(disk), disk->minors); 646 blk_unregister_region(disk_devt(disk), disk->minors);
647
648 part_stat_set_all(&disk->part0, 0);
649 disk->part0.stamp = 0;
650
651 kobject_put(disk->part0.holder_dir);
652 kobject_put(disk->slave_dir);
653 disk->driverfs_dev = NULL;
654 if (!sysfs_deprecated)
655 sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
656 device_del(disk_to_dev(disk));
565} 657}
658EXPORT_SYMBOL(del_gendisk);
566 659
567/** 660/**
568 * get_gendisk - get partitioning information for a given device 661 * get_gendisk - get partitioning information for a given device
@@ -1005,6 +1098,7 @@ static void disk_release(struct device *dev)
1005{ 1098{
1006 struct gendisk *disk = dev_to_disk(dev); 1099 struct gendisk *disk = dev_to_disk(dev);
1007 1100
1101 disk_release_events(disk);
1008 kfree(disk->random); 1102 kfree(disk->random);
1009 disk_replace_part_tbl(disk, NULL); 1103 disk_replace_part_tbl(disk, NULL);
1010 free_part_stats(&disk->part0); 1104 free_part_stats(&disk->part0);
@@ -1110,29 +1204,6 @@ static int __init proc_genhd_init(void)
1110module_init(proc_genhd_init); 1204module_init(proc_genhd_init);
1111#endif /* CONFIG_PROC_FS */ 1205#endif /* CONFIG_PROC_FS */
1112 1206
1113static void media_change_notify_thread(struct work_struct *work)
1114{
1115 struct gendisk *gd = container_of(work, struct gendisk, async_notify);
1116 char event[] = "MEDIA_CHANGE=1";
1117 char *envp[] = { event, NULL };
1118
1119 /*
1120 * set enviroment vars to indicate which event this is for
1121 * so that user space will know to go check the media status.
1122 */
1123 kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp);
1124 put_device(gd->driverfs_dev);
1125}
1126
1127#if 0
1128void genhd_media_change_notify(struct gendisk *disk)
1129{
1130 get_device(disk->driverfs_dev);
1131 schedule_work(&disk->async_notify);
1132}
1133EXPORT_SYMBOL_GPL(genhd_media_change_notify);
1134#endif /* 0 */
1135
1136dev_t blk_lookup_devt(const char *name, int partno) 1207dev_t blk_lookup_devt(const char *name, int partno)
1137{ 1208{
1138 dev_t devt = MKDEV(0, 0); 1209 dev_t devt = MKDEV(0, 0);
@@ -1200,8 +1271,6 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
1200 disk_to_dev(disk)->class = &block_class; 1271 disk_to_dev(disk)->class = &block_class;
1201 disk_to_dev(disk)->type = &disk_type; 1272 disk_to_dev(disk)->type = &disk_type;
1202 device_initialize(disk_to_dev(disk)); 1273 device_initialize(disk_to_dev(disk));
1203 INIT_WORK(&disk->async_notify,
1204 media_change_notify_thread);
1205 } 1274 }
1206 return disk; 1275 return disk;
1207} 1276}
@@ -1293,3 +1362,422 @@ int invalidate_partition(struct gendisk *disk, int partno)
1293} 1362}
1294 1363
1295EXPORT_SYMBOL(invalidate_partition); 1364EXPORT_SYMBOL(invalidate_partition);
1365
1366/*
1367 * Disk events - monitor disk events like media change and eject request.
1368 */
1369struct disk_events {
1370 struct list_head node; /* all disk_event's */
1371 struct gendisk *disk; /* the associated disk */
1372 spinlock_t lock;
1373
1374 int block; /* event blocking depth */
1375 unsigned int pending; /* events already sent out */
1376 unsigned int clearing; /* events being cleared */
1377
1378 long poll_msecs; /* interval, -1 for default */
1379 struct delayed_work dwork;
1380};
1381
1382static const char *disk_events_strs[] = {
1383 [ilog2(DISK_EVENT_MEDIA_CHANGE)] = "media_change",
1384 [ilog2(DISK_EVENT_EJECT_REQUEST)] = "eject_request",
1385};
1386
1387static char *disk_uevents[] = {
1388 [ilog2(DISK_EVENT_MEDIA_CHANGE)] = "DISK_MEDIA_CHANGE=1",
1389 [ilog2(DISK_EVENT_EJECT_REQUEST)] = "DISK_EJECT_REQUEST=1",
1390};
1391
1392/* list of all disk_events */
1393static DEFINE_MUTEX(disk_events_mutex);
1394static LIST_HEAD(disk_events);
1395
1396/* disable in-kernel polling by default */
1397static unsigned long disk_events_dfl_poll_msecs = 0;
1398
1399static unsigned long disk_events_poll_jiffies(struct gendisk *disk)
1400{
1401 struct disk_events *ev = disk->ev;
1402 long intv_msecs = 0;
1403
1404 /*
1405 * If device-specific poll interval is set, always use it. If
1406 * the default is being used, poll iff there are events which
1407 * can't be monitored asynchronously.
1408 */
1409 if (ev->poll_msecs >= 0)
1410 intv_msecs = ev->poll_msecs;
1411 else if (disk->events & ~disk->async_events)
1412 intv_msecs = disk_events_dfl_poll_msecs;
1413
1414 return msecs_to_jiffies(intv_msecs);
1415}
1416
1417static void __disk_block_events(struct gendisk *disk, bool sync)
1418{
1419 struct disk_events *ev = disk->ev;
1420 unsigned long flags;
1421 bool cancel;
1422
1423 spin_lock_irqsave(&ev->lock, flags);
1424 cancel = !ev->block++;
1425 spin_unlock_irqrestore(&ev->lock, flags);
1426
1427 if (cancel) {
1428 if (sync)
1429 cancel_delayed_work_sync(&disk->ev->dwork);
1430 else
1431 cancel_delayed_work(&disk->ev->dwork);
1432 }
1433}
1434
1435static void __disk_unblock_events(struct gendisk *disk, bool check_now)
1436{
1437 struct disk_events *ev = disk->ev;
1438 unsigned long intv;
1439 unsigned long flags;
1440
1441 spin_lock_irqsave(&ev->lock, flags);
1442
1443 if (WARN_ON_ONCE(ev->block <= 0))
1444 goto out_unlock;
1445
1446 if (--ev->block)
1447 goto out_unlock;
1448
1449 /*
1450 * Not exactly a latency critical operation, set poll timer
1451 * slack to 25% and kick event check.
1452 */
1453 intv = disk_events_poll_jiffies(disk);
1454 set_timer_slack(&ev->dwork.timer, intv / 4);
1455 if (check_now)
1456 queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
1457 else if (intv)
1458 queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
1459out_unlock:
1460 spin_unlock_irqrestore(&ev->lock, flags);
1461}
1462
1463/**
1464 * disk_block_events - block and flush disk event checking
1465 * @disk: disk to block events for
1466 *
1467 * On return from this function, it is guaranteed that event checking
1468 * isn't in progress and won't happen until unblocked by
1469 * disk_unblock_events(). Events blocking is counted and the actual
1470 * unblocking happens after the matching number of unblocks are done.
1471 *
1472 * Note that this intentionally does not block event checking from
1473 * disk_clear_events().
1474 *
1475 * CONTEXT:
1476 * Might sleep.
1477 */
1478void disk_block_events(struct gendisk *disk)
1479{
1480 if (disk->ev)
1481 __disk_block_events(disk, true);
1482}
1483
1484/**
1485 * disk_unblock_events - unblock disk event checking
1486 * @disk: disk to unblock events for
1487 *
1488 * Undo disk_block_events(). When the block count reaches zero, it
1489 * starts events polling if configured.
1490 *
1491 * CONTEXT:
1492 * Don't care. Safe to call from irq context.
1493 */
1494void disk_unblock_events(struct gendisk *disk)
1495{
1496 if (disk->ev)
1497 __disk_unblock_events(disk, true);
1498}
1499
1500/**
1501 * disk_check_events - schedule immediate event checking
1502 * @disk: disk to check events for
1503 *
1504 * Schedule immediate event checking on @disk if not blocked.
1505 *
1506 * CONTEXT:
1507 * Don't care. Safe to call from irq context.
1508 */
1509void disk_check_events(struct gendisk *disk)
1510{
1511 if (disk->ev) {
1512 __disk_block_events(disk, false);
1513 __disk_unblock_events(disk, true);
1514 }
1515}
1516EXPORT_SYMBOL_GPL(disk_check_events);
1517
1518/**
1519 * disk_clear_events - synchronously check, clear and return pending events
1520 * @disk: disk to fetch and clear events from
1521 * @mask: mask of events to be fetched and clearted
1522 *
1523 * Disk events are synchronously checked and pending events in @mask
1524 * are cleared and returned. This ignores the block count.
1525 *
1526 * CONTEXT:
1527 * Might sleep.
1528 */
1529unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
1530{
1531 const struct block_device_operations *bdops = disk->fops;
1532 struct disk_events *ev = disk->ev;
1533 unsigned int pending;
1534
1535 if (!ev) {
1536 /* for drivers still using the old ->media_changed method */
1537 if ((mask & DISK_EVENT_MEDIA_CHANGE) &&
1538 bdops->media_changed && bdops->media_changed(disk))
1539 return DISK_EVENT_MEDIA_CHANGE;
1540 return 0;
1541 }
1542
1543 /* tell the workfn about the events being cleared */
1544 spin_lock_irq(&ev->lock);
1545 ev->clearing |= mask;
1546 spin_unlock_irq(&ev->lock);
1547
1548 /* uncondtionally schedule event check and wait for it to finish */
1549 __disk_block_events(disk, true);
1550 queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
1551 flush_delayed_work(&ev->dwork);
1552 __disk_unblock_events(disk, false);
1553
1554 /* then, fetch and clear pending events */
1555 spin_lock_irq(&ev->lock);
1556 WARN_ON_ONCE(ev->clearing & mask); /* cleared by workfn */
1557 pending = ev->pending & mask;
1558 ev->pending &= ~mask;
1559 spin_unlock_irq(&ev->lock);
1560
1561 return pending;
1562}
1563
1564static void disk_events_workfn(struct work_struct *work)
1565{
1566 struct delayed_work *dwork = to_delayed_work(work);
1567 struct disk_events *ev = container_of(dwork, struct disk_events, dwork);
1568 struct gendisk *disk = ev->disk;
1569 char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
1570 unsigned int clearing = ev->clearing;
1571 unsigned int events;
1572 unsigned long intv;
1573 int nr_events = 0, i;
1574
1575 /* check events */
1576 events = disk->fops->check_events(disk, clearing);
1577
1578 /* accumulate pending events and schedule next poll if necessary */
1579 spin_lock_irq(&ev->lock);
1580
1581 events &= ~ev->pending;
1582 ev->pending |= events;
1583 ev->clearing &= ~clearing;
1584
1585 intv = disk_events_poll_jiffies(disk);
1586 if (!ev->block && intv)
1587 queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
1588
1589 spin_unlock_irq(&ev->lock);
1590
1591 /* tell userland about new events */
1592 for (i = 0; i < ARRAY_SIZE(disk_uevents); i++)
1593 if (events & (1 << i))
1594 envp[nr_events++] = disk_uevents[i];
1595
1596 if (nr_events)
1597 kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
1598}
1599
1600/*
1601 * A disk events enabled device has the following sysfs nodes under
1602 * its /sys/block/X/ directory.
1603 *
1604 * events : list of all supported events
1605 * events_async : list of events which can be detected w/o polling
1606 * events_poll_msecs : polling interval, 0: disable, -1: system default
1607 */
1608static ssize_t __disk_events_show(unsigned int events, char *buf)
1609{
1610 const char *delim = "";
1611 ssize_t pos = 0;
1612 int i;
1613
1614 for (i = 0; i < ARRAY_SIZE(disk_events_strs); i++)
1615 if (events & (1 << i)) {
1616 pos += sprintf(buf + pos, "%s%s",
1617 delim, disk_events_strs[i]);
1618 delim = " ";
1619 }
1620 if (pos)
1621 pos += sprintf(buf + pos, "\n");
1622 return pos;
1623}
1624
1625static ssize_t disk_events_show(struct device *dev,
1626 struct device_attribute *attr, char *buf)
1627{
1628 struct gendisk *disk = dev_to_disk(dev);
1629
1630 return __disk_events_show(disk->events, buf);
1631}
1632
1633static ssize_t disk_events_async_show(struct device *dev,
1634 struct device_attribute *attr, char *buf)
1635{
1636 struct gendisk *disk = dev_to_disk(dev);
1637
1638 return __disk_events_show(disk->async_events, buf);
1639}
1640
1641static ssize_t disk_events_poll_msecs_show(struct device *dev,
1642 struct device_attribute *attr,
1643 char *buf)
1644{
1645 struct gendisk *disk = dev_to_disk(dev);
1646
1647 return sprintf(buf, "%ld\n", disk->ev->poll_msecs);
1648}
1649
1650static ssize_t disk_events_poll_msecs_store(struct device *dev,
1651 struct device_attribute *attr,
1652 const char *buf, size_t count)
1653{
1654 struct gendisk *disk = dev_to_disk(dev);
1655 long intv;
1656
1657 if (!count || !sscanf(buf, "%ld", &intv))
1658 return -EINVAL;
1659
1660 if (intv < 0 && intv != -1)
1661 return -EINVAL;
1662
1663 __disk_block_events(disk, true);
1664 disk->ev->poll_msecs = intv;
1665 __disk_unblock_events(disk, true);
1666
1667 return count;
1668}
1669
1670static const DEVICE_ATTR(events, S_IRUGO, disk_events_show, NULL);
1671static const DEVICE_ATTR(events_async, S_IRUGO, disk_events_async_show, NULL);
1672static const DEVICE_ATTR(events_poll_msecs, S_IRUGO|S_IWUSR,
1673 disk_events_poll_msecs_show,
1674 disk_events_poll_msecs_store);
1675
1676static const struct attribute *disk_events_attrs[] = {
1677 &dev_attr_events.attr,
1678 &dev_attr_events_async.attr,
1679 &dev_attr_events_poll_msecs.attr,
1680 NULL,
1681};
1682
1683/*
1684 * The default polling interval can be specified by the kernel
1685 * parameter block.events_dfl_poll_msecs which defaults to 0
1686 * (disable). This can also be modified runtime by writing to
1687 * /sys/module/block/events_dfl_poll_msecs.
1688 */
1689static int disk_events_set_dfl_poll_msecs(const char *val,
1690 const struct kernel_param *kp)
1691{
1692 struct disk_events *ev;
1693 int ret;
1694
1695 ret = param_set_ulong(val, kp);
1696 if (ret < 0)
1697 return ret;
1698
1699 mutex_lock(&disk_events_mutex);
1700
1701 list_for_each_entry(ev, &disk_events, node)
1702 disk_check_events(ev->disk);
1703
1704 mutex_unlock(&disk_events_mutex);
1705
1706 return 0;
1707}
1708
1709static const struct kernel_param_ops disk_events_dfl_poll_msecs_param_ops = {
1710 .set = disk_events_set_dfl_poll_msecs,
1711 .get = param_get_ulong,
1712};
1713
1714#undef MODULE_PARAM_PREFIX
1715#define MODULE_PARAM_PREFIX "block."
1716
1717module_param_cb(events_dfl_poll_msecs, &disk_events_dfl_poll_msecs_param_ops,
1718 &disk_events_dfl_poll_msecs, 0644);
1719
1720/*
1721 * disk_{add|del|release}_events - initialize and destroy disk_events.
1722 */
1723static void disk_add_events(struct gendisk *disk)
1724{
1725 struct disk_events *ev;
1726
1727 if (!disk->fops->check_events || !(disk->events | disk->async_events))
1728 return;
1729
1730 ev = kzalloc(sizeof(*ev), GFP_KERNEL);
1731 if (!ev) {
1732 pr_warn("%s: failed to initialize events\n", disk->disk_name);
1733 return;
1734 }
1735
1736 if (sysfs_create_files(&disk_to_dev(disk)->kobj,
1737 disk_events_attrs) < 0) {
1738 pr_warn("%s: failed to create sysfs files for events\n",
1739 disk->disk_name);
1740 kfree(ev);
1741 return;
1742 }
1743
1744 disk->ev = ev;
1745
1746 INIT_LIST_HEAD(&ev->node);
1747 ev->disk = disk;
1748 spin_lock_init(&ev->lock);
1749 ev->block = 1;
1750 ev->poll_msecs = -1;
1751 INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
1752
1753 mutex_lock(&disk_events_mutex);
1754 list_add_tail(&ev->node, &disk_events);
1755 mutex_unlock(&disk_events_mutex);
1756
1757 /*
1758 * Block count is initialized to 1 and the following initial
1759 * unblock kicks it into action.
1760 */
1761 __disk_unblock_events(disk, true);
1762}
1763
1764static void disk_del_events(struct gendisk *disk)
1765{
1766 if (!disk->ev)
1767 return;
1768
1769 __disk_block_events(disk, true);
1770
1771 mutex_lock(&disk_events_mutex);
1772 list_del_init(&disk->ev->node);
1773 mutex_unlock(&disk_events_mutex);
1774
1775 sysfs_remove_files(&disk_to_dev(disk)->kobj, disk_events_attrs);
1776}
1777
1778static void disk_release_events(struct gendisk *disk)
1779{
1780 /* the block count should be 1 from disk_del_events() */
1781 WARN_ON_ONCE(disk->ev && disk->ev->block != 1);
1782 kfree(disk->ev);
1783}