aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cdrom
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 13:45:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 13:45:01 -0500
commit275220f0fcff1adf28a717076e00f575edf05fda (patch)
treed249bccc80c64443dab211639050c4fb14332648 /drivers/cdrom
parentfe3c560b8a22cb28e54fe8950abef38e88d75831 (diff)
parent81c5e2ae33c4b19e53966b427e33646bf6811830 (diff)
Merge branch 'for-2.6.38/core' of git://git.kernel.dk/linux-2.6-block
* 'for-2.6.38/core' of git://git.kernel.dk/linux-2.6-block: (43 commits) block: ensure that completion error gets properly traced blktrace: add missing probe argument to block_bio_complete block cfq: don't use atomic_t for cfq_group block cfq: don't use atomic_t for cfq_queue block: trace event block fix unassigned field block: add internal hd part table references block: fix accounting bug on cross partition merges kref: add kref_test_and_get bio-integrity: mark kintegrityd_wq highpri and CPU intensive block: make kblockd_workqueue smarter Revert "sd: implement sd_check_events()" block: Clean up exit_io_context() source code. Fix compile warnings due to missing removal of a 'ret' variable fs/block: type signature of major_to_index(int) to major_to_index(unsigned) block: convert !IS_ERR(p) && p to !IS_ERR_NOR_NULL(p) cfq-iosched: don't check cfqg in choose_service_tree() fs/splice: Pull buf->ops->confirm() from splice_from_pipe actors cdrom: export cdrom_check_events() sd: implement sd_check_events() sr: implement sr_check_events() ...
Diffstat (limited to 'drivers/cdrom')
-rw-r--r--drivers/cdrom/cdrom.c56
1 files changed, 53 insertions, 3 deletions
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index af13c62dc473..14033a36bcd0 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,42 @@ 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 */
1412static 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
1422unsigned 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}
1432EXPORT_SYMBOL(cdrom_check_events);
1433
1395/* We want to make media_changed accessible to the user through an 1434/* 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 1435 * 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 1436 * low-level implementation, to assure that the VFS and the user both
@@ -1403,15 +1442,26 @@ int media_changed(struct cdrom_device_info *cdi, int queue)
1403{ 1442{
1404 unsigned int mask = (1 << (queue & 1)); 1443 unsigned int mask = (1 << (queue & 1));
1405 int ret = !!(cdi->mc_flags & mask); 1444 int ret = !!(cdi->mc_flags & mask);
1445 bool changed;
1406 1446
1407 if (!CDROM_CAN(CDC_MEDIA_CHANGED)) 1447 if (!CDROM_CAN(CDC_MEDIA_CHANGED))
1408 return ret; 1448 return ret;
1449
1409 /* changed since last call? */ 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 cdi->mc_flags = 0x3; /* set bit on both queues */ 1460 cdi->mc_flags = 0x3; /* set bit on both queues */
1412 ret |= 1; 1461 ret |= 1;
1413 cdi->media_written = 0; 1462 cdi->media_written = 0;
1414 } 1463 }
1464
1415 cdi->mc_flags &= ~mask; /* clear bit */ 1465 cdi->mc_flags &= ~mask; /* clear bit */
1416 return ret; 1466 return ret;
1417} 1467}