Merge branch 'for-linus' of git://git.kernel.dk/linux-block
Pull block fixes from Jens Axboe: "Here's the second round of block updates for this merge window. It's a mix of fixes for changes that went in previously in this round, and fixes in general. This pull request contains: - Fixes for loop from Christoph - A bdi vs gendisk lifetime fix from Dan, worth two cookies. - A blk-mq timeout fix, when on frozen queues. From Gabriel. - Writeback fix from Jan, ensuring that __writeback_single_inode() does the right thing. - Fix for bio->bi_rw usage in f2fs from me. - Error path deadlock fix in blk-mq sysfs registration from me. - Floppy O_ACCMODE fix from Jiri. - Fix to the new bio op methods from Mike. One more followup will be coming here, ensuring that we don't propagate the block types outside of block. That, and a rename of bio->bi_rw is coming right after -rc1 is cut. - Various little fixes" * 'for-linus' of git://git.kernel.dk/linux-block: mm/block: convert rw_page users to bio op use loop: make do_req_filebacked more robust loop: don't try to use AIO for discards blk-mq: fix deadlock in blk_mq_register_disk() error path Include: blkdev: Removed duplicate 'struct request;' declaration. Fixup direct bi_rw modifiers block: fix bdi vs gendisk lifetime mismatch blk-mq: Allow timeouts to run while queue is freezing nbd: fix race in ioctl block: fix use-after-free in seq file f2fs: drop bio->bi_rw manual assignment block: add missing group association in bio-cloning functions blkcg: kill unused field nr_undestroyed_grps writeback: Write dirty times for WB_SYNC_ALL writeback floppy: fix open(O_ACCMODE) for ioctl-only open
This commit is contained in:
Коммит
fff648da96
15
block/bio.c
15
block/bio.c
|
@ -583,6 +583,8 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
|
|||
bio->bi_rw = bio_src->bi_rw;
|
||||
bio->bi_iter = bio_src->bi_iter;
|
||||
bio->bi_io_vec = bio_src->bi_io_vec;
|
||||
|
||||
bio_clone_blkcg_association(bio, bio_src);
|
||||
}
|
||||
EXPORT_SYMBOL(__bio_clone_fast);
|
||||
|
||||
|
@ -687,6 +689,8 @@ integrity_clone:
|
|||
}
|
||||
}
|
||||
|
||||
bio_clone_blkcg_association(bio, bio_src);
|
||||
|
||||
return bio;
|
||||
}
|
||||
EXPORT_SYMBOL(bio_clone_bioset);
|
||||
|
@ -2004,6 +2008,17 @@ void bio_disassociate_task(struct bio *bio)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bio_clone_blkcg_association - clone blkcg association from src to dst bio
|
||||
* @dst: destination bio
|
||||
* @src: source bio
|
||||
*/
|
||||
void bio_clone_blkcg_association(struct bio *dst, struct bio *src)
|
||||
{
|
||||
if (src->bi_css)
|
||||
WARN_ON(bio_associate_blkcg(dst, src->bi_css));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BLK_CGROUP */
|
||||
|
||||
static void __init biovec_init_slabs(void)
|
||||
|
|
|
@ -380,15 +380,13 @@ static int blk_mq_register_hctx(struct blk_mq_hw_ctx *hctx)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void blk_mq_unregister_disk(struct gendisk *disk)
|
||||
static void __blk_mq_unregister_disk(struct gendisk *disk)
|
||||
{
|
||||
struct request_queue *q = disk->queue;
|
||||
struct blk_mq_hw_ctx *hctx;
|
||||
struct blk_mq_ctx *ctx;
|
||||
int i, j;
|
||||
|
||||
blk_mq_disable_hotplug();
|
||||
|
||||
queue_for_each_hw_ctx(q, hctx, i) {
|
||||
blk_mq_unregister_hctx(hctx);
|
||||
|
||||
|
@ -405,6 +403,12 @@ void blk_mq_unregister_disk(struct gendisk *disk)
|
|||
kobject_put(&disk_to_dev(disk)->kobj);
|
||||
|
||||
q->mq_sysfs_init_done = false;
|
||||
}
|
||||
|
||||
void blk_mq_unregister_disk(struct gendisk *disk)
|
||||
{
|
||||
blk_mq_disable_hotplug();
|
||||
__blk_mq_unregister_disk(disk);
|
||||
blk_mq_enable_hotplug();
|
||||
}
|
||||
|
||||
|
@ -450,7 +454,7 @@ int blk_mq_register_disk(struct gendisk *disk)
|
|||
}
|
||||
|
||||
if (ret)
|
||||
blk_mq_unregister_disk(disk);
|
||||
__blk_mq_unregister_disk(disk);
|
||||
else
|
||||
q->mq_sysfs_init_done = true;
|
||||
out:
|
||||
|
|
|
@ -672,7 +672,20 @@ static void blk_mq_timeout_work(struct work_struct *work)
|
|||
};
|
||||
int i;
|
||||
|
||||
if (blk_queue_enter(q, true))
|
||||
/* A deadlock might occur if a request is stuck requiring a
|
||||
* timeout at the same time a queue freeze is waiting
|
||||
* completion, since the timeout code would not be able to
|
||||
* acquire the queue reference here.
|
||||
*
|
||||
* That's why we don't use blk_queue_enter here; instead, we use
|
||||
* percpu_ref_tryget directly, because we need to be able to
|
||||
* obtain a reference even in the short window between the queue
|
||||
* starting to freeze, by dropping the first reference in
|
||||
* blk_mq_freeze_queue_start, and the moment the last request is
|
||||
* consumed, marked by the instant q_usage_counter reaches
|
||||
* zero.
|
||||
*/
|
||||
if (!percpu_ref_tryget(&q->q_usage_counter))
|
||||
return;
|
||||
|
||||
blk_mq_queue_tag_busy_iter(q, blk_mq_check_expired, &data);
|
||||
|
|
|
@ -145,11 +145,6 @@ struct throtl_data
|
|||
/* Total Number of queued bios on READ and WRITE lists */
|
||||
unsigned int nr_queued[2];
|
||||
|
||||
/*
|
||||
* number of total undestroyed groups
|
||||
*/
|
||||
unsigned int nr_undestroyed_grps;
|
||||
|
||||
/* Work for dispatching throttled bios */
|
||||
struct work_struct dispatch_work;
|
||||
};
|
||||
|
|
|
@ -614,7 +614,7 @@ void device_add_disk(struct device *parent, struct gendisk *disk)
|
|||
|
||||
/* Register BDI before referencing it from bdev */
|
||||
bdi = &disk->queue->backing_dev_info;
|
||||
bdi_register_dev(bdi, disk_devt(disk));
|
||||
bdi_register_owner(bdi, disk_to_dev(disk));
|
||||
|
||||
blk_register_region(disk_devt(disk), disk->minors, NULL,
|
||||
exact_match, exact_lock, disk);
|
||||
|
@ -856,6 +856,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v)
|
|||
if (iter) {
|
||||
class_dev_iter_exit(iter);
|
||||
kfree(iter);
|
||||
seqf->private = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -300,20 +300,20 @@ static void copy_from_brd(void *dst, struct brd_device *brd,
|
|||
* Process a single bvec of a bio.
|
||||
*/
|
||||
static int brd_do_bvec(struct brd_device *brd, struct page *page,
|
||||
unsigned int len, unsigned int off, int rw,
|
||||
unsigned int len, unsigned int off, int op,
|
||||
sector_t sector)
|
||||
{
|
||||
void *mem;
|
||||
int err = 0;
|
||||
|
||||
if (rw != READ) {
|
||||
if (op_is_write(op)) {
|
||||
err = copy_to_brd_setup(brd, sector, len);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
mem = kmap_atomic(page);
|
||||
if (rw == READ) {
|
||||
if (!op_is_write(op)) {
|
||||
copy_from_brd(mem + off, brd, sector, len);
|
||||
flush_dcache_page(page);
|
||||
} else {
|
||||
|
@ -330,7 +330,6 @@ static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio)
|
|||
{
|
||||
struct block_device *bdev = bio->bi_bdev;
|
||||
struct brd_device *brd = bdev->bd_disk->private_data;
|
||||
int rw;
|
||||
struct bio_vec bvec;
|
||||
sector_t sector;
|
||||
struct bvec_iter iter;
|
||||
|
@ -347,14 +346,12 @@ static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio)
|
|||
goto out;
|
||||
}
|
||||
|
||||
rw = bio_data_dir(bio);
|
||||
|
||||
bio_for_each_segment(bvec, bio, iter) {
|
||||
unsigned int len = bvec.bv_len;
|
||||
int err;
|
||||
|
||||
err = brd_do_bvec(brd, bvec.bv_page, len,
|
||||
bvec.bv_offset, rw, sector);
|
||||
bvec.bv_offset, bio_op(bio), sector);
|
||||
if (err)
|
||||
goto io_error;
|
||||
sector += len >> SECTOR_SHIFT;
|
||||
|
@ -369,11 +366,11 @@ io_error:
|
|||
}
|
||||
|
||||
static int brd_rw_page(struct block_device *bdev, sector_t sector,
|
||||
struct page *page, int rw)
|
||||
struct page *page, int op)
|
||||
{
|
||||
struct brd_device *brd = bdev->bd_disk->private_data;
|
||||
int err = brd_do_bvec(brd, page, PAGE_SIZE, 0, rw, sector);
|
||||
page_endio(page, rw & WRITE, err);
|
||||
int err = brd_do_bvec(brd, page, PAGE_SIZE, 0, op, sector);
|
||||
page_endio(page, op, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -3663,11 +3663,6 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
|
|||
|
||||
opened_bdev[drive] = bdev;
|
||||
|
||||
if (!(mode & (FMODE_READ|FMODE_WRITE))) {
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = -ENXIO;
|
||||
|
||||
if (!floppy_track_buffer) {
|
||||
|
@ -3711,13 +3706,15 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
|
|||
if (UFDCS->rawcmd == 1)
|
||||
UFDCS->rawcmd = 2;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
|
|
|
@ -510,14 +510,10 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int lo_rw_simple(struct loop_device *lo,
|
||||
struct request *rq, loff_t pos, bool rw)
|
||||
static int do_req_filebacked(struct loop_device *lo, struct request *rq)
|
||||
{
|
||||
struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
|
||||
|
||||
if (cmd->use_aio)
|
||||
return lo_rw_aio(lo, cmd, pos, rw);
|
||||
loff_t pos = ((loff_t) blk_rq_pos(rq) << 9) + lo->lo_offset;
|
||||
|
||||
/*
|
||||
* lo_write_simple and lo_read_simple should have been covered
|
||||
|
@ -528,37 +524,30 @@ static inline int lo_rw_simple(struct loop_device *lo,
|
|||
* of the req at one time. And direct read IO doesn't need to
|
||||
* run flush_dcache_page().
|
||||
*/
|
||||
if (rw == WRITE)
|
||||
return lo_write_simple(lo, rq, pos);
|
||||
else
|
||||
return lo_read_simple(lo, rq, pos);
|
||||
}
|
||||
|
||||
static int do_req_filebacked(struct loop_device *lo, struct request *rq)
|
||||
{
|
||||
loff_t pos;
|
||||
int ret;
|
||||
|
||||
pos = ((loff_t) blk_rq_pos(rq) << 9) + lo->lo_offset;
|
||||
|
||||
if (op_is_write(req_op(rq))) {
|
||||
if (req_op(rq) == REQ_OP_FLUSH)
|
||||
ret = lo_req_flush(lo, rq);
|
||||
else if (req_op(rq) == REQ_OP_DISCARD)
|
||||
ret = lo_discard(lo, rq, pos);
|
||||
else if (lo->transfer)
|
||||
ret = lo_write_transfer(lo, rq, pos);
|
||||
else
|
||||
ret = lo_rw_simple(lo, rq, pos, WRITE);
|
||||
|
||||
} else {
|
||||
switch (req_op(rq)) {
|
||||
case REQ_OP_FLUSH:
|
||||
return lo_req_flush(lo, rq);
|
||||
case REQ_OP_DISCARD:
|
||||
return lo_discard(lo, rq, pos);
|
||||
case REQ_OP_WRITE:
|
||||
if (lo->transfer)
|
||||
ret = lo_read_transfer(lo, rq, pos);
|
||||
return lo_write_transfer(lo, rq, pos);
|
||||
else if (cmd->use_aio)
|
||||
return lo_rw_aio(lo, cmd, pos, WRITE);
|
||||
else
|
||||
ret = lo_rw_simple(lo, rq, pos, READ);
|
||||
return lo_write_simple(lo, rq, pos);
|
||||
case REQ_OP_READ:
|
||||
if (lo->transfer)
|
||||
return lo_read_transfer(lo, rq, pos);
|
||||
else if (cmd->use_aio)
|
||||
return lo_rw_aio(lo, cmd, pos, READ);
|
||||
else
|
||||
return lo_read_simple(lo, rq, pos);
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct switch_request {
|
||||
|
@ -1659,11 +1648,15 @@ static int loop_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
if (lo->lo_state != Lo_bound)
|
||||
return -EIO;
|
||||
|
||||
if (lo->use_dio && (req_op(cmd->rq) != REQ_OP_FLUSH ||
|
||||
req_op(cmd->rq) == REQ_OP_DISCARD))
|
||||
cmd->use_aio = true;
|
||||
else
|
||||
switch (req_op(cmd->rq)) {
|
||||
case REQ_OP_FLUSH:
|
||||
case REQ_OP_DISCARD:
|
||||
cmd->use_aio = false;
|
||||
break;
|
||||
default:
|
||||
cmd->use_aio = lo->use_dio;
|
||||
break;
|
||||
}
|
||||
|
||||
queue_kthread_work(&lo->worker, &cmd->work);
|
||||
|
||||
|
|
|
@ -451,14 +451,9 @@ static int nbd_thread_recv(struct nbd_device *nbd, struct block_device *bdev)
|
|||
|
||||
sk_set_memalloc(nbd->sock->sk);
|
||||
|
||||
nbd->task_recv = current;
|
||||
|
||||
ret = device_create_file(disk_to_dev(nbd->disk), &pid_attr);
|
||||
if (ret) {
|
||||
dev_err(disk_to_dev(nbd->disk), "device_create_file failed!\n");
|
||||
|
||||
nbd->task_recv = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -477,9 +472,6 @@ static int nbd_thread_recv(struct nbd_device *nbd, struct block_device *bdev)
|
|||
nbd_size_clear(nbd, bdev);
|
||||
|
||||
device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
|
||||
|
||||
nbd->task_recv = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -788,6 +780,8 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
|
|||
if (!nbd->sock)
|
||||
return -EINVAL;
|
||||
|
||||
/* We have to claim the device under the lock */
|
||||
nbd->task_recv = current;
|
||||
mutex_unlock(&nbd->tx_lock);
|
||||
|
||||
nbd_parse_flags(nbd, bdev);
|
||||
|
@ -796,6 +790,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
|
|||
nbd_name(nbd));
|
||||
if (IS_ERR(thread)) {
|
||||
mutex_lock(&nbd->tx_lock);
|
||||
nbd->task_recv = NULL;
|
||||
return PTR_ERR(thread);
|
||||
}
|
||||
|
||||
|
@ -805,6 +800,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
|
|||
kthread_stop(thread);
|
||||
|
||||
mutex_lock(&nbd->tx_lock);
|
||||
nbd->task_recv = NULL;
|
||||
|
||||
sock_shutdown(nbd);
|
||||
nbd_clear_que(nbd);
|
||||
|
|
|
@ -843,15 +843,15 @@ static void zram_bio_discard(struct zram *zram, u32 index,
|
|||
}
|
||||
|
||||
static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
|
||||
int offset, int rw)
|
||||
int offset, int op)
|
||||
{
|
||||
unsigned long start_time = jiffies;
|
||||
int ret;
|
||||
|
||||
generic_start_io_acct(rw, bvec->bv_len >> SECTOR_SHIFT,
|
||||
generic_start_io_acct(op, bvec->bv_len >> SECTOR_SHIFT,
|
||||
&zram->disk->part0);
|
||||
|
||||
if (rw == READ) {
|
||||
if (!op_is_write(op)) {
|
||||
atomic64_inc(&zram->stats.num_reads);
|
||||
ret = zram_bvec_read(zram, bvec, index, offset);
|
||||
} else {
|
||||
|
@ -859,10 +859,10 @@ static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
|
|||
ret = zram_bvec_write(zram, bvec, index, offset);
|
||||
}
|
||||
|
||||
generic_end_io_acct(rw, &zram->disk->part0, start_time);
|
||||
generic_end_io_acct(op, &zram->disk->part0, start_time);
|
||||
|
||||
if (unlikely(ret)) {
|
||||
if (rw == READ)
|
||||
if (!op_is_write(op))
|
||||
atomic64_inc(&zram->stats.failed_reads);
|
||||
else
|
||||
atomic64_inc(&zram->stats.failed_writes);
|
||||
|
@ -873,7 +873,7 @@ static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
|
|||
|
||||
static void __zram_make_request(struct zram *zram, struct bio *bio)
|
||||
{
|
||||
int offset, rw;
|
||||
int offset;
|
||||
u32 index;
|
||||
struct bio_vec bvec;
|
||||
struct bvec_iter iter;
|
||||
|
@ -888,7 +888,6 @@ static void __zram_make_request(struct zram *zram, struct bio *bio)
|
|||
return;
|
||||
}
|
||||
|
||||
rw = bio_data_dir(bio);
|
||||
bio_for_each_segment(bvec, bio, iter) {
|
||||
int max_transfer_size = PAGE_SIZE - offset;
|
||||
|
||||
|
@ -903,15 +902,18 @@ static void __zram_make_request(struct zram *zram, struct bio *bio)
|
|||
bv.bv_len = max_transfer_size;
|
||||
bv.bv_offset = bvec.bv_offset;
|
||||
|
||||
if (zram_bvec_rw(zram, &bv, index, offset, rw) < 0)
|
||||
if (zram_bvec_rw(zram, &bv, index, offset,
|
||||
bio_op(bio)) < 0)
|
||||
goto out;
|
||||
|
||||
bv.bv_len = bvec.bv_len - max_transfer_size;
|
||||
bv.bv_offset += max_transfer_size;
|
||||
if (zram_bvec_rw(zram, &bv, index + 1, 0, rw) < 0)
|
||||
if (zram_bvec_rw(zram, &bv, index + 1, 0,
|
||||
bio_op(bio)) < 0)
|
||||
goto out;
|
||||
} else
|
||||
if (zram_bvec_rw(zram, &bvec, index, offset, rw) < 0)
|
||||
if (zram_bvec_rw(zram, &bvec, index, offset,
|
||||
bio_op(bio)) < 0)
|
||||
goto out;
|
||||
|
||||
update_position(&index, &offset, &bvec);
|
||||
|
@ -968,7 +970,7 @@ static void zram_slot_free_notify(struct block_device *bdev,
|
|||
}
|
||||
|
||||
static int zram_rw_page(struct block_device *bdev, sector_t sector,
|
||||
struct page *page, int rw)
|
||||
struct page *page, int op)
|
||||
{
|
||||
int offset, err = -EIO;
|
||||
u32 index;
|
||||
|
@ -992,7 +994,7 @@ static int zram_rw_page(struct block_device *bdev, sector_t sector,
|
|||
bv.bv_len = PAGE_SIZE;
|
||||
bv.bv_offset = 0;
|
||||
|
||||
err = zram_bvec_rw(zram, &bv, index, offset, rw);
|
||||
err = zram_bvec_rw(zram, &bv, index, offset, op);
|
||||
put_zram:
|
||||
zram_meta_put(zram);
|
||||
out:
|
||||
|
@ -1005,7 +1007,7 @@ out:
|
|||
* (e.g., SetPageError, set_page_dirty and extra works).
|
||||
*/
|
||||
if (err == 0)
|
||||
page_endio(page, rw, 0);
|
||||
page_endio(page, op, 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -1133,11 +1133,11 @@ static int btt_write_pg(struct btt *btt, struct bio_integrity_payload *bip,
|
|||
|
||||
static int btt_do_bvec(struct btt *btt, struct bio_integrity_payload *bip,
|
||||
struct page *page, unsigned int len, unsigned int off,
|
||||
int rw, sector_t sector)
|
||||
int op, sector_t sector)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (rw == READ) {
|
||||
if (!op_is_write(op)) {
|
||||
ret = btt_read_pg(btt, bip, page, off, sector, len);
|
||||
flush_dcache_page(page);
|
||||
} else {
|
||||
|
@ -1155,7 +1155,7 @@ static blk_qc_t btt_make_request(struct request_queue *q, struct bio *bio)
|
|||
struct bvec_iter iter;
|
||||
unsigned long start;
|
||||
struct bio_vec bvec;
|
||||
int err = 0, rw;
|
||||
int err = 0;
|
||||
bool do_acct;
|
||||
|
||||
/*
|
||||
|
@ -1170,7 +1170,6 @@ static blk_qc_t btt_make_request(struct request_queue *q, struct bio *bio)
|
|||
}
|
||||
|
||||
do_acct = nd_iostat_start(bio, &start);
|
||||
rw = bio_data_dir(bio);
|
||||
bio_for_each_segment(bvec, bio, iter) {
|
||||
unsigned int len = bvec.bv_len;
|
||||
|
||||
|
@ -1181,11 +1180,12 @@ static blk_qc_t btt_make_request(struct request_queue *q, struct bio *bio)
|
|||
BUG_ON(len % btt->sector_size);
|
||||
|
||||
err = btt_do_bvec(btt, bip, bvec.bv_page, len, bvec.bv_offset,
|
||||
rw, iter.bi_sector);
|
||||
bio_op(bio), iter.bi_sector);
|
||||
if (err) {
|
||||
dev_info(&btt->nd_btt->dev,
|
||||
"io error in %s sector %lld, len %d,\n",
|
||||
(rw == READ) ? "READ" : "WRITE",
|
||||
(op_is_write(bio_op(bio))) ? "WRITE" :
|
||||
"READ",
|
||||
(unsigned long long) iter.bi_sector, len);
|
||||
bio->bi_error = err;
|
||||
break;
|
||||
|
@ -1200,12 +1200,12 @@ out:
|
|||
}
|
||||
|
||||
static int btt_rw_page(struct block_device *bdev, sector_t sector,
|
||||
struct page *page, int rw)
|
||||
struct page *page, int op)
|
||||
{
|
||||
struct btt *btt = bdev->bd_disk->private_data;
|
||||
|
||||
btt_do_bvec(btt, NULL, page, PAGE_SIZE, 0, rw, sector);
|
||||
page_endio(page, rw & WRITE, 0);
|
||||
btt_do_bvec(btt, NULL, page, PAGE_SIZE, 0, op, sector);
|
||||
page_endio(page, op, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
|
|||
}
|
||||
|
||||
static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
|
||||
unsigned int len, unsigned int off, int rw,
|
||||
unsigned int len, unsigned int off, int op,
|
||||
sector_t sector)
|
||||
{
|
||||
int rc = 0;
|
||||
|
@ -79,7 +79,7 @@ static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
|
|||
if (unlikely(is_bad_pmem(&pmem->bb, sector, len)))
|
||||
bad_pmem = true;
|
||||
|
||||
if (rw == READ) {
|
||||
if (!op_is_write(op)) {
|
||||
if (unlikely(bad_pmem))
|
||||
rc = -EIO;
|
||||
else {
|
||||
|
@ -134,7 +134,7 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
|
|||
do_acct = nd_iostat_start(bio, &start);
|
||||
bio_for_each_segment(bvec, bio, iter) {
|
||||
rc = pmem_do_bvec(pmem, bvec.bv_page, bvec.bv_len,
|
||||
bvec.bv_offset, bio_data_dir(bio),
|
||||
bvec.bv_offset, bio_op(bio),
|
||||
iter.bi_sector);
|
||||
if (rc) {
|
||||
bio->bi_error = rc;
|
||||
|
@ -152,12 +152,12 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
|
|||
}
|
||||
|
||||
static int pmem_rw_page(struct block_device *bdev, sector_t sector,
|
||||
struct page *page, int rw)
|
||||
struct page *page, int op)
|
||||
{
|
||||
struct pmem_device *pmem = bdev->bd_queue->queuedata;
|
||||
int rc;
|
||||
|
||||
rc = pmem_do_bvec(pmem, page, PAGE_SIZE, 0, rw, sector);
|
||||
rc = pmem_do_bvec(pmem, page, PAGE_SIZE, 0, op, sector);
|
||||
|
||||
/*
|
||||
* The ->rw_page interface is subtle and tricky. The core
|
||||
|
@ -166,7 +166,7 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
|
|||
* caused by double completion.
|
||||
*/
|
||||
if (rc == 0)
|
||||
page_endio(page, rw & WRITE, 0);
|
||||
page_endio(page, op, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -416,7 +416,8 @@ int bdev_read_page(struct block_device *bdev, sector_t sector,
|
|||
result = blk_queue_enter(bdev->bd_queue, false);
|
||||
if (result)
|
||||
return result;
|
||||
result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, READ);
|
||||
result = ops->rw_page(bdev, sector + get_start_sect(bdev), page,
|
||||
REQ_OP_READ);
|
||||
blk_queue_exit(bdev->bd_queue);
|
||||
return result;
|
||||
}
|
||||
|
@ -445,7 +446,6 @@ int bdev_write_page(struct block_device *bdev, sector_t sector,
|
|||
struct page *page, struct writeback_control *wbc)
|
||||
{
|
||||
int result;
|
||||
int rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE;
|
||||
const struct block_device_operations *ops = bdev->bd_disk->fops;
|
||||
|
||||
if (!ops->rw_page || bdev_get_integrity(bdev))
|
||||
|
@ -455,7 +455,8 @@ int bdev_write_page(struct block_device *bdev, sector_t sector,
|
|||
return result;
|
||||
|
||||
set_page_writeback(page);
|
||||
result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, rw);
|
||||
result = ops->rw_page(bdev, sector + get_start_sect(bdev), page,
|
||||
REQ_OP_WRITE);
|
||||
if (result)
|
||||
end_page_writeback(page);
|
||||
else
|
||||
|
|
|
@ -2049,7 +2049,7 @@ int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical,
|
|||
return -EIO;
|
||||
}
|
||||
bio->bi_bdev = dev->bdev;
|
||||
bio->bi_rw = WRITE_SYNC;
|
||||
bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_SYNC);
|
||||
bio_add_page(bio, page, length, pg_offset);
|
||||
|
||||
if (btrfsic_submit_bio_wait(bio)) {
|
||||
|
@ -2697,12 +2697,6 @@ struct bio *btrfs_bio_clone(struct bio *bio, gfp_t gfp_mask)
|
|||
btrfs_bio->csum = NULL;
|
||||
btrfs_bio->csum_allocated = NULL;
|
||||
btrfs_bio->end_io = NULL;
|
||||
|
||||
#ifdef CONFIG_BLK_CGROUP
|
||||
/* FIXME, put this into bio_clone_bioset */
|
||||
if (bio->bi_css)
|
||||
bio_associate_blkcg(new, bio->bi_css);
|
||||
#endif
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
|
|
@ -245,7 +245,6 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
|
|||
bio_put(bio);
|
||||
return -EFAULT;
|
||||
}
|
||||
bio->bi_rw = fio->op_flags;
|
||||
bio_set_op_attrs(bio, fio->op, fio->op_flags);
|
||||
|
||||
__submit_bio(fio->sbi, bio, fio->type);
|
||||
|
|
|
@ -1327,6 +1327,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
|
|||
dirty = inode->i_state & I_DIRTY;
|
||||
if (inode->i_state & I_DIRTY_TIME) {
|
||||
if ((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) ||
|
||||
wbc->sync_mode == WB_SYNC_ALL ||
|
||||
unlikely(inode->i_state & I_DIRTY_TIME_EXPIRED) ||
|
||||
unlikely(time_after(jiffies,
|
||||
(inode->dirtied_time_when +
|
||||
|
|
|
@ -50,7 +50,7 @@ static void mpage_end_io(struct bio *bio)
|
|||
|
||||
bio_for_each_segment_all(bv, bio, i) {
|
||||
struct page *page = bv->bv_page;
|
||||
page_endio(page, bio_data_dir(bio), bio->bi_error);
|
||||
page_endio(page, bio_op(bio), bio->bi_error);
|
||||
}
|
||||
|
||||
bio_put(bio);
|
||||
|
|
|
@ -163,6 +163,7 @@ struct backing_dev_info {
|
|||
wait_queue_head_t wb_waitq;
|
||||
|
||||
struct device *dev;
|
||||
struct device *owner;
|
||||
|
||||
struct timer_list laptop_mode_wb_timer;
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ __printf(3, 4)
|
|||
int bdi_register(struct backing_dev_info *bdi, struct device *parent,
|
||||
const char *fmt, ...);
|
||||
int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
|
||||
int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner);
|
||||
void bdi_unregister(struct backing_dev_info *bdi);
|
||||
|
||||
int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);
|
||||
|
|
|
@ -470,11 +470,14 @@ extern unsigned int bvec_nr_vecs(unsigned short idx);
|
|||
int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css);
|
||||
int bio_associate_current(struct bio *bio);
|
||||
void bio_disassociate_task(struct bio *bio);
|
||||
void bio_clone_blkcg_association(struct bio *dst, struct bio *src);
|
||||
#else /* CONFIG_BLK_CGROUP */
|
||||
static inline int bio_associate_blkcg(struct bio *bio,
|
||||
struct cgroup_subsys_state *blkcg_css) { return 0; }
|
||||
static inline int bio_associate_current(struct bio *bio) { return -ENOENT; }
|
||||
static inline void bio_disassociate_task(struct bio *bio) { }
|
||||
static inline void bio_clone_blkcg_association(struct bio *dst,
|
||||
struct bio *src) { }
|
||||
#endif /* CONFIG_BLK_CGROUP */
|
||||
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
|
|
|
@ -18,6 +18,17 @@ struct cgroup_subsys_state;
|
|||
typedef void (bio_end_io_t) (struct bio *);
|
||||
typedef void (bio_destructor_t) (struct bio *);
|
||||
|
||||
enum req_op {
|
||||
REQ_OP_READ,
|
||||
REQ_OP_WRITE,
|
||||
REQ_OP_DISCARD, /* request to discard sectors */
|
||||
REQ_OP_SECURE_ERASE, /* request to securely erase sectors */
|
||||
REQ_OP_WRITE_SAME, /* write same block many times */
|
||||
REQ_OP_FLUSH, /* request for cache flush */
|
||||
};
|
||||
|
||||
#define REQ_OP_BITS 3
|
||||
|
||||
#ifdef CONFIG_BLOCK
|
||||
/*
|
||||
* main unit of I/O for the block layer and lower layers (ie drivers and
|
||||
|
@ -228,17 +239,6 @@ enum rq_flag_bits {
|
|||
#define REQ_HASHED (1ULL << __REQ_HASHED)
|
||||
#define REQ_MQ_INFLIGHT (1ULL << __REQ_MQ_INFLIGHT)
|
||||
|
||||
enum req_op {
|
||||
REQ_OP_READ,
|
||||
REQ_OP_WRITE,
|
||||
REQ_OP_DISCARD, /* request to discard sectors */
|
||||
REQ_OP_SECURE_ERASE, /* request to securely erase sectors */
|
||||
REQ_OP_WRITE_SAME, /* write same block many times */
|
||||
REQ_OP_FLUSH, /* request for cache flush */
|
||||
};
|
||||
|
||||
#define REQ_OP_BITS 3
|
||||
|
||||
typedef unsigned int blk_qc_t;
|
||||
#define BLK_QC_T_NONE -1U
|
||||
#define BLK_QC_T_SHIFT 16
|
||||
|
|
|
@ -47,7 +47,6 @@ struct pr_ops;
|
|||
*/
|
||||
#define BLKCG_MAX_POLS 2
|
||||
|
||||
struct request;
|
||||
typedef void (rq_end_io_fn)(struct request *, int);
|
||||
|
||||
#define BLK_RL_SYNCFULL (1U << 0)
|
||||
|
@ -1673,7 +1672,7 @@ struct blk_dax_ctl {
|
|||
struct block_device_operations {
|
||||
int (*open) (struct block_device *, fmode_t);
|
||||
void (*release) (struct gendisk *, fmode_t);
|
||||
int (*rw_page)(struct block_device *, sector_t, struct page *, int rw);
|
||||
int (*rw_page)(struct block_device *, sector_t, struct page *, int op);
|
||||
int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
|
||||
int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
|
||||
long (*direct_access)(struct block_device *, sector_t, void **, pfn_t *,
|
||||
|
|
|
@ -2480,12 +2480,13 @@ extern void init_special_inode(struct inode *, umode_t, dev_t);
|
|||
extern void make_bad_inode(struct inode *);
|
||||
extern bool is_bad_inode(struct inode *);
|
||||
|
||||
#ifdef CONFIG_BLOCK
|
||||
static inline bool op_is_write(unsigned int op)
|
||||
{
|
||||
return op == REQ_OP_READ ? false : true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLOCK
|
||||
|
||||
/*
|
||||
* return data direction, READ or WRITE
|
||||
*/
|
||||
|
|
|
@ -510,7 +510,7 @@ static inline void wait_on_page_writeback(struct page *page)
|
|||
extern void end_page_writeback(struct page *page);
|
||||
void wait_for_stable_page(struct page *page);
|
||||
|
||||
void page_endio(struct page *page, int rw, int err);
|
||||
void page_endio(struct page *page, int op, int err);
|
||||
|
||||
/*
|
||||
* Add an arbitrary waiter to a page's wait queue
|
||||
|
|
|
@ -825,6 +825,20 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev)
|
|||
}
|
||||
EXPORT_SYMBOL(bdi_register_dev);
|
||||
|
||||
int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = bdi_register(bdi, NULL, "%u:%u", MAJOR(owner->devt),
|
||||
MINOR(owner->devt));
|
||||
if (rc)
|
||||
return rc;
|
||||
bdi->owner = owner;
|
||||
get_device(owner);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(bdi_register_owner);
|
||||
|
||||
/*
|
||||
* Remove bdi from bdi_list, and ensure that it is no longer visible
|
||||
*/
|
||||
|
@ -849,6 +863,11 @@ void bdi_unregister(struct backing_dev_info *bdi)
|
|||
device_unregister(bdi->dev);
|
||||
bdi->dev = NULL;
|
||||
}
|
||||
|
||||
if (bdi->owner) {
|
||||
put_device(bdi->owner);
|
||||
bdi->owner = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void bdi_exit(struct backing_dev_info *bdi)
|
||||
|
|
|
@ -887,9 +887,9 @@ EXPORT_SYMBOL(end_page_writeback);
|
|||
* After completing I/O on a page, call this routine to update the page
|
||||
* flags appropriately
|
||||
*/
|
||||
void page_endio(struct page *page, int rw, int err)
|
||||
void page_endio(struct page *page, int op, int err)
|
||||
{
|
||||
if (rw == READ) {
|
||||
if (!op_is_write(op)) {
|
||||
if (!err) {
|
||||
SetPageUptodate(page);
|
||||
} else {
|
||||
|
@ -897,7 +897,7 @@ void page_endio(struct page *page, int rw, int err)
|
|||
SetPageError(page);
|
||||
}
|
||||
unlock_page(page);
|
||||
} else { /* rw == WRITE */
|
||||
} else {
|
||||
if (err) {
|
||||
SetPageError(page);
|
||||
if (page->mapping)
|
||||
|
|
Загрузка…
Ссылка в новой задаче