Commit 81c5e2ae33c4b19e53966b427e33646bf6811830
Exists in
master
and in
4 other branches
Merge branch 'for-2.6.38/event-handling' into for-2.6.38/core
Showing 14 changed files Side-by-side Diff
block/genhd.c
... | ... | @@ -18,6 +18,7 @@ |
18 | 18 | #include <linux/buffer_head.h> |
19 | 19 | #include <linux/mutex.h> |
20 | 20 | #include <linux/idr.h> |
21 | +#include <linux/log2.h> | |
21 | 22 | |
22 | 23 | #include "blk.h" |
23 | 24 | |
... | ... | @@ -35,6 +36,10 @@ |
35 | 36 | |
36 | 37 | static struct device_type disk_type; |
37 | 38 | |
39 | +static void disk_add_events(struct gendisk *disk); | |
40 | +static void disk_del_events(struct gendisk *disk); | |
41 | +static void disk_release_events(struct gendisk *disk); | |
42 | + | |
38 | 43 | /** |
39 | 44 | * disk_get_part - get partition |
40 | 45 | * @disk: disk to look partition from |
... | ... | @@ -502,6 +507,64 @@ |
502 | 507 | return 0; |
503 | 508 | } |
504 | 509 | |
510 | +void 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 | + | |
556 | +exit: | |
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 | 569 | * add_disk - add partitioning information to kernel list |
507 | 570 | * @disk: per-device partitioning information |
508 | 571 | |
509 | 572 | |
510 | 573 | |
511 | 574 | |
512 | 575 | |
513 | 576 | |
... | ... | @@ -551,18 +614,48 @@ |
551 | 614 | retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj, |
552 | 615 | "bdi"); |
553 | 616 | WARN_ON(retval); |
554 | -} | |
555 | 617 | |
618 | + disk_add_events(disk); | |
619 | +} | |
556 | 620 | EXPORT_SYMBOL(add_disk); |
557 | -EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */ | |
558 | 621 | |
559 | -void unlink_gendisk(struct gendisk *disk) | |
622 | +void 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 | 643 | sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi"); |
562 | 644 | bdi_unregister(&disk->queue->backing_dev_info); |
563 | 645 | blk_unregister_queue(disk); |
564 | 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 | } |
658 | +EXPORT_SYMBOL(del_gendisk); | |
566 | 659 | |
567 | 660 | /** |
568 | 661 | * get_gendisk - get partitioning information for a given device |
... | ... | @@ -1005,6 +1098,7 @@ |
1005 | 1098 | { |
1006 | 1099 | struct gendisk *disk = dev_to_disk(dev); |
1007 | 1100 | |
1101 | + disk_release_events(disk); | |
1008 | 1102 | kfree(disk->random); |
1009 | 1103 | disk_replace_part_tbl(disk, NULL); |
1010 | 1104 | free_part_stats(&disk->part0); |
... | ... | @@ -1110,29 +1204,6 @@ |
1110 | 1204 | module_init(proc_genhd_init); |
1111 | 1205 | #endif /* CONFIG_PROC_FS */ |
1112 | 1206 | |
1113 | -static 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 | |
1128 | -void genhd_media_change_notify(struct gendisk *disk) | |
1129 | -{ | |
1130 | - get_device(disk->driverfs_dev); | |
1131 | - schedule_work(&disk->async_notify); | |
1132 | -} | |
1133 | -EXPORT_SYMBOL_GPL(genhd_media_change_notify); | |
1134 | -#endif /* 0 */ | |
1135 | - | |
1136 | 1207 | dev_t blk_lookup_devt(const char *name, int partno) |
1137 | 1208 | { |
1138 | 1209 | dev_t devt = MKDEV(0, 0); |
... | ... | @@ -1200,8 +1271,6 @@ |
1200 | 1271 | disk_to_dev(disk)->class = &block_class; |
1201 | 1272 | disk_to_dev(disk)->type = &disk_type; |
1202 | 1273 | device_initialize(disk_to_dev(disk)); |
1203 | - INIT_WORK(&disk->async_notify, | |
1204 | - media_change_notify_thread); | |
1205 | 1274 | } |
1206 | 1275 | return disk; |
1207 | 1276 | } |
... | ... | @@ -1293,4 +1362,423 @@ |
1293 | 1362 | } |
1294 | 1363 | |
1295 | 1364 | EXPORT_SYMBOL(invalidate_partition); |
1365 | + | |
1366 | +/* | |
1367 | + * Disk events - monitor disk events like media change and eject request. | |
1368 | + */ | |
1369 | +struct 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 | + | |
1382 | +static const char *disk_events_strs[] = { | |
1383 | + [ilog2(DISK_EVENT_MEDIA_CHANGE)] = "media_change", | |
1384 | + [ilog2(DISK_EVENT_EJECT_REQUEST)] = "eject_request", | |
1385 | +}; | |
1386 | + | |
1387 | +static 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 */ | |
1393 | +static DEFINE_MUTEX(disk_events_mutex); | |
1394 | +static LIST_HEAD(disk_events); | |
1395 | + | |
1396 | +/* disable in-kernel polling by default */ | |
1397 | +static unsigned long disk_events_dfl_poll_msecs = 0; | |
1398 | + | |
1399 | +static 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 | + | |
1417 | +static 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 | + | |
1435 | +static 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); | |
1459 | +out_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 | + */ | |
1478 | +void 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 | + */ | |
1494 | +void 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 | + */ | |
1509 | +void 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 | +} | |
1516 | +EXPORT_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 | + */ | |
1529 | +unsigned 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 | + | |
1564 | +static 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 | + */ | |
1608 | +static 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 | + | |
1625 | +static 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 | + | |
1633 | +static 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 | + | |
1641 | +static 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 | + | |
1650 | +static 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 | + | |
1670 | +static const DEVICE_ATTR(events, S_IRUGO, disk_events_show, NULL); | |
1671 | +static const DEVICE_ATTR(events_async, S_IRUGO, disk_events_async_show, NULL); | |
1672 | +static const DEVICE_ATTR(events_poll_msecs, S_IRUGO|S_IWUSR, | |
1673 | + disk_events_poll_msecs_show, | |
1674 | + disk_events_poll_msecs_store); | |
1675 | + | |
1676 | +static 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 | + */ | |
1689 | +static 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 | + | |
1709 | +static 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 | + | |
1717 | +module_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 | + */ | |
1723 | +static 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 | + | |
1764 | +static 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 | + | |
1778 | +static 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 | +} |
drivers/cdrom/cdrom.c
... | ... | @@ -1348,7 +1348,10 @@ |
1348 | 1348 | if (!CDROM_CAN(CDC_SELECT_DISC)) |
1349 | 1349 | return -EDRIVE_CANT_DO_THIS; |
1350 | 1350 | |
1351 | - (void) cdi->ops->media_changed(cdi, slot); | |
1351 | + if (cdi->ops->check_events) | |
1352 | + cdi->ops->check_events(cdi, 0, slot); | |
1353 | + else | |
1354 | + cdi->ops->media_changed(cdi, slot); | |
1352 | 1355 | |
1353 | 1356 | if (slot == CDSL_NONE) { |
1354 | 1357 | /* set media changed bits, on both queues */ |
... | ... | @@ -1392,6 +1395,42 @@ |
1392 | 1395 | return slot; |
1393 | 1396 | } |
1394 | 1397 | |
1398 | +/* | |
1399 | + * As cdrom implements an extra ioctl consumer for media changed | |
1400 | + * event, it needs to buffer ->check_events() output, such that event | |
1401 | + * is not lost for both the usual VFS and ioctl paths. | |
1402 | + * cdi->{vfs|ioctl}_events are used to buffer pending events for each | |
1403 | + * path. | |
1404 | + * | |
1405 | + * XXX: Locking is non-existent. cdi->ops->check_events() can be | |
1406 | + * called in parallel and buffering fields are accessed without any | |
1407 | + * exclusion. The original media_changed code had the same problem. | |
1408 | + * It might be better to simply deprecate CDROM_MEDIA_CHANGED ioctl | |
1409 | + * and remove this cruft altogether. It doesn't have much usefulness | |
1410 | + * at this point. | |
1411 | + */ | |
1412 | +static void cdrom_update_events(struct cdrom_device_info *cdi, | |
1413 | + unsigned int clearing) | |
1414 | +{ | |
1415 | + unsigned int events; | |
1416 | + | |
1417 | + events = cdi->ops->check_events(cdi, clearing, CDSL_CURRENT); | |
1418 | + cdi->vfs_events |= events; | |
1419 | + cdi->ioctl_events |= events; | |
1420 | +} | |
1421 | + | |
1422 | +unsigned int cdrom_check_events(struct cdrom_device_info *cdi, | |
1423 | + unsigned int clearing) | |
1424 | +{ | |
1425 | + unsigned int events; | |
1426 | + | |
1427 | + cdrom_update_events(cdi, clearing); | |
1428 | + events = cdi->vfs_events; | |
1429 | + cdi->vfs_events = 0; | |
1430 | + return events; | |
1431 | +} | |
1432 | +EXPORT_SYMBOL(cdrom_check_events); | |
1433 | + | |
1395 | 1434 | /* We want to make media_changed accessible to the user through an |
1396 | 1435 | * ioctl. The main problem now is that we must double-buffer the |
1397 | 1436 | * low-level implementation, to assure that the VFS and the user both |
1398 | 1437 | |
1399 | 1438 | |
1400 | 1439 | |
... | ... | @@ -1403,15 +1442,26 @@ |
1403 | 1442 | { |
1404 | 1443 | unsigned int mask = (1 << (queue & 1)); |
1405 | 1444 | int ret = !!(cdi->mc_flags & mask); |
1445 | + bool changed; | |
1406 | 1446 | |
1407 | 1447 | if (!CDROM_CAN(CDC_MEDIA_CHANGED)) |
1408 | - return ret; | |
1448 | + return ret; | |
1449 | + | |
1409 | 1450 | /* changed since last call? */ |
1410 | - if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { | |
1451 | + if (cdi->ops->check_events) { | |
1452 | + BUG_ON(!queue); /* shouldn't be called from VFS path */ | |
1453 | + cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE); | |
1454 | + changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE; | |
1455 | + cdi->ioctl_events = 0; | |
1456 | + } else | |
1457 | + changed = cdi->ops->media_changed(cdi, CDSL_CURRENT); | |
1458 | + | |
1459 | + if (changed) { | |
1411 | 1460 | cdi->mc_flags = 0x3; /* set bit on both queues */ |
1412 | 1461 | ret |= 1; |
1413 | 1462 | cdi->media_written = 0; |
1414 | 1463 | } |
1464 | + | |
1415 | 1465 | cdi->mc_flags &= ~mask; /* clear bit */ |
1416 | 1466 | return ret; |
1417 | 1467 | } |
drivers/scsi/scsi_lib.c
... | ... | @@ -1984,8 +1984,7 @@ |
1984 | 1984 | * in. |
1985 | 1985 | * |
1986 | 1986 | * Returns zero if unsuccessful or an error if TUR failed. For |
1987 | - * removable media, a return of NOT_READY or UNIT_ATTENTION is | |
1988 | - * translated to success, with the ->changed flag updated. | |
1987 | + * removable media, UNIT_ATTENTION sets ->changed flag. | |
1989 | 1988 | **/ |
1990 | 1989 | int |
1991 | 1990 | scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, |
... | ... | @@ -2012,16 +2011,6 @@ |
2012 | 2011 | } while (scsi_sense_valid(sshdr) && |
2013 | 2012 | sshdr->sense_key == UNIT_ATTENTION && --retries); |
2014 | 2013 | |
2015 | - if (!sshdr) | |
2016 | - /* could not allocate sense buffer, so can't process it */ | |
2017 | - return result; | |
2018 | - | |
2019 | - if (sdev->removable && scsi_sense_valid(sshdr) && | |
2020 | - (sshdr->sense_key == UNIT_ATTENTION || | |
2021 | - sshdr->sense_key == NOT_READY)) { | |
2022 | - sdev->changed = 1; | |
2023 | - result = 0; | |
2024 | - } | |
2025 | 2014 | if (!sshdr_external) |
2026 | 2015 | kfree(sshdr); |
2027 | 2016 | return result; |
drivers/scsi/sd.c
... | ... | @@ -1045,15 +1045,7 @@ |
1045 | 1045 | sshdr); |
1046 | 1046 | } |
1047 | 1047 | |
1048 | - /* | |
1049 | - * Unable to test, unit probably not ready. This usually | |
1050 | - * means there is no disc in the drive. Mark as changed, | |
1051 | - * and we will figure it out later once the drive is | |
1052 | - * available again. | |
1053 | - */ | |
1054 | - if (retval || (scsi_sense_valid(sshdr) && | |
1055 | - /* 0x3a is medium not present */ | |
1056 | - sshdr->asc == 0x3a)) { | |
1048 | + if (retval) { | |
1057 | 1049 | set_media_not_present(sdkp); |
1058 | 1050 | retval = 1; |
1059 | 1051 | goto out; |
drivers/scsi/sr.c
... | ... | @@ -104,14 +104,15 @@ |
104 | 104 | static void get_sectorsize(struct scsi_cd *); |
105 | 105 | static void get_capabilities(struct scsi_cd *); |
106 | 106 | |
107 | -static int sr_media_change(struct cdrom_device_info *, int); | |
107 | +static unsigned int sr_check_events(struct cdrom_device_info *cdi, | |
108 | + unsigned int clearing, int slot); | |
108 | 109 | static int sr_packet(struct cdrom_device_info *, struct packet_command *); |
109 | 110 | |
110 | 111 | static struct cdrom_device_ops sr_dops = { |
111 | 112 | .open = sr_open, |
112 | 113 | .release = sr_release, |
113 | 114 | .drive_status = sr_drive_status, |
114 | - .media_changed = sr_media_change, | |
115 | + .check_events = sr_check_events, | |
115 | 116 | .tray_move = sr_tray_move, |
116 | 117 | .lock_door = sr_lock_door, |
117 | 118 | .select_speed = sr_select_speed, |
118 | 119 | |
119 | 120 | |
120 | 121 | |
121 | 122 | |
122 | 123 | |
123 | 124 | |
124 | 125 | |
125 | 126 | |
126 | 127 | |
127 | 128 | |
128 | 129 | |
129 | 130 | |
... | ... | @@ -165,90 +166,96 @@ |
165 | 166 | mutex_unlock(&sr_ref_mutex); |
166 | 167 | } |
167 | 168 | |
168 | -/* identical to scsi_test_unit_ready except that it doesn't | |
169 | - * eat the NOT_READY returns for removable media */ | |
170 | -int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr) | |
169 | +static unsigned int sr_get_events(struct scsi_device *sdev) | |
171 | 170 | { |
172 | - int retries = MAX_RETRIES; | |
173 | - int the_result; | |
174 | - u8 cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0 }; | |
171 | + u8 buf[8]; | |
172 | + u8 cmd[] = { GET_EVENT_STATUS_NOTIFICATION, | |
173 | + 1, /* polled */ | |
174 | + 0, 0, /* reserved */ | |
175 | + 1 << 4, /* notification class: media */ | |
176 | + 0, 0, /* reserved */ | |
177 | + 0, sizeof(buf), /* allocation length */ | |
178 | + 0, /* control */ | |
179 | + }; | |
180 | + struct event_header *eh = (void *)buf; | |
181 | + struct media_event_desc *med = (void *)(buf + 4); | |
182 | + struct scsi_sense_hdr sshdr; | |
183 | + int result; | |
175 | 184 | |
176 | - /* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION | |
177 | - * conditions are gone, or a timeout happens | |
178 | - */ | |
179 | - do { | |
180 | - the_result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, | |
181 | - 0, sshdr, SR_TIMEOUT, | |
182 | - retries--, NULL); | |
183 | - if (scsi_sense_valid(sshdr) && | |
184 | - sshdr->sense_key == UNIT_ATTENTION) | |
185 | - sdev->changed = 1; | |
185 | + result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, sizeof(buf), | |
186 | + &sshdr, SR_TIMEOUT, MAX_RETRIES, NULL); | |
187 | + if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION) | |
188 | + return DISK_EVENT_MEDIA_CHANGE; | |
186 | 189 | |
187 | - } while (retries > 0 && | |
188 | - (!scsi_status_is_good(the_result) || | |
189 | - (scsi_sense_valid(sshdr) && | |
190 | - sshdr->sense_key == UNIT_ATTENTION))); | |
191 | - return the_result; | |
190 | + if (result || be16_to_cpu(eh->data_len) < sizeof(*med)) | |
191 | + return 0; | |
192 | + | |
193 | + if (eh->nea || eh->notification_class != 0x4) | |
194 | + return 0; | |
195 | + | |
196 | + if (med->media_event_code == 1) | |
197 | + return DISK_EVENT_EJECT_REQUEST; | |
198 | + else if (med->media_event_code == 2) | |
199 | + return DISK_EVENT_MEDIA_CHANGE; | |
200 | + return 0; | |
192 | 201 | } |
193 | 202 | |
194 | 203 | /* |
195 | - * This function checks to see if the media has been changed in the | |
196 | - * CDROM drive. It is possible that we have already sensed a change, | |
197 | - * or the drive may have sensed one and not yet reported it. We must | |
198 | - * be ready for either case. This function always reports the current | |
199 | - * value of the changed bit. If flag is 0, then the changed bit is reset. | |
200 | - * This function could be done as an ioctl, but we would need to have | |
201 | - * an inode for that to work, and we do not always have one. | |
204 | + * This function checks to see if the media has been changed or eject | |
205 | + * button has been pressed. It is possible that we have already | |
206 | + * sensed a change, or the drive may have sensed one and not yet | |
207 | + * reported it. The past events are accumulated in sdev->changed and | |
208 | + * returned together with the current state. | |
202 | 209 | */ |
203 | - | |
204 | -static int sr_media_change(struct cdrom_device_info *cdi, int slot) | |
210 | +static unsigned int sr_check_events(struct cdrom_device_info *cdi, | |
211 | + unsigned int clearing, int slot) | |
205 | 212 | { |
206 | 213 | struct scsi_cd *cd = cdi->handle; |
207 | - int retval; | |
208 | - struct scsi_sense_hdr *sshdr; | |
214 | + bool last_present; | |
215 | + struct scsi_sense_hdr sshdr; | |
216 | + unsigned int events; | |
217 | + int ret; | |
209 | 218 | |
210 | - if (CDSL_CURRENT != slot) { | |
211 | - /* no changer support */ | |
212 | - return -EINVAL; | |
213 | - } | |
219 | + /* no changer support */ | |
220 | + if (CDSL_CURRENT != slot) | |
221 | + return 0; | |
214 | 222 | |
215 | - sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); | |
216 | - retval = sr_test_unit_ready(cd->device, sshdr); | |
217 | - if (retval || (scsi_sense_valid(sshdr) && | |
218 | - /* 0x3a is medium not present */ | |
219 | - sshdr->asc == 0x3a)) { | |
220 | - /* Media not present or unable to test, unit probably not | |
221 | - * ready. This usually means there is no disc in the drive. | |
222 | - * Mark as changed, and we will figure it out later once | |
223 | - * the drive is available again. | |
224 | - */ | |
225 | - cd->device->changed = 1; | |
226 | - /* This will force a flush, if called from check_disk_change */ | |
227 | - retval = 1; | |
228 | - goto out; | |
229 | - }; | |
223 | + events = sr_get_events(cd->device); | |
224 | + /* | |
225 | + * GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE | |
226 | + * is being cleared. Note that there are devices which hang | |
227 | + * if asked to execute TUR repeatedly. | |
228 | + */ | |
229 | + if (!(clearing & DISK_EVENT_MEDIA_CHANGE)) | |
230 | + goto skip_tur; | |
230 | 231 | |
231 | - retval = cd->device->changed; | |
232 | - cd->device->changed = 0; | |
233 | - /* If the disk changed, the capacity will now be different, | |
234 | - * so we force a re-read of this information */ | |
235 | - if (retval) { | |
236 | - /* check multisession offset etc */ | |
237 | - sr_cd_check(cdi); | |
238 | - get_sectorsize(cd); | |
232 | + /* let's see whether the media is there with TUR */ | |
233 | + last_present = cd->media_present; | |
234 | + ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); | |
235 | + | |
236 | + /* | |
237 | + * Media is considered to be present if TUR succeeds or fails with | |
238 | + * sense data indicating something other than media-not-present | |
239 | + * (ASC 0x3a). | |
240 | + */ | |
241 | + cd->media_present = scsi_status_is_good(ret) || | |
242 | + (scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a); | |
243 | + | |
244 | + if (last_present != cd->media_present) | |
245 | + events |= DISK_EVENT_MEDIA_CHANGE; | |
246 | +skip_tur: | |
247 | + if (cd->device->changed) { | |
248 | + events |= DISK_EVENT_MEDIA_CHANGE; | |
249 | + cd->device->changed = 0; | |
239 | 250 | } |
240 | 251 | |
241 | -out: | |
242 | - /* Notify userspace, that media has changed. */ | |
243 | - if (retval != cd->previous_state) | |
252 | + /* for backward compatibility */ | |
253 | + if (events & DISK_EVENT_MEDIA_CHANGE) | |
244 | 254 | sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE, |
245 | 255 | GFP_KERNEL); |
246 | - cd->previous_state = retval; | |
247 | - kfree(sshdr); | |
248 | - | |
249 | - return retval; | |
256 | + return events; | |
250 | 257 | } |
251 | - | |
258 | + | |
252 | 259 | /* |
253 | 260 | * sr_done is the interrupt routine for the device driver. |
254 | 261 | * |
255 | 262 | |
256 | 263 | |
257 | 264 | |
... | ... | @@ -533,19 +540,35 @@ |
533 | 540 | return ret; |
534 | 541 | } |
535 | 542 | |
536 | -static int sr_block_media_changed(struct gendisk *disk) | |
543 | +static unsigned int sr_block_check_events(struct gendisk *disk, | |
544 | + unsigned int clearing) | |
537 | 545 | { |
538 | 546 | struct scsi_cd *cd = scsi_cd(disk); |
539 | - return cdrom_media_changed(&cd->cdi); | |
547 | + return cdrom_check_events(&cd->cdi, clearing); | |
540 | 548 | } |
541 | 549 | |
550 | +static int sr_block_revalidate_disk(struct gendisk *disk) | |
551 | +{ | |
552 | + struct scsi_cd *cd = scsi_cd(disk); | |
553 | + struct scsi_sense_hdr sshdr; | |
554 | + | |
555 | + /* if the unit is not ready, nothing more to do */ | |
556 | + if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) | |
557 | + return 0; | |
558 | + | |
559 | + sr_cd_check(&cd->cdi); | |
560 | + get_sectorsize(cd); | |
561 | + return 0; | |
562 | +} | |
563 | + | |
542 | 564 | static const struct block_device_operations sr_bdops = |
543 | 565 | { |
544 | 566 | .owner = THIS_MODULE, |
545 | 567 | .open = sr_block_open, |
546 | 568 | .release = sr_block_release, |
547 | 569 | .ioctl = sr_block_ioctl, |
548 | - .media_changed = sr_block_media_changed, | |
570 | + .check_events = sr_block_check_events, | |
571 | + .revalidate_disk = sr_block_revalidate_disk, | |
549 | 572 | /* |
550 | 573 | * No compat_ioctl for now because sr_block_ioctl never |
551 | 574 | * seems to pass arbitary ioctls down to host drivers. |
... | ... | @@ -618,6 +641,7 @@ |
618 | 641 | sprintf(disk->disk_name, "sr%d", minor); |
619 | 642 | disk->fops = &sr_bdops; |
620 | 643 | disk->flags = GENHD_FL_CD; |
644 | + disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST; | |
621 | 645 | |
622 | 646 | blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT); |
623 | 647 | |
... | ... | @@ -627,7 +651,7 @@ |
627 | 651 | cd->disk = disk; |
628 | 652 | cd->capacity = 0x1fffff; |
629 | 653 | cd->device->changed = 1; /* force recheck CD type */ |
630 | - cd->previous_state = 1; | |
654 | + cd->media_present = 1; | |
631 | 655 | cd->use = 1; |
632 | 656 | cd->readcd_known = 0; |
633 | 657 | cd->readcd_cdda = 0; |
... | ... | @@ -780,7 +804,7 @@ |
780 | 804 | } |
781 | 805 | |
782 | 806 | /* eat unit attentions */ |
783 | - sr_test_unit_ready(cd->device, &sshdr); | |
807 | + scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); | |
784 | 808 | |
785 | 809 | /* ask for mode page 0x2a */ |
786 | 810 | rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, |
drivers/scsi/sr.h
... | ... | @@ -40,7 +40,7 @@ |
40 | 40 | unsigned xa_flag:1; /* CD has XA sectors ? */ |
41 | 41 | unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ |
42 | 42 | unsigned readcd_cdda:1; /* reading audio data using READ_CD */ |
43 | - unsigned previous_state:1; /* media has changed */ | |
43 | + unsigned media_present:1; /* media is present */ | |
44 | 44 | struct cdrom_device_info cdi; |
45 | 45 | /* We hold gendisk and scsi_device references on probe and use |
46 | 46 | * the refs on this kref to decide when to release them */ |
... | ... | @@ -61,7 +61,6 @@ |
61 | 61 | int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); |
62 | 62 | |
63 | 63 | int sr_is_xa(Scsi_CD *); |
64 | -int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr); | |
65 | 64 | |
66 | 65 | /* sr_vendor.c */ |
67 | 66 | void sr_vendor_init(Scsi_CD *); |
drivers/scsi/sr_ioctl.c
... | ... | @@ -307,7 +307,7 @@ |
307 | 307 | /* we have no changer support */ |
308 | 308 | return -EINVAL; |
309 | 309 | } |
310 | - if (0 == sr_test_unit_ready(cd->device, &sshdr)) | |
310 | + if (!scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) | |
311 | 311 | return CDS_DISC_OK; |
312 | 312 | |
313 | 313 | /* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */ |
fs/block_dev.c
... | ... | @@ -948,11 +948,12 @@ |
948 | 948 | { |
949 | 949 | struct gendisk *disk = bdev->bd_disk; |
950 | 950 | const struct block_device_operations *bdops = disk->fops; |
951 | + unsigned int events; | |
951 | 952 | |
952 | - if (!bdops->media_changed) | |
953 | + events = disk_clear_events(disk, DISK_EVENT_MEDIA_CHANGE | | |
954 | + DISK_EVENT_EJECT_REQUEST); | |
955 | + if (!(events & DISK_EVENT_MEDIA_CHANGE)) | |
953 | 956 | return 0; |
954 | - if (!bdops->media_changed(bdev->bd_disk)) | |
955 | - return 0; | |
956 | 957 | |
957 | 958 | flush_disk(bdev); |
958 | 959 | if (bdops->revalidate_disk) |
959 | 960 | |
... | ... | @@ -1158,9 +1159,10 @@ |
1158 | 1159 | |
1159 | 1160 | if (whole) { |
1160 | 1161 | /* finish claiming */ |
1162 | + mutex_lock(&bdev->bd_mutex); | |
1161 | 1163 | spin_lock(&bdev_lock); |
1162 | 1164 | |
1163 | - if (res == 0) { | |
1165 | + if (!res) { | |
1164 | 1166 | BUG_ON(!bd_may_claim(bdev, whole, holder)); |
1165 | 1167 | /* |
1166 | 1168 | * Note that for a whole device bd_holders |
... | ... | @@ -1180,6 +1182,20 @@ |
1180 | 1182 | wake_up_bit(&whole->bd_claiming, 0); |
1181 | 1183 | |
1182 | 1184 | spin_unlock(&bdev_lock); |
1185 | + | |
1186 | + /* | |
1187 | + * Block event polling for write claims. Any write | |
1188 | + * holder makes the write_holder state stick until all | |
1189 | + * are released. This is good enough and tracking | |
1190 | + * individual writeable reference is too fragile given | |
1191 | + * the way @mode is used in blkdev_get/put(). | |
1192 | + */ | |
1193 | + if (!res && (mode & FMODE_WRITE) && !bdev->bd_write_holder) { | |
1194 | + bdev->bd_write_holder = true; | |
1195 | + disk_block_events(bdev->bd_disk); | |
1196 | + } | |
1197 | + | |
1198 | + mutex_unlock(&bdev->bd_mutex); | |
1183 | 1199 | bdput(whole); |
1184 | 1200 | } |
1185 | 1201 | |
1186 | 1202 | |
1187 | 1203 | |
... | ... | @@ -1353,12 +1369,23 @@ |
1353 | 1369 | |
1354 | 1370 | spin_unlock(&bdev_lock); |
1355 | 1371 | |
1356 | - /* if this was the last claim, holder link should go too */ | |
1357 | - if (bdev_free) | |
1372 | + /* | |
1373 | + * If this was the last claim, remove holder link and | |
1374 | + * unblock evpoll if it was a write holder. | |
1375 | + */ | |
1376 | + if (bdev_free) { | |
1358 | 1377 | bd_unlink_disk_holder(bdev); |
1378 | + if (bdev->bd_write_holder) { | |
1379 | + disk_unblock_events(bdev->bd_disk); | |
1380 | + bdev->bd_write_holder = false; | |
1381 | + } else | |
1382 | + disk_check_events(bdev->bd_disk); | |
1383 | + } | |
1359 | 1384 | |
1360 | 1385 | mutex_unlock(&bdev->bd_mutex); |
1361 | - } | |
1386 | + } else | |
1387 | + disk_check_events(bdev->bd_disk); | |
1388 | + | |
1362 | 1389 | return __blkdev_put(bdev, mode, 0); |
1363 | 1390 | } |
1364 | 1391 | EXPORT_SYMBOL(blkdev_put); |
fs/partitions/check.c
... | ... | @@ -522,65 +522,6 @@ |
522 | 522 | return ERR_PTR(err); |
523 | 523 | } |
524 | 524 | |
525 | -/* Not exported, helper to add_disk(). */ | |
526 | -void register_disk(struct gendisk *disk) | |
527 | -{ | |
528 | - struct device *ddev = disk_to_dev(disk); | |
529 | - struct block_device *bdev; | |
530 | - struct disk_part_iter piter; | |
531 | - struct hd_struct *part; | |
532 | - int err; | |
533 | - | |
534 | - ddev->parent = disk->driverfs_dev; | |
535 | - | |
536 | - dev_set_name(ddev, disk->disk_name); | |
537 | - | |
538 | - /* delay uevents, until we scanned partition table */ | |
539 | - dev_set_uevent_suppress(ddev, 1); | |
540 | - | |
541 | - if (device_add(ddev)) | |
542 | - return; | |
543 | - if (!sysfs_deprecated) { | |
544 | - err = sysfs_create_link(block_depr, &ddev->kobj, | |
545 | - kobject_name(&ddev->kobj)); | |
546 | - if (err) { | |
547 | - device_del(ddev); | |
548 | - return; | |
549 | - } | |
550 | - } | |
551 | - disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj); | |
552 | - disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); | |
553 | - | |
554 | - /* No minors to use for partitions */ | |
555 | - if (!disk_partitionable(disk)) | |
556 | - goto exit; | |
557 | - | |
558 | - /* No such device (e.g., media were just removed) */ | |
559 | - if (!get_capacity(disk)) | |
560 | - goto exit; | |
561 | - | |
562 | - bdev = bdget_disk(disk, 0); | |
563 | - if (!bdev) | |
564 | - goto exit; | |
565 | - | |
566 | - bdev->bd_invalidated = 1; | |
567 | - err = blkdev_get(bdev, FMODE_READ, NULL); | |
568 | - if (err < 0) | |
569 | - goto exit; | |
570 | - blkdev_put(bdev, FMODE_READ); | |
571 | - | |
572 | -exit: | |
573 | - /* announce disk after possible partitions are created */ | |
574 | - dev_set_uevent_suppress(ddev, 0); | |
575 | - kobject_uevent(&ddev->kobj, KOBJ_ADD); | |
576 | - | |
577 | - /* announce possible partitions */ | |
578 | - disk_part_iter_init(&piter, disk, 0); | |
579 | - while ((part = disk_part_iter_next(&piter))) | |
580 | - kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD); | |
581 | - disk_part_iter_exit(&piter); | |
582 | -} | |
583 | - | |
584 | 525 | static bool disk_unlock_native_capacity(struct gendisk *disk) |
585 | 526 | { |
586 | 527 | const struct block_device_operations *bdops = disk->fops; |
... | ... | @@ -743,34 +684,4 @@ |
743 | 684 | } |
744 | 685 | |
745 | 686 | EXPORT_SYMBOL(read_dev_sector); |
746 | - | |
747 | -void del_gendisk(struct gendisk *disk) | |
748 | -{ | |
749 | - struct disk_part_iter piter; | |
750 | - struct hd_struct *part; | |
751 | - | |
752 | - /* invalidate stuff */ | |
753 | - disk_part_iter_init(&piter, disk, | |
754 | - DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE); | |
755 | - while ((part = disk_part_iter_next(&piter))) { | |
756 | - invalidate_partition(disk, part->partno); | |
757 | - delete_partition(disk, part->partno); | |
758 | - } | |
759 | - disk_part_iter_exit(&piter); | |
760 | - | |
761 | - invalidate_partition(disk, 0); | |
762 | - blk_free_devt(disk_to_dev(disk)->devt); | |
763 | - set_capacity(disk, 0); | |
764 | - disk->flags &= ~GENHD_FL_UP; | |
765 | - unlink_gendisk(disk); | |
766 | - part_stat_set_all(&disk->part0, 0); | |
767 | - disk->part0.stamp = 0; | |
768 | - | |
769 | - kobject_put(disk->part0.holder_dir); | |
770 | - kobject_put(disk->slave_dir); | |
771 | - disk->driverfs_dev = NULL; | |
772 | - if (!sysfs_deprecated) | |
773 | - sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); | |
774 | - device_del(disk_to_dev(disk)); | |
775 | -} |
include/linux/blkdev.h
... | ... | @@ -644,7 +644,6 @@ |
644 | 644 | |
645 | 645 | extern int blk_register_queue(struct gendisk *disk); |
646 | 646 | extern void blk_unregister_queue(struct gendisk *disk); |
647 | -extern void register_disk(struct gendisk *dev); | |
648 | 647 | extern void generic_make_request(struct bio *bio); |
649 | 648 | extern void blk_rq_init(struct request_queue *q, struct request *rq); |
650 | 649 | extern void blk_put_request(struct request *); |
... | ... | @@ -1253,6 +1252,9 @@ |
1253 | 1252 | int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); |
1254 | 1253 | int (*direct_access) (struct block_device *, sector_t, |
1255 | 1254 | void **, unsigned long *); |
1255 | + unsigned int (*check_events) (struct gendisk *disk, | |
1256 | + unsigned int clearing); | |
1257 | + /* ->media_changed() is DEPRECATED, use ->check_events() instead */ | |
1256 | 1258 | int (*media_changed) (struct gendisk *); |
1257 | 1259 | void (*unlock_native_capacity) (struct gendisk *); |
1258 | 1260 | int (*revalidate_disk) (struct gendisk *); |
include/linux/cdrom.h
... | ... | @@ -946,6 +946,8 @@ |
946 | 946 | /* device-related storage */ |
947 | 947 | unsigned int options : 30; /* options flags */ |
948 | 948 | unsigned mc_flags : 2; /* media change buffer flags */ |
949 | + unsigned int vfs_events; /* cached events for vfs path */ | |
950 | + unsigned int ioctl_events; /* cached events for ioctl path */ | |
949 | 951 | int use_count; /* number of times device opened */ |
950 | 952 | char name[20]; /* name of the device type */ |
951 | 953 | /* per-device flags */ |
... | ... | @@ -965,6 +967,8 @@ |
965 | 967 | int (*open) (struct cdrom_device_info *, int); |
966 | 968 | void (*release) (struct cdrom_device_info *); |
967 | 969 | int (*drive_status) (struct cdrom_device_info *, int); |
970 | + unsigned int (*check_events) (struct cdrom_device_info *cdi, | |
971 | + unsigned int clearing, int slot); | |
968 | 972 | int (*media_changed) (struct cdrom_device_info *, int); |
969 | 973 | int (*tray_move) (struct cdrom_device_info *, int); |
970 | 974 | int (*lock_door) (struct cdrom_device_info *, int); |
... | ... | @@ -993,6 +997,8 @@ |
993 | 997 | extern void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode); |
994 | 998 | extern int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, |
995 | 999 | fmode_t mode, unsigned int cmd, unsigned long arg); |
1000 | +extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, | |
1001 | + unsigned int clearing); | |
996 | 1002 | extern int cdrom_media_changed(struct cdrom_device_info *); |
997 | 1003 | |
998 | 1004 | extern int register_cdrom(struct cdrom_device_info *cdi); |
include/linux/fs.h
include/linux/genhd.h
... | ... | @@ -128,6 +128,11 @@ |
128 | 128 | #define GENHD_FL_EXT_DEVT 64 /* allow extended devt */ |
129 | 129 | #define GENHD_FL_NATIVE_CAPACITY 128 |
130 | 130 | |
131 | +enum { | |
132 | + DISK_EVENT_MEDIA_CHANGE = 1 << 0, /* media changed */ | |
133 | + DISK_EVENT_EJECT_REQUEST = 1 << 1, /* eject requested */ | |
134 | +}; | |
135 | + | |
131 | 136 | #define BLK_SCSI_MAX_CMDS (256) |
132 | 137 | #define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8)) |
133 | 138 | |
... | ... | @@ -144,6 +149,8 @@ |
144 | 149 | struct hd_struct __rcu *part[]; |
145 | 150 | }; |
146 | 151 | |
152 | +struct disk_events; | |
153 | + | |
147 | 154 | struct gendisk { |
148 | 155 | /* major, first_minor and minors are input parameters only, |
149 | 156 | * don't use directly. Use disk_devt() and disk_max_parts(). |
... | ... | @@ -155,6 +162,10 @@ |
155 | 162 | |
156 | 163 | char disk_name[DISK_NAME_LEN]; /* name of major driver */ |
157 | 164 | char *(*devnode)(struct gendisk *gd, mode_t *mode); |
165 | + | |
166 | + unsigned int events; /* supported events */ | |
167 | + unsigned int async_events; /* async events, subset of all */ | |
168 | + | |
158 | 169 | /* Array of pointers to partitions indexed by partno. |
159 | 170 | * Protected with matching bdev lock but stat and other |
160 | 171 | * non-critical accesses use RCU. Always access through |
161 | 172 | |
... | ... | @@ -172,9 +183,8 @@ |
172 | 183 | struct kobject *slave_dir; |
173 | 184 | |
174 | 185 | struct timer_rand_state *random; |
175 | - | |
176 | 186 | atomic_t sync_io; /* RAID */ |
177 | - struct work_struct async_notify; | |
187 | + struct disk_events *ev; | |
178 | 188 | #ifdef CONFIG_BLK_DEV_INTEGRITY |
179 | 189 | struct blk_integrity *integrity; |
180 | 190 | #endif |
... | ... | @@ -396,7 +406,6 @@ |
396 | 406 | /* block/genhd.c */ |
397 | 407 | extern void add_disk(struct gendisk *disk); |
398 | 408 | extern void del_gendisk(struct gendisk *gp); |
399 | -extern void unlink_gendisk(struct gendisk *gp); | |
400 | 409 | extern struct gendisk *get_gendisk(dev_t dev, int *partno); |
401 | 410 | extern struct block_device *bdget_disk(struct gendisk *disk, int partno); |
402 | 411 | |
... | ... | @@ -407,6 +416,11 @@ |
407 | 416 | { |
408 | 417 | return disk->part0.policy; |
409 | 418 | } |
419 | + | |
420 | +extern void disk_block_events(struct gendisk *disk); | |
421 | +extern void disk_unblock_events(struct gendisk *disk); | |
422 | +extern void disk_check_events(struct gendisk *disk); | |
423 | +extern unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask); | |
410 | 424 | |
411 | 425 | /* drivers/char/random.c */ |
412 | 426 | extern void add_disk_randomness(struct gendisk *disk); |
include/scsi/scsi.h