Merge branch 'for-linus' of git://git.kernel.dk/linux-block
Pull block fixes from Jens Axboe: "Here's a set of block fixes for the current 4.8-rc release. This contains: - a fix for a secure erase regression, from Adrian. - a fix for an mmc use-after-free bug regression, also from Adrian. - potential zero pointer deference in bdev freezing, from Andrey. - a race fix for blk_set_queue_dying() from Bart. - a set of xen blkfront fixes from Bob Liu. - three small fixes for bcache, from Eric and Kent. - a fix for a potential invalid NVMe state transition, from Gabriel. - blk-mq CPU offline fix, preventing us from issuing and completing a request on the wrong queue. From me. - revert two previous floppy changes, since they caused a user visibile regression. A better fix is in the works. - ensure that we don't send down bios that have more than 256 elements in them. Fixes a crash with bcache, for example. From Ming. - a fix for deferencing an error pointer with cgroup writeback. Fixes a regression. From Vegard" * 'for-linus' of git://git.kernel.dk/linux-block: mmc: fix use-after-free of struct request Revert "floppy: refactor open() flags handling" Revert "floppy: fix open(O_ACCMODE) for ioctl-only open" fs/block_dev: fix potential NULL ptr deref in freeze_bdev() blk-mq: improve warning for running a queue on the wrong CPU blk-mq: don't overwrite rq->mq_ctx block: make sure a big bio is split into at most 256 bvecs nvme: Fix nvme_get/set_features() with a NULL result pointer bdev: fix NULL pointer dereference xen-blkfront: free resources if xlvbd_alloc_gendisk fails xen-blkfront: introduce blkif_set_queue_limits() xen-blkfront: fix places not updated after introducing 64KB page granularity bcache: pr_err: more meaningful error message when nr_stripes is invalid bcache: RESERVE_PRIO is too small by one when prio_buckets() is a power of two. bcache: register_bcache(): call blkdev_put() when cache_alloc() fails block: Fix race triggered by blk_set_queue_dying() block: Fix secure erase nvme: Prevent controller state invalid transition
This commit is contained in:
Коммит
fd1ae51452
21
block/bio.c
21
block/bio.c
|
@ -667,18 +667,19 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask,
|
|||
bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector;
|
||||
bio->bi_iter.bi_size = bio_src->bi_iter.bi_size;
|
||||
|
||||
if (bio_op(bio) == REQ_OP_DISCARD)
|
||||
goto integrity_clone;
|
||||
|
||||
if (bio_op(bio) == REQ_OP_WRITE_SAME) {
|
||||
switch (bio_op(bio)) {
|
||||
case REQ_OP_DISCARD:
|
||||
case REQ_OP_SECURE_ERASE:
|
||||
break;
|
||||
case REQ_OP_WRITE_SAME:
|
||||
bio->bi_io_vec[bio->bi_vcnt++] = bio_src->bi_io_vec[0];
|
||||
goto integrity_clone;
|
||||
break;
|
||||
default:
|
||||
bio_for_each_segment(bv, bio_src, iter)
|
||||
bio->bi_io_vec[bio->bi_vcnt++] = bv;
|
||||
break;
|
||||
}
|
||||
|
||||
bio_for_each_segment(bv, bio_src, iter)
|
||||
bio->bi_io_vec[bio->bi_vcnt++] = bv;
|
||||
|
||||
integrity_clone:
|
||||
if (bio_integrity(bio_src)) {
|
||||
int ret;
|
||||
|
||||
|
@ -1788,7 +1789,7 @@ struct bio *bio_split(struct bio *bio, int sectors,
|
|||
* Discards need a mutable bio_vec to accommodate the payload
|
||||
* required by the DSM TRIM and UNMAP commands.
|
||||
*/
|
||||
if (bio_op(bio) == REQ_OP_DISCARD)
|
||||
if (bio_op(bio) == REQ_OP_DISCARD || bio_op(bio) == REQ_OP_SECURE_ERASE)
|
||||
split = bio_clone_bioset(bio, gfp, bs);
|
||||
else
|
||||
split = bio_clone_fast(bio, gfp, bs);
|
||||
|
|
|
@ -515,7 +515,9 @@ EXPORT_SYMBOL_GPL(blk_queue_bypass_end);
|
|||
|
||||
void blk_set_queue_dying(struct request_queue *q)
|
||||
{
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DYING, q);
|
||||
spin_lock_irq(q->queue_lock);
|
||||
queue_flag_set(QUEUE_FLAG_DYING, q);
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
|
||||
if (q->mq_ops)
|
||||
blk_mq_wake_waiters(q);
|
||||
|
|
|
@ -94,8 +94,30 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
|
|||
bool do_split = true;
|
||||
struct bio *new = NULL;
|
||||
const unsigned max_sectors = get_max_io_size(q, bio);
|
||||
unsigned bvecs = 0;
|
||||
|
||||
bio_for_each_segment(bv, bio, iter) {
|
||||
/*
|
||||
* With arbitrary bio size, the incoming bio may be very
|
||||
* big. We have to split the bio into small bios so that
|
||||
* each holds at most BIO_MAX_PAGES bvecs because
|
||||
* bio_clone() can fail to allocate big bvecs.
|
||||
*
|
||||
* It should have been better to apply the limit per
|
||||
* request queue in which bio_clone() is involved,
|
||||
* instead of globally. The biggest blocker is the
|
||||
* bio_clone() in bio bounce.
|
||||
*
|
||||
* If bio is splitted by this reason, we should have
|
||||
* allowed to continue bios merging, but don't do
|
||||
* that now for making the change simple.
|
||||
*
|
||||
* TODO: deal with bio bounce's bio_clone() gracefully
|
||||
* and convert the global limit into per-queue limit.
|
||||
*/
|
||||
if (bvecs++ >= BIO_MAX_PAGES)
|
||||
goto split;
|
||||
|
||||
/*
|
||||
* If the queue doesn't support SG gaps and adding this
|
||||
* offset would create a gap, disallow it.
|
||||
|
@ -172,12 +194,18 @@ void blk_queue_split(struct request_queue *q, struct bio **bio,
|
|||
struct bio *split, *res;
|
||||
unsigned nsegs;
|
||||
|
||||
if (bio_op(*bio) == REQ_OP_DISCARD)
|
||||
switch (bio_op(*bio)) {
|
||||
case REQ_OP_DISCARD:
|
||||
case REQ_OP_SECURE_ERASE:
|
||||
split = blk_bio_discard_split(q, *bio, bs, &nsegs);
|
||||
else if (bio_op(*bio) == REQ_OP_WRITE_SAME)
|
||||
break;
|
||||
case REQ_OP_WRITE_SAME:
|
||||
split = blk_bio_write_same_split(q, *bio, bs, &nsegs);
|
||||
else
|
||||
break;
|
||||
default:
|
||||
split = blk_bio_segment_split(q, *bio, q->bio_split, &nsegs);
|
||||
break;
|
||||
}
|
||||
|
||||
/* physical segments can be figured out during splitting */
|
||||
res = split ? split : *bio;
|
||||
|
@ -213,7 +241,7 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q,
|
|||
* This should probably be returning 0, but blk_add_request_payload()
|
||||
* (Christoph!!!!)
|
||||
*/
|
||||
if (bio_op(bio) == REQ_OP_DISCARD)
|
||||
if (bio_op(bio) == REQ_OP_DISCARD || bio_op(bio) == REQ_OP_SECURE_ERASE)
|
||||
return 1;
|
||||
|
||||
if (bio_op(bio) == REQ_OP_WRITE_SAME)
|
||||
|
@ -385,7 +413,9 @@ static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio,
|
|||
nsegs = 0;
|
||||
cluster = blk_queue_cluster(q);
|
||||
|
||||
if (bio_op(bio) == REQ_OP_DISCARD) {
|
||||
switch (bio_op(bio)) {
|
||||
case REQ_OP_DISCARD:
|
||||
case REQ_OP_SECURE_ERASE:
|
||||
/*
|
||||
* This is a hack - drivers should be neither modifying the
|
||||
* biovec, nor relying on bi_vcnt - but because of
|
||||
|
@ -393,19 +423,16 @@ static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio,
|
|||
* a payload we need to set up here (thank you Christoph) and
|
||||
* bi_vcnt is really the only way of telling if we need to.
|
||||
*/
|
||||
|
||||
if (bio->bi_vcnt)
|
||||
goto single_segment;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bio_op(bio) == REQ_OP_WRITE_SAME) {
|
||||
single_segment:
|
||||
if (!bio->bi_vcnt)
|
||||
return 0;
|
||||
/* Fall through */
|
||||
case REQ_OP_WRITE_SAME:
|
||||
*sg = sglist;
|
||||
bvec = bio_iovec(bio);
|
||||
sg_set_page(*sg, bvec.bv_page, bvec.bv_len, bvec.bv_offset);
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for_each_bio(bio)
|
||||
|
|
|
@ -793,11 +793,12 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
|
|||
struct list_head *dptr;
|
||||
int queued;
|
||||
|
||||
WARN_ON(!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask));
|
||||
|
||||
if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state)))
|
||||
return;
|
||||
|
||||
WARN_ON(!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask) &&
|
||||
cpu_online(hctx->next_cpu));
|
||||
|
||||
hctx->run++;
|
||||
|
||||
/*
|
||||
|
@ -1036,10 +1037,11 @@ void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs)
|
|||
EXPORT_SYMBOL(blk_mq_delay_queue);
|
||||
|
||||
static inline void __blk_mq_insert_req_list(struct blk_mq_hw_ctx *hctx,
|
||||
struct blk_mq_ctx *ctx,
|
||||
struct request *rq,
|
||||
bool at_head)
|
||||
{
|
||||
struct blk_mq_ctx *ctx = rq->mq_ctx;
|
||||
|
||||
trace_block_rq_insert(hctx->queue, rq);
|
||||
|
||||
if (at_head)
|
||||
|
@ -1053,20 +1055,16 @@ static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
|
|||
{
|
||||
struct blk_mq_ctx *ctx = rq->mq_ctx;
|
||||
|
||||
__blk_mq_insert_req_list(hctx, ctx, rq, at_head);
|
||||
__blk_mq_insert_req_list(hctx, rq, at_head);
|
||||
blk_mq_hctx_mark_pending(hctx, ctx);
|
||||
}
|
||||
|
||||
void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
|
||||
bool async)
|
||||
bool async)
|
||||
{
|
||||
struct blk_mq_ctx *ctx = rq->mq_ctx;
|
||||
struct request_queue *q = rq->q;
|
||||
struct blk_mq_hw_ctx *hctx;
|
||||
struct blk_mq_ctx *ctx = rq->mq_ctx, *current_ctx;
|
||||
|
||||
current_ctx = blk_mq_get_ctx(q);
|
||||
if (!cpu_online(ctx->cpu))
|
||||
rq->mq_ctx = ctx = current_ctx;
|
||||
|
||||
hctx = q->mq_ops->map_queue(q, ctx->cpu);
|
||||
|
||||
|
@ -1076,8 +1074,6 @@ void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
|
|||
|
||||
if (run_queue)
|
||||
blk_mq_run_hw_queue(hctx, async);
|
||||
|
||||
blk_mq_put_ctx(current_ctx);
|
||||
}
|
||||
|
||||
static void blk_mq_insert_requests(struct request_queue *q,
|
||||
|
@ -1088,14 +1084,9 @@ static void blk_mq_insert_requests(struct request_queue *q,
|
|||
|
||||
{
|
||||
struct blk_mq_hw_ctx *hctx;
|
||||
struct blk_mq_ctx *current_ctx;
|
||||
|
||||
trace_block_unplug(q, depth, !from_schedule);
|
||||
|
||||
current_ctx = blk_mq_get_ctx(q);
|
||||
|
||||
if (!cpu_online(ctx->cpu))
|
||||
ctx = current_ctx;
|
||||
hctx = q->mq_ops->map_queue(q, ctx->cpu);
|
||||
|
||||
/*
|
||||
|
@ -1107,15 +1098,14 @@ static void blk_mq_insert_requests(struct request_queue *q,
|
|||
struct request *rq;
|
||||
|
||||
rq = list_first_entry(list, struct request, queuelist);
|
||||
BUG_ON(rq->mq_ctx != ctx);
|
||||
list_del_init(&rq->queuelist);
|
||||
rq->mq_ctx = ctx;
|
||||
__blk_mq_insert_req_list(hctx, ctx, rq, false);
|
||||
__blk_mq_insert_req_list(hctx, rq, false);
|
||||
}
|
||||
blk_mq_hctx_mark_pending(hctx, ctx);
|
||||
spin_unlock(&ctx->lock);
|
||||
|
||||
blk_mq_run_hw_queue(hctx, from_schedule);
|
||||
blk_mq_put_ctx(current_ctx);
|
||||
}
|
||||
|
||||
static int plug_ctx_cmp(void *priv, struct list_head *a, struct list_head *b)
|
||||
|
@ -1630,16 +1620,17 @@ static int blk_mq_alloc_bitmap(struct blk_mq_ctxmap *bitmap, int node)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'cpu' is going away. splice any existing rq_list entries from this
|
||||
* software queue to the hw queue dispatch list, and ensure that it
|
||||
* gets run.
|
||||
*/
|
||||
static int blk_mq_hctx_cpu_offline(struct blk_mq_hw_ctx *hctx, int cpu)
|
||||
{
|
||||
struct request_queue *q = hctx->queue;
|
||||
struct blk_mq_ctx *ctx;
|
||||
LIST_HEAD(tmp);
|
||||
|
||||
/*
|
||||
* Move ctx entries to new CPU, if this one is going away.
|
||||
*/
|
||||
ctx = __blk_mq_get_ctx(q, cpu);
|
||||
ctx = __blk_mq_get_ctx(hctx->queue, cpu);
|
||||
|
||||
spin_lock(&ctx->lock);
|
||||
if (!list_empty(&ctx->rq_list)) {
|
||||
|
@ -1651,24 +1642,11 @@ static int blk_mq_hctx_cpu_offline(struct blk_mq_hw_ctx *hctx, int cpu)
|
|||
if (list_empty(&tmp))
|
||||
return NOTIFY_OK;
|
||||
|
||||
ctx = blk_mq_get_ctx(q);
|
||||
spin_lock(&ctx->lock);
|
||||
|
||||
while (!list_empty(&tmp)) {
|
||||
struct request *rq;
|
||||
|
||||
rq = list_first_entry(&tmp, struct request, queuelist);
|
||||
rq->mq_ctx = ctx;
|
||||
list_move_tail(&rq->queuelist, &ctx->rq_list);
|
||||
}
|
||||
|
||||
hctx = q->mq_ops->map_queue(q, ctx->cpu);
|
||||
blk_mq_hctx_mark_pending(hctx, ctx);
|
||||
|
||||
spin_unlock(&ctx->lock);
|
||||
spin_lock(&hctx->lock);
|
||||
list_splice_tail_init(&tmp, &hctx->dispatch);
|
||||
spin_unlock(&hctx->lock);
|
||||
|
||||
blk_mq_run_hw_queue(hctx, true);
|
||||
blk_mq_put_ctx(ctx);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -366,7 +366,7 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
|
|||
list_for_each_prev(entry, &q->queue_head) {
|
||||
struct request *pos = list_entry_rq(entry);
|
||||
|
||||
if ((req_op(rq) == REQ_OP_DISCARD) != (req_op(pos) == REQ_OP_DISCARD))
|
||||
if (req_op(rq) != req_op(pos))
|
||||
break;
|
||||
if (rq_data_dir(rq) != rq_data_dir(pos))
|
||||
break;
|
||||
|
|
|
@ -3706,22 +3706,21 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
|
|||
if (UFDCS->rawcmd == 1)
|
||||
UFDCS->rawcmd = 2;
|
||||
|
||||
if (mode & (FMODE_READ|FMODE_WRITE)) {
|
||||
UDRS->last_checked = 0;
|
||||
clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
|
||||
check_disk_change(bdev);
|
||||
if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
|
||||
goto out;
|
||||
if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
|
||||
if (!(mode & FMODE_NDELAY)) {
|
||||
if (mode & (FMODE_READ|FMODE_WRITE)) {
|
||||
UDRS->last_checked = 0;
|
||||
clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
|
||||
check_disk_change(bdev);
|
||||
if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
|
||||
goto out;
|
||||
if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
|
||||
goto out;
|
||||
}
|
||||
res = -EROFS;
|
||||
if ((mode & FMODE_WRITE) &&
|
||||
!test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = -EROFS;
|
||||
|
||||
if ((mode & FMODE_WRITE) &&
|
||||
!test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
|
||||
goto out;
|
||||
|
||||
mutex_unlock(&open_lock);
|
||||
mutex_unlock(&floppy_mutex);
|
||||
return 0;
|
||||
|
|
|
@ -189,6 +189,8 @@ struct blkfront_info
|
|||
struct mutex mutex;
|
||||
struct xenbus_device *xbdev;
|
||||
struct gendisk *gd;
|
||||
u16 sector_size;
|
||||
unsigned int physical_sector_size;
|
||||
int vdevice;
|
||||
blkif_vdev_t handle;
|
||||
enum blkif_state connected;
|
||||
|
@ -910,9 +912,45 @@ static struct blk_mq_ops blkfront_mq_ops = {
|
|||
.map_queue = blk_mq_map_queue,
|
||||
};
|
||||
|
||||
static void blkif_set_queue_limits(struct blkfront_info *info)
|
||||
{
|
||||
struct request_queue *rq = info->rq;
|
||||
struct gendisk *gd = info->gd;
|
||||
unsigned int segments = info->max_indirect_segments ? :
|
||||
BLKIF_MAX_SEGMENTS_PER_REQUEST;
|
||||
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_VIRT, rq);
|
||||
|
||||
if (info->feature_discard) {
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, rq);
|
||||
blk_queue_max_discard_sectors(rq, get_capacity(gd));
|
||||
rq->limits.discard_granularity = info->discard_granularity;
|
||||
rq->limits.discard_alignment = info->discard_alignment;
|
||||
if (info->feature_secdiscard)
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, rq);
|
||||
}
|
||||
|
||||
/* Hard sector size and max sectors impersonate the equiv. hardware. */
|
||||
blk_queue_logical_block_size(rq, info->sector_size);
|
||||
blk_queue_physical_block_size(rq, info->physical_sector_size);
|
||||
blk_queue_max_hw_sectors(rq, (segments * XEN_PAGE_SIZE) / 512);
|
||||
|
||||
/* Each segment in a request is up to an aligned page in size. */
|
||||
blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
|
||||
blk_queue_max_segment_size(rq, PAGE_SIZE);
|
||||
|
||||
/* Ensure a merged request will fit in a single I/O ring slot. */
|
||||
blk_queue_max_segments(rq, segments / GRANTS_PER_PSEG);
|
||||
|
||||
/* Make sure buffer addresses are sector-aligned. */
|
||||
blk_queue_dma_alignment(rq, 511);
|
||||
|
||||
/* Make sure we don't use bounce buffers. */
|
||||
blk_queue_bounce_limit(rq, BLK_BOUNCE_ANY);
|
||||
}
|
||||
|
||||
static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size,
|
||||
unsigned int physical_sector_size,
|
||||
unsigned int segments)
|
||||
unsigned int physical_sector_size)
|
||||
{
|
||||
struct request_queue *rq;
|
||||
struct blkfront_info *info = gd->private_data;
|
||||
|
@ -944,36 +982,11 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size,
|
|||
}
|
||||
|
||||
rq->queuedata = info;
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_VIRT, rq);
|
||||
|
||||
if (info->feature_discard) {
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, rq);
|
||||
blk_queue_max_discard_sectors(rq, get_capacity(gd));
|
||||
rq->limits.discard_granularity = info->discard_granularity;
|
||||
rq->limits.discard_alignment = info->discard_alignment;
|
||||
if (info->feature_secdiscard)
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, rq);
|
||||
}
|
||||
|
||||
/* Hard sector size and max sectors impersonate the equiv. hardware. */
|
||||
blk_queue_logical_block_size(rq, sector_size);
|
||||
blk_queue_physical_block_size(rq, physical_sector_size);
|
||||
blk_queue_max_hw_sectors(rq, (segments * XEN_PAGE_SIZE) / 512);
|
||||
|
||||
/* Each segment in a request is up to an aligned page in size. */
|
||||
blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
|
||||
blk_queue_max_segment_size(rq, PAGE_SIZE);
|
||||
|
||||
/* Ensure a merged request will fit in a single I/O ring slot. */
|
||||
blk_queue_max_segments(rq, segments / GRANTS_PER_PSEG);
|
||||
|
||||
/* Make sure buffer addresses are sector-aligned. */
|
||||
blk_queue_dma_alignment(rq, 511);
|
||||
|
||||
/* Make sure we don't use bounce buffers. */
|
||||
blk_queue_bounce_limit(rq, BLK_BOUNCE_ANY);
|
||||
|
||||
gd->queue = rq;
|
||||
info->rq = gd->queue = rq;
|
||||
info->gd = gd;
|
||||
info->sector_size = sector_size;
|
||||
info->physical_sector_size = physical_sector_size;
|
||||
blkif_set_queue_limits(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1136,16 +1149,11 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
|
|||
gd->private_data = info;
|
||||
set_capacity(gd, capacity);
|
||||
|
||||
if (xlvbd_init_blk_queue(gd, sector_size, physical_sector_size,
|
||||
info->max_indirect_segments ? :
|
||||
BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
|
||||
if (xlvbd_init_blk_queue(gd, sector_size, physical_sector_size)) {
|
||||
del_gendisk(gd);
|
||||
goto release;
|
||||
}
|
||||
|
||||
info->rq = gd->queue;
|
||||
info->gd = gd;
|
||||
|
||||
xlvbd_flush(info);
|
||||
|
||||
if (vdisk_info & VDISK_READONLY)
|
||||
|
@ -1315,7 +1323,7 @@ free_shadow:
|
|||
rinfo->ring_ref[i] = GRANT_INVALID_REF;
|
||||
}
|
||||
}
|
||||
free_pages((unsigned long)rinfo->ring.sring, get_order(info->nr_ring_pages * PAGE_SIZE));
|
||||
free_pages((unsigned long)rinfo->ring.sring, get_order(info->nr_ring_pages * XEN_PAGE_SIZE));
|
||||
rinfo->ring.sring = NULL;
|
||||
|
||||
if (rinfo->irq)
|
||||
|
@ -2007,8 +2015,10 @@ static int blkif_recover(struct blkfront_info *info)
|
|||
struct split_bio *split_bio;
|
||||
|
||||
blkfront_gather_backend_features(info);
|
||||
/* Reset limits changed by blk_mq_update_nr_hw_queues(). */
|
||||
blkif_set_queue_limits(info);
|
||||
segs = info->max_indirect_segments ? : BLKIF_MAX_SEGMENTS_PER_REQUEST;
|
||||
blk_queue_max_segments(info->rq, segs);
|
||||
blk_queue_max_segments(info->rq, segs / GRANTS_PER_PSEG);
|
||||
|
||||
for (r_index = 0; r_index < info->nr_rings; r_index++) {
|
||||
struct blkfront_ring_info *rinfo = &info->rinfo[r_index];
|
||||
|
@ -2432,7 +2442,7 @@ static void blkfront_connect(struct blkfront_info *info)
|
|||
if (err) {
|
||||
xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
|
||||
info->xbdev->otherend);
|
||||
return;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
xenbus_switch_state(info->xbdev, XenbusStateConnected);
|
||||
|
@ -2445,6 +2455,11 @@ static void blkfront_connect(struct blkfront_info *info)
|
|||
device_add_disk(&info->xbdev->dev, info->gd);
|
||||
|
||||
info->is_ready = 1;
|
||||
return;
|
||||
|
||||
fail:
|
||||
blkif_free(info, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -760,7 +760,8 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size,
|
|||
if (!d->nr_stripes ||
|
||||
d->nr_stripes > INT_MAX ||
|
||||
d->nr_stripes > SIZE_MAX / sizeof(atomic_t)) {
|
||||
pr_err("nr_stripes too large");
|
||||
pr_err("nr_stripes too large or invalid: %u (start sector beyond end of disk?)",
|
||||
(unsigned)d->nr_stripes);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -1820,7 +1821,7 @@ static int cache_alloc(struct cache *ca)
|
|||
free = roundup_pow_of_two(ca->sb.nbuckets) >> 10;
|
||||
|
||||
if (!init_fifo(&ca->free[RESERVE_BTREE], 8, GFP_KERNEL) ||
|
||||
!init_fifo(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) ||
|
||||
!init_fifo_exact(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) ||
|
||||
!init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL) ||
|
||||
!init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) ||
|
||||
!init_fifo(&ca->free_inc, free << 2, GFP_KERNEL) ||
|
||||
|
@ -1844,7 +1845,7 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page,
|
|||
struct block_device *bdev, struct cache *ca)
|
||||
{
|
||||
char name[BDEVNAME_SIZE];
|
||||
const char *err = NULL;
|
||||
const char *err = NULL; /* must be set for any error case */
|
||||
int ret = 0;
|
||||
|
||||
memcpy(&ca->sb, sb, sizeof(struct cache_sb));
|
||||
|
@ -1861,8 +1862,13 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page,
|
|||
ca->discard = CACHE_DISCARD(&ca->sb);
|
||||
|
||||
ret = cache_alloc(ca);
|
||||
if (ret != 0)
|
||||
if (ret != 0) {
|
||||
if (ret == -ENOMEM)
|
||||
err = "cache_alloc(): -ENOMEM";
|
||||
else
|
||||
err = "cache_alloc(): unknown error";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache")) {
|
||||
err = "error calling kobject_add";
|
||||
|
|
|
@ -1726,6 +1726,7 @@ static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
|
|||
break;
|
||||
|
||||
if (req_op(next) == REQ_OP_DISCARD ||
|
||||
req_op(next) == REQ_OP_SECURE_ERASE ||
|
||||
req_op(next) == REQ_OP_FLUSH)
|
||||
break;
|
||||
|
||||
|
@ -2150,6 +2151,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|||
struct mmc_card *card = md->queue.card;
|
||||
struct mmc_host *host = card->host;
|
||||
unsigned long flags;
|
||||
bool req_is_special = mmc_req_is_special(req);
|
||||
|
||||
if (req && !mq->mqrq_prev->req)
|
||||
/* claim host only for the first request */
|
||||
|
@ -2190,8 +2192,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
|
|||
}
|
||||
|
||||
out:
|
||||
if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) ||
|
||||
mmc_req_is_special(req))
|
||||
if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) || req_is_special)
|
||||
/*
|
||||
* Release host when there are no more requests
|
||||
* and after special request(discard, flush) is done.
|
||||
|
|
|
@ -33,7 +33,8 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
|
|||
/*
|
||||
* We only like normal block requests and discards.
|
||||
*/
|
||||
if (req->cmd_type != REQ_TYPE_FS && req_op(req) != REQ_OP_DISCARD) {
|
||||
if (req->cmd_type != REQ_TYPE_FS && req_op(req) != REQ_OP_DISCARD &&
|
||||
req_op(req) != REQ_OP_SECURE_ERASE) {
|
||||
blk_dump_rq_flags(req, "MMC bad request");
|
||||
return BLKPREP_KILL;
|
||||
}
|
||||
|
@ -64,6 +65,8 @@ static int mmc_queue_thread(void *d)
|
|||
spin_unlock_irq(q->queue_lock);
|
||||
|
||||
if (req || mq->mqrq_prev->req) {
|
||||
bool req_is_special = mmc_req_is_special(req);
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
mq->issue_fn(mq, req);
|
||||
cond_resched();
|
||||
|
@ -79,7 +82,7 @@ static int mmc_queue_thread(void *d)
|
|||
* has been finished. Do not assign it to previous
|
||||
* request.
|
||||
*/
|
||||
if (mmc_req_is_special(req))
|
||||
if (req_is_special)
|
||||
mq->mqrq_cur->req = NULL;
|
||||
|
||||
mq->mqrq_prev->brq.mrq.data = NULL;
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
static inline bool mmc_req_is_special(struct request *req)
|
||||
{
|
||||
return req &&
|
||||
(req_op(req) == REQ_OP_FLUSH || req_op(req) == REQ_OP_DISCARD);
|
||||
(req_op(req) == REQ_OP_FLUSH ||
|
||||
req_op(req) == REQ_OP_DISCARD ||
|
||||
req_op(req) == REQ_OP_SECURE_ERASE);
|
||||
}
|
||||
|
||||
struct request;
|
||||
|
|
|
@ -81,10 +81,12 @@ EXPORT_SYMBOL_GPL(nvme_cancel_request);
|
|||
bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
|
||||
enum nvme_ctrl_state new_state)
|
||||
{
|
||||
enum nvme_ctrl_state old_state = ctrl->state;
|
||||
enum nvme_ctrl_state old_state;
|
||||
bool changed = false;
|
||||
|
||||
spin_lock_irq(&ctrl->lock);
|
||||
|
||||
old_state = ctrl->state;
|
||||
switch (new_state) {
|
||||
case NVME_CTRL_LIVE:
|
||||
switch (old_state) {
|
||||
|
@ -140,11 +142,12 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
spin_unlock_irq(&ctrl->lock);
|
||||
|
||||
if (changed)
|
||||
ctrl->state = new_state;
|
||||
|
||||
spin_unlock_irq(&ctrl->lock);
|
||||
|
||||
return changed;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nvme_change_ctrl_state);
|
||||
|
@ -608,7 +611,7 @@ int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
|
|||
|
||||
ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe, NULL, 0, 0,
|
||||
NVME_QID_ANY, 0, 0);
|
||||
if (ret >= 0)
|
||||
if (ret >= 0 && result)
|
||||
*result = le32_to_cpu(cqe.result);
|
||||
return ret;
|
||||
}
|
||||
|
@ -628,7 +631,7 @@ int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
|
|||
|
||||
ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe, NULL, 0, 0,
|
||||
NVME_QID_ANY, 0, 0);
|
||||
if (ret >= 0)
|
||||
if (ret >= 0 && result)
|
||||
*result = le32_to_cpu(cqe.result);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -249,7 +249,8 @@ struct super_block *freeze_bdev(struct block_device *bdev)
|
|||
* thaw_bdev drops it.
|
||||
*/
|
||||
sb = get_super(bdev);
|
||||
drop_super(sb);
|
||||
if (sb)
|
||||
drop_super(sb);
|
||||
mutex_unlock(&bdev->bd_fsfreeze_mutex);
|
||||
return sb;
|
||||
}
|
||||
|
@ -646,7 +647,7 @@ static struct dentry *bd_mount(struct file_system_type *fs_type,
|
|||
{
|
||||
struct dentry *dent;
|
||||
dent = mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, BDEVFS_MAGIC);
|
||||
if (dent)
|
||||
if (!IS_ERR(dent))
|
||||
dent->d_sb->s_iflags |= SB_I_CGROUPWB;
|
||||
return dent;
|
||||
}
|
||||
|
|
|
@ -71,7 +71,8 @@ static inline bool bio_has_data(struct bio *bio)
|
|||
{
|
||||
if (bio &&
|
||||
bio->bi_iter.bi_size &&
|
||||
bio_op(bio) != REQ_OP_DISCARD)
|
||||
bio_op(bio) != REQ_OP_DISCARD &&
|
||||
bio_op(bio) != REQ_OP_SECURE_ERASE)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -79,7 +80,9 @@ static inline bool bio_has_data(struct bio *bio)
|
|||
|
||||
static inline bool bio_no_advance_iter(struct bio *bio)
|
||||
{
|
||||
return bio_op(bio) == REQ_OP_DISCARD || bio_op(bio) == REQ_OP_WRITE_SAME;
|
||||
return bio_op(bio) == REQ_OP_DISCARD ||
|
||||
bio_op(bio) == REQ_OP_SECURE_ERASE ||
|
||||
bio_op(bio) == REQ_OP_WRITE_SAME;
|
||||
}
|
||||
|
||||
static inline bool bio_is_rw(struct bio *bio)
|
||||
|
@ -199,6 +202,9 @@ static inline unsigned bio_segments(struct bio *bio)
|
|||
if (bio_op(bio) == REQ_OP_DISCARD)
|
||||
return 1;
|
||||
|
||||
if (bio_op(bio) == REQ_OP_SECURE_ERASE)
|
||||
return 1;
|
||||
|
||||
if (bio_op(bio) == REQ_OP_WRITE_SAME)
|
||||
return 1;
|
||||
|
||||
|
|
|
@ -882,7 +882,7 @@ static inline unsigned int blk_rq_cur_sectors(const struct request *rq)
|
|||
static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q,
|
||||
int op)
|
||||
{
|
||||
if (unlikely(op == REQ_OP_DISCARD))
|
||||
if (unlikely(op == REQ_OP_DISCARD || op == REQ_OP_SECURE_ERASE))
|
||||
return min(q->limits.max_discard_sectors, UINT_MAX >> 9);
|
||||
|
||||
if (unlikely(op == REQ_OP_WRITE_SAME))
|
||||
|
@ -913,7 +913,9 @@ static inline unsigned int blk_rq_get_max_sectors(struct request *rq,
|
|||
if (unlikely(rq->cmd_type != REQ_TYPE_FS))
|
||||
return q->limits.max_hw_sectors;
|
||||
|
||||
if (!q->limits.chunk_sectors || (req_op(rq) == REQ_OP_DISCARD))
|
||||
if (!q->limits.chunk_sectors ||
|
||||
req_op(rq) == REQ_OP_DISCARD ||
|
||||
req_op(rq) == REQ_OP_SECURE_ERASE)
|
||||
return blk_queue_get_max_sectors(q, req_op(rq));
|
||||
|
||||
return min(blk_max_size_offset(q, offset),
|
||||
|
|
|
@ -223,7 +223,7 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
|
|||
what |= MASK_TC_BIT(op_flags, META);
|
||||
what |= MASK_TC_BIT(op_flags, PREFLUSH);
|
||||
what |= MASK_TC_BIT(op_flags, FUA);
|
||||
if (op == REQ_OP_DISCARD)
|
||||
if (op == REQ_OP_DISCARD || op == REQ_OP_SECURE_ERASE)
|
||||
what |= BLK_TC_ACT(BLK_TC_DISCARD);
|
||||
if (op == REQ_OP_FLUSH)
|
||||
what |= BLK_TC_ACT(BLK_TC_FLUSH);
|
||||
|
|
Загрузка…
Ссылка в новой задаче