Commit ac904ae6 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.dk/linux-block

Pull block IO fixes from Jens Axboe:
 "Three small fixes that have been queued up and tested for this series:

   - A bug fix for xen-blkfront from Bob Liu, fixing an issue with
     incomplete requests during migration.

   - A fix for an ancient issue in retrieving the IO priority of a
     different PID than self, preventing that task from going away while
     we access it.  From Omar.

   - A writeback fix from Tahsin, fixing a case where we'd call ihold()
     with a zero ref count inode"

* 'for-linus' of git://git.kernel.dk/linux-block:
  block: fix use-after-free in sys_ioprio_get()
  writeback: inode cgroup wb switch should not call ihold()
  xen-blkfront: save uncompleted reqs in blkfront_resume()
parents 4c2a8499 8ba86821
...@@ -150,8 +150,10 @@ static int get_task_ioprio(struct task_struct *p) ...@@ -150,8 +150,10 @@ static int get_task_ioprio(struct task_struct *p)
if (ret) if (ret)
goto out; goto out;
ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM); ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
task_lock(p);
if (p->io_context) if (p->io_context)
ret = p->io_context->ioprio; ret = p->io_context->ioprio;
task_unlock(p);
out: out:
return ret; return ret;
} }
......
...@@ -207,6 +207,9 @@ struct blkfront_info ...@@ -207,6 +207,9 @@ struct blkfront_info
struct blk_mq_tag_set tag_set; struct blk_mq_tag_set tag_set;
struct blkfront_ring_info *rinfo; struct blkfront_ring_info *rinfo;
unsigned int nr_rings; unsigned int nr_rings;
/* Save uncomplete reqs and bios for migration. */
struct list_head requests;
struct bio_list bio_list;
}; };
static unsigned int nr_minors; static unsigned int nr_minors;
...@@ -2002,69 +2005,22 @@ static int blkif_recover(struct blkfront_info *info) ...@@ -2002,69 +2005,22 @@ static int blkif_recover(struct blkfront_info *info)
{ {
unsigned int i, r_index; unsigned int i, r_index;
struct request *req, *n; struct request *req, *n;
struct blk_shadow *copy;
int rc; int rc;
struct bio *bio, *cloned_bio; struct bio *bio, *cloned_bio;
struct bio_list bio_list, merge_bio;
unsigned int segs, offset; unsigned int segs, offset;
int pending, size; int pending, size;
struct split_bio *split_bio; struct split_bio *split_bio;
struct list_head requests;
blkfront_gather_backend_features(info); blkfront_gather_backend_features(info);
segs = info->max_indirect_segments ? : BLKIF_MAX_SEGMENTS_PER_REQUEST; segs = info->max_indirect_segments ? : BLKIF_MAX_SEGMENTS_PER_REQUEST;
blk_queue_max_segments(info->rq, segs); blk_queue_max_segments(info->rq, segs);
bio_list_init(&bio_list);
INIT_LIST_HEAD(&requests);
for (r_index = 0; r_index < info->nr_rings; r_index++) { for (r_index = 0; r_index < info->nr_rings; r_index++) {
struct blkfront_ring_info *rinfo; struct blkfront_ring_info *rinfo = &info->rinfo[r_index];
rinfo = &info->rinfo[r_index];
/* Stage 1: Make a safe copy of the shadow state. */
copy = kmemdup(rinfo->shadow, sizeof(rinfo->shadow),
GFP_NOIO | __GFP_REPEAT | __GFP_HIGH);
if (!copy)
return -ENOMEM;
/* Stage 2: Set up free list. */
memset(&rinfo->shadow, 0, sizeof(rinfo->shadow));
for (i = 0; i < BLK_RING_SIZE(info); i++)
rinfo->shadow[i].req.u.rw.id = i+1;
rinfo->shadow_free = rinfo->ring.req_prod_pvt;
rinfo->shadow[BLK_RING_SIZE(info)-1].req.u.rw.id = 0x0fffffff;
rc = blkfront_setup_indirect(rinfo); rc = blkfront_setup_indirect(rinfo);
if (rc) { if (rc)
kfree(copy);
return rc; return rc;
}
for (i = 0; i < BLK_RING_SIZE(info); i++) {
/* Not in use? */
if (!copy[i].request)
continue;
/*
* Get the bios in the request so we can re-queue them.
*/
if (copy[i].request->cmd_flags &
(REQ_FLUSH | REQ_FUA | REQ_DISCARD | REQ_SECURE)) {
/*
* Flush operations don't contain bios, so
* we need to requeue the whole request
*/
list_add(&copy[i].request->queuelist, &requests);
continue;
}
merge_bio.head = copy[i].request->bio;
merge_bio.tail = copy[i].request->biotail;
bio_list_merge(&bio_list, &merge_bio);
copy[i].request->bio = NULL;
blk_end_request_all(copy[i].request, 0);
}
kfree(copy);
} }
xenbus_switch_state(info->xbdev, XenbusStateConnected); xenbus_switch_state(info->xbdev, XenbusStateConnected);
...@@ -2079,7 +2035,7 @@ static int blkif_recover(struct blkfront_info *info) ...@@ -2079,7 +2035,7 @@ static int blkif_recover(struct blkfront_info *info)
kick_pending_request_queues(rinfo); kick_pending_request_queues(rinfo);
} }
list_for_each_entry_safe(req, n, &requests, queuelist) { list_for_each_entry_safe(req, n, &info->requests, queuelist) {
/* Requeue pending requests (flush or discard) */ /* Requeue pending requests (flush or discard) */
list_del_init(&req->queuelist); list_del_init(&req->queuelist);
BUG_ON(req->nr_phys_segments > segs); BUG_ON(req->nr_phys_segments > segs);
...@@ -2087,7 +2043,7 @@ static int blkif_recover(struct blkfront_info *info) ...@@ -2087,7 +2043,7 @@ static int blkif_recover(struct blkfront_info *info)
} }
blk_mq_kick_requeue_list(info->rq); blk_mq_kick_requeue_list(info->rq);
while ((bio = bio_list_pop(&bio_list)) != NULL) { while ((bio = bio_list_pop(&info->bio_list)) != NULL) {
/* Traverse the list of pending bios and re-queue them */ /* Traverse the list of pending bios and re-queue them */
if (bio_segments(bio) > segs) { if (bio_segments(bio) > segs) {
/* /*
...@@ -2133,9 +2089,42 @@ static int blkfront_resume(struct xenbus_device *dev) ...@@ -2133,9 +2089,42 @@ static int blkfront_resume(struct xenbus_device *dev)
{ {
struct blkfront_info *info = dev_get_drvdata(&dev->dev); struct blkfront_info *info = dev_get_drvdata(&dev->dev);
int err = 0; int err = 0;
unsigned int i, j;
dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename); dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
bio_list_init(&info->bio_list);
INIT_LIST_HEAD(&info->requests);
for (i = 0; i < info->nr_rings; i++) {
struct blkfront_ring_info *rinfo = &info->rinfo[i];
struct bio_list merge_bio;
struct blk_shadow *shadow = rinfo->shadow;
for (j = 0; j < BLK_RING_SIZE(info); j++) {
/* Not in use? */
if (!shadow[j].request)
continue;
/*
* Get the bios in the request so we can re-queue them.
*/
if (shadow[j].request->cmd_flags &
(REQ_FLUSH | REQ_FUA | REQ_DISCARD | REQ_SECURE)) {
/*
* Flush operations don't contain bios, so
* we need to requeue the whole request
*/
list_add(&shadow[j].request->queuelist, &info->requests);
continue;
}
merge_bio.head = shadow[j].request->bio;
merge_bio.tail = shadow[j].request->biotail;
bio_list_merge(&info->bio_list, &merge_bio);
shadow[j].request->bio = NULL;
blk_mq_end_request(shadow[j].request, 0);
}
}
blkif_free(info, info->connected == BLKIF_STATE_CONNECTED); blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
err = negotiate_mq(info); err = negotiate_mq(info);
......
...@@ -483,9 +483,9 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id) ...@@ -483,9 +483,9 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
goto out_free; goto out_free;
} }
inode->i_state |= I_WB_SWITCH; inode->i_state |= I_WB_SWITCH;
__iget(inode);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
ihold(inode);
isw->inode = inode; isw->inode = inode;
atomic_inc(&isw_nr_in_flight); atomic_inc(&isw_nr_in_flight);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment