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()
  ...
This commit is contained in:
Linus Torvalds
2011-01-13 10:45:01 -08:00
53 changed files with 1329 additions and 1091 deletions

View File

@@ -1348,7 +1348,10 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
if (!CDROM_CAN(CDC_SELECT_DISC))
return -EDRIVE_CANT_DO_THIS;
(void) cdi->ops->media_changed(cdi, slot);
if (cdi->ops->check_events)
cdi->ops->check_events(cdi, 0, slot);
else
cdi->ops->media_changed(cdi, slot);
if (slot == CDSL_NONE) {
/* set media changed bits, on both queues */
@@ -1392,6 +1395,42 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
return slot;
}
/*
* As cdrom implements an extra ioctl consumer for media changed
* event, it needs to buffer ->check_events() output, such that event
* is not lost for both the usual VFS and ioctl paths.
* cdi->{vfs|ioctl}_events are used to buffer pending events for each
* path.
*
* XXX: Locking is non-existent. cdi->ops->check_events() can be
* called in parallel and buffering fields are accessed without any
* exclusion. The original media_changed code had the same problem.
* It might be better to simply deprecate CDROM_MEDIA_CHANGED ioctl
* and remove this cruft altogether. It doesn't have much usefulness
* at this point.
*/
static void cdrom_update_events(struct cdrom_device_info *cdi,
unsigned int clearing)
{
unsigned int events;
events = cdi->ops->check_events(cdi, clearing, CDSL_CURRENT);
cdi->vfs_events |= events;
cdi->ioctl_events |= events;
}
unsigned int cdrom_check_events(struct cdrom_device_info *cdi,
unsigned int clearing)
{
unsigned int events;
cdrom_update_events(cdi, clearing);
events = cdi->vfs_events;
cdi->vfs_events = 0;
return events;
}
EXPORT_SYMBOL(cdrom_check_events);
/* We want to make media_changed accessible to the user through an
* ioctl. The main problem now is that we must double-buffer the
* 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)
{
unsigned int mask = (1 << (queue & 1));
int ret = !!(cdi->mc_flags & mask);
bool changed;
if (!CDROM_CAN(CDC_MEDIA_CHANGED))
return ret;
return ret;
/* changed since last call? */
if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) {
if (cdi->ops->check_events) {
BUG_ON(!queue); /* shouldn't be called from VFS path */
cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE);
changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE;
cdi->ioctl_events = 0;
} else
changed = cdi->ops->media_changed(cdi, CDSL_CURRENT);
if (changed) {
cdi->mc_flags = 0x3; /* set bit on both queues */
ret |= 1;
cdi->media_written = 0;
}
cdi->mc_flags &= ~mask; /* clear bit */
return ret;
}