diff options
| author | Jens Axboe <jaxboe@fusionio.com> | 2010-12-16 11:54:38 -0500 |
|---|---|---|
| committer | Jens Axboe <jaxboe@fusionio.com> | 2010-12-16 11:54:38 -0500 |
| commit | 8ae47c1e7deda7fa959a1dd272ff67e8a1830490 (patch) | |
| tree | f8c6f40b45b60c17a12015a1e94cac562c07b94f | |
| parent | c4ffa146849099e9178d3fcfa48ba114d3d1e432 (diff) | |
| parent | c8d2e937355d02db3055c2fc203e5f017297ee1f (diff) | |
Merge branch 'for-2.6.38/event-handling' into for-next
| -rw-r--r-- | block/genhd.c | 544 | ||||
| -rw-r--r-- | drivers/cdrom/cdrom.c | 55 | ||||
| -rw-r--r-- | drivers/scsi/scsi_lib.c | 13 | ||||
| -rw-r--r-- | drivers/scsi/sd.c | 95 | ||||
| -rw-r--r-- | drivers/scsi/sd.h | 1 | ||||
| -rw-r--r-- | drivers/scsi/sr.c | 174 | ||||
| -rw-r--r-- | drivers/scsi/sr.h | 3 | ||||
| -rw-r--r-- | drivers/scsi/sr_ioctl.c | 2 | ||||
| -rw-r--r-- | fs/block_dev.c | 41 | ||||
| -rw-r--r-- | fs/partitions/check.c | 89 | ||||
| -rw-r--r-- | include/linux/blkdev.h | 4 | ||||
| -rw-r--r-- | include/linux/cdrom.h | 6 | ||||
| -rw-r--r-- | include/linux/fs.h | 1 | ||||
| -rw-r--r-- | include/linux/genhd.h | 20 | ||||
| -rw-r--r-- | include/scsi/scsi.h | 1 |
15 files changed, 779 insertions, 270 deletions
diff --git a/block/genhd.c b/block/genhd.c index 5fa2b44a72ff..5465a824d489 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 | ||
| 36 | static struct device_type disk_type; | 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 | * 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 | ||
| 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 | * 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 | } | ||
| 556 | EXPORT_SYMBOL(add_disk); | 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 | 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 | } |
| 658 | EXPORT_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) | |||
| 1110 | module_init(proc_genhd_init); | 1204 | module_init(proc_genhd_init); |
| 1111 | #endif /* CONFIG_PROC_FS */ | 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 | dev_t blk_lookup_devt(const char *name, int partno) | 1207 | dev_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); |
| @@ -1198,8 +1269,6 @@ struct gendisk *alloc_disk_node(int minors, int node_id) | |||
| 1198 | disk_to_dev(disk)->class = &block_class; | 1269 | disk_to_dev(disk)->class = &block_class; |
| 1199 | disk_to_dev(disk)->type = &disk_type; | 1270 | disk_to_dev(disk)->type = &disk_type; |
| 1200 | device_initialize(disk_to_dev(disk)); | 1271 | device_initialize(disk_to_dev(disk)); |
| 1201 | INIT_WORK(&disk->async_notify, | ||
| 1202 | media_change_notify_thread); | ||
| 1203 | } | 1272 | } |
| 1204 | return disk; | 1273 | return disk; |
| 1205 | } | 1274 | } |
| @@ -1291,3 +1360,422 @@ int invalidate_partition(struct gendisk *disk, int partno) | |||
| 1291 | } | 1360 | } |
| 1292 | 1361 | ||
| 1293 | EXPORT_SYMBOL(invalidate_partition); | 1362 | EXPORT_SYMBOL(invalidate_partition); |
| 1363 | |||
| 1364 | /* | ||
| 1365 | * Disk events - monitor disk events like media change and eject request. | ||
| 1366 | */ | ||
| 1367 | struct disk_events { | ||
| 1368 | struct list_head node; /* all disk_event's */ | ||
| 1369 | struct gendisk *disk; /* the associated disk */ | ||
| 1370 | spinlock_t lock; | ||
| 1371 | |||
| 1372 | int block; /* event blocking depth */ | ||
| 1373 | unsigned int pending; /* events already sent out */ | ||
| 1374 | unsigned int clearing; /* events being cleared */ | ||
| 1375 | |||
| 1376 | long poll_msecs; /* interval, -1 for default */ | ||
| 1377 | struct delayed_work dwork; | ||
| 1378 | }; | ||
| 1379 | |||
| 1380 | static const char *disk_events_strs[] = { | ||
| 1381 | [ilog2(DISK_EVENT_MEDIA_CHANGE)] = "media_change", | ||
| 1382 | [ilog2(DISK_EVENT_EJECT_REQUEST)] = "eject_request", | ||
| 1383 | }; | ||
| 1384 | |||
| 1385 | static char *disk_uevents[] = { | ||
| 1386 | [ilog2(DISK_EVENT_MEDIA_CHANGE)] = "DISK_MEDIA_CHANGE=1", | ||
| 1387 | [ilog2(DISK_EVENT_EJECT_REQUEST)] = "DISK_EJECT_REQUEST=1", | ||
| 1388 | }; | ||
| 1389 | |||
| 1390 | /* list of all disk_events */ | ||
| 1391 | static DEFINE_MUTEX(disk_events_mutex); | ||
| 1392 | static LIST_HEAD(disk_events); | ||
| 1393 | |||
| 1394 | /* disable in-kernel polling by default */ | ||
| 1395 | static unsigned long disk_events_dfl_poll_msecs = 0; | ||
| 1396 | |||
| 1397 | static unsigned long disk_events_poll_jiffies(struct gendisk *disk) | ||
| 1398 | { | ||
| 1399 | struct disk_events *ev = disk->ev; | ||
| 1400 | long intv_msecs = 0; | ||
| 1401 | |||
| 1402 | /* | ||
| 1403 | * If device-specific poll interval is set, always use it. If | ||
| 1404 | * the default is being used, poll iff there are events which | ||
| 1405 | * can't be monitored asynchronously. | ||
| 1406 | */ | ||
| 1407 | if (ev->poll_msecs >= 0) | ||
| 1408 | intv_msecs = ev->poll_msecs; | ||
| 1409 | else if (disk->events & ~disk->async_events) | ||
| 1410 | intv_msecs = disk_events_dfl_poll_msecs; | ||
| 1411 | |||
| 1412 | return msecs_to_jiffies(intv_msecs); | ||
| 1413 | } | ||
| 1414 | |||
| 1415 | static void __disk_block_events(struct gendisk *disk, bool sync) | ||
| 1416 | { | ||
| 1417 | struct disk_events *ev = disk->ev; | ||
| 1418 | unsigned long flags; | ||
| 1419 | bool cancel; | ||
| 1420 | |||
| 1421 | spin_lock_irqsave(&ev->lock, flags); | ||
| 1422 | cancel = !ev->block++; | ||
| 1423 | spin_unlock_irqrestore(&ev->lock, flags); | ||
| 1424 | |||
| 1425 | if (cancel) { | ||
| 1426 | if (sync) | ||
| 1427 | cancel_delayed_work_sync(&disk->ev->dwork); | ||
| 1428 | else | ||
| 1429 | cancel_delayed_work(&disk->ev->dwork); | ||
| 1430 | } | ||
| 1431 | } | ||
| 1432 | |||
| 1433 | static void __disk_unblock_events(struct gendisk *disk, bool check_now) | ||
| 1434 | { | ||
| 1435 | struct disk_events *ev = disk->ev; | ||
| 1436 | unsigned long intv; | ||
| 1437 | unsigned long flags; | ||
| 1438 | |||
| 1439 | spin_lock_irqsave(&ev->lock, flags); | ||
| 1440 | |||
| 1441 | if (WARN_ON_ONCE(ev->block <= 0)) | ||
| 1442 | goto out_unlock; | ||
| 1443 | |||
| 1444 | if (--ev->block) | ||
| 1445 | goto out_unlock; | ||
| 1446 | |||
| 1447 | /* | ||
| 1448 | * Not exactly a latency critical operation, set poll timer | ||
| 1449 | * slack to 25% and kick event check. | ||
| 1450 | */ | ||
| 1451 | intv = disk_events_poll_jiffies(disk); | ||
| 1452 | set_timer_slack(&ev->dwork.timer, intv / 4); | ||
| 1453 | if (check_now) | ||
| 1454 | queue_delayed_work(system_nrt_wq, &ev->dwork, 0); | ||
| 1455 | else if (intv) | ||
| 1456 | queue_delayed_work(system_nrt_wq, &ev->dwork, intv); | ||
| 1457 | out_unlock: | ||
| 1458 | spin_unlock_irqrestore(&ev->lock, flags); | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | /** | ||
| 1462 | * disk_block_events - block and flush disk event checking | ||
| 1463 | * @disk: disk to block events for | ||
| 1464 | * | ||
| 1465 | * On return from this function, it is guaranteed that event checking | ||
| 1466 | * isn't in progress and won't happen until unblocked by | ||
| 1467 | * disk_unblock_events(). Events blocking is counted and the actual | ||
| 1468 | * unblocking happens after the matching number of unblocks are done. | ||
| 1469 | * | ||
| 1470 | * Note that this intentionally does not block event checking from | ||
| 1471 | * disk_clear_events(). | ||
| 1472 | * | ||
| 1473 | * CONTEXT: | ||
| 1474 | * Might sleep. | ||
| 1475 | */ | ||
| 1476 | void disk_block_events(struct gendisk *disk) | ||
| 1477 | { | ||
| 1478 | if (disk->ev) | ||
| 1479 | __disk_block_events(disk, true); | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | /** | ||
| 1483 | * disk_unblock_events - unblock disk event checking | ||
| 1484 | * @disk: disk to unblock events for | ||
| 1485 | * | ||
| 1486 | * Undo disk_block_events(). When the block count reaches zero, it | ||
| 1487 | * starts events polling if configured. | ||
| 1488 | * | ||
| 1489 | * CONTEXT: | ||
| 1490 | * Don't care. Safe to call from irq context. | ||
| 1491 | */ | ||
| 1492 | void disk_unblock_events(struct gendisk *disk) | ||
| 1493 | { | ||
| 1494 | if (disk->ev) | ||
| 1495 | __disk_unblock_events(disk, true); | ||
| 1496 | } | ||
| 1497 | |||
| 1498 | /** | ||
| 1499 | * disk_check_events - schedule immediate event checking | ||
| 1500 | * @disk: disk to check events for | ||
| 1501 | * | ||
| 1502 | * Schedule immediate event checking on @disk if not blocked. | ||
| 1503 | * | ||
| 1504 | * CONTEXT: | ||
| 1505 | * Don't care. Safe to call from irq context. | ||
| 1506 | */ | ||
| 1507 | void disk_check_events(struct gendisk *disk) | ||
| 1508 | { | ||
| 1509 | if (disk->ev) { | ||
| 1510 | __disk_block_events(disk, false); | ||
| 1511 | __disk_unblock_events(disk, true); | ||
| 1512 | } | ||
| 1513 | } | ||
| 1514 | EXPORT_SYMBOL_GPL(disk_check_events); | ||
| 1515 | |||
| 1516 | /** | ||
| 1517 | * disk_clear_events - synchronously check, clear and return pending events | ||
| 1518 | * @disk: disk to fetch and clear events from | ||
| 1519 | * @mask: mask of events to be fetched and clearted | ||
| 1520 | * | ||
| 1521 | * Disk events are synchronously checked and pending events in @mask | ||
| 1522 | * are cleared and returned. This ignores the block count. | ||
| 1523 | * | ||
| 1524 | * CONTEXT: | ||
| 1525 | * Might sleep. | ||
| 1526 | */ | ||
| 1527 | unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask) | ||
| 1528 | { | ||
| 1529 | const struct block_device_operations *bdops = disk->fops; | ||
| 1530 | struct disk_events *ev = disk->ev; | ||
| 1531 | unsigned int pending; | ||
| 1532 | |||
| 1533 | if (!ev) { | ||
| 1534 | /* for drivers still using the old ->media_changed method */ | ||
| 1535 | if ((mask & DISK_EVENT_MEDIA_CHANGE) && | ||
| 1536 | bdops->media_changed && bdops->media_changed(disk)) | ||
| 1537 | return DISK_EVENT_MEDIA_CHANGE; | ||
| 1538 | return 0; | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | /* tell the workfn about the events being cleared */ | ||
| 1542 | spin_lock_irq(&ev->lock); | ||
| 1543 | ev->clearing |= mask; | ||
| 1544 | spin_unlock_irq(&ev->lock); | ||
| 1545 | |||
| 1546 | /* uncondtionally schedule event check and wait for it to finish */ | ||
| 1547 | __disk_block_events(disk, true); | ||
| 1548 | queue_delayed_work(system_nrt_wq, &ev->dwork, 0); | ||
| 1549 | flush_delayed_work(&ev->dwork); | ||
| 1550 | __disk_unblock_events(disk, false); | ||
| 1551 | |||
| 1552 | /* then, fetch and clear pending events */ | ||
| 1553 | spin_lock_irq(&ev->lock); | ||
| 1554 | WARN_ON_ONCE(ev->clearing & mask); /* cleared by workfn */ | ||
| 1555 | pending = ev->pending & mask; | ||
| 1556 | ev->pending &= ~mask; | ||
| 1557 | spin_unlock_irq(&ev->lock); | ||
| 1558 | |||
| 1559 | return pending; | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | static void disk_events_workfn(struct work_struct *work) | ||
| 1563 | { | ||
| 1564 | struct delayed_work *dwork = to_delayed_work(work); | ||
| 1565 | struct disk_events *ev = container_of(dwork, struct disk_events, dwork); | ||
| 1566 | struct gendisk *disk = ev->disk; | ||
| 1567 | char *envp[ARRAY_SIZE(disk_uevents) + 1] = { }; | ||
| 1568 | unsigned int clearing = ev->clearing; | ||
| 1569 | unsigned int events; | ||
| 1570 | unsigned long intv; | ||
| 1571 | int nr_events = 0, i; | ||
| 1572 | |||
| 1573 | /* check events */ | ||
| 1574 | events = disk->fops->check_events(disk, clearing); | ||
| 1575 | |||
| 1576 | /* accumulate pending events and schedule next poll if necessary */ | ||
| 1577 | spin_lock_irq(&ev->lock); | ||
| 1578 | |||
| 1579 | events &= ~ev->pending; | ||
| 1580 | ev->pending |= events; | ||
| 1581 | ev->clearing &= ~clearing; | ||
| 1582 | |||
| 1583 | intv = disk_events_poll_jiffies(disk); | ||
| 1584 | if (!ev->block && intv) | ||
| 1585 | queue_delayed_work(system_nrt_wq, &ev->dwork, intv); | ||
| 1586 | |||
| 1587 | spin_unlock_irq(&ev->lock); | ||
| 1588 | |||
| 1589 | /* tell userland about new events */ | ||
| 1590 | for (i = 0; i < ARRAY_SIZE(disk_uevents); i++) | ||
| 1591 | if (events & (1 << i)) | ||
| 1592 | envp[nr_events++] = disk_uevents[i]; | ||
| 1593 | |||
| 1594 | if (nr_events) | ||
| 1595 | kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp); | ||
| 1596 | } | ||
| 1597 | |||
| 1598 | /* | ||
| 1599 | * A disk events enabled device has the following sysfs nodes under | ||
| 1600 | * its /sys/block/X/ directory. | ||
| 1601 | * | ||
| 1602 | * events : list of all supported events | ||
| 1603 | * events_async : list of events which can be detected w/o polling | ||
| 1604 | * events_poll_msecs : polling interval, 0: disable, -1: system default | ||
| 1605 | */ | ||
| 1606 | static ssize_t __disk_events_show(unsigned int events, char *buf) | ||
| 1607 | { | ||
| 1608 | const char *delim = ""; | ||
| 1609 | ssize_t pos = 0; | ||
| 1610 | int i; | ||
| 1611 | |||
| 1612 | for (i = 0; i < ARRAY_SIZE(disk_events_strs); i++) | ||
| 1613 | if (events & (1 << i)) { | ||
| 1614 | pos += sprintf(buf + pos, "%s%s", | ||
| 1615 | delim, disk_events_strs[i]); | ||
| 1616 | delim = " "; | ||
| 1617 | } | ||
| 1618 | if (pos) | ||
| 1619 | pos += sprintf(buf + pos, "\n"); | ||
| 1620 | return pos; | ||
| 1621 | } | ||
| 1622 | |||
| 1623 | static ssize_t disk_events_show(struct device *dev, | ||
| 1624 | struct device_attribute *attr, char *buf) | ||
| 1625 | { | ||
| 1626 | struct gendisk *disk = dev_to_disk(dev); | ||
| 1627 | |||
| 1628 | return __disk_events_show(disk->events, buf); | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | static ssize_t disk_events_async_show(struct device *dev, | ||
| 1632 | struct device_attribute *attr, char *buf) | ||
| 1633 | { | ||
| 1634 | struct gendisk *disk = dev_to_disk(dev); | ||
| 1635 | |||
| 1636 | return __disk_events_show(disk->async_events, buf); | ||
| 1637 | } | ||
| 1638 | |||
| 1639 | static ssize_t disk_events_poll_msecs_show(struct device *dev, | ||
| 1640 | struct device_attribute *attr, | ||
| 1641 | char *buf) | ||
| 1642 | { | ||
| 1643 | struct gendisk *disk = dev_to_disk(dev); | ||
| 1644 | |||
| 1645 | return sprintf(buf, "%ld\n", disk->ev->poll_msecs); | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | static ssize_t disk_events_poll_msecs_store(struct device *dev, | ||
| 1649 | struct device_attribute *attr, | ||
| 1650 | const char *buf, size_t count) | ||
| 1651 | { | ||
| 1652 | struct gendisk *disk = dev_to_disk(dev); | ||
| 1653 | long intv; | ||
| 1654 | |||
| 1655 | if (!count || !sscanf(buf, "%ld", &intv)) | ||
| 1656 | return -EINVAL; | ||
| 1657 | |||
| 1658 | if (intv < 0 && intv != -1) | ||
| 1659 | return -EINVAL; | ||
| 1660 | |||
| 1661 | __disk_block_events(disk, true); | ||
| 1662 | disk->ev->poll_msecs = intv; | ||
| 1663 | __disk_unblock_events(disk, true); | ||
| 1664 | |||
| 1665 | return count; | ||
| 1666 | } | ||
| 1667 | |||
| 1668 | static const DEVICE_ATTR(events, S_IRUGO, disk_events_show, NULL); | ||
| 1669 | static const DEVICE_ATTR(events_async, S_IRUGO, disk_events_async_show, NULL); | ||
| 1670 | static const DEVICE_ATTR(events_poll_msecs, S_IRUGO|S_IWUSR, | ||
| 1671 | disk_events_poll_msecs_show, | ||
| 1672 | disk_events_poll_msecs_store); | ||
| 1673 | |||
| 1674 | static const struct attribute *disk_events_attrs[] = { | ||
| 1675 | &dev_attr_events.attr, | ||
| 1676 | &dev_attr_events_async.attr, | ||
| 1677 | &dev_attr_events_poll_msecs.attr, | ||
| 1678 | NULL, | ||
| 1679 | }; | ||
| 1680 | |||
| 1681 | /* | ||
| 1682 | * The default polling interval can be specified by the kernel | ||
| 1683 | * parameter block.events_dfl_poll_msecs which defaults to 0 | ||
| 1684 | * (disable). This can also be modified runtime by writing to | ||
| 1685 | * /sys/module/block/events_dfl_poll_msecs. | ||
| 1686 | */ | ||
| 1687 | static int disk_events_set_dfl_poll_msecs(const char *val, | ||
| 1688 | const struct kernel_param *kp) | ||
| 1689 | { | ||
| 1690 | struct disk_events *ev; | ||
| 1691 | int ret; | ||
| 1692 | |||
| 1693 | ret = param_set_ulong(val, kp); | ||
| 1694 | if (ret < 0) | ||
| 1695 | return ret; | ||
| 1696 | |||
| 1697 | mutex_lock(&disk_events_mutex); | ||
| 1698 | |||
| 1699 | list_for_each_entry(ev, &disk_events, node) | ||
| 1700 | disk_check_events(ev->disk); | ||
| 1701 | |||
| 1702 | mutex_unlock(&disk_events_mutex); | ||
| 1703 | |||
| 1704 | return 0; | ||
| 1705 | } | ||
| 1706 | |||
| 1707 | static const struct kernel_param_ops disk_events_dfl_poll_msecs_param_ops = { | ||
| 1708 | .set = disk_events_set_dfl_poll_msecs, | ||
| 1709 | .get = param_get_ulong, | ||
| 1710 | }; | ||
| 1711 | |||
| 1712 | #undef MODULE_PARAM_PREFIX | ||
| 1713 | #define MODULE_PARAM_PREFIX "block." | ||
| 1714 | |||
| 1715 | module_param_cb(events_dfl_poll_msecs, &disk_events_dfl_poll_msecs_param_ops, | ||
| 1716 | &disk_events_dfl_poll_msecs, 0644); | ||
| 1717 | |||
| 1718 | /* | ||
| 1719 | * disk_{add|del|release}_events - initialize and destroy disk_events. | ||
| 1720 | */ | ||
| 1721 | static void disk_add_events(struct gendisk *disk) | ||
| 1722 | { | ||
| 1723 | struct disk_events *ev; | ||
| 1724 | |||
| 1725 | if (!disk->fops->check_events || !(disk->events | disk->async_events)) | ||
| 1726 | return; | ||
| 1727 | |||
| 1728 | ev = kzalloc(sizeof(*ev), GFP_KERNEL); | ||
| 1729 | if (!ev) { | ||
| 1730 | pr_warn("%s: failed to initialize events\n", disk->disk_name); | ||
| 1731 | return; | ||
| 1732 | } | ||
| 1733 | |||
| 1734 | if (sysfs_create_files(&disk_to_dev(disk)->kobj, | ||
| 1735 | disk_events_attrs) < 0) { | ||
| 1736 | pr_warn("%s: failed to create sysfs files for events\n", | ||
| 1737 | disk->disk_name); | ||
| 1738 | kfree(ev); | ||
| 1739 | return; | ||
| 1740 | } | ||
| 1741 | |||
| 1742 | disk->ev = ev; | ||
| 1743 | |||
| 1744 | INIT_LIST_HEAD(&ev->node); | ||
| 1745 | ev->disk = disk; | ||
| 1746 | spin_lock_init(&ev->lock); | ||
| 1747 | ev->block = 1; | ||
| 1748 | ev->poll_msecs = -1; | ||
| 1749 | INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn); | ||
| 1750 | |||
| 1751 | mutex_lock(&disk_events_mutex); | ||
| 1752 | list_add_tail(&ev->node, &disk_events); | ||
| 1753 | mutex_unlock(&disk_events_mutex); | ||
| 1754 | |||
| 1755 | /* | ||
| 1756 | * Block count is initialized to 1 and the following initial | ||
| 1757 | * unblock kicks it into action. | ||
| 1758 | */ | ||
| 1759 | __disk_unblock_events(disk, true); | ||
| 1760 | } | ||
| 1761 | |||
| 1762 | static void disk_del_events(struct gendisk *disk) | ||
| 1763 | { | ||
| 1764 | if (!disk->ev) | ||
| 1765 | return; | ||
| 1766 | |||
| 1767 | __disk_block_events(disk, true); | ||
| 1768 | |||
| 1769 | mutex_lock(&disk_events_mutex); | ||
| 1770 | list_del_init(&disk->ev->node); | ||
| 1771 | mutex_unlock(&disk_events_mutex); | ||
| 1772 | |||
| 1773 | sysfs_remove_files(&disk_to_dev(disk)->kobj, disk_events_attrs); | ||
| 1774 | } | ||
| 1775 | |||
| 1776 | static void disk_release_events(struct gendisk *disk) | ||
| 1777 | { | ||
| 1778 | /* the block count should be 1 from disk_del_events() */ | ||
| 1779 | WARN_ON_ONCE(disk->ev && disk->ev->block != 1); | ||
| 1780 | kfree(disk->ev); | ||
| 1781 | } | ||
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index af13c62dc473..1ea8f8d363c6 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c | |||
| @@ -1348,7 +1348,10 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot) | |||
| 1348 | if (!CDROM_CAN(CDC_SELECT_DISC)) | 1348 | if (!CDROM_CAN(CDC_SELECT_DISC)) |
| 1349 | return -EDRIVE_CANT_DO_THIS; | 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 | if (slot == CDSL_NONE) { | 1356 | if (slot == CDSL_NONE) { |
| 1354 | /* set media changed bits, on both queues */ | 1357 | /* set media changed bits, on both queues */ |
| @@ -1392,6 +1395,41 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot) | |||
| 1392 | return slot; | 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 | |||
| 1395 | /* We want to make media_changed accessible to the user through an | 1433 | /* We want to make media_changed accessible to the user through an |
| 1396 | * ioctl. The main problem now is that we must double-buffer the | 1434 | * ioctl. The main problem now is that we must double-buffer the |
| 1397 | * low-level implementation, to assure that the VFS and the user both | 1435 | * low-level implementation, to assure that the VFS and the user both |
| @@ -1403,15 +1441,26 @@ int media_changed(struct cdrom_device_info *cdi, int queue) | |||
| 1403 | { | 1441 | { |
| 1404 | unsigned int mask = (1 << (queue & 1)); | 1442 | unsigned int mask = (1 << (queue & 1)); |
| 1405 | int ret = !!(cdi->mc_flags & mask); | 1443 | int ret = !!(cdi->mc_flags & mask); |
| 1444 | bool changed; | ||
| 1406 | 1445 | ||
| 1407 | if (!CDROM_CAN(CDC_MEDIA_CHANGED)) | 1446 | if (!CDROM_CAN(CDC_MEDIA_CHANGED)) |
| 1408 | return ret; | 1447 | return ret; |
| 1448 | |||
| 1409 | /* changed since last call? */ | 1449 | /* changed since last call? */ |
| 1410 | if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { | 1450 | if (cdi->ops->check_events) { |
| 1451 | BUG_ON(!queue); /* shouldn't be called from VFS path */ | ||
| 1452 | cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE); | ||
| 1453 | changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE; | ||
| 1454 | cdi->ioctl_events = 0; | ||
| 1455 | } else | ||
| 1456 | changed = cdi->ops->media_changed(cdi, CDSL_CURRENT); | ||
| 1457 | |||
| 1458 | if (changed) { | ||
| 1411 | cdi->mc_flags = 0x3; /* set bit on both queues */ | 1459 | cdi->mc_flags = 0x3; /* set bit on both queues */ |
| 1412 | ret |= 1; | 1460 | ret |= 1; |
| 1413 | cdi->media_written = 0; | 1461 | cdi->media_written = 0; |
| 1414 | } | 1462 | } |
| 1463 | |||
| 1415 | cdi->mc_flags &= ~mask; /* clear bit */ | 1464 | cdi->mc_flags &= ~mask; /* clear bit */ |
| 1416 | return ret; | 1465 | return ret; |
| 1417 | } | 1466 | } |
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index eafeeda6e194..13bf89145b18 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
| @@ -1984,8 +1984,7 @@ EXPORT_SYMBOL(scsi_mode_sense); | |||
| 1984 | * in. | 1984 | * in. |
| 1985 | * | 1985 | * |
| 1986 | * Returns zero if unsuccessful or an error if TUR failed. For | 1986 | * Returns zero if unsuccessful or an error if TUR failed. For |
| 1987 | * removable media, a return of NOT_READY or UNIT_ATTENTION is | 1987 | * removable media, UNIT_ATTENTION sets ->changed flag. |
| 1988 | * translated to success, with the ->changed flag updated. | ||
| 1989 | **/ | 1988 | **/ |
| 1990 | int | 1989 | int |
| 1991 | scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, | 1990 | scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, |
| @@ -2012,16 +2011,6 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, | |||
| 2012 | } while (scsi_sense_valid(sshdr) && | 2011 | } while (scsi_sense_valid(sshdr) && |
| 2013 | sshdr->sense_key == UNIT_ATTENTION && --retries); | 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 | if (!sshdr_external) | 2014 | if (!sshdr_external) |
| 2026 | kfree(sshdr); | 2015 | kfree(sshdr); |
| 2027 | return result; | 2016 | return result; |
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b9ab3a590e4b..b179b0e39a3b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
| @@ -991,30 +991,50 @@ out: | |||
| 991 | 991 | ||
| 992 | static void set_media_not_present(struct scsi_disk *sdkp) | 992 | static void set_media_not_present(struct scsi_disk *sdkp) |
| 993 | { | 993 | { |
| 994 | if (sdkp->media_present) | ||
| 995 | sdkp->device->changed = 1; | ||
| 994 | sdkp->media_present = 0; | 996 | sdkp->media_present = 0; |
| 995 | sdkp->capacity = 0; | 997 | sdkp->capacity = 0; |
| 996 | sdkp->device->changed = 1; | 998 | } |
| 999 | |||
| 1000 | static int media_not_present(struct scsi_disk *sdkp, | ||
| 1001 | struct scsi_sense_hdr *sshdr) | ||
| 1002 | { | ||
| 1003 | if (!scsi_sense_valid(sshdr)) | ||
| 1004 | return 0; | ||
| 1005 | |||
| 1006 | /* not invoked for commands that could return deferred errors */ | ||
| 1007 | switch (sshdr->sense_key) { | ||
| 1008 | case UNIT_ATTENTION: | ||
| 1009 | sdkp->device->changed = 1; | ||
| 1010 | /* fall through */ | ||
| 1011 | case NOT_READY: | ||
| 1012 | /* medium not present */ | ||
| 1013 | if (sshdr->asc == 0x3A) { | ||
| 1014 | set_media_not_present(sdkp); | ||
| 1015 | return 1; | ||
| 1016 | } | ||
| 1017 | } | ||
| 1018 | return 0; | ||
| 997 | } | 1019 | } |
| 998 | 1020 | ||
| 999 | /** | 1021 | /** |
| 1000 | * sd_media_changed - check if our medium changed | 1022 | * sd_check_events - check media events |
| 1001 | * @disk: kernel device descriptor | 1023 | * @disk: kernel device descriptor |
| 1024 | * @clearing: disk events currently being cleared | ||
| 1002 | * | 1025 | * |
| 1003 | * Returns 0 if not applicable or no change; 1 if change | 1026 | * Returns mask of DISK_EVENT_*. |
| 1004 | * | 1027 | * |
| 1005 | * Note: this function is invoked from the block subsystem. | 1028 | * Note: this function is invoked from the block subsystem. |
| 1006 | **/ | 1029 | **/ |
| 1007 | static int sd_media_changed(struct gendisk *disk) | 1030 | static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing) |
| 1008 | { | 1031 | { |
| 1009 | struct scsi_disk *sdkp = scsi_disk(disk); | 1032 | struct scsi_disk *sdkp = scsi_disk(disk); |
| 1010 | struct scsi_device *sdp = sdkp->device; | 1033 | struct scsi_device *sdp = sdkp->device; |
| 1011 | struct scsi_sense_hdr *sshdr = NULL; | 1034 | struct scsi_sense_hdr *sshdr = NULL; |
| 1012 | int retval; | 1035 | int retval; |
| 1013 | 1036 | ||
| 1014 | SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); | 1037 | SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n")); |
| 1015 | |||
| 1016 | if (!sdp->removable) | ||
| 1017 | return 0; | ||
| 1018 | 1038 | ||
| 1019 | /* | 1039 | /* |
| 1020 | * If the device is offline, don't send any commands - just pretend as | 1040 | * If the device is offline, don't send any commands - just pretend as |
| @@ -1024,7 +1044,6 @@ static int sd_media_changed(struct gendisk *disk) | |||
| 1024 | */ | 1044 | */ |
| 1025 | if (!scsi_device_online(sdp)) { | 1045 | if (!scsi_device_online(sdp)) { |
| 1026 | set_media_not_present(sdkp); | 1046 | set_media_not_present(sdkp); |
| 1027 | retval = 1; | ||
| 1028 | goto out; | 1047 | goto out; |
| 1029 | } | 1048 | } |
| 1030 | 1049 | ||
| @@ -1045,34 +1064,30 @@ static int sd_media_changed(struct gendisk *disk) | |||
| 1045 | sshdr); | 1064 | sshdr); |
| 1046 | } | 1065 | } |
| 1047 | 1066 | ||
| 1048 | /* | 1067 | /* failed to execute TUR, assume media not present */ |
| 1049 | * Unable to test, unit probably not ready. This usually | 1068 | if (host_byte(retval)) { |
| 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)) { | ||
| 1057 | set_media_not_present(sdkp); | 1069 | set_media_not_present(sdkp); |
| 1058 | retval = 1; | ||
| 1059 | goto out; | 1070 | goto out; |
| 1060 | } | 1071 | } |
| 1061 | 1072 | ||
| 1073 | if (media_not_present(sdkp, sshdr)) | ||
| 1074 | goto out; | ||
| 1075 | |||
| 1062 | /* | 1076 | /* |
| 1063 | * For removable scsi disk we have to recognise the presence | 1077 | * For removable scsi disk we have to recognise the presence |
| 1064 | * of a disk in the drive. This is kept in the struct scsi_disk | 1078 | * of a disk in the drive. |
| 1065 | * struct and tested at open ! Daniel Roche (dan@lectra.fr) | ||
| 1066 | */ | 1079 | */ |
| 1080 | if (!sdkp->media_present) | ||
| 1081 | sdp->changed = 1; | ||
| 1067 | sdkp->media_present = 1; | 1082 | sdkp->media_present = 1; |
| 1068 | |||
| 1069 | retval = sdp->changed; | ||
| 1070 | sdp->changed = 0; | ||
| 1071 | out: | 1083 | out: |
| 1072 | if (retval != sdkp->previous_state) | 1084 | /* for backward compatibility */ |
| 1085 | if (sdp->changed) | ||
| 1073 | sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); | 1086 | sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); |
| 1074 | sdkp->previous_state = retval; | ||
| 1075 | kfree(sshdr); | 1087 | kfree(sshdr); |
| 1088 | |||
| 1089 | retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0; | ||
| 1090 | sdp->changed = 0; | ||
| 1076 | return retval; | 1091 | return retval; |
| 1077 | } | 1092 | } |
| 1078 | 1093 | ||
| @@ -1165,7 +1180,7 @@ static const struct block_device_operations sd_fops = { | |||
| 1165 | #ifdef CONFIG_COMPAT | 1180 | #ifdef CONFIG_COMPAT |
| 1166 | .compat_ioctl = sd_compat_ioctl, | 1181 | .compat_ioctl = sd_compat_ioctl, |
| 1167 | #endif | 1182 | #endif |
| 1168 | .media_changed = sd_media_changed, | 1183 | .check_events = sd_check_events, |
| 1169 | .revalidate_disk = sd_revalidate_disk, | 1184 | .revalidate_disk = sd_revalidate_disk, |
| 1170 | .unlock_native_capacity = sd_unlock_native_capacity, | 1185 | .unlock_native_capacity = sd_unlock_native_capacity, |
| 1171 | }; | 1186 | }; |
| @@ -1301,23 +1316,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
| 1301 | return good_bytes; | 1316 | return good_bytes; |
| 1302 | } | 1317 | } |
| 1303 | 1318 | ||
| 1304 | static int media_not_present(struct scsi_disk *sdkp, | ||
| 1305 | struct scsi_sense_hdr *sshdr) | ||
| 1306 | { | ||
| 1307 | |||
| 1308 | if (!scsi_sense_valid(sshdr)) | ||
| 1309 | return 0; | ||
| 1310 | /* not invoked for commands that could return deferred errors */ | ||
| 1311 | if (sshdr->sense_key != NOT_READY && | ||
| 1312 | sshdr->sense_key != UNIT_ATTENTION) | ||
| 1313 | return 0; | ||
| 1314 | if (sshdr->asc != 0x3A) /* medium not present */ | ||
| 1315 | return 0; | ||
| 1316 | |||
| 1317 | set_media_not_present(sdkp); | ||
| 1318 | return 1; | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | /* | 1319 | /* |
| 1322 | * spinup disk - called only in sd_revalidate_disk() | 1320 | * spinup disk - called only in sd_revalidate_disk() |
| 1323 | */ | 1321 | */ |
| @@ -1492,7 +1490,7 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, | |||
| 1492 | */ | 1490 | */ |
| 1493 | if (sdp->removable && | 1491 | if (sdp->removable && |
| 1494 | sense_valid && sshdr->sense_key == NOT_READY) | 1492 | sense_valid && sshdr->sense_key == NOT_READY) |
| 1495 | sdp->changed = 1; | 1493 | set_media_not_present(sdkp); |
| 1496 | 1494 | ||
| 1497 | /* | 1495 | /* |
| 1498 | * We used to set media_present to 0 here to indicate no media | 1496 | * We used to set media_present to 0 here to indicate no media |
| @@ -2347,8 +2345,10 @@ static void sd_probe_async(void *data, async_cookie_t cookie) | |||
| 2347 | 2345 | ||
| 2348 | gd->driverfs_dev = &sdp->sdev_gendev; | 2346 | gd->driverfs_dev = &sdp->sdev_gendev; |
| 2349 | gd->flags = GENHD_FL_EXT_DEVT; | 2347 | gd->flags = GENHD_FL_EXT_DEVT; |
| 2350 | if (sdp->removable) | 2348 | if (sdp->removable) { |
| 2351 | gd->flags |= GENHD_FL_REMOVABLE; | 2349 | gd->flags |= GENHD_FL_REMOVABLE; |
| 2350 | gd->events |= DISK_EVENT_MEDIA_CHANGE; | ||
| 2351 | } | ||
| 2352 | 2352 | ||
| 2353 | add_disk(gd); | 2353 | add_disk(gd); |
| 2354 | sd_dif_config_host(sdkp); | 2354 | sd_dif_config_host(sdkp); |
| @@ -2430,7 +2430,6 @@ static int sd_probe(struct device *dev) | |||
| 2430 | sdkp->disk = gd; | 2430 | sdkp->disk = gd; |
| 2431 | sdkp->index = index; | 2431 | sdkp->index = index; |
| 2432 | atomic_set(&sdkp->openers, 0); | 2432 | atomic_set(&sdkp->openers, 0); |
| 2433 | sdkp->previous_state = 1; | ||
| 2434 | 2433 | ||
| 2435 | if (!sdp->request_queue->rq_timeout) { | 2434 | if (!sdp->request_queue->rq_timeout) { |
| 2436 | if (sdp->type != TYPE_MOD) | 2435 | if (sdp->type != TYPE_MOD) |
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 55488faf0815..c9d8f6ca49e2 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h | |||
| @@ -55,7 +55,6 @@ struct scsi_disk { | |||
| 55 | u8 media_present; | 55 | u8 media_present; |
| 56 | u8 write_prot; | 56 | u8 write_prot; |
| 57 | u8 protection_type;/* Data Integrity Field */ | 57 | u8 protection_type;/* Data Integrity Field */ |
| 58 | unsigned previous_state : 1; | ||
| 59 | unsigned ATO : 1; /* state of disk ATO bit */ | 58 | unsigned ATO : 1; /* state of disk ATO bit */ |
| 60 | unsigned WCE : 1; /* state of disk WCE bit */ | 59 | unsigned WCE : 1; /* state of disk WCE bit */ |
| 61 | unsigned RCD : 1; /* state of disk RCD bit, unused */ | 60 | unsigned RCD : 1; /* state of disk RCD bit, unused */ |
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index d7b383c96d5d..be6baf8ad704 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c | |||
| @@ -104,14 +104,15 @@ static void sr_release(struct cdrom_device_info *); | |||
| 104 | static void get_sectorsize(struct scsi_cd *); | 104 | static void get_sectorsize(struct scsi_cd *); |
| 105 | static void get_capabilities(struct scsi_cd *); | 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 | static int sr_packet(struct cdrom_device_info *, struct packet_command *); | 109 | static int sr_packet(struct cdrom_device_info *, struct packet_command *); |
| 109 | 110 | ||
| 110 | static struct cdrom_device_ops sr_dops = { | 111 | static struct cdrom_device_ops sr_dops = { |
| 111 | .open = sr_open, | 112 | .open = sr_open, |
| 112 | .release = sr_release, | 113 | .release = sr_release, |
| 113 | .drive_status = sr_drive_status, | 114 | .drive_status = sr_drive_status, |
| 114 | .media_changed = sr_media_change, | 115 | .check_events = sr_check_events, |
| 115 | .tray_move = sr_tray_move, | 116 | .tray_move = sr_tray_move, |
| 116 | .lock_door = sr_lock_door, | 117 | .lock_door = sr_lock_door, |
| 117 | .select_speed = sr_select_speed, | 118 | .select_speed = sr_select_speed, |
| @@ -165,90 +166,96 @@ static void scsi_cd_put(struct scsi_cd *cd) | |||
| 165 | mutex_unlock(&sr_ref_mutex); | 166 | mutex_unlock(&sr_ref_mutex); |
| 166 | } | 167 | } |
| 167 | 168 | ||
| 168 | /* identical to scsi_test_unit_ready except that it doesn't | 169 | static unsigned int sr_get_events(struct scsi_device *sdev) |
| 169 | * eat the NOT_READY returns for removable media */ | ||
| 170 | int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr) | ||
| 171 | { | 170 | { |
| 172 | int retries = MAX_RETRIES; | 171 | u8 buf[8]; |
| 173 | int the_result; | 172 | u8 cmd[] = { GET_EVENT_STATUS_NOTIFICATION, |
| 174 | u8 cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0 }; | 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 | 185 | result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, sizeof(buf), |
| 177 | * conditions are gone, or a timeout happens | 186 | &sshdr, SR_TIMEOUT, MAX_RETRIES, NULL); |
| 178 | */ | 187 | if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION) |
| 179 | do { | 188 | return DISK_EVENT_MEDIA_CHANGE; |
| 180 | the_result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, | 189 | |
| 181 | 0, sshdr, SR_TIMEOUT, | 190 | if (result || be16_to_cpu(eh->data_len) < sizeof(*med)) |
| 182 | retries--, NULL); | 191 | return 0; |
| 183 | if (scsi_sense_valid(sshdr) && | 192 | |
| 184 | sshdr->sense_key == UNIT_ATTENTION) | 193 | if (eh->nea || eh->notification_class != 0x4) |
| 185 | sdev->changed = 1; | 194 | return 0; |
| 186 | 195 | ||
| 187 | } while (retries > 0 && | 196 | if (med->media_event_code == 1) |
| 188 | (!scsi_status_is_good(the_result) || | 197 | return DISK_EVENT_EJECT_REQUEST; |
| 189 | (scsi_sense_valid(sshdr) && | 198 | else if (med->media_event_code == 2) |
| 190 | sshdr->sense_key == UNIT_ATTENTION))); | 199 | return DISK_EVENT_MEDIA_CHANGE; |
| 191 | return the_result; | 200 | return 0; |
| 192 | } | 201 | } |
| 193 | 202 | ||
| 194 | /* | 203 | /* |
| 195 | * This function checks to see if the media has been changed in the | 204 | * This function checks to see if the media has been changed or eject |
| 196 | * CDROM drive. It is possible that we have already sensed a change, | 205 | * button has been pressed. It is possible that we have already |
| 197 | * or the drive may have sensed one and not yet reported it. We must | 206 | * sensed a change, or the drive may have sensed one and not yet |
| 198 | * be ready for either case. This function always reports the current | 207 | * reported it. The past events are accumulated in sdev->changed and |
| 199 | * value of the changed bit. If flag is 0, then the changed bit is reset. | 208 | * returned together with the current state. |
| 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. | ||
| 202 | */ | 209 | */ |
| 203 | 210 | static unsigned int sr_check_events(struct cdrom_device_info *cdi, | |
| 204 | static int sr_media_change(struct cdrom_device_info *cdi, int slot) | 211 | unsigned int clearing, int slot) |
| 205 | { | 212 | { |
| 206 | struct scsi_cd *cd = cdi->handle; | 213 | struct scsi_cd *cd = cdi->handle; |
| 207 | int retval; | 214 | bool last_present; |
| 208 | struct scsi_sense_hdr *sshdr; | 215 | struct scsi_sense_hdr sshdr; |
| 216 | unsigned int events; | ||
| 217 | int ret; | ||
| 209 | 218 | ||
| 210 | if (CDSL_CURRENT != slot) { | 219 | /* no changer support */ |
| 211 | /* no changer support */ | 220 | if (CDSL_CURRENT != slot) |
| 212 | return -EINVAL; | 221 | return 0; |
| 213 | } | ||
| 214 | 222 | ||
| 215 | sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); | 223 | events = sr_get_events(cd->device); |
| 216 | retval = sr_test_unit_ready(cd->device, sshdr); | 224 | /* |
| 217 | if (retval || (scsi_sense_valid(sshdr) && | 225 | * GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE |
| 218 | /* 0x3a is medium not present */ | 226 | * is being cleared. Note that there are devices which hang |
| 219 | sshdr->asc == 0x3a)) { | 227 | * if asked to execute TUR repeatedly. |
| 220 | /* Media not present or unable to test, unit probably not | 228 | */ |
| 221 | * ready. This usually means there is no disc in the drive. | 229 | if (!(clearing & DISK_EVENT_MEDIA_CHANGE)) |
| 222 | * Mark as changed, and we will figure it out later once | 230 | goto skip_tur; |
| 223 | * the drive is available again. | 231 | |
| 224 | */ | 232 | /* let's see whether the media is there with TUR */ |
| 225 | cd->device->changed = 1; | 233 | last_present = cd->media_present; |
| 226 | /* This will force a flush, if called from check_disk_change */ | 234 | ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); |
| 227 | retval = 1; | 235 | |
| 228 | goto out; | 236 | /* |
| 229 | }; | 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); | ||
| 230 | 243 | ||
| 231 | retval = cd->device->changed; | 244 | if (last_present != cd->media_present) |
| 232 | cd->device->changed = 0; | 245 | events |= DISK_EVENT_MEDIA_CHANGE; |
| 233 | /* If the disk changed, the capacity will now be different, | 246 | skip_tur: |
| 234 | * so we force a re-read of this information */ | 247 | if (cd->device->changed) { |
| 235 | if (retval) { | 248 | events |= DISK_EVENT_MEDIA_CHANGE; |
| 236 | /* check multisession offset etc */ | 249 | cd->device->changed = 0; |
| 237 | sr_cd_check(cdi); | ||
| 238 | get_sectorsize(cd); | ||
| 239 | } | 250 | } |
| 240 | 251 | ||
| 241 | out: | 252 | /* for backward compatibility */ |
| 242 | /* Notify userspace, that media has changed. */ | 253 | if (events & DISK_EVENT_MEDIA_CHANGE) |
| 243 | if (retval != cd->previous_state) | ||
| 244 | sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE, | 254 | sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE, |
| 245 | GFP_KERNEL); | 255 | GFP_KERNEL); |
| 246 | cd->previous_state = retval; | 256 | return events; |
| 247 | kfree(sshdr); | ||
| 248 | |||
| 249 | return retval; | ||
| 250 | } | 257 | } |
| 251 | 258 | ||
| 252 | /* | 259 | /* |
| 253 | * sr_done is the interrupt routine for the device driver. | 260 | * sr_done is the interrupt routine for the device driver. |
| 254 | * | 261 | * |
| @@ -533,10 +540,25 @@ out: | |||
| 533 | return ret; | 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 | struct scsi_cd *cd = scsi_cd(disk); | 546 | struct scsi_cd *cd = scsi_cd(disk); |
| 539 | return cdrom_media_changed(&cd->cdi); | 547 | return cdrom_check_events(&cd->cdi, clearing); |
| 548 | } | ||
| 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; | ||
| 540 | } | 562 | } |
| 541 | 563 | ||
| 542 | static const struct block_device_operations sr_bdops = | 564 | static const struct block_device_operations sr_bdops = |
| @@ -545,7 +567,8 @@ static const struct block_device_operations sr_bdops = | |||
| 545 | .open = sr_block_open, | 567 | .open = sr_block_open, |
| 546 | .release = sr_block_release, | 568 | .release = sr_block_release, |
| 547 | .ioctl = sr_block_ioctl, | 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 | * No compat_ioctl for now because sr_block_ioctl never | 573 | * No compat_ioctl for now because sr_block_ioctl never |
| 551 | * seems to pass arbitary ioctls down to host drivers. | 574 | * seems to pass arbitary ioctls down to host drivers. |
| @@ -618,6 +641,7 @@ static int sr_probe(struct device *dev) | |||
| 618 | sprintf(disk->disk_name, "sr%d", minor); | 641 | sprintf(disk->disk_name, "sr%d", minor); |
| 619 | disk->fops = &sr_bdops; | 642 | disk->fops = &sr_bdops; |
| 620 | disk->flags = GENHD_FL_CD; | 643 | disk->flags = GENHD_FL_CD; |
| 644 | disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST; | ||
| 621 | 645 | ||
| 622 | blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT); | 646 | blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT); |
| 623 | 647 | ||
| @@ -627,7 +651,7 @@ static int sr_probe(struct device *dev) | |||
| 627 | cd->disk = disk; | 651 | cd->disk = disk; |
| 628 | cd->capacity = 0x1fffff; | 652 | cd->capacity = 0x1fffff; |
| 629 | cd->device->changed = 1; /* force recheck CD type */ | 653 | cd->device->changed = 1; /* force recheck CD type */ |
| 630 | cd->previous_state = 1; | 654 | cd->media_present = 1; |
| 631 | cd->use = 1; | 655 | cd->use = 1; |
| 632 | cd->readcd_known = 0; | 656 | cd->readcd_known = 0; |
| 633 | cd->readcd_cdda = 0; | 657 | cd->readcd_cdda = 0; |
| @@ -780,7 +804,7 @@ static void get_capabilities(struct scsi_cd *cd) | |||
| 780 | } | 804 | } |
| 781 | 805 | ||
| 782 | /* eat unit attentions */ | 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 | /* ask for mode page 0x2a */ | 809 | /* ask for mode page 0x2a */ |
| 786 | rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, | 810 | rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, |
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index 1e144dfdbd4b..e036f1dc83c8 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h | |||
| @@ -40,7 +40,7 @@ typedef struct scsi_cd { | |||
| 40 | unsigned xa_flag:1; /* CD has XA sectors ? */ | 40 | unsigned xa_flag:1; /* CD has XA sectors ? */ |
| 41 | unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ | 41 | unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ |
| 42 | unsigned readcd_cdda:1; /* reading audio data using READ_CD */ | 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 | struct cdrom_device_info cdi; | 44 | struct cdrom_device_info cdi; |
| 45 | /* We hold gendisk and scsi_device references on probe and use | 45 | /* We hold gendisk and scsi_device references on probe and use |
| 46 | * the refs on this kref to decide when to release them */ | 46 | * the refs on this kref to decide when to release them */ |
| @@ -61,7 +61,6 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed); | |||
| 61 | int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); | 61 | int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); |
| 62 | 62 | ||
| 63 | int sr_is_xa(Scsi_CD *); | 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 | /* sr_vendor.c */ | 65 | /* sr_vendor.c */ |
| 67 | void sr_vendor_init(Scsi_CD *); | 66 | void sr_vendor_init(Scsi_CD *); |
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 3cd8ffbad577..8be30554119b 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c | |||
| @@ -307,7 +307,7 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot) | |||
| 307 | /* we have no changer support */ | 307 | /* we have no changer support */ |
| 308 | return -EINVAL; | 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 | return CDS_DISC_OK; | 311 | return CDS_DISC_OK; |
| 312 | 312 | ||
| 313 | /* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */ | 313 | /* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */ |
diff --git a/fs/block_dev.c b/fs/block_dev.c index c1c1b8c3fb99..6017389711ee 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -948,10 +948,11 @@ int check_disk_change(struct block_device *bdev) | |||
| 948 | { | 948 | { |
| 949 | struct gendisk *disk = bdev->bd_disk; | 949 | struct gendisk *disk = bdev->bd_disk; |
| 950 | const struct block_device_operations *bdops = disk->fops; | 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 | |
| 953 | return 0; | 954 | DISK_EVENT_EJECT_REQUEST); |
| 954 | if (!bdops->media_changed(bdev->bd_disk)) | 955 | if (!(events & DISK_EVENT_MEDIA_CHANGE)) |
| 955 | return 0; | 956 | return 0; |
| 956 | 957 | ||
| 957 | flush_disk(bdev); | 958 | flush_disk(bdev); |
| @@ -1158,9 +1159,10 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) | |||
| 1158 | 1159 | ||
| 1159 | if (whole) { | 1160 | if (whole) { |
| 1160 | /* finish claiming */ | 1161 | /* finish claiming */ |
| 1162 | mutex_lock(&bdev->bd_mutex); | ||
| 1161 | spin_lock(&bdev_lock); | 1163 | spin_lock(&bdev_lock); |
| 1162 | 1164 | ||
| 1163 | if (res == 0) { | 1165 | if (!res) { |
| 1164 | BUG_ON(!bd_may_claim(bdev, whole, holder)); | 1166 | BUG_ON(!bd_may_claim(bdev, whole, holder)); |
| 1165 | /* | 1167 | /* |
| 1166 | * Note that for a whole device bd_holders | 1168 | * Note that for a whole device bd_holders |
| @@ -1180,6 +1182,20 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) | |||
| 1180 | wake_up_bit(&whole->bd_claiming, 0); | 1182 | wake_up_bit(&whole->bd_claiming, 0); |
| 1181 | 1183 | ||
| 1182 | spin_unlock(&bdev_lock); | 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 | bdput(whole); | 1199 | bdput(whole); |
| 1184 | } | 1200 | } |
| 1185 | 1201 | ||
| @@ -1353,12 +1369,23 @@ int blkdev_put(struct block_device *bdev, fmode_t mode) | |||
| 1353 | 1369 | ||
| 1354 | spin_unlock(&bdev_lock); | 1370 | spin_unlock(&bdev_lock); |
| 1355 | 1371 | ||
| 1356 | /* if this was the last claim, holder link should go too */ | 1372 | /* |
| 1357 | if (bdev_free) | 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 | bd_unlink_disk_holder(bdev); | 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 | mutex_unlock(&bdev->bd_mutex); | 1385 | mutex_unlock(&bdev->bd_mutex); |
| 1361 | } | 1386 | } else |
| 1387 | disk_check_events(bdev->bd_disk); | ||
| 1388 | |||
| 1362 | return __blkdev_put(bdev, mode, 0); | 1389 | return __blkdev_put(bdev, mode, 0); |
| 1363 | } | 1390 | } |
| 1364 | EXPORT_SYMBOL(blkdev_put); | 1391 | EXPORT_SYMBOL(blkdev_put); |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index bdf8d3cc95a4..9a48d65d9855 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
| @@ -516,65 +516,6 @@ out_put: | |||
| 516 | return ERR_PTR(err); | 516 | return ERR_PTR(err); |
| 517 | } | 517 | } |
| 518 | 518 | ||
| 519 | /* Not exported, helper to add_disk(). */ | ||
| 520 | void register_disk(struct gendisk *disk) | ||
| 521 | { | ||
| 522 | struct device *ddev = disk_to_dev(disk); | ||
| 523 | struct block_device *bdev; | ||
| 524 | struct disk_part_iter piter; | ||
| 525 | struct hd_struct *part; | ||
| 526 | int err; | ||
| 527 | |||
| 528 | ddev->parent = disk->driverfs_dev; | ||
| 529 | |||
| 530 | dev_set_name(ddev, disk->disk_name); | ||
| 531 | |||
| 532 | /* delay uevents, until we scanned partition table */ | ||
| 533 | dev_set_uevent_suppress(ddev, 1); | ||
| 534 | |||
| 535 | if (device_add(ddev)) | ||
| 536 | return; | ||
| 537 | if (!sysfs_deprecated) { | ||
| 538 | err = sysfs_create_link(block_depr, &ddev->kobj, | ||
| 539 | kobject_name(&ddev->kobj)); | ||
| 540 | if (err) { | ||
| 541 | device_del(ddev); | ||
| 542 | return; | ||
| 543 | } | ||
| 544 | } | ||
| 545 | disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj); | ||
| 546 | disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); | ||
| 547 | |||
| 548 | /* No minors to use for partitions */ | ||
| 549 | if (!disk_partitionable(disk)) | ||
| 550 | goto exit; | ||
| 551 | |||
| 552 | /* No such device (e.g., media were just removed) */ | ||
| 553 | if (!get_capacity(disk)) | ||
| 554 | goto exit; | ||
| 555 | |||
| 556 | bdev = bdget_disk(disk, 0); | ||
| 557 | if (!bdev) | ||
| 558 | goto exit; | ||
| 559 | |||
| 560 | bdev->bd_invalidated = 1; | ||
| 561 | err = blkdev_get(bdev, FMODE_READ, NULL); | ||
| 562 | if (err < 0) | ||
| 563 | goto exit; | ||
| 564 | blkdev_put(bdev, FMODE_READ); | ||
| 565 | |||
| 566 | exit: | ||
| 567 | /* announce disk after possible partitions are created */ | ||
| 568 | dev_set_uevent_suppress(ddev, 0); | ||
| 569 | kobject_uevent(&ddev->kobj, KOBJ_ADD); | ||
| 570 | |||
| 571 | /* announce possible partitions */ | ||
| 572 | disk_part_iter_init(&piter, disk, 0); | ||
| 573 | while ((part = disk_part_iter_next(&piter))) | ||
| 574 | kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD); | ||
| 575 | disk_part_iter_exit(&piter); | ||
| 576 | } | ||
| 577 | |||
| 578 | static bool disk_unlock_native_capacity(struct gendisk *disk) | 519 | static bool disk_unlock_native_capacity(struct gendisk *disk) |
| 579 | { | 520 | { |
| 580 | const struct block_device_operations *bdops = disk->fops; | 521 | const struct block_device_operations *bdops = disk->fops; |
| @@ -737,33 +678,3 @@ fail: | |||
| 737 | } | 678 | } |
| 738 | 679 | ||
| 739 | EXPORT_SYMBOL(read_dev_sector); | 680 | EXPORT_SYMBOL(read_dev_sector); |
| 740 | |||
| 741 | void del_gendisk(struct gendisk *disk) | ||
| 742 | { | ||
| 743 | struct disk_part_iter piter; | ||
| 744 | struct hd_struct *part; | ||
| 745 | |||
| 746 | /* invalidate stuff */ | ||
| 747 | disk_part_iter_init(&piter, disk, | ||
| 748 | DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE); | ||
| 749 | while ((part = disk_part_iter_next(&piter))) { | ||
| 750 | invalidate_partition(disk, part->partno); | ||
| 751 | delete_partition(disk, part->partno); | ||
| 752 | } | ||
| 753 | disk_part_iter_exit(&piter); | ||
| 754 | |||
| 755 | invalidate_partition(disk, 0); | ||
| 756 | blk_free_devt(disk_to_dev(disk)->devt); | ||
| 757 | set_capacity(disk, 0); | ||
| 758 | disk->flags &= ~GENHD_FL_UP; | ||
| 759 | unlink_gendisk(disk); | ||
| 760 | part_stat_set_all(&disk->part0, 0); | ||
| 761 | disk->part0.stamp = 0; | ||
| 762 | |||
| 763 | kobject_put(disk->part0.holder_dir); | ||
| 764 | kobject_put(disk->slave_dir); | ||
| 765 | disk->driverfs_dev = NULL; | ||
| 766 | if (!sysfs_deprecated) | ||
| 767 | sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); | ||
| 768 | device_del(disk_to_dev(disk)); | ||
| 769 | } | ||
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index aae86fd10c4f..05667e6989f1 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
| @@ -643,7 +643,6 @@ static inline void rq_flush_dcache_pages(struct request *rq) | |||
| 643 | 643 | ||
| 644 | extern int blk_register_queue(struct gendisk *disk); | 644 | extern int blk_register_queue(struct gendisk *disk); |
| 645 | extern void blk_unregister_queue(struct gendisk *disk); | 645 | extern void blk_unregister_queue(struct gendisk *disk); |
| 646 | extern void register_disk(struct gendisk *dev); | ||
| 647 | extern void generic_make_request(struct bio *bio); | 646 | extern void generic_make_request(struct bio *bio); |
| 648 | extern void blk_rq_init(struct request_queue *q, struct request *rq); | 647 | extern void blk_rq_init(struct request_queue *q, struct request *rq); |
| 649 | extern void blk_put_request(struct request *); | 648 | extern void blk_put_request(struct request *); |
| @@ -1252,6 +1251,9 @@ struct block_device_operations { | |||
| 1252 | int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); | 1251 | int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); |
| 1253 | int (*direct_access) (struct block_device *, sector_t, | 1252 | int (*direct_access) (struct block_device *, sector_t, |
| 1254 | void **, unsigned long *); | 1253 | void **, unsigned long *); |
| 1254 | unsigned int (*check_events) (struct gendisk *disk, | ||
| 1255 | unsigned int clearing); | ||
| 1256 | /* ->media_changed() is DEPRECATED, use ->check_events() instead */ | ||
| 1255 | int (*media_changed) (struct gendisk *); | 1257 | int (*media_changed) (struct gendisk *); |
| 1256 | void (*unlock_native_capacity) (struct gendisk *); | 1258 | void (*unlock_native_capacity) (struct gendisk *); |
| 1257 | int (*revalidate_disk) (struct gendisk *); | 1259 | int (*revalidate_disk) (struct gendisk *); |
diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h index 78e904796622..35eae4b67503 100644 --- a/include/linux/cdrom.h +++ b/include/linux/cdrom.h | |||
| @@ -946,6 +946,8 @@ struct cdrom_device_info { | |||
| 946 | /* device-related storage */ | 946 | /* device-related storage */ |
| 947 | unsigned int options : 30; /* options flags */ | 947 | unsigned int options : 30; /* options flags */ |
| 948 | unsigned mc_flags : 2; /* media change buffer flags */ | 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 | int use_count; /* number of times device opened */ | 951 | int use_count; /* number of times device opened */ |
| 950 | char name[20]; /* name of the device type */ | 952 | char name[20]; /* name of the device type */ |
| 951 | /* per-device flags */ | 953 | /* per-device flags */ |
| @@ -965,6 +967,8 @@ struct cdrom_device_ops { | |||
| 965 | int (*open) (struct cdrom_device_info *, int); | 967 | int (*open) (struct cdrom_device_info *, int); |
| 966 | void (*release) (struct cdrom_device_info *); | 968 | void (*release) (struct cdrom_device_info *); |
| 967 | int (*drive_status) (struct cdrom_device_info *, int); | 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 | int (*media_changed) (struct cdrom_device_info *, int); | 972 | int (*media_changed) (struct cdrom_device_info *, int); |
| 969 | int (*tray_move) (struct cdrom_device_info *, int); | 973 | int (*tray_move) (struct cdrom_device_info *, int); |
| 970 | int (*lock_door) (struct cdrom_device_info *, int); | 974 | int (*lock_door) (struct cdrom_device_info *, int); |
| @@ -993,6 +997,8 @@ extern int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, | |||
| 993 | extern void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode); | 997 | extern void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode); |
| 994 | extern int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, | 998 | extern int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, |
| 995 | fmode_t mode, unsigned int cmd, unsigned long arg); | 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 | extern int cdrom_media_changed(struct cdrom_device_info *); | 1002 | extern int cdrom_media_changed(struct cdrom_device_info *); |
| 997 | 1003 | ||
| 998 | extern int register_cdrom(struct cdrom_device_info *cdi); | 1004 | extern int register_cdrom(struct cdrom_device_info *cdi); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index f48501563917..997d22efdef0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -662,6 +662,7 @@ struct block_device { | |||
| 662 | void * bd_claiming; | 662 | void * bd_claiming; |
| 663 | void * bd_holder; | 663 | void * bd_holder; |
| 664 | int bd_holders; | 664 | int bd_holders; |
| 665 | bool bd_write_holder; | ||
| 665 | #ifdef CONFIG_SYSFS | 666 | #ifdef CONFIG_SYSFS |
| 666 | struct gendisk * bd_holder_disk; /* for sysfs slave linkng */ | 667 | struct gendisk * bd_holder_disk; /* for sysfs slave linkng */ |
| 667 | #endif | 668 | #endif |
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 7a7b9c1644e4..13893aa2ac9d 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
| @@ -127,6 +127,11 @@ struct hd_struct { | |||
| 127 | #define GENHD_FL_EXT_DEVT 64 /* allow extended devt */ | 127 | #define GENHD_FL_EXT_DEVT 64 /* allow extended devt */ |
| 128 | #define GENHD_FL_NATIVE_CAPACITY 128 | 128 | #define GENHD_FL_NATIVE_CAPACITY 128 |
| 129 | 129 | ||
| 130 | enum { | ||
| 131 | DISK_EVENT_MEDIA_CHANGE = 1 << 0, /* media changed */ | ||
| 132 | DISK_EVENT_EJECT_REQUEST = 1 << 1, /* eject requested */ | ||
| 133 | }; | ||
| 134 | |||
| 130 | #define BLK_SCSI_MAX_CMDS (256) | 135 | #define BLK_SCSI_MAX_CMDS (256) |
| 131 | #define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8)) | 136 | #define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8)) |
| 132 | 137 | ||
| @@ -143,6 +148,8 @@ struct disk_part_tbl { | |||
| 143 | struct hd_struct __rcu *part[]; | 148 | struct hd_struct __rcu *part[]; |
| 144 | }; | 149 | }; |
| 145 | 150 | ||
| 151 | struct disk_events; | ||
| 152 | |||
| 146 | struct gendisk { | 153 | struct gendisk { |
| 147 | /* major, first_minor and minors are input parameters only, | 154 | /* major, first_minor and minors are input parameters only, |
| 148 | * don't use directly. Use disk_devt() and disk_max_parts(). | 155 | * don't use directly. Use disk_devt() and disk_max_parts(). |
| @@ -154,6 +161,10 @@ struct gendisk { | |||
| 154 | 161 | ||
| 155 | char disk_name[DISK_NAME_LEN]; /* name of major driver */ | 162 | char disk_name[DISK_NAME_LEN]; /* name of major driver */ |
| 156 | char *(*devnode)(struct gendisk *gd, mode_t *mode); | 163 | char *(*devnode)(struct gendisk *gd, mode_t *mode); |
| 164 | |||
| 165 | unsigned int events; /* supported events */ | ||
| 166 | unsigned int async_events; /* async events, subset of all */ | ||
| 167 | |||
| 157 | /* Array of pointers to partitions indexed by partno. | 168 | /* Array of pointers to partitions indexed by partno. |
| 158 | * Protected with matching bdev lock but stat and other | 169 | * Protected with matching bdev lock but stat and other |
| 159 | * non-critical accesses use RCU. Always access through | 170 | * non-critical accesses use RCU. Always access through |
| @@ -171,9 +182,8 @@ struct gendisk { | |||
| 171 | struct kobject *slave_dir; | 182 | struct kobject *slave_dir; |
| 172 | 183 | ||
| 173 | struct timer_rand_state *random; | 184 | struct timer_rand_state *random; |
| 174 | |||
| 175 | atomic_t sync_io; /* RAID */ | 185 | atomic_t sync_io; /* RAID */ |
| 176 | struct work_struct async_notify; | 186 | struct disk_events *ev; |
| 177 | #ifdef CONFIG_BLK_DEV_INTEGRITY | 187 | #ifdef CONFIG_BLK_DEV_INTEGRITY |
| 178 | struct blk_integrity *integrity; | 188 | struct blk_integrity *integrity; |
| 179 | #endif | 189 | #endif |
| @@ -395,7 +405,6 @@ extern void part_round_stats(int cpu, struct hd_struct *part); | |||
| 395 | /* block/genhd.c */ | 405 | /* block/genhd.c */ |
| 396 | extern void add_disk(struct gendisk *disk); | 406 | extern void add_disk(struct gendisk *disk); |
| 397 | extern void del_gendisk(struct gendisk *gp); | 407 | extern void del_gendisk(struct gendisk *gp); |
| 398 | extern void unlink_gendisk(struct gendisk *gp); | ||
| 399 | extern struct gendisk *get_gendisk(dev_t dev, int *partno); | 408 | extern struct gendisk *get_gendisk(dev_t dev, int *partno); |
| 400 | extern struct block_device *bdget_disk(struct gendisk *disk, int partno); | 409 | extern struct block_device *bdget_disk(struct gendisk *disk, int partno); |
| 401 | 410 | ||
| @@ -407,6 +416,11 @@ static inline int get_disk_ro(struct gendisk *disk) | |||
| 407 | return disk->part0.policy; | 416 | return disk->part0.policy; |
| 408 | } | 417 | } |
| 409 | 418 | ||
| 419 | extern void disk_block_events(struct gendisk *disk); | ||
| 420 | extern void disk_unblock_events(struct gendisk *disk); | ||
| 421 | extern void disk_check_events(struct gendisk *disk); | ||
| 422 | extern unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask); | ||
| 423 | |||
| 410 | /* drivers/char/random.c */ | 424 | /* drivers/char/random.c */ |
| 411 | extern void add_disk_randomness(struct gendisk *disk); | 425 | extern void add_disk_randomness(struct gendisk *disk); |
| 412 | extern void rand_initialize_disk(struct gendisk *disk); | 426 | extern void rand_initialize_disk(struct gendisk *disk); |
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 216af8538cc9..86758618d4f8 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h | |||
| @@ -104,6 +104,7 @@ struct scsi_cmnd; | |||
| 104 | #define UNMAP 0x42 | 104 | #define UNMAP 0x42 |
| 105 | #define READ_TOC 0x43 | 105 | #define READ_TOC 0x43 |
| 106 | #define READ_HEADER 0x44 | 106 | #define READ_HEADER 0x44 |
| 107 | #define GET_EVENT_STATUS_NOTIFICATION 0x4a | ||
| 107 | #define LOG_SELECT 0x4c | 108 | #define LOG_SELECT 0x4c |
| 108 | #define LOG_SENSE 0x4d | 109 | #define LOG_SENSE 0x4d |
| 109 | #define XDWRITEREAD_10 0x53 | 110 | #define XDWRITEREAD_10 0x53 |
