static void blkfront_closing(struct xenbus_device *dev)
{
struct blkfront_info *info = dev->data;
+ unsigned long flags;
DPRINTK("blkfront_closing: %s removed\n", dev->nodename);
+ if (info->rq == NULL)
+ return;
+
+ spin_lock_irqsave(&blkif_io_lock, flags);
+ /* No more blkif_request(). */
+ blk_stop_queue(info->rq);
+ /* No more gnttab callback work. */
+ gnttab_cancel_free_callback(&info->callback);
+ flush_scheduled_work();
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
xlvbd_del(info);
xenbus_switch_state(dev, XenbusStateClosed);
spin_lock_irq(&blkif_io_lock);
info->connected = suspend ?
BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED;
- blk_stop_queue(info->rq); /* no more blkif_request() */
+ /* No more blkif_request(). */
+ if (info->rq)
+ blk_stop_queue(info->rq);
+ /* No more gnttab callback work. */
+ gnttab_cancel_free_callback(&info->callback);
+ flush_scheduled_work();
spin_unlock_irq(&blkif_io_lock);
/* Free resources associated with old device channel. */
spin_unlock_irqrestore(&gnttab_list_lock, flags);
}
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
+{
+ struct gnttab_free_callback **pcb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
+ if (*pcb == callback) {
+ *pcb = callback->next;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+
#ifndef __ia64__
static int map_pte_fn(pte_t *pte, struct page *pmd_page,
unsigned long addr, void *data)
void gnttab_request_free_callback(struct gnttab_free_callback *callback,
void (*fn)(void *), void *arg, u16 count);
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback);
void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
unsigned long frame, int readonly);