forked from Minki/linux
for-5.9/block-20200802
-----BEGIN PGP SIGNATURE----- iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAl8m7YwQHGF4Ym9lQGtl cm5lbC5kawAKCRD301j7KXHgpt+dEAC7a0HYuX2OrkyawBnsgd1QQR/soC7surec yDDa7SMM8cOq3935bfzcYHV9FWJszEGIknchiGb9R3/T+vmSohbvDsM5zgwya9u/ FHUIuTq324I6JWXKl30k4rwjiX9wQeMt+WZ5gC8KJYCWA296i2IpJwd0A45aaKuS x4bTjxqknE+fD4gQiMUSt+bmuOUAp81fEku3EPapCRYDPAj8f5uoY7R2arT/POwB b+s+AtXqzBymIqx1z0sZ/XcdZKmDuhdurGCWu7BfJFIzw5kQ2Qe3W8rUmrQ3pGut 8a21YfilhUFiBv+B4wptfrzJuzU6Ps0BXHCnBsQjzvXwq5uFcZH495mM/4E4OJvh SbjL2K4iFj+O1ngFkukG/F8tdEM1zKBYy2ZEkGoWKUpyQanbAaGI6QKKJA+DCdBi yPEb7yRAa5KfLqMiocm1qCEO1I56HRiNHaJVMqCPOZxLmpXj19Fs71yIRplP1Trv GGXdWZsccjuY6OljoXWdEfnxAr5zBsO3Yf2yFT95AD+egtGsU1oOzlqAaU1mtflw ABo452pvh6FFpxGXqz6oK4VqY4Et7WgXOiljA4yIGoPpG/08L1Yle4eVc2EE01Jb +BL49xNJVeUhGFrvUjPGl9kVMeLmubPFbmgrtipW+VRg9W8+Yirw7DPP6K+gbPAR RzAUdZFbWw== =abJG -----END PGP SIGNATURE----- Merge tag 'for-5.9/block-20200802' of git://git.kernel.dk/linux-block Pull core block updates from Jens Axboe: "Good amount of cleanups and tech debt removals in here, and as a result, the diffstat shows a nice net reduction in code. - Softirq completion cleanups (Christoph) - Stop using ->queuedata (Christoph) - Cleanup bd claiming (Christoph) - Use check_events, moving away from the legacy media change (Christoph) - Use inode i_blkbits consistently (Christoph) - Remove old unused writeback congestion bits (Christoph) - Cleanup/unify submission path (Christoph) - Use bio_uninit consistently, instead of bio_disassociate_blkg (Christoph) - sbitmap cleared bits handling (John) - Request merging blktrace event addition (Jan) - sysfs add/remove race fixes (Luis) - blk-mq tag fixes/optimizations (Ming) - Duplicate words in comments (Randy) - Flush deferral cleanup (Yufen) - IO context locking/retry fixes (John) - struct_size() usage (Gustavo) - blk-iocost fixes (Chengming) - blk-cgroup IO stats fixes (Boris) - Various little fixes" * tag 'for-5.9/block-20200802' of git://git.kernel.dk/linux-block: (135 commits) block: blk-timeout: delete duplicated word block: blk-mq-sched: delete duplicated word block: blk-mq: delete duplicated word block: genhd: delete duplicated words block: elevator: delete duplicated word and fix typos block: bio: delete duplicated words block: bfq-iosched: fix duplicated word iocost_monitor: start from the oldest usage index iocost: Fix check condition of iocg abs_vdebt block: Remove callback typedefs for blk_mq_ops block: Use non _rcu version of list functions for tag_set_list blk-cgroup: show global disk stats in root cgroup io.stat blk-cgroup: make iostat functions visible to stat printing block: improve discard bio alignment in __blkdev_issue_discard() block: change REQ_OP_ZONE_RESET and REQ_OP_ZONE_RESET_ALL to be odd numbers block: defer flush request no matter whether we have elevator block: make blk_timeout_init() static block: remove retry loop in ioc_release_fn() block: remove unnecessary ioc nested locking block: integrate bd_start_claiming into __blkdev_get ...
This commit is contained in:
commit
382625d0d4
@ -1483,8 +1483,7 @@ IO Interface Files
|
|||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
io.stat
|
io.stat
|
||||||
A read-only nested-keyed file which exists on non-root
|
A read-only nested-keyed file.
|
||||||
cgroups.
|
|
||||||
|
|
||||||
Lines are keyed by $MAJ:$MIN device numbers and not ordered.
|
Lines are keyed by $MAJ:$MIN device numbers and not ordered.
|
||||||
The following nested keys are defined.
|
The following nested keys are defined.
|
||||||
|
@ -1036,7 +1036,7 @@ Now the generic block layer performs partition-remapping early and thus
|
|||||||
provides drivers with a sector number relative to whole device, rather than
|
provides drivers with a sector number relative to whole device, rather than
|
||||||
having to take partition number into account in order to arrive at the true
|
having to take partition number into account in order to arrive at the true
|
||||||
sector number. The routine blk_partition_remap() is invoked by
|
sector number. The routine blk_partition_remap() is invoked by
|
||||||
generic_make_request even before invoking the queue specific make_request_fn,
|
submit_bio_noacct even before invoking the queue specific ->submit_bio,
|
||||||
so the i/o scheduler also gets to operate on whole disk sector numbers. This
|
so the i/o scheduler also gets to operate on whole disk sector numbers. This
|
||||||
should typically not require changes to block drivers, it just never gets
|
should typically not require changes to block drivers, it just never gets
|
||||||
to invoke its own partition sector offset calculations since all bios
|
to invoke its own partition sector offset calculations since all bios
|
||||||
|
@ -47,7 +47,7 @@ the Forced Unit Access is implemented. The REQ_PREFLUSH and REQ_FUA flags
|
|||||||
may both be set on a single bio.
|
may both be set on a single bio.
|
||||||
|
|
||||||
|
|
||||||
Implementation details for make_request_fn based block drivers
|
Implementation details for bio based block drivers
|
||||||
--------------------------------------------------------------
|
--------------------------------------------------------------
|
||||||
|
|
||||||
These drivers will always see the REQ_PREFLUSH and REQ_FUA bits as they sit
|
These drivers will always see the REQ_PREFLUSH and REQ_FUA bits as they sit
|
||||||
|
@ -157,7 +157,6 @@ with the kernel as a block device by registering the following general
|
|||||||
cdrom_release, /∗ release ∗/
|
cdrom_release, /∗ release ∗/
|
||||||
NULL, /∗ fsync ∗/
|
NULL, /∗ fsync ∗/
|
||||||
NULL, /∗ fasync ∗/
|
NULL, /∗ fasync ∗/
|
||||||
cdrom_media_changed, /∗ media change ∗/
|
|
||||||
NULL /∗ revalidate ∗/
|
NULL /∗ revalidate ∗/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -366,19 +365,6 @@ which may or may not be in the drive). If the drive is not a changer,
|
|||||||
CDS_DRIVE_NOT_READY /* something is wrong, tray is moving? */
|
CDS_DRIVE_NOT_READY /* something is wrong, tray is moving? */
|
||||||
CDS_DISC_OK /* a disc is loaded and everything is fine */
|
CDS_DISC_OK /* a disc is loaded and everything is fine */
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
int media_changed(struct cdrom_device_info *cdi, int disc_nr)
|
|
||||||
|
|
||||||
This function is very similar to the original function in $struct
|
|
||||||
file_operations*. It returns 1 if the medium of the device *cdi->dev*
|
|
||||||
has changed since the last call, and 0 otherwise. The parameter
|
|
||||||
*disc_nr* identifies a specific slot in a juke-box, it should be
|
|
||||||
ignored for single-disc drives. Note that by `re-routing` this
|
|
||||||
function through *cdrom_media_changed()*, we can implement separate
|
|
||||||
queues for the VFS and a new *ioctl()* function that can report device
|
|
||||||
changes to software (e. g., an auto-mounting daemon).
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
int tray_move(struct cdrom_device_info *cdi, int position)
|
int tray_move(struct cdrom_device_info *cdi, int position)
|
||||||
@ -917,9 +903,7 @@ commands can be identified by the underscores in their names.
|
|||||||
maximum number of discs in the juke-box found in the *cdrom_dops*.
|
maximum number of discs in the juke-box found in the *cdrom_dops*.
|
||||||
`CDROM_MEDIA_CHANGED`
|
`CDROM_MEDIA_CHANGED`
|
||||||
Returns 1 if a disc has been changed since the last call.
|
Returns 1 if a disc has been changed since the last call.
|
||||||
Note that calls to *cdrom_media_changed* by the VFS are treated
|
For juke-boxes, an extra argument *arg*
|
||||||
by an independent queue, so both mechanisms will detect a
|
|
||||||
media change once. For juke-boxes, an extra argument *arg*
|
|
||||||
specifies the slot for which the information is given. The special
|
specifies the slot for which the information is given. The special
|
||||||
value *CDSL_CURRENT* requests that information about the currently
|
value *CDSL_CURRENT* requests that information about the currently
|
||||||
selected slot be returned.
|
selected slot be returned.
|
||||||
|
@ -24,7 +24,7 @@ Available fault injection capabilities
|
|||||||
|
|
||||||
injects disk IO errors on devices permitted by setting
|
injects disk IO errors on devices permitted by setting
|
||||||
/sys/block/<device>/make-it-fail or
|
/sys/block/<device>/make-it-fail or
|
||||||
/sys/block/<device>/<partition>/make-it-fail. (generic_make_request())
|
/sys/block/<device>/<partition>/make-it-fail. (submit_bio_noacct())
|
||||||
|
|
||||||
- fail_mmc_request
|
- fail_mmc_request
|
||||||
|
|
||||||
|
@ -467,7 +467,6 @@ prototypes::
|
|||||||
int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
|
int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
|
||||||
int (*direct_access) (struct block_device *, sector_t, void **,
|
int (*direct_access) (struct block_device *, sector_t, void **,
|
||||||
unsigned long *);
|
unsigned long *);
|
||||||
int (*media_changed) (struct gendisk *);
|
|
||||||
void (*unlock_native_capacity) (struct gendisk *);
|
void (*unlock_native_capacity) (struct gendisk *);
|
||||||
int (*revalidate_disk) (struct gendisk *);
|
int (*revalidate_disk) (struct gendisk *);
|
||||||
int (*getgeo)(struct block_device *, struct hd_geometry *);
|
int (*getgeo)(struct block_device *, struct hd_geometry *);
|
||||||
@ -483,14 +482,13 @@ release: yes
|
|||||||
ioctl: no
|
ioctl: no
|
||||||
compat_ioctl: no
|
compat_ioctl: no
|
||||||
direct_access: no
|
direct_access: no
|
||||||
media_changed: no
|
|
||||||
unlock_native_capacity: no
|
unlock_native_capacity: no
|
||||||
revalidate_disk: no
|
revalidate_disk: no
|
||||||
getgeo: no
|
getgeo: no
|
||||||
swap_slot_free_notify: no (see below)
|
swap_slot_free_notify: no (see below)
|
||||||
======================= ===================
|
======================= ===================
|
||||||
|
|
||||||
media_changed, unlock_native_capacity and revalidate_disk are called only from
|
unlock_native_capacity and revalidate_disk are called only from
|
||||||
check_disk_change().
|
check_disk_change().
|
||||||
|
|
||||||
swap_slot_free_notify is called with swap_lock and sometimes the page lock
|
swap_slot_free_notify is called with swap_lock and sometimes the page lock
|
||||||
|
@ -1453,7 +1453,7 @@ function-trace, we get a much larger output::
|
|||||||
=> __blk_run_queue_uncond
|
=> __blk_run_queue_uncond
|
||||||
=> __blk_run_queue
|
=> __blk_run_queue
|
||||||
=> blk_queue_bio
|
=> blk_queue_bio
|
||||||
=> generic_make_request
|
=> submit_bio_noacct
|
||||||
=> submit_bio
|
=> submit_bio
|
||||||
=> submit_bh
|
=> submit_bh
|
||||||
=> __ext3_get_inode_loc
|
=> __ext3_get_inode_loc
|
||||||
@ -1738,7 +1738,7 @@ tracers.
|
|||||||
=> __blk_run_queue_uncond
|
=> __blk_run_queue_uncond
|
||||||
=> __blk_run_queue
|
=> __blk_run_queue
|
||||||
=> blk_queue_bio
|
=> blk_queue_bio
|
||||||
=> generic_make_request
|
=> submit_bio_noacct
|
||||||
=> submit_bio
|
=> submit_bio
|
||||||
=> submit_bh
|
=> submit_bh
|
||||||
=> ext3_bread
|
=> ext3_bread
|
||||||
|
@ -59,9 +59,9 @@ struct nfhd_device {
|
|||||||
struct gendisk *disk;
|
struct gendisk *disk;
|
||||||
};
|
};
|
||||||
|
|
||||||
static blk_qc_t nfhd_make_request(struct request_queue *queue, struct bio *bio)
|
static blk_qc_t nfhd_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct nfhd_device *dev = queue->queuedata;
|
struct nfhd_device *dev = bio->bi_disk->private_data;
|
||||||
struct bio_vec bvec;
|
struct bio_vec bvec;
|
||||||
struct bvec_iter iter;
|
struct bvec_iter iter;
|
||||||
int dir, len, shift;
|
int dir, len, shift;
|
||||||
@ -93,6 +93,7 @@ static int nfhd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
|||||||
|
|
||||||
static const struct block_device_operations nfhd_ops = {
|
static const struct block_device_operations nfhd_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = nfhd_submit_bio,
|
||||||
.getgeo = nfhd_getgeo,
|
.getgeo = nfhd_getgeo,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -118,11 +119,10 @@ static int __init nfhd_init_one(int id, u32 blocks, u32 bsize)
|
|||||||
dev->bsize = bsize;
|
dev->bsize = bsize;
|
||||||
dev->bshift = ffs(bsize) - 10;
|
dev->bshift = ffs(bsize) - 10;
|
||||||
|
|
||||||
dev->queue = blk_alloc_queue(nfhd_make_request, NUMA_NO_NODE);
|
dev->queue = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (dev->queue == NULL)
|
if (dev->queue == NULL)
|
||||||
goto free_dev;
|
goto free_dev;
|
||||||
|
|
||||||
dev->queue->queuedata = dev;
|
|
||||||
blk_queue_logical_block_size(dev->queue, bsize);
|
blk_queue_logical_block_size(dev->queue, bsize);
|
||||||
|
|
||||||
dev->disk = alloc_disk(16);
|
dev->disk = alloc_disk(16);
|
||||||
|
@ -101,9 +101,9 @@ static void simdisk_transfer(struct simdisk *dev, unsigned long sector,
|
|||||||
spin_unlock(&dev->lock);
|
spin_unlock(&dev->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t simdisk_make_request(struct request_queue *q, struct bio *bio)
|
static blk_qc_t simdisk_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct simdisk *dev = q->queuedata;
|
struct simdisk *dev = bio->bi_disk->private_data;
|
||||||
struct bio_vec bvec;
|
struct bio_vec bvec;
|
||||||
struct bvec_iter iter;
|
struct bvec_iter iter;
|
||||||
sector_t sector = bio->bi_iter.bi_sector;
|
sector_t sector = bio->bi_iter.bi_sector;
|
||||||
@ -127,8 +127,6 @@ static int simdisk_open(struct block_device *bdev, fmode_t mode)
|
|||||||
struct simdisk *dev = bdev->bd_disk->private_data;
|
struct simdisk *dev = bdev->bd_disk->private_data;
|
||||||
|
|
||||||
spin_lock(&dev->lock);
|
spin_lock(&dev->lock);
|
||||||
if (!dev->users)
|
|
||||||
check_disk_change(bdev);
|
|
||||||
++dev->users;
|
++dev->users;
|
||||||
spin_unlock(&dev->lock);
|
spin_unlock(&dev->lock);
|
||||||
return 0;
|
return 0;
|
||||||
@ -144,6 +142,7 @@ static void simdisk_release(struct gendisk *disk, fmode_t mode)
|
|||||||
|
|
||||||
static const struct block_device_operations simdisk_ops = {
|
static const struct block_device_operations simdisk_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = simdisk_submit_bio,
|
||||||
.open = simdisk_open,
|
.open = simdisk_open,
|
||||||
.release = simdisk_release,
|
.release = simdisk_release,
|
||||||
};
|
};
|
||||||
@ -267,14 +266,12 @@ static int __init simdisk_setup(struct simdisk *dev, int which,
|
|||||||
spin_lock_init(&dev->lock);
|
spin_lock_init(&dev->lock);
|
||||||
dev->users = 0;
|
dev->users = 0;
|
||||||
|
|
||||||
dev->queue = blk_alloc_queue(simdisk_make_request, NUMA_NO_NODE);
|
dev->queue = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (dev->queue == NULL) {
|
if (dev->queue == NULL) {
|
||||||
pr_err("blk_alloc_queue failed\n");
|
pr_err("blk_alloc_queue failed\n");
|
||||||
goto out_alloc_queue;
|
goto out_alloc_queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->queue->queuedata = dev;
|
|
||||||
|
|
||||||
dev->gd = alloc_disk(SIMDISK_MINORS);
|
dev->gd = alloc_disk(SIMDISK_MINORS);
|
||||||
if (dev->gd == NULL) {
|
if (dev->gd == NULL) {
|
||||||
pr_err("alloc_disk failed\n");
|
pr_err("alloc_disk failed\n");
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-sysfs.o \
|
obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-sysfs.o \
|
||||||
blk-flush.o blk-settings.o blk-ioc.o blk-map.o \
|
blk-flush.o blk-settings.o blk-ioc.o blk-map.o \
|
||||||
blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \
|
blk-exec.o blk-merge.o blk-timeout.o \
|
||||||
blk-lib.o blk-mq.o blk-mq-tag.o blk-stat.o \
|
blk-lib.o blk-mq.o blk-mq-tag.o blk-stat.o \
|
||||||
blk-mq-sysfs.o blk-mq-cpumap.o blk-mq-sched.o ioctl.o \
|
blk-mq-sysfs.o blk-mq-cpumap.o blk-mq-sched.o ioctl.o \
|
||||||
genhd.o ioprio.o badblocks.o partitions/ blk-rq-qos.o
|
genhd.o ioprio.o badblocks.o partitions/ blk-rq-qos.o
|
||||||
|
@ -4714,7 +4714,7 @@ static struct request *__bfq_dispatch_request(struct blk_mq_hw_ctx *hctx)
|
|||||||
* some unlucky request wait for as long as the device
|
* some unlucky request wait for as long as the device
|
||||||
* wishes.
|
* wishes.
|
||||||
*
|
*
|
||||||
* Of course, serving one request at at time may cause loss of
|
* Of course, serving one request at a time may cause loss of
|
||||||
* throughput.
|
* throughput.
|
||||||
*/
|
*/
|
||||||
if (bfqd->strict_guarantees && bfqd->rq_in_driver > 0)
|
if (bfqd->strict_guarantees && bfqd->rq_in_driver > 0)
|
||||||
|
165
block/bio.c
165
block/bio.c
@ -234,8 +234,12 @@ fallback:
|
|||||||
|
|
||||||
void bio_uninit(struct bio *bio)
|
void bio_uninit(struct bio *bio)
|
||||||
{
|
{
|
||||||
bio_disassociate_blkg(bio);
|
#ifdef CONFIG_BLK_CGROUP
|
||||||
|
if (bio->bi_blkg) {
|
||||||
|
blkg_put(bio->bi_blkg);
|
||||||
|
bio->bi_blkg = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (bio_integrity(bio))
|
if (bio_integrity(bio))
|
||||||
bio_integrity_free(bio);
|
bio_integrity_free(bio);
|
||||||
|
|
||||||
@ -354,7 +358,7 @@ static void bio_alloc_rescue(struct work_struct *work)
|
|||||||
if (!bio)
|
if (!bio)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,19 +416,19 @@ static void punt_bios_to_rescuer(struct bio_set *bs)
|
|||||||
* submit the previously allocated bio for IO before attempting to allocate
|
* submit the previously allocated bio for IO before attempting to allocate
|
||||||
* a new one. Failure to do so can cause deadlocks under memory pressure.
|
* a new one. Failure to do so can cause deadlocks under memory pressure.
|
||||||
*
|
*
|
||||||
* Note that when running under generic_make_request() (i.e. any block
|
* Note that when running under submit_bio_noacct() (i.e. any block
|
||||||
* driver), bios are not submitted until after you return - see the code in
|
* driver), bios are not submitted until after you return - see the code in
|
||||||
* generic_make_request() that converts recursion into iteration, to prevent
|
* submit_bio_noacct() that converts recursion into iteration, to prevent
|
||||||
* stack overflows.
|
* stack overflows.
|
||||||
*
|
*
|
||||||
* This would normally mean allocating multiple bios under
|
* This would normally mean allocating multiple bios under
|
||||||
* generic_make_request() would be susceptible to deadlocks, but we have
|
* submit_bio_noacct() would be susceptible to deadlocks, but we have
|
||||||
* deadlock avoidance code that resubmits any blocked bios from a rescuer
|
* deadlock avoidance code that resubmits any blocked bios from a rescuer
|
||||||
* thread.
|
* thread.
|
||||||
*
|
*
|
||||||
* However, we do not guarantee forward progress for allocations from other
|
* However, we do not guarantee forward progress for allocations from other
|
||||||
* mempools. Doing multiple allocations from the same mempool under
|
* mempools. Doing multiple allocations from the same mempool under
|
||||||
* generic_make_request() should be avoided - instead, use bio_set's front_pad
|
* submit_bio_noacct() should be avoided - instead, use bio_set's front_pad
|
||||||
* for per bio allocations.
|
* for per bio allocations.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* RETURNS:
|
||||||
@ -444,9 +448,7 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, unsigned int nr_iovecs,
|
|||||||
if (nr_iovecs > UIO_MAXIOV)
|
if (nr_iovecs > UIO_MAXIOV)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
p = kmalloc(sizeof(struct bio) +
|
p = kmalloc(struct_size(bio, bi_inline_vecs, nr_iovecs), gfp_mask);
|
||||||
nr_iovecs * sizeof(struct bio_vec),
|
|
||||||
gfp_mask);
|
|
||||||
front_pad = 0;
|
front_pad = 0;
|
||||||
inline_vecs = nr_iovecs;
|
inline_vecs = nr_iovecs;
|
||||||
} else {
|
} else {
|
||||||
@ -455,14 +457,14 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, unsigned int nr_iovecs,
|
|||||||
nr_iovecs > 0))
|
nr_iovecs > 0))
|
||||||
return NULL;
|
return NULL;
|
||||||
/*
|
/*
|
||||||
* generic_make_request() converts recursion to iteration; this
|
* submit_bio_noacct() converts recursion to iteration; this
|
||||||
* means if we're running beneath it, any bios we allocate and
|
* means if we're running beneath it, any bios we allocate and
|
||||||
* submit will not be submitted (and thus freed) until after we
|
* submit will not be submitted (and thus freed) until after we
|
||||||
* return.
|
* return.
|
||||||
*
|
*
|
||||||
* This exposes us to a potential deadlock if we allocate
|
* This exposes us to a potential deadlock if we allocate
|
||||||
* multiple bios from the same bio_set() while running
|
* multiple bios from the same bio_set() while running
|
||||||
* underneath generic_make_request(). If we were to allocate
|
* underneath submit_bio_noacct(). If we were to allocate
|
||||||
* multiple bios (say a stacking block driver that was splitting
|
* multiple bios (say a stacking block driver that was splitting
|
||||||
* bios), we would deadlock if we exhausted the mempool's
|
* bios), we would deadlock if we exhausted the mempool's
|
||||||
* reserve.
|
* reserve.
|
||||||
@ -860,7 +862,7 @@ EXPORT_SYMBOL(bio_add_pc_page);
|
|||||||
* @same_page: return if the segment has been merged inside the same page
|
* @same_page: return if the segment has been merged inside the same page
|
||||||
*
|
*
|
||||||
* Try to add the data at @page + @off to the last bvec of @bio. This is a
|
* Try to add the data at @page + @off to the last bvec of @bio. This is a
|
||||||
* a useful optimisation for file systems with a block size smaller than the
|
* useful optimisation for file systems with a block size smaller than the
|
||||||
* page size.
|
* page size.
|
||||||
*
|
*
|
||||||
* Warn if (@len, @off) crosses pages in case that @same_page is true.
|
* Warn if (@len, @off) crosses pages in case that @same_page is true.
|
||||||
@ -986,7 +988,7 @@ static int __bio_iov_bvec_add_pages(struct bio *bio, struct iov_iter *iter)
|
|||||||
* Pins pages from *iter and appends them to @bio's bvec array. The
|
* Pins pages from *iter and appends them to @bio's bvec array. The
|
||||||
* pages will have to be released using put_page() when done.
|
* pages will have to be released using put_page() when done.
|
||||||
* For multi-segment *iter, this function only adds pages from the
|
* For multi-segment *iter, this function only adds pages from the
|
||||||
* the next non-empty segment of the iov iterator.
|
* next non-empty segment of the iov iterator.
|
||||||
*/
|
*/
|
||||||
static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
|
static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
|
||||||
{
|
{
|
||||||
@ -1625,141 +1627,6 @@ int bioset_init_from_src(struct bio_set *bs, struct bio_set *src)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bioset_init_from_src);
|
EXPORT_SYMBOL(bioset_init_from_src);
|
||||||
|
|
||||||
#ifdef CONFIG_BLK_CGROUP
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bio_disassociate_blkg - puts back the blkg reference if associated
|
|
||||||
* @bio: target bio
|
|
||||||
*
|
|
||||||
* Helper to disassociate the blkg from @bio if a blkg is associated.
|
|
||||||
*/
|
|
||||||
void bio_disassociate_blkg(struct bio *bio)
|
|
||||||
{
|
|
||||||
if (bio->bi_blkg) {
|
|
||||||
blkg_put(bio->bi_blkg);
|
|
||||||
bio->bi_blkg = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(bio_disassociate_blkg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __bio_associate_blkg - associate a bio with the a blkg
|
|
||||||
* @bio: target bio
|
|
||||||
* @blkg: the blkg to associate
|
|
||||||
*
|
|
||||||
* This tries to associate @bio with the specified @blkg. Association failure
|
|
||||||
* is handled by walking up the blkg tree. Therefore, the blkg associated can
|
|
||||||
* be anything between @blkg and the root_blkg. This situation only happens
|
|
||||||
* when a cgroup is dying and then the remaining bios will spill to the closest
|
|
||||||
* alive blkg.
|
|
||||||
*
|
|
||||||
* A reference will be taken on the @blkg and will be released when @bio is
|
|
||||||
* freed.
|
|
||||||
*/
|
|
||||||
static void __bio_associate_blkg(struct bio *bio, struct blkcg_gq *blkg)
|
|
||||||
{
|
|
||||||
bio_disassociate_blkg(bio);
|
|
||||||
|
|
||||||
bio->bi_blkg = blkg_tryget_closest(blkg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bio_associate_blkg_from_css - associate a bio with a specified css
|
|
||||||
* @bio: target bio
|
|
||||||
* @css: target css
|
|
||||||
*
|
|
||||||
* Associate @bio with the blkg found by combining the css's blkg and the
|
|
||||||
* request_queue of the @bio. This falls back to the queue's root_blkg if
|
|
||||||
* the association fails with the css.
|
|
||||||
*/
|
|
||||||
void bio_associate_blkg_from_css(struct bio *bio,
|
|
||||||
struct cgroup_subsys_state *css)
|
|
||||||
{
|
|
||||||
struct request_queue *q = bio->bi_disk->queue;
|
|
||||||
struct blkcg_gq *blkg;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
if (!css || !css->parent)
|
|
||||||
blkg = q->root_blkg;
|
|
||||||
else
|
|
||||||
blkg = blkg_lookup_create(css_to_blkcg(css), q);
|
|
||||||
|
|
||||||
__bio_associate_blkg(bio, blkg);
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(bio_associate_blkg_from_css);
|
|
||||||
|
|
||||||
#ifdef CONFIG_MEMCG
|
|
||||||
/**
|
|
||||||
* bio_associate_blkg_from_page - associate a bio with the page's blkg
|
|
||||||
* @bio: target bio
|
|
||||||
* @page: the page to lookup the blkcg from
|
|
||||||
*
|
|
||||||
* Associate @bio with the blkg from @page's owning memcg and the respective
|
|
||||||
* request_queue. If cgroup_e_css returns %NULL, fall back to the queue's
|
|
||||||
* root_blkg.
|
|
||||||
*/
|
|
||||||
void bio_associate_blkg_from_page(struct bio *bio, struct page *page)
|
|
||||||
{
|
|
||||||
struct cgroup_subsys_state *css;
|
|
||||||
|
|
||||||
if (!page->mem_cgroup)
|
|
||||||
return;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
css = cgroup_e_css(page->mem_cgroup->css.cgroup, &io_cgrp_subsys);
|
|
||||||
bio_associate_blkg_from_css(bio, css);
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_MEMCG */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bio_associate_blkg - associate a bio with a blkg
|
|
||||||
* @bio: target bio
|
|
||||||
*
|
|
||||||
* Associate @bio with the blkg found from the bio's css and request_queue.
|
|
||||||
* If one is not found, bio_lookup_blkg() creates the blkg. If a blkg is
|
|
||||||
* already associated, the css is reused and association redone as the
|
|
||||||
* request_queue may have changed.
|
|
||||||
*/
|
|
||||||
void bio_associate_blkg(struct bio *bio)
|
|
||||||
{
|
|
||||||
struct cgroup_subsys_state *css;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
if (bio->bi_blkg)
|
|
||||||
css = &bio_blkcg(bio)->css;
|
|
||||||
else
|
|
||||||
css = blkcg_css();
|
|
||||||
|
|
||||||
bio_associate_blkg_from_css(bio, css);
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(bio_associate_blkg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bio_clone_blkg_association - clone blkg association from src to dst bio
|
|
||||||
* @dst: destination bio
|
|
||||||
* @src: source bio
|
|
||||||
*/
|
|
||||||
void bio_clone_blkg_association(struct bio *dst, struct bio *src)
|
|
||||||
{
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
if (src->bi_blkg)
|
|
||||||
__bio_associate_blkg(dst, src->bi_blkg);
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(bio_clone_blkg_association);
|
|
||||||
#endif /* CONFIG_BLK_CGROUP */
|
|
||||||
|
|
||||||
static void __init biovec_init_slabs(void)
|
static void __init biovec_init_slabs(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -95,9 +95,6 @@ static void __blkg_release(struct rcu_head *rcu)
|
|||||||
css_put(&blkg->blkcg->css);
|
css_put(&blkg->blkcg->css);
|
||||||
if (blkg->parent)
|
if (blkg->parent)
|
||||||
blkg_put(blkg->parent);
|
blkg_put(blkg->parent);
|
||||||
|
|
||||||
wb_congested_put(blkg->wb_congested);
|
|
||||||
|
|
||||||
blkg_free(blkg);
|
blkg_free(blkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +224,6 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
|
|||||||
struct blkcg_gq *new_blkg)
|
struct blkcg_gq *new_blkg)
|
||||||
{
|
{
|
||||||
struct blkcg_gq *blkg;
|
struct blkcg_gq *blkg;
|
||||||
struct bdi_writeback_congested *wb_congested;
|
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
WARN_ON_ONCE(!rcu_read_lock_held());
|
||||||
@ -245,31 +241,22 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
|
|||||||
goto err_free_blkg;
|
goto err_free_blkg;
|
||||||
}
|
}
|
||||||
|
|
||||||
wb_congested = wb_congested_get_create(q->backing_dev_info,
|
|
||||||
blkcg->css.id,
|
|
||||||
GFP_NOWAIT | __GFP_NOWARN);
|
|
||||||
if (!wb_congested) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto err_put_css;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate */
|
/* allocate */
|
||||||
if (!new_blkg) {
|
if (!new_blkg) {
|
||||||
new_blkg = blkg_alloc(blkcg, q, GFP_NOWAIT | __GFP_NOWARN);
|
new_blkg = blkg_alloc(blkcg, q, GFP_NOWAIT | __GFP_NOWARN);
|
||||||
if (unlikely(!new_blkg)) {
|
if (unlikely(!new_blkg)) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_put_congested;
|
goto err_put_css;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blkg = new_blkg;
|
blkg = new_blkg;
|
||||||
blkg->wb_congested = wb_congested;
|
|
||||||
|
|
||||||
/* link parent */
|
/* link parent */
|
||||||
if (blkcg_parent(blkcg)) {
|
if (blkcg_parent(blkcg)) {
|
||||||
blkg->parent = __blkg_lookup(blkcg_parent(blkcg), q, false);
|
blkg->parent = __blkg_lookup(blkcg_parent(blkcg), q, false);
|
||||||
if (WARN_ON_ONCE(!blkg->parent)) {
|
if (WARN_ON_ONCE(!blkg->parent)) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto err_put_congested;
|
goto err_put_css;
|
||||||
}
|
}
|
||||||
blkg_get(blkg->parent);
|
blkg_get(blkg->parent);
|
||||||
}
|
}
|
||||||
@ -306,8 +293,6 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
|
|||||||
blkg_put(blkg);
|
blkg_put(blkg);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
err_put_congested:
|
|
||||||
wb_congested_put(wb_congested);
|
|
||||||
err_put_css:
|
err_put_css:
|
||||||
css_put(&blkcg->css);
|
css_put(&blkcg->css);
|
||||||
err_free_blkg:
|
err_free_blkg:
|
||||||
@ -316,30 +301,35 @@ err_free_blkg:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __blkg_lookup_create - lookup blkg, try to create one if not there
|
* blkg_lookup_create - lookup blkg, try to create one if not there
|
||||||
* @blkcg: blkcg of interest
|
* @blkcg: blkcg of interest
|
||||||
* @q: request_queue of interest
|
* @q: request_queue of interest
|
||||||
*
|
*
|
||||||
* Lookup blkg for the @blkcg - @q pair. If it doesn't exist, try to
|
* Lookup blkg for the @blkcg - @q pair. If it doesn't exist, try to
|
||||||
* create one. blkg creation is performed recursively from blkcg_root such
|
* create one. blkg creation is performed recursively from blkcg_root such
|
||||||
* that all non-root blkg's have access to the parent blkg. This function
|
* that all non-root blkg's have access to the parent blkg. This function
|
||||||
* should be called under RCU read lock and @q->queue_lock.
|
* should be called under RCU read lock and takes @q->queue_lock.
|
||||||
*
|
*
|
||||||
* Returns the blkg or the closest blkg if blkg_create() fails as it walks
|
* Returns the blkg or the closest blkg if blkg_create() fails as it walks
|
||||||
* down from root.
|
* down from root.
|
||||||
*/
|
*/
|
||||||
struct blkcg_gq *__blkg_lookup_create(struct blkcg *blkcg,
|
static struct blkcg_gq *blkg_lookup_create(struct blkcg *blkcg,
|
||||||
struct request_queue *q)
|
struct request_queue *q)
|
||||||
{
|
{
|
||||||
struct blkcg_gq *blkg;
|
struct blkcg_gq *blkg;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
WARN_ON_ONCE(!rcu_read_lock_held());
|
||||||
lockdep_assert_held(&q->queue_lock);
|
|
||||||
|
|
||||||
blkg = __blkg_lookup(blkcg, q, true);
|
blkg = blkg_lookup(blkcg, q);
|
||||||
if (blkg)
|
if (blkg)
|
||||||
return blkg;
|
return blkg;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&q->queue_lock, flags);
|
||||||
|
blkg = __blkg_lookup(blkcg, q, true);
|
||||||
|
if (blkg)
|
||||||
|
goto found;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create blkgs walking down from blkcg_root to @blkcg, so that all
|
* Create blkgs walking down from blkcg_root to @blkcg, so that all
|
||||||
* non-root blkgs have access to their parents. Returns the closest
|
* non-root blkgs have access to their parents. Returns the closest
|
||||||
@ -362,34 +352,16 @@ struct blkcg_gq *__blkg_lookup_create(struct blkcg *blkcg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
blkg = blkg_create(pos, q, NULL);
|
blkg = blkg_create(pos, q, NULL);
|
||||||
if (IS_ERR(blkg))
|
if (IS_ERR(blkg)) {
|
||||||
return ret_blkg;
|
blkg = ret_blkg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (pos == blkcg)
|
if (pos == blkcg)
|
||||||
return blkg;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* blkg_lookup_create - find or create a blkg
|
|
||||||
* @blkcg: target block cgroup
|
|
||||||
* @q: target request_queue
|
|
||||||
*
|
|
||||||
* This looks up or creates the blkg representing the unique pair
|
|
||||||
* of the blkcg and the request_queue.
|
|
||||||
*/
|
|
||||||
struct blkcg_gq *blkg_lookup_create(struct blkcg *blkcg,
|
|
||||||
struct request_queue *q)
|
|
||||||
{
|
|
||||||
struct blkcg_gq *blkg = blkg_lookup(blkcg, q);
|
|
||||||
|
|
||||||
if (unlikely(!blkg)) {
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&q->queue_lock, flags);
|
|
||||||
blkg = __blkg_lookup_create(blkcg, q);
|
|
||||||
spin_unlock_irqrestore(&q->queue_lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
found:
|
||||||
|
spin_unlock_irqrestore(&q->queue_lock, flags);
|
||||||
return blkg;
|
return blkg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,12 +711,137 @@ void blkg_conf_finish(struct blkg_conf_ctx *ctx)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(blkg_conf_finish);
|
EXPORT_SYMBOL_GPL(blkg_conf_finish);
|
||||||
|
|
||||||
|
static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < BLKG_IOSTAT_NR; i++) {
|
||||||
|
dst->bytes[i] = src->bytes[i];
|
||||||
|
dst->ios[i] = src->ios[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blkg_iostat_add(struct blkg_iostat *dst, struct blkg_iostat *src)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < BLKG_IOSTAT_NR; i++) {
|
||||||
|
dst->bytes[i] += src->bytes[i];
|
||||||
|
dst->ios[i] += src->ios[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blkg_iostat_sub(struct blkg_iostat *dst, struct blkg_iostat *src)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < BLKG_IOSTAT_NR; i++) {
|
||||||
|
dst->bytes[i] -= src->bytes[i];
|
||||||
|
dst->ios[i] -= src->ios[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
|
||||||
|
{
|
||||||
|
struct blkcg *blkcg = css_to_blkcg(css);
|
||||||
|
struct blkcg_gq *blkg;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
hlist_for_each_entry_rcu(blkg, &blkcg->blkg_list, blkcg_node) {
|
||||||
|
struct blkcg_gq *parent = blkg->parent;
|
||||||
|
struct blkg_iostat_set *bisc = per_cpu_ptr(blkg->iostat_cpu, cpu);
|
||||||
|
struct blkg_iostat cur, delta;
|
||||||
|
unsigned int seq;
|
||||||
|
|
||||||
|
/* fetch the current per-cpu values */
|
||||||
|
do {
|
||||||
|
seq = u64_stats_fetch_begin(&bisc->sync);
|
||||||
|
blkg_iostat_set(&cur, &bisc->cur);
|
||||||
|
} while (u64_stats_fetch_retry(&bisc->sync, seq));
|
||||||
|
|
||||||
|
/* propagate percpu delta to global */
|
||||||
|
u64_stats_update_begin(&blkg->iostat.sync);
|
||||||
|
blkg_iostat_set(&delta, &cur);
|
||||||
|
blkg_iostat_sub(&delta, &bisc->last);
|
||||||
|
blkg_iostat_add(&blkg->iostat.cur, &delta);
|
||||||
|
blkg_iostat_add(&bisc->last, &delta);
|
||||||
|
u64_stats_update_end(&blkg->iostat.sync);
|
||||||
|
|
||||||
|
/* propagate global delta to parent */
|
||||||
|
if (parent) {
|
||||||
|
u64_stats_update_begin(&parent->iostat.sync);
|
||||||
|
blkg_iostat_set(&delta, &blkg->iostat.cur);
|
||||||
|
blkg_iostat_sub(&delta, &blkg->iostat.last);
|
||||||
|
blkg_iostat_add(&parent->iostat.cur, &delta);
|
||||||
|
blkg_iostat_add(&blkg->iostat.last, &delta);
|
||||||
|
u64_stats_update_end(&parent->iostat.sync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The rstat algorithms intentionally don't handle the root cgroup to avoid
|
||||||
|
* incurring overhead when no cgroups are defined. For that reason,
|
||||||
|
* cgroup_rstat_flush in blkcg_print_stat does not actually fill out the
|
||||||
|
* iostat in the root cgroup's blkcg_gq.
|
||||||
|
*
|
||||||
|
* However, we would like to re-use the printing code between the root and
|
||||||
|
* non-root cgroups to the extent possible. For that reason, we simulate
|
||||||
|
* flushing the root cgroup's stats by explicitly filling in the iostat
|
||||||
|
* with disk level statistics.
|
||||||
|
*/
|
||||||
|
static void blkcg_fill_root_iostats(void)
|
||||||
|
{
|
||||||
|
struct class_dev_iter iter;
|
||||||
|
struct device *dev;
|
||||||
|
|
||||||
|
class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
|
||||||
|
while ((dev = class_dev_iter_next(&iter))) {
|
||||||
|
struct gendisk *disk = dev_to_disk(dev);
|
||||||
|
struct hd_struct *part = disk_get_part(disk, 0);
|
||||||
|
struct blkcg_gq *blkg = blk_queue_root_blkg(disk->queue);
|
||||||
|
struct blkg_iostat tmp;
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
memset(&tmp, 0, sizeof(tmp));
|
||||||
|
for_each_possible_cpu(cpu) {
|
||||||
|
struct disk_stats *cpu_dkstats;
|
||||||
|
|
||||||
|
cpu_dkstats = per_cpu_ptr(part->dkstats, cpu);
|
||||||
|
tmp.ios[BLKG_IOSTAT_READ] +=
|
||||||
|
cpu_dkstats->ios[STAT_READ];
|
||||||
|
tmp.ios[BLKG_IOSTAT_WRITE] +=
|
||||||
|
cpu_dkstats->ios[STAT_WRITE];
|
||||||
|
tmp.ios[BLKG_IOSTAT_DISCARD] +=
|
||||||
|
cpu_dkstats->ios[STAT_DISCARD];
|
||||||
|
// convert sectors to bytes
|
||||||
|
tmp.bytes[BLKG_IOSTAT_READ] +=
|
||||||
|
cpu_dkstats->sectors[STAT_READ] << 9;
|
||||||
|
tmp.bytes[BLKG_IOSTAT_WRITE] +=
|
||||||
|
cpu_dkstats->sectors[STAT_WRITE] << 9;
|
||||||
|
tmp.bytes[BLKG_IOSTAT_DISCARD] +=
|
||||||
|
cpu_dkstats->sectors[STAT_DISCARD] << 9;
|
||||||
|
|
||||||
|
u64_stats_update_begin(&blkg->iostat.sync);
|
||||||
|
blkg_iostat_set(&blkg->iostat.cur, &tmp);
|
||||||
|
u64_stats_update_end(&blkg->iostat.sync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int blkcg_print_stat(struct seq_file *sf, void *v)
|
static int blkcg_print_stat(struct seq_file *sf, void *v)
|
||||||
{
|
{
|
||||||
struct blkcg *blkcg = css_to_blkcg(seq_css(sf));
|
struct blkcg *blkcg = css_to_blkcg(seq_css(sf));
|
||||||
struct blkcg_gq *blkg;
|
struct blkcg_gq *blkg;
|
||||||
|
|
||||||
cgroup_rstat_flush(blkcg->css.cgroup);
|
if (!seq_css(sf)->parent)
|
||||||
|
blkcg_fill_root_iostats();
|
||||||
|
else
|
||||||
|
cgroup_rstat_flush(blkcg->css.cgroup);
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
hlist_for_each_entry_rcu(blkg, &blkcg->blkg_list, blkcg_node) {
|
hlist_for_each_entry_rcu(blkg, &blkcg->blkg_list, blkcg_node) {
|
||||||
@ -833,7 +930,6 @@ static int blkcg_print_stat(struct seq_file *sf, void *v)
|
|||||||
static struct cftype blkcg_files[] = {
|
static struct cftype blkcg_files[] = {
|
||||||
{
|
{
|
||||||
.name = "stat",
|
.name = "stat",
|
||||||
.flags = CFTYPE_NOT_ON_ROOT,
|
|
||||||
.seq_show = blkcg_print_stat,
|
.seq_show = blkcg_print_stat,
|
||||||
},
|
},
|
||||||
{ } /* terminate */
|
{ } /* terminate */
|
||||||
@ -1025,7 +1121,7 @@ static int blkcg_css_online(struct cgroup_subsys_state *css)
|
|||||||
* blkcg_init_queue - initialize blkcg part of request queue
|
* blkcg_init_queue - initialize blkcg part of request queue
|
||||||
* @q: request_queue to initialize
|
* @q: request_queue to initialize
|
||||||
*
|
*
|
||||||
* Called from __blk_alloc_queue(). Responsible for initializing blkcg
|
* Called from blk_alloc_queue(). Responsible for initializing blkcg
|
||||||
* part of new request_queue @q.
|
* part of new request_queue @q.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* RETURNS:
|
||||||
@ -1114,77 +1210,6 @@ static int blkcg_can_attach(struct cgroup_taskset *tset)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < BLKG_IOSTAT_NR; i++) {
|
|
||||||
dst->bytes[i] = src->bytes[i];
|
|
||||||
dst->ios[i] = src->ios[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void blkg_iostat_add(struct blkg_iostat *dst, struct blkg_iostat *src)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < BLKG_IOSTAT_NR; i++) {
|
|
||||||
dst->bytes[i] += src->bytes[i];
|
|
||||||
dst->ios[i] += src->ios[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void blkg_iostat_sub(struct blkg_iostat *dst, struct blkg_iostat *src)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < BLKG_IOSTAT_NR; i++) {
|
|
||||||
dst->bytes[i] -= src->bytes[i];
|
|
||||||
dst->ios[i] -= src->ios[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
|
|
||||||
{
|
|
||||||
struct blkcg *blkcg = css_to_blkcg(css);
|
|
||||||
struct blkcg_gq *blkg;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
hlist_for_each_entry_rcu(blkg, &blkcg->blkg_list, blkcg_node) {
|
|
||||||
struct blkcg_gq *parent = blkg->parent;
|
|
||||||
struct blkg_iostat_set *bisc = per_cpu_ptr(blkg->iostat_cpu, cpu);
|
|
||||||
struct blkg_iostat cur, delta;
|
|
||||||
unsigned seq;
|
|
||||||
|
|
||||||
/* fetch the current per-cpu values */
|
|
||||||
do {
|
|
||||||
seq = u64_stats_fetch_begin(&bisc->sync);
|
|
||||||
blkg_iostat_set(&cur, &bisc->cur);
|
|
||||||
} while (u64_stats_fetch_retry(&bisc->sync, seq));
|
|
||||||
|
|
||||||
/* propagate percpu delta to global */
|
|
||||||
u64_stats_update_begin(&blkg->iostat.sync);
|
|
||||||
blkg_iostat_set(&delta, &cur);
|
|
||||||
blkg_iostat_sub(&delta, &bisc->last);
|
|
||||||
blkg_iostat_add(&blkg->iostat.cur, &delta);
|
|
||||||
blkg_iostat_add(&bisc->last, &delta);
|
|
||||||
u64_stats_update_end(&blkg->iostat.sync);
|
|
||||||
|
|
||||||
/* propagate global delta to parent */
|
|
||||||
if (parent) {
|
|
||||||
u64_stats_update_begin(&parent->iostat.sync);
|
|
||||||
blkg_iostat_set(&delta, &blkg->iostat.cur);
|
|
||||||
blkg_iostat_sub(&delta, &blkg->iostat.last);
|
|
||||||
blkg_iostat_add(&parent->iostat.cur, &delta);
|
|
||||||
blkg_iostat_add(&blkg->iostat.last, &delta);
|
|
||||||
u64_stats_update_end(&parent->iostat.sync);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void blkcg_bind(struct cgroup_subsys_state *root_css)
|
static void blkcg_bind(struct cgroup_subsys_state *root_css)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -1727,6 +1752,139 @@ void blkcg_add_delay(struct blkcg_gq *blkg, u64 now, u64 delta)
|
|||||||
atomic64_add(delta, &blkg->delay_nsec);
|
atomic64_add(delta, &blkg->delay_nsec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* blkg_tryget_closest - try and get a blkg ref on the closet blkg
|
||||||
|
* @bio: target bio
|
||||||
|
* @css: target css
|
||||||
|
*
|
||||||
|
* As the failure mode here is to walk up the blkg tree, this ensure that the
|
||||||
|
* blkg->parent pointers are always valid. This returns the blkg that it ended
|
||||||
|
* up taking a reference on or %NULL if no reference was taken.
|
||||||
|
*/
|
||||||
|
static inline struct blkcg_gq *blkg_tryget_closest(struct bio *bio,
|
||||||
|
struct cgroup_subsys_state *css)
|
||||||
|
{
|
||||||
|
struct blkcg_gq *blkg, *ret_blkg = NULL;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
blkg = blkg_lookup_create(css_to_blkcg(css), bio->bi_disk->queue);
|
||||||
|
while (blkg) {
|
||||||
|
if (blkg_tryget(blkg)) {
|
||||||
|
ret_blkg = blkg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
blkg = blkg->parent;
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
return ret_blkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bio_associate_blkg_from_css - associate a bio with a specified css
|
||||||
|
* @bio: target bio
|
||||||
|
* @css: target css
|
||||||
|
*
|
||||||
|
* Associate @bio with the blkg found by combining the css's blkg and the
|
||||||
|
* request_queue of the @bio. An association failure is handled by walking up
|
||||||
|
* the blkg tree. Therefore, the blkg associated can be anything between @blkg
|
||||||
|
* and q->root_blkg. This situation only happens when a cgroup is dying and
|
||||||
|
* then the remaining bios will spill to the closest alive blkg.
|
||||||
|
*
|
||||||
|
* A reference will be taken on the blkg and will be released when @bio is
|
||||||
|
* freed.
|
||||||
|
*/
|
||||||
|
void bio_associate_blkg_from_css(struct bio *bio,
|
||||||
|
struct cgroup_subsys_state *css)
|
||||||
|
{
|
||||||
|
if (bio->bi_blkg)
|
||||||
|
blkg_put(bio->bi_blkg);
|
||||||
|
|
||||||
|
if (css && css->parent) {
|
||||||
|
bio->bi_blkg = blkg_tryget_closest(bio, css);
|
||||||
|
} else {
|
||||||
|
blkg_get(bio->bi_disk->queue->root_blkg);
|
||||||
|
bio->bi_blkg = bio->bi_disk->queue->root_blkg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(bio_associate_blkg_from_css);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bio_associate_blkg - associate a bio with a blkg
|
||||||
|
* @bio: target bio
|
||||||
|
*
|
||||||
|
* Associate @bio with the blkg found from the bio's css and request_queue.
|
||||||
|
* If one is not found, bio_lookup_blkg() creates the blkg. If a blkg is
|
||||||
|
* already associated, the css is reused and association redone as the
|
||||||
|
* request_queue may have changed.
|
||||||
|
*/
|
||||||
|
void bio_associate_blkg(struct bio *bio)
|
||||||
|
{
|
||||||
|
struct cgroup_subsys_state *css;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
if (bio->bi_blkg)
|
||||||
|
css = &bio_blkcg(bio)->css;
|
||||||
|
else
|
||||||
|
css = blkcg_css();
|
||||||
|
|
||||||
|
bio_associate_blkg_from_css(bio, css);
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(bio_associate_blkg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bio_clone_blkg_association - clone blkg association from src to dst bio
|
||||||
|
* @dst: destination bio
|
||||||
|
* @src: source bio
|
||||||
|
*/
|
||||||
|
void bio_clone_blkg_association(struct bio *dst, struct bio *src)
|
||||||
|
{
|
||||||
|
if (src->bi_blkg) {
|
||||||
|
if (dst->bi_blkg)
|
||||||
|
blkg_put(dst->bi_blkg);
|
||||||
|
blkg_get(src->bi_blkg);
|
||||||
|
dst->bi_blkg = src->bi_blkg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(bio_clone_blkg_association);
|
||||||
|
|
||||||
|
static int blk_cgroup_io_type(struct bio *bio)
|
||||||
|
{
|
||||||
|
if (op_is_discard(bio->bi_opf))
|
||||||
|
return BLKG_IOSTAT_DISCARD;
|
||||||
|
if (op_is_write(bio->bi_opf))
|
||||||
|
return BLKG_IOSTAT_WRITE;
|
||||||
|
return BLKG_IOSTAT_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void blk_cgroup_bio_start(struct bio *bio)
|
||||||
|
{
|
||||||
|
int rwd = blk_cgroup_io_type(bio), cpu;
|
||||||
|
struct blkg_iostat_set *bis;
|
||||||
|
|
||||||
|
cpu = get_cpu();
|
||||||
|
bis = per_cpu_ptr(bio->bi_blkg->iostat_cpu, cpu);
|
||||||
|
u64_stats_update_begin(&bis->sync);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the bio is flagged with BIO_CGROUP_ACCT it means this is a split
|
||||||
|
* bio and we would have already accounted for the size of the bio.
|
||||||
|
*/
|
||||||
|
if (!bio_flagged(bio, BIO_CGROUP_ACCT)) {
|
||||||
|
bio_set_flag(bio, BIO_CGROUP_ACCT);
|
||||||
|
bis->cur.bytes[rwd] += bio->bi_iter.bi_size;
|
||||||
|
}
|
||||||
|
bis->cur.ios[rwd]++;
|
||||||
|
|
||||||
|
u64_stats_update_end(&bis->sync);
|
||||||
|
if (cgroup_subsys_on_dfl(io_cgrp_subsys))
|
||||||
|
cgroup_rstat_updated(bio->bi_blkg->blkcg->css.cgroup, cpu);
|
||||||
|
put_cpu();
|
||||||
|
}
|
||||||
|
|
||||||
static int __init blkcg_init(void)
|
static int __init blkcg_init(void)
|
||||||
{
|
{
|
||||||
blkcg_punt_bio_wq = alloc_workqueue("blkcg_punt_bio",
|
blkcg_punt_bio_wq = alloc_workqueue("blkcg_punt_bio",
|
||||||
|
308
block/blk-core.c
308
block/blk-core.c
@ -51,9 +51,7 @@
|
|||||||
#include "blk-pm.h"
|
#include "blk-pm.h"
|
||||||
#include "blk-rq-qos.h"
|
#include "blk-rq-qos.h"
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
|
||||||
struct dentry *blk_debugfs_root;
|
struct dentry *blk_debugfs_root;
|
||||||
#endif
|
|
||||||
|
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap);
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap);
|
||||||
@ -285,7 +283,7 @@ EXPORT_SYMBOL(blk_dump_rq_flags);
|
|||||||
* A block device may call blk_sync_queue to ensure that any
|
* A block device may call blk_sync_queue to ensure that any
|
||||||
* such activity is cancelled, thus allowing it to release resources
|
* such activity is cancelled, thus allowing it to release resources
|
||||||
* that the callbacks might use. The caller must already have made sure
|
* that the callbacks might use. The caller must already have made sure
|
||||||
* that its ->make_request_fn will not re-add plugging prior to calling
|
* that its ->submit_bio will not re-add plugging prior to calling
|
||||||
* this function.
|
* this function.
|
||||||
*
|
*
|
||||||
* This function does not cancel any asynchronous activity arising
|
* This function does not cancel any asynchronous activity arising
|
||||||
@ -321,6 +319,16 @@ void blk_clear_pm_only(struct request_queue *q)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(blk_clear_pm_only);
|
EXPORT_SYMBOL_GPL(blk_clear_pm_only);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* blk_put_queue - decrement the request_queue refcount
|
||||||
|
* @q: the request_queue structure to decrement the refcount for
|
||||||
|
*
|
||||||
|
* Decrements the refcount of the request_queue kobject. When this reaches 0
|
||||||
|
* we'll have blk_release_queue() called.
|
||||||
|
*
|
||||||
|
* Context: Any context, but the last reference must not be dropped from
|
||||||
|
* atomic context.
|
||||||
|
*/
|
||||||
void blk_put_queue(struct request_queue *q)
|
void blk_put_queue(struct request_queue *q)
|
||||||
{
|
{
|
||||||
kobject_put(&q->kobj);
|
kobject_put(&q->kobj);
|
||||||
@ -352,9 +360,14 @@ EXPORT_SYMBOL_GPL(blk_set_queue_dying);
|
|||||||
*
|
*
|
||||||
* Mark @q DYING, drain all pending requests, mark @q DEAD, destroy and
|
* Mark @q DYING, drain all pending requests, mark @q DEAD, destroy and
|
||||||
* put it. All future requests will be failed immediately with -ENODEV.
|
* put it. All future requests will be failed immediately with -ENODEV.
|
||||||
|
*
|
||||||
|
* Context: can sleep
|
||||||
*/
|
*/
|
||||||
void blk_cleanup_queue(struct request_queue *q)
|
void blk_cleanup_queue(struct request_queue *q)
|
||||||
{
|
{
|
||||||
|
/* cannot be called from atomic context */
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
WARN_ON_ONCE(blk_queue_registered(q));
|
WARN_ON_ONCE(blk_queue_registered(q));
|
||||||
|
|
||||||
/* mark @q DYING, no new request or merges will be allowed afterwards */
|
/* mark @q DYING, no new request or merges will be allowed afterwards */
|
||||||
@ -497,7 +510,7 @@ static void blk_timeout_work(struct work_struct *work)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
struct request_queue *__blk_alloc_queue(int node_id)
|
struct request_queue *blk_alloc_queue(int node_id)
|
||||||
{
|
{
|
||||||
struct request_queue *q;
|
struct request_queue *q;
|
||||||
int ret;
|
int ret;
|
||||||
@ -540,9 +553,7 @@ struct request_queue *__blk_alloc_queue(int node_id)
|
|||||||
|
|
||||||
kobject_init(&q->kobj, &blk_queue_ktype);
|
kobject_init(&q->kobj, &blk_queue_ktype);
|
||||||
|
|
||||||
#ifdef CONFIG_BLK_DEV_IO_TRACE
|
mutex_init(&q->debugfs_mutex);
|
||||||
mutex_init(&q->blk_trace_mutex);
|
|
||||||
#endif
|
|
||||||
mutex_init(&q->sysfs_lock);
|
mutex_init(&q->sysfs_lock);
|
||||||
mutex_init(&q->sysfs_dir_lock);
|
mutex_init(&q->sysfs_dir_lock);
|
||||||
spin_lock_init(&q->queue_lock);
|
spin_lock_init(&q->queue_lock);
|
||||||
@ -564,6 +575,7 @@ struct request_queue *__blk_alloc_queue(int node_id)
|
|||||||
|
|
||||||
blk_queue_dma_alignment(q, 511);
|
blk_queue_dma_alignment(q, 511);
|
||||||
blk_set_default_limits(&q->limits);
|
blk_set_default_limits(&q->limits);
|
||||||
|
q->nr_requests = BLKDEV_MAX_RQ;
|
||||||
|
|
||||||
return q;
|
return q;
|
||||||
|
|
||||||
@ -581,23 +593,16 @@ fail_q:
|
|||||||
kmem_cache_free(blk_requestq_cachep, q);
|
kmem_cache_free(blk_requestq_cachep, q);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct request_queue *blk_alloc_queue(make_request_fn make_request, int node_id)
|
|
||||||
{
|
|
||||||
struct request_queue *q;
|
|
||||||
|
|
||||||
if (WARN_ON_ONCE(!make_request))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
q = __blk_alloc_queue(node_id);
|
|
||||||
if (!q)
|
|
||||||
return NULL;
|
|
||||||
q->make_request_fn = make_request;
|
|
||||||
q->nr_requests = BLKDEV_MAX_RQ;
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(blk_alloc_queue);
|
EXPORT_SYMBOL(blk_alloc_queue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* blk_get_queue - increment the request_queue refcount
|
||||||
|
* @q: the request_queue structure to increment the refcount for
|
||||||
|
*
|
||||||
|
* Increment the refcount of the request_queue kobject.
|
||||||
|
*
|
||||||
|
* Context: Any context.
|
||||||
|
*/
|
||||||
bool blk_get_queue(struct request_queue *q)
|
bool blk_get_queue(struct request_queue *q)
|
||||||
{
|
{
|
||||||
if (likely(!blk_queue_dying(q))) {
|
if (likely(!blk_queue_dying(q))) {
|
||||||
@ -850,8 +855,7 @@ static inline bool bio_check_ro(struct bio *bio, struct hd_struct *part)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
WARN_ONCE(1,
|
WARN_ONCE(1,
|
||||||
"generic_make_request: Trying to write "
|
"Trying to write to read-only block-device %s (partno %d)\n",
|
||||||
"to read-only block-device %s (partno %d)\n",
|
|
||||||
bio_devname(bio, b), part->partno);
|
bio_devname(bio, b), part->partno);
|
||||||
/* Older lvm-tools actually trigger this */
|
/* Older lvm-tools actually trigger this */
|
||||||
return false;
|
return false;
|
||||||
@ -952,25 +956,13 @@ static inline blk_status_t blk_check_zone_append(struct request_queue *q,
|
|||||||
return BLK_STS_OK;
|
return BLK_STS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline_for_stack bool
|
static noinline_for_stack bool submit_bio_checks(struct bio *bio)
|
||||||
generic_make_request_checks(struct bio *bio)
|
|
||||||
{
|
{
|
||||||
struct request_queue *q;
|
struct request_queue *q = bio->bi_disk->queue;
|
||||||
int nr_sectors = bio_sectors(bio);
|
|
||||||
blk_status_t status = BLK_STS_IOERR;
|
blk_status_t status = BLK_STS_IOERR;
|
||||||
char b[BDEVNAME_SIZE];
|
|
||||||
|
|
||||||
might_sleep();
|
might_sleep();
|
||||||
|
|
||||||
q = bio->bi_disk->queue;
|
|
||||||
if (unlikely(!q)) {
|
|
||||||
printk(KERN_ERR
|
|
||||||
"generic_make_request: Trying to access "
|
|
||||||
"nonexistent block-device %s (%Lu)\n",
|
|
||||||
bio_devname(bio, b), (long long)bio->bi_iter.bi_sector);
|
|
||||||
goto end_io;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For a REQ_NOWAIT based request, return -EOPNOTSUPP
|
* For a REQ_NOWAIT based request, return -EOPNOTSUPP
|
||||||
* if queue is not a request based queue.
|
* if queue is not a request based queue.
|
||||||
@ -992,14 +984,13 @@ generic_make_request_checks(struct bio *bio)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Filter flush bio's early so that make_request based
|
* Filter flush bio's early so that bio based drivers without flush
|
||||||
* drivers without flush support don't have to worry
|
* support don't have to worry about them.
|
||||||
* about them.
|
|
||||||
*/
|
*/
|
||||||
if (op_is_flush(bio->bi_opf) &&
|
if (op_is_flush(bio->bi_opf) &&
|
||||||
!test_bit(QUEUE_FLAG_WC, &q->queue_flags)) {
|
!test_bit(QUEUE_FLAG_WC, &q->queue_flags)) {
|
||||||
bio->bi_opf &= ~(REQ_PREFLUSH | REQ_FUA);
|
bio->bi_opf &= ~(REQ_PREFLUSH | REQ_FUA);
|
||||||
if (!nr_sectors) {
|
if (!bio_sectors(bio)) {
|
||||||
status = BLK_STS_OK;
|
status = BLK_STS_OK;
|
||||||
goto end_io;
|
goto end_io;
|
||||||
}
|
}
|
||||||
@ -1054,8 +1045,13 @@ generic_make_request_checks(struct bio *bio)
|
|||||||
if (unlikely(!current->io_context))
|
if (unlikely(!current->io_context))
|
||||||
create_task_io_context(current, GFP_ATOMIC, q->node);
|
create_task_io_context(current, GFP_ATOMIC, q->node);
|
||||||
|
|
||||||
if (!blkcg_bio_issue_check(q, bio))
|
if (blk_throtl_bio(bio)) {
|
||||||
|
blkcg_bio_issue_init(bio);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
blk_cgroup_bio_start(bio);
|
||||||
|
blkcg_bio_issue_init(bio);
|
||||||
|
|
||||||
if (!bio_flagged(bio, BIO_TRACE_COMPLETION)) {
|
if (!bio_flagged(bio, BIO_TRACE_COMPLETION)) {
|
||||||
trace_block_bio_queue(q, bio);
|
trace_block_bio_queue(q, bio);
|
||||||
@ -1074,22 +1070,116 @@ end_io:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t do_make_request(struct bio *bio)
|
static blk_qc_t __submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct request_queue *q = bio->bi_disk->queue;
|
struct gendisk *disk = bio->bi_disk;
|
||||||
blk_qc_t ret = BLK_QC_T_NONE;
|
blk_qc_t ret = BLK_QC_T_NONE;
|
||||||
|
|
||||||
if (blk_crypto_bio_prep(&bio)) {
|
if (blk_crypto_bio_prep(&bio)) {
|
||||||
if (!q->make_request_fn)
|
if (!disk->fops->submit_bio)
|
||||||
return blk_mq_make_request(q, bio);
|
return blk_mq_submit_bio(bio);
|
||||||
ret = q->make_request_fn(q, bio);
|
ret = disk->fops->submit_bio(bio);
|
||||||
}
|
}
|
||||||
blk_queue_exit(q);
|
blk_queue_exit(disk->queue);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The loop in this function may be a bit non-obvious, and so deserves some
|
||||||
|
* explanation:
|
||||||
|
*
|
||||||
|
* - Before entering the loop, bio->bi_next is NULL (as all callers ensure
|
||||||
|
* that), so we have a list with a single bio.
|
||||||
|
* - We pretend that we have just taken it off a longer list, so we assign
|
||||||
|
* bio_list to a pointer to the bio_list_on_stack, thus initialising the
|
||||||
|
* bio_list of new bios to be added. ->submit_bio() may indeed add some more
|
||||||
|
* bios through a recursive call to submit_bio_noacct. If it did, we find a
|
||||||
|
* non-NULL value in bio_list and re-enter the loop from the top.
|
||||||
|
* - In this case we really did just take the bio of the top of the list (no
|
||||||
|
* pretending) and so remove it from bio_list, and call into ->submit_bio()
|
||||||
|
* again.
|
||||||
|
*
|
||||||
|
* bio_list_on_stack[0] contains bios submitted by the current ->submit_bio.
|
||||||
|
* bio_list_on_stack[1] contains bios that were submitted before the current
|
||||||
|
* ->submit_bio_bio, but that haven't been processed yet.
|
||||||
|
*/
|
||||||
|
static blk_qc_t __submit_bio_noacct(struct bio *bio)
|
||||||
|
{
|
||||||
|
struct bio_list bio_list_on_stack[2];
|
||||||
|
blk_qc_t ret = BLK_QC_T_NONE;
|
||||||
|
|
||||||
|
BUG_ON(bio->bi_next);
|
||||||
|
|
||||||
|
bio_list_init(&bio_list_on_stack[0]);
|
||||||
|
current->bio_list = bio_list_on_stack;
|
||||||
|
|
||||||
|
do {
|
||||||
|
struct request_queue *q = bio->bi_disk->queue;
|
||||||
|
struct bio_list lower, same;
|
||||||
|
|
||||||
|
if (unlikely(bio_queue_enter(bio) != 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a fresh bio_list for all subordinate requests.
|
||||||
|
*/
|
||||||
|
bio_list_on_stack[1] = bio_list_on_stack[0];
|
||||||
|
bio_list_init(&bio_list_on_stack[0]);
|
||||||
|
|
||||||
|
ret = __submit_bio(bio);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sort new bios into those for a lower level and those for the
|
||||||
|
* same level.
|
||||||
|
*/
|
||||||
|
bio_list_init(&lower);
|
||||||
|
bio_list_init(&same);
|
||||||
|
while ((bio = bio_list_pop(&bio_list_on_stack[0])) != NULL)
|
||||||
|
if (q == bio->bi_disk->queue)
|
||||||
|
bio_list_add(&same, bio);
|
||||||
|
else
|
||||||
|
bio_list_add(&lower, bio);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now assemble so we handle the lowest level first.
|
||||||
|
*/
|
||||||
|
bio_list_merge(&bio_list_on_stack[0], &lower);
|
||||||
|
bio_list_merge(&bio_list_on_stack[0], &same);
|
||||||
|
bio_list_merge(&bio_list_on_stack[0], &bio_list_on_stack[1]);
|
||||||
|
} while ((bio = bio_list_pop(&bio_list_on_stack[0])));
|
||||||
|
|
||||||
|
current->bio_list = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static blk_qc_t __submit_bio_noacct_mq(struct bio *bio)
|
||||||
|
{
|
||||||
|
struct bio_list bio_list[2] = { };
|
||||||
|
blk_qc_t ret = BLK_QC_T_NONE;
|
||||||
|
|
||||||
|
current->bio_list = bio_list;
|
||||||
|
|
||||||
|
do {
|
||||||
|
struct gendisk *disk = bio->bi_disk;
|
||||||
|
|
||||||
|
if (unlikely(bio_queue_enter(bio) != 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!blk_crypto_bio_prep(&bio)) {
|
||||||
|
blk_queue_exit(disk->queue);
|
||||||
|
ret = BLK_QC_T_NONE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = blk_mq_submit_bio(bio);
|
||||||
|
} while ((bio = bio_list_pop(&bio_list[0])));
|
||||||
|
|
||||||
|
current->bio_list = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generic_make_request - re-submit a bio to the block device layer for I/O
|
* submit_bio_noacct - re-submit a bio to the block device layer for I/O
|
||||||
* @bio: The bio describing the location in memory and on the device.
|
* @bio: The bio describing the location in memory and on the device.
|
||||||
*
|
*
|
||||||
* This is a version of submit_bio() that shall only be used for I/O that is
|
* This is a version of submit_bio() that shall only be used for I/O that is
|
||||||
@ -1097,115 +1187,27 @@ static blk_qc_t do_make_request(struct bio *bio)
|
|||||||
* systems and other upper level users of the block layer should use
|
* systems and other upper level users of the block layer should use
|
||||||
* submit_bio() instead.
|
* submit_bio() instead.
|
||||||
*/
|
*/
|
||||||
blk_qc_t generic_make_request(struct bio *bio)
|
blk_qc_t submit_bio_noacct(struct bio *bio)
|
||||||
{
|
{
|
||||||
/*
|
if (!submit_bio_checks(bio))
|
||||||
* bio_list_on_stack[0] contains bios submitted by the current
|
return BLK_QC_T_NONE;
|
||||||
* make_request_fn.
|
|
||||||
* bio_list_on_stack[1] contains bios that were submitted before
|
|
||||||
* the current make_request_fn, but that haven't been processed
|
|
||||||
* yet.
|
|
||||||
*/
|
|
||||||
struct bio_list bio_list_on_stack[2];
|
|
||||||
blk_qc_t ret = BLK_QC_T_NONE;
|
|
||||||
|
|
||||||
if (!generic_make_request_checks(bio))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We only want one ->make_request_fn to be active at a time, else
|
* We only want one ->submit_bio to be active at a time, else stack
|
||||||
* stack usage with stacked devices could be a problem. So use
|
* usage with stacked devices could be a problem. Use current->bio_list
|
||||||
* current->bio_list to keep a list of requests submited by a
|
* to collect a list of requests submited by a ->submit_bio method while
|
||||||
* make_request_fn function. current->bio_list is also used as a
|
* it is active, and then process them after it returned.
|
||||||
* flag to say if generic_make_request is currently active in this
|
|
||||||
* task or not. If it is NULL, then no make_request is active. If
|
|
||||||
* it is non-NULL, then a make_request is active, and new requests
|
|
||||||
* should be added at the tail
|
|
||||||
*/
|
*/
|
||||||
if (current->bio_list) {
|
if (current->bio_list) {
|
||||||
bio_list_add(¤t->bio_list[0], bio);
|
bio_list_add(¤t->bio_list[0], bio);
|
||||||
goto out;
|
return BLK_QC_T_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* following loop may be a bit non-obvious, and so deserves some
|
if (!bio->bi_disk->fops->submit_bio)
|
||||||
* explanation.
|
return __submit_bio_noacct_mq(bio);
|
||||||
* Before entering the loop, bio->bi_next is NULL (as all callers
|
return __submit_bio_noacct(bio);
|
||||||
* ensure that) so we have a list with a single bio.
|
|
||||||
* We pretend that we have just taken it off a longer list, so
|
|
||||||
* we assign bio_list to a pointer to the bio_list_on_stack,
|
|
||||||
* thus initialising the bio_list of new bios to be
|
|
||||||
* added. ->make_request() may indeed add some more bios
|
|
||||||
* through a recursive call to generic_make_request. If it
|
|
||||||
* did, we find a non-NULL value in bio_list and re-enter the loop
|
|
||||||
* from the top. In this case we really did just take the bio
|
|
||||||
* of the top of the list (no pretending) and so remove it from
|
|
||||||
* bio_list, and call into ->make_request() again.
|
|
||||||
*/
|
|
||||||
BUG_ON(bio->bi_next);
|
|
||||||
bio_list_init(&bio_list_on_stack[0]);
|
|
||||||
current->bio_list = bio_list_on_stack;
|
|
||||||
do {
|
|
||||||
struct request_queue *q = bio->bi_disk->queue;
|
|
||||||
|
|
||||||
if (likely(bio_queue_enter(bio) == 0)) {
|
|
||||||
struct bio_list lower, same;
|
|
||||||
|
|
||||||
/* Create a fresh bio_list for all subordinate requests */
|
|
||||||
bio_list_on_stack[1] = bio_list_on_stack[0];
|
|
||||||
bio_list_init(&bio_list_on_stack[0]);
|
|
||||||
ret = do_make_request(bio);
|
|
||||||
|
|
||||||
/* sort new bios into those for a lower level
|
|
||||||
* and those for the same level
|
|
||||||
*/
|
|
||||||
bio_list_init(&lower);
|
|
||||||
bio_list_init(&same);
|
|
||||||
while ((bio = bio_list_pop(&bio_list_on_stack[0])) != NULL)
|
|
||||||
if (q == bio->bi_disk->queue)
|
|
||||||
bio_list_add(&same, bio);
|
|
||||||
else
|
|
||||||
bio_list_add(&lower, bio);
|
|
||||||
/* now assemble so we handle the lowest level first */
|
|
||||||
bio_list_merge(&bio_list_on_stack[0], &lower);
|
|
||||||
bio_list_merge(&bio_list_on_stack[0], &same);
|
|
||||||
bio_list_merge(&bio_list_on_stack[0], &bio_list_on_stack[1]);
|
|
||||||
}
|
|
||||||
bio = bio_list_pop(&bio_list_on_stack[0]);
|
|
||||||
} while (bio);
|
|
||||||
current->bio_list = NULL; /* deactivate */
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(generic_make_request);
|
EXPORT_SYMBOL(submit_bio_noacct);
|
||||||
|
|
||||||
/**
|
|
||||||
* direct_make_request - hand a buffer directly to its device driver for I/O
|
|
||||||
* @bio: The bio describing the location in memory and on the device.
|
|
||||||
*
|
|
||||||
* This function behaves like generic_make_request(), but does not protect
|
|
||||||
* against recursion. Must only be used if the called driver is known
|
|
||||||
* to be blk-mq based.
|
|
||||||
*/
|
|
||||||
blk_qc_t direct_make_request(struct bio *bio)
|
|
||||||
{
|
|
||||||
struct request_queue *q = bio->bi_disk->queue;
|
|
||||||
|
|
||||||
if (WARN_ON_ONCE(q->make_request_fn)) {
|
|
||||||
bio_io_error(bio);
|
|
||||||
return BLK_QC_T_NONE;
|
|
||||||
}
|
|
||||||
if (!generic_make_request_checks(bio))
|
|
||||||
return BLK_QC_T_NONE;
|
|
||||||
if (unlikely(bio_queue_enter(bio)))
|
|
||||||
return BLK_QC_T_NONE;
|
|
||||||
if (!blk_crypto_bio_prep(&bio)) {
|
|
||||||
blk_queue_exit(q);
|
|
||||||
return BLK_QC_T_NONE;
|
|
||||||
}
|
|
||||||
return blk_mq_make_request(q, bio);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(direct_make_request);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* submit_bio - submit a bio to the block device layer for I/O
|
* submit_bio - submit a bio to the block device layer for I/O
|
||||||
@ -1266,13 +1268,13 @@ blk_qc_t submit_bio(struct bio *bio)
|
|||||||
blk_qc_t ret;
|
blk_qc_t ret;
|
||||||
|
|
||||||
psi_memstall_enter(&pflags);
|
psi_memstall_enter(&pflags);
|
||||||
ret = generic_make_request(bio);
|
ret = submit_bio_noacct(bio);
|
||||||
psi_memstall_leave(&pflags);
|
psi_memstall_leave(&pflags);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return generic_make_request(bio);
|
return submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(submit_bio);
|
EXPORT_SYMBOL(submit_bio);
|
||||||
|
|
||||||
@ -1908,9 +1910,7 @@ int __init blk_dev_init(void)
|
|||||||
blk_requestq_cachep = kmem_cache_create("request_queue",
|
blk_requestq_cachep = kmem_cache_create("request_queue",
|
||||||
sizeof(struct request_queue), 0, SLAB_PANIC, NULL);
|
sizeof(struct request_queue), 0, SLAB_PANIC, NULL);
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
|
||||||
blk_debugfs_root = debugfs_create_dir("block", NULL);
|
blk_debugfs_root = debugfs_create_dir("block", NULL);
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ static bool blk_crypto_split_bio_if_needed(struct bio **bio_ptr)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bio_chain(split_bio, bio);
|
bio_chain(split_bio, bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
*bio_ptr = split_bio;
|
*bio_ptr = split_bio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ void __blk_crypto_free_request(struct request *rq)
|
|||||||
* kernel crypto API. When the crypto API fallback is used for encryption,
|
* kernel crypto API. When the crypto API fallback is used for encryption,
|
||||||
* blk-crypto may choose to split the bio into 2 - the first one that will
|
* blk-crypto may choose to split the bio into 2 - the first one that will
|
||||||
* continue to be processed and the second one that will be resubmitted via
|
* continue to be processed and the second one that will be resubmitted via
|
||||||
* generic_make_request. A bounce bio will be allocated to encrypt the contents
|
* submit_bio_noacct. A bounce bio will be allocated to encrypt the contents
|
||||||
* of the aforementioned "first one", and *bio_ptr will be updated to this
|
* of the aforementioned "first one", and *bio_ptr will be updated to this
|
||||||
* bounce bio.
|
* bounce bio.
|
||||||
*
|
*
|
||||||
|
@ -219,7 +219,6 @@ static void flush_end_io(struct request *flush_rq, blk_status_t error)
|
|||||||
struct request *rq, *n;
|
struct request *rq, *n;
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
struct blk_flush_queue *fq = blk_get_flush_queue(q, flush_rq->mq_ctx);
|
struct blk_flush_queue *fq = blk_get_flush_queue(q, flush_rq->mq_ctx);
|
||||||
struct blk_mq_hw_ctx *hctx;
|
|
||||||
|
|
||||||
blk_account_io_flush(flush_rq);
|
blk_account_io_flush(flush_rq);
|
||||||
|
|
||||||
@ -235,13 +234,11 @@ static void flush_end_io(struct request *flush_rq, blk_status_t error)
|
|||||||
if (fq->rq_status != BLK_STS_OK)
|
if (fq->rq_status != BLK_STS_OK)
|
||||||
error = fq->rq_status;
|
error = fq->rq_status;
|
||||||
|
|
||||||
hctx = flush_rq->mq_hctx;
|
|
||||||
if (!q->elevator) {
|
if (!q->elevator) {
|
||||||
blk_mq_tag_set_rq(hctx, flush_rq->tag, fq->orig_rq);
|
flush_rq->tag = BLK_MQ_NO_TAG;
|
||||||
flush_rq->tag = -1;
|
|
||||||
} else {
|
} else {
|
||||||
blk_mq_put_driver_tag(flush_rq);
|
blk_mq_put_driver_tag(flush_rq);
|
||||||
flush_rq->internal_tag = -1;
|
flush_rq->internal_tag = BLK_MQ_NO_TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
running = &fq->flush_queue[fq->flush_running_idx];
|
running = &fq->flush_queue[fq->flush_running_idx];
|
||||||
@ -286,13 +283,8 @@ static void blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq,
|
|||||||
if (fq->flush_pending_idx != fq->flush_running_idx || list_empty(pending))
|
if (fq->flush_pending_idx != fq->flush_running_idx || list_empty(pending))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* C2 and C3
|
/* C2 and C3 */
|
||||||
*
|
if (!list_empty(&fq->flush_data_in_flight) &&
|
||||||
* For blk-mq + scheduling, we can risk having all driver tags
|
|
||||||
* assigned to empty flushes, and we deadlock if we are expecting
|
|
||||||
* other requests to make progress. Don't defer for that case.
|
|
||||||
*/
|
|
||||||
if (!list_empty(&fq->flush_data_in_flight) && q->elevator &&
|
|
||||||
time_before(jiffies,
|
time_before(jiffies,
|
||||||
fq->flush_pending_since + FLUSH_PENDING_TIMEOUT))
|
fq->flush_pending_since + FLUSH_PENDING_TIMEOUT))
|
||||||
return;
|
return;
|
||||||
@ -316,13 +308,10 @@ static void blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq,
|
|||||||
flush_rq->mq_ctx = first_rq->mq_ctx;
|
flush_rq->mq_ctx = first_rq->mq_ctx;
|
||||||
flush_rq->mq_hctx = first_rq->mq_hctx;
|
flush_rq->mq_hctx = first_rq->mq_hctx;
|
||||||
|
|
||||||
if (!q->elevator) {
|
if (!q->elevator)
|
||||||
fq->orig_rq = first_rq;
|
|
||||||
flush_rq->tag = first_rq->tag;
|
flush_rq->tag = first_rq->tag;
|
||||||
blk_mq_tag_set_rq(flush_rq->mq_hctx, first_rq->tag, flush_rq);
|
else
|
||||||
} else {
|
|
||||||
flush_rq->internal_tag = first_rq->internal_tag;
|
flush_rq->internal_tag = first_rq->internal_tag;
|
||||||
}
|
|
||||||
|
|
||||||
flush_rq->cmd_flags = REQ_OP_FLUSH | REQ_PREFLUSH;
|
flush_rq->cmd_flags = REQ_OP_FLUSH | REQ_PREFLUSH;
|
||||||
flush_rq->cmd_flags |= (flags & REQ_DRV) | (flags & REQ_FAILFAST_MASK);
|
flush_rq->cmd_flags |= (flags & REQ_DRV) | (flags & REQ_FAILFAST_MASK);
|
||||||
|
@ -96,15 +96,7 @@ static void ioc_release_fn(struct work_struct *work)
|
|||||||
{
|
{
|
||||||
struct io_context *ioc = container_of(work, struct io_context,
|
struct io_context *ioc = container_of(work, struct io_context,
|
||||||
release_work);
|
release_work);
|
||||||
unsigned long flags;
|
spin_lock_irq(&ioc->lock);
|
||||||
|
|
||||||
/*
|
|
||||||
* Exiting icq may call into put_io_context() through elevator
|
|
||||||
* which will trigger lockdep warning. The ioc's are guaranteed to
|
|
||||||
* be different, use a different locking subclass here. Use
|
|
||||||
* irqsave variant as there's no spin_lock_irq_nested().
|
|
||||||
*/
|
|
||||||
spin_lock_irqsave_nested(&ioc->lock, flags, 1);
|
|
||||||
|
|
||||||
while (!hlist_empty(&ioc->icq_list)) {
|
while (!hlist_empty(&ioc->icq_list)) {
|
||||||
struct io_cq *icq = hlist_entry(ioc->icq_list.first,
|
struct io_cq *icq = hlist_entry(ioc->icq_list.first,
|
||||||
@ -115,13 +107,27 @@ static void ioc_release_fn(struct work_struct *work)
|
|||||||
ioc_destroy_icq(icq);
|
ioc_destroy_icq(icq);
|
||||||
spin_unlock(&q->queue_lock);
|
spin_unlock(&q->queue_lock);
|
||||||
} else {
|
} else {
|
||||||
spin_unlock_irqrestore(&ioc->lock, flags);
|
/* Make sure q and icq cannot be freed. */
|
||||||
cpu_relax();
|
rcu_read_lock();
|
||||||
spin_lock_irqsave_nested(&ioc->lock, flags, 1);
|
|
||||||
|
/* Re-acquire the locks in the correct order. */
|
||||||
|
spin_unlock(&ioc->lock);
|
||||||
|
spin_lock(&q->queue_lock);
|
||||||
|
spin_lock(&ioc->lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The icq may have been destroyed when the ioc lock
|
||||||
|
* was released.
|
||||||
|
*/
|
||||||
|
if (!(icq->flags & ICQ_DESTROYED))
|
||||||
|
ioc_destroy_icq(icq);
|
||||||
|
|
||||||
|
spin_unlock(&q->queue_lock);
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ioc->lock, flags);
|
spin_unlock_irq(&ioc->lock);
|
||||||
|
|
||||||
kmem_cache_free(iocontext_cachep, ioc);
|
kmem_cache_free(iocontext_cachep, ioc);
|
||||||
}
|
}
|
||||||
@ -170,7 +176,6 @@ void put_io_context(struct io_context *ioc)
|
|||||||
*/
|
*/
|
||||||
void put_io_context_active(struct io_context *ioc)
|
void put_io_context_active(struct io_context *ioc)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
struct io_cq *icq;
|
struct io_cq *icq;
|
||||||
|
|
||||||
if (!atomic_dec_and_test(&ioc->active_ref)) {
|
if (!atomic_dec_and_test(&ioc->active_ref)) {
|
||||||
@ -178,19 +183,14 @@ void put_io_context_active(struct io_context *ioc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
spin_lock_irq(&ioc->lock);
|
||||||
* Need ioc lock to walk icq_list and q lock to exit icq. Perform
|
|
||||||
* reverse double locking. Read comment in ioc_release_fn() for
|
|
||||||
* explanation on the nested locking annotation.
|
|
||||||
*/
|
|
||||||
spin_lock_irqsave_nested(&ioc->lock, flags, 1);
|
|
||||||
hlist_for_each_entry(icq, &ioc->icq_list, ioc_node) {
|
hlist_for_each_entry(icq, &ioc->icq_list, ioc_node) {
|
||||||
if (icq->flags & ICQ_EXITED)
|
if (icq->flags & ICQ_EXITED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ioc_exit_icq(icq);
|
ioc_exit_icq(icq);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&ioc->lock, flags);
|
spin_unlock_irq(&ioc->lock);
|
||||||
|
|
||||||
put_io_context(ioc);
|
put_io_context(ioc);
|
||||||
}
|
}
|
||||||
|
@ -1370,7 +1370,7 @@ static void ioc_timer_fn(struct timer_list *timer)
|
|||||||
* should have woken up in the last period and expire idle iocgs.
|
* should have woken up in the last period and expire idle iocgs.
|
||||||
*/
|
*/
|
||||||
list_for_each_entry_safe(iocg, tiocg, &ioc->active_iocgs, active_list) {
|
list_for_each_entry_safe(iocg, tiocg, &ioc->active_iocgs, active_list) {
|
||||||
if (!waitqueue_active(&iocg->waitq) && iocg->abs_vdebt &&
|
if (!waitqueue_active(&iocg->waitq) && !iocg->abs_vdebt &&
|
||||||
!iocg_is_idle(iocg))
|
!iocg_is_idle(iocg))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -2045,8 +2045,7 @@ static struct blkg_policy_data *ioc_pd_alloc(gfp_t gfp, struct request_queue *q,
|
|||||||
int levels = blkcg->css.cgroup->level + 1;
|
int levels = blkcg->css.cgroup->level + 1;
|
||||||
struct ioc_gq *iocg;
|
struct ioc_gq *iocg;
|
||||||
|
|
||||||
iocg = kzalloc_node(sizeof(*iocg) + levels * sizeof(iocg->ancestors[0]),
|
iocg = kzalloc_node(struct_size(iocg, ancestors, levels), gfp, q->node);
|
||||||
gfp, q->node);
|
|
||||||
if (!iocg)
|
if (!iocg)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -591,7 +591,7 @@ static void blkcg_iolatency_done_bio(struct rq_qos *rqos, struct bio *bio)
|
|||||||
struct rq_wait *rqw;
|
struct rq_wait *rqw;
|
||||||
struct iolatency_grp *iolat;
|
struct iolatency_grp *iolat;
|
||||||
u64 window_start;
|
u64 window_start;
|
||||||
u64 now = ktime_to_ns(ktime_get());
|
u64 now;
|
||||||
bool issue_as_root = bio_issue_as_root_blkg(bio);
|
bool issue_as_root = bio_issue_as_root_blkg(bio);
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
int inflight = 0;
|
int inflight = 0;
|
||||||
@ -608,6 +608,7 @@ static void blkcg_iolatency_done_bio(struct rq_qos *rqos, struct bio *bio)
|
|||||||
if (!enabled)
|
if (!enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
now = ktime_to_ns(ktime_get());
|
||||||
while (blkg && blkg->parent) {
|
while (blkg && blkg->parent) {
|
||||||
iolat = blkg_to_lat(blkg);
|
iolat = blkg_to_lat(blkg);
|
||||||
if (!iolat) {
|
if (!iolat) {
|
||||||
|
@ -29,7 +29,7 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
|
|||||||
struct request_queue *q = bdev_get_queue(bdev);
|
struct request_queue *q = bdev_get_queue(bdev);
|
||||||
struct bio *bio = *biop;
|
struct bio *bio = *biop;
|
||||||
unsigned int op;
|
unsigned int op;
|
||||||
sector_t bs_mask;
|
sector_t bs_mask, part_offset = 0;
|
||||||
|
|
||||||
if (!q)
|
if (!q)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
@ -54,9 +54,34 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
|
|||||||
if (!nr_sects)
|
if (!nr_sects)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* In case the discard request is in a partition */
|
||||||
|
if (bdev->bd_partno)
|
||||||
|
part_offset = bdev->bd_part->start_sect;
|
||||||
|
|
||||||
while (nr_sects) {
|
while (nr_sects) {
|
||||||
sector_t req_sects = min_t(sector_t, nr_sects,
|
sector_t granularity_aligned_lba, req_sects;
|
||||||
bio_allowed_max_sectors(q));
|
sector_t sector_mapped = sector + part_offset;
|
||||||
|
|
||||||
|
granularity_aligned_lba = round_up(sector_mapped,
|
||||||
|
q->limits.discard_granularity >> SECTOR_SHIFT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether the discard bio starts at a discard_granularity
|
||||||
|
* aligned LBA,
|
||||||
|
* - If no: set (granularity_aligned_lba - sector_mapped) to
|
||||||
|
* bi_size of the first split bio, then the second bio will
|
||||||
|
* start at a discard_granularity aligned LBA on the device.
|
||||||
|
* - If yes: use bio_aligned_discard_max_sectors() as the max
|
||||||
|
* possible bi_size of the first split bio. Then when this bio
|
||||||
|
* is split in device drive, the split ones are very probably
|
||||||
|
* to be aligned to discard_granularity of the device's queue.
|
||||||
|
*/
|
||||||
|
if (granularity_aligned_lba == sector_mapped)
|
||||||
|
req_sects = min_t(sector_t, nr_sects,
|
||||||
|
bio_aligned_discard_max_sectors(q));
|
||||||
|
else
|
||||||
|
req_sects = min_t(sector_t, nr_sects,
|
||||||
|
granularity_aligned_lba - sector_mapped);
|
||||||
|
|
||||||
WARN_ON_ONCE((req_sects << 9) > UINT_MAX);
|
WARN_ON_ONCE((req_sects << 9) > UINT_MAX);
|
||||||
|
|
||||||
|
@ -283,20 +283,20 @@ split:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* __blk_queue_split - split a bio and submit the second half
|
* __blk_queue_split - split a bio and submit the second half
|
||||||
* @q: [in] request queue pointer
|
|
||||||
* @bio: [in, out] bio to be split
|
* @bio: [in, out] bio to be split
|
||||||
* @nr_segs: [out] number of segments in the first bio
|
* @nr_segs: [out] number of segments in the first bio
|
||||||
*
|
*
|
||||||
* Split a bio into two bios, chain the two bios, submit the second half and
|
* Split a bio into two bios, chain the two bios, submit the second half and
|
||||||
* store a pointer to the first half in *@bio. If the second bio is still too
|
* store a pointer to the first half in *@bio. If the second bio is still too
|
||||||
* big it will be split by a recursive call to this function. Since this
|
* big it will be split by a recursive call to this function. Since this
|
||||||
* function may allocate a new bio from @q->bio_split, it is the responsibility
|
* function may allocate a new bio from @bio->bi_disk->queue->bio_split, it is
|
||||||
* of the caller to ensure that @q is only released after processing of the
|
* the responsibility of the caller to ensure that
|
||||||
|
* @bio->bi_disk->queue->bio_split is only released after processing of the
|
||||||
* split bio has finished.
|
* split bio has finished.
|
||||||
*/
|
*/
|
||||||
void __blk_queue_split(struct request_queue *q, struct bio **bio,
|
void __blk_queue_split(struct bio **bio, unsigned int *nr_segs)
|
||||||
unsigned int *nr_segs)
|
|
||||||
{
|
{
|
||||||
|
struct request_queue *q = (*bio)->bi_disk->queue;
|
||||||
struct bio *split = NULL;
|
struct bio *split = NULL;
|
||||||
|
|
||||||
switch (bio_op(*bio)) {
|
switch (bio_op(*bio)) {
|
||||||
@ -338,27 +338,26 @@ void __blk_queue_split(struct request_queue *q, struct bio **bio,
|
|||||||
|
|
||||||
bio_chain(split, *bio);
|
bio_chain(split, *bio);
|
||||||
trace_block_split(q, split, (*bio)->bi_iter.bi_sector);
|
trace_block_split(q, split, (*bio)->bi_iter.bi_sector);
|
||||||
generic_make_request(*bio);
|
submit_bio_noacct(*bio);
|
||||||
*bio = split;
|
*bio = split;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* blk_queue_split - split a bio and submit the second half
|
* blk_queue_split - split a bio and submit the second half
|
||||||
* @q: [in] request queue pointer
|
|
||||||
* @bio: [in, out] bio to be split
|
* @bio: [in, out] bio to be split
|
||||||
*
|
*
|
||||||
* Split a bio into two bios, chains the two bios, submit the second half and
|
* Split a bio into two bios, chains the two bios, submit the second half and
|
||||||
* store a pointer to the first half in *@bio. Since this function may allocate
|
* store a pointer to the first half in *@bio. Since this function may allocate
|
||||||
* a new bio from @q->bio_split, it is the responsibility of the caller to
|
* a new bio from @bio->bi_disk->queue->bio_split, it is the responsibility of
|
||||||
* ensure that @q is only released after processing of the split bio has
|
* the caller to ensure that @bio->bi_disk->queue->bio_split is only released
|
||||||
* finished.
|
* after processing of the split bio has finished.
|
||||||
*/
|
*/
|
||||||
void blk_queue_split(struct request_queue *q, struct bio **bio)
|
void blk_queue_split(struct bio **bio)
|
||||||
{
|
{
|
||||||
unsigned int nr_segs;
|
unsigned int nr_segs;
|
||||||
|
|
||||||
__blk_queue_split(q, bio, &nr_segs);
|
__blk_queue_split(bio, &nr_segs);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(blk_queue_split);
|
EXPORT_SYMBOL(blk_queue_split);
|
||||||
|
|
||||||
@ -793,6 +792,8 @@ static struct request *attempt_merge(struct request_queue *q,
|
|||||||
*/
|
*/
|
||||||
blk_account_io_merge_request(next);
|
blk_account_io_merge_request(next);
|
||||||
|
|
||||||
|
trace_block_rq_merge(q, next);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ownership of bio passed from next to req, return 'next' for
|
* ownership of bio passed from next to req, return 'next' for
|
||||||
* the caller to free
|
* the caller to free
|
||||||
|
@ -404,8 +404,7 @@ static bool hctx_show_busy_rq(struct request *rq, void *data, bool reserved)
|
|||||||
const struct show_busy_params *params = data;
|
const struct show_busy_params *params = data;
|
||||||
|
|
||||||
if (rq->mq_hctx == params->hctx)
|
if (rq->mq_hctx == params->hctx)
|
||||||
__blk_mq_debugfs_rq_show(params->m,
|
__blk_mq_debugfs_rq_show(params->m, rq);
|
||||||
list_entry_rq(&rq->queuelist));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -827,9 +826,6 @@ void blk_mq_debugfs_register(struct request_queue *q)
|
|||||||
struct blk_mq_hw_ctx *hctx;
|
struct blk_mq_hw_ctx *hctx;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
q->debugfs_dir = debugfs_create_dir(kobject_name(q->kobj.parent),
|
|
||||||
blk_debugfs_root);
|
|
||||||
|
|
||||||
debugfs_create_files(q->debugfs_dir, q, blk_mq_debugfs_queue_attrs);
|
debugfs_create_files(q->debugfs_dir, q, blk_mq_debugfs_queue_attrs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -860,9 +856,7 @@ void blk_mq_debugfs_register(struct request_queue *q)
|
|||||||
|
|
||||||
void blk_mq_debugfs_unregister(struct request_queue *q)
|
void blk_mq_debugfs_unregister(struct request_queue *q)
|
||||||
{
|
{
|
||||||
debugfs_remove_recursive(q->debugfs_dir);
|
|
||||||
q->sched_debugfs_dir = NULL;
|
q->sched_debugfs_dir = NULL;
|
||||||
q->debugfs_dir = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx,
|
static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx,
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/blk-mq.h>
|
#include <linux/blk-mq.h>
|
||||||
|
#include <linux/list_sort.h>
|
||||||
|
|
||||||
#include <trace/events/block.h>
|
#include <trace/events/block.h>
|
||||||
|
|
||||||
@ -80,6 +81,35 @@ void blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx)
|
|||||||
blk_mq_run_hw_queue(hctx, true);
|
blk_mq_run_hw_queue(hctx, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sched_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
|
||||||
|
{
|
||||||
|
struct request *rqa = container_of(a, struct request, queuelist);
|
||||||
|
struct request *rqb = container_of(b, struct request, queuelist);
|
||||||
|
|
||||||
|
return rqa->mq_hctx > rqb->mq_hctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool blk_mq_dispatch_hctx_list(struct list_head *rq_list)
|
||||||
|
{
|
||||||
|
struct blk_mq_hw_ctx *hctx =
|
||||||
|
list_first_entry(rq_list, struct request, queuelist)->mq_hctx;
|
||||||
|
struct request *rq;
|
||||||
|
LIST_HEAD(hctx_list);
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
list_for_each_entry(rq, rq_list, queuelist) {
|
||||||
|
if (rq->mq_hctx != hctx) {
|
||||||
|
list_cut_before(&hctx_list, rq_list, &rq->queuelist);
|
||||||
|
goto dispatch;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
list_splice_tail_init(rq_list, &hctx_list);
|
||||||
|
|
||||||
|
dispatch:
|
||||||
|
return blk_mq_dispatch_rq_list(hctx, &hctx_list, count);
|
||||||
|
}
|
||||||
|
|
||||||
#define BLK_MQ_BUDGET_DELAY 3 /* ms units */
|
#define BLK_MQ_BUDGET_DELAY 3 /* ms units */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -90,12 +120,20 @@ void blk_mq_sched_restart(struct blk_mq_hw_ctx *hctx)
|
|||||||
* Returns -EAGAIN if hctx->dispatch was found non-empty and run_work has to
|
* Returns -EAGAIN if hctx->dispatch was found non-empty and run_work has to
|
||||||
* be run again. This is necessary to avoid starving flushes.
|
* be run again. This is necessary to avoid starving flushes.
|
||||||
*/
|
*/
|
||||||
static int blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx)
|
static int __blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx)
|
||||||
{
|
{
|
||||||
struct request_queue *q = hctx->queue;
|
struct request_queue *q = hctx->queue;
|
||||||
struct elevator_queue *e = q->elevator;
|
struct elevator_queue *e = q->elevator;
|
||||||
|
bool multi_hctxs = false, run_queue = false;
|
||||||
|
bool dispatched = false, busy = false;
|
||||||
|
unsigned int max_dispatch;
|
||||||
LIST_HEAD(rq_list);
|
LIST_HEAD(rq_list);
|
||||||
int ret = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
if (hctx->dispatch_busy)
|
||||||
|
max_dispatch = 1;
|
||||||
|
else
|
||||||
|
max_dispatch = hctx->queue->nr_requests;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
struct request *rq;
|
struct request *rq;
|
||||||
@ -104,16 +142,16 @@ static int blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (!list_empty_careful(&hctx->dispatch)) {
|
if (!list_empty_careful(&hctx->dispatch)) {
|
||||||
ret = -EAGAIN;
|
busy = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!blk_mq_get_dispatch_budget(hctx))
|
if (!blk_mq_get_dispatch_budget(q))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
rq = e->type->ops.dispatch_request(hctx);
|
rq = e->type->ops.dispatch_request(hctx);
|
||||||
if (!rq) {
|
if (!rq) {
|
||||||
blk_mq_put_dispatch_budget(hctx);
|
blk_mq_put_dispatch_budget(q);
|
||||||
/*
|
/*
|
||||||
* We're releasing without dispatching. Holding the
|
* We're releasing without dispatching. Holding the
|
||||||
* budget could have blocked any "hctx"s with the
|
* budget could have blocked any "hctx"s with the
|
||||||
@ -121,7 +159,7 @@ static int blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx)
|
|||||||
* no guarantee anyone will kick the queue. Kick it
|
* no guarantee anyone will kick the queue. Kick it
|
||||||
* ourselves.
|
* ourselves.
|
||||||
*/
|
*/
|
||||||
blk_mq_delay_run_hw_queues(q, BLK_MQ_BUDGET_DELAY);
|
run_queue = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,8 +168,42 @@ static int blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx)
|
|||||||
* if this rq won't be queued to driver via .queue_rq()
|
* if this rq won't be queued to driver via .queue_rq()
|
||||||
* in blk_mq_dispatch_rq_list().
|
* in blk_mq_dispatch_rq_list().
|
||||||
*/
|
*/
|
||||||
list_add(&rq->queuelist, &rq_list);
|
list_add_tail(&rq->queuelist, &rq_list);
|
||||||
} while (blk_mq_dispatch_rq_list(q, &rq_list, true));
|
if (rq->mq_hctx != hctx)
|
||||||
|
multi_hctxs = true;
|
||||||
|
} while (++count < max_dispatch);
|
||||||
|
|
||||||
|
if (!count) {
|
||||||
|
if (run_queue)
|
||||||
|
blk_mq_delay_run_hw_queues(q, BLK_MQ_BUDGET_DELAY);
|
||||||
|
} else if (multi_hctxs) {
|
||||||
|
/*
|
||||||
|
* Requests from different hctx may be dequeued from some
|
||||||
|
* schedulers, such as bfq and deadline.
|
||||||
|
*
|
||||||
|
* Sort the requests in the list according to their hctx,
|
||||||
|
* dispatch batching requests from same hctx at a time.
|
||||||
|
*/
|
||||||
|
list_sort(NULL, &rq_list, sched_rq_cmp);
|
||||||
|
do {
|
||||||
|
dispatched |= blk_mq_dispatch_hctx_list(&rq_list);
|
||||||
|
} while (!list_empty(&rq_list));
|
||||||
|
} else {
|
||||||
|
dispatched = blk_mq_dispatch_rq_list(hctx, &rq_list, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (busy)
|
||||||
|
return -EAGAIN;
|
||||||
|
return !!dispatched;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = __blk_mq_do_dispatch_sched(hctx);
|
||||||
|
} while (ret == 1);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -153,7 +225,7 @@ static struct blk_mq_ctx *blk_mq_next_ctx(struct blk_mq_hw_ctx *hctx,
|
|||||||
* restart queue if .get_budget() returns BLK_STS_NO_RESOURCE.
|
* restart queue if .get_budget() returns BLK_STS_NO_RESOURCE.
|
||||||
*
|
*
|
||||||
* Returns -EAGAIN if hctx->dispatch was found non-empty and run_work has to
|
* Returns -EAGAIN if hctx->dispatch was found non-empty and run_work has to
|
||||||
* to be run again. This is necessary to avoid starving flushes.
|
* be run again. This is necessary to avoid starving flushes.
|
||||||
*/
|
*/
|
||||||
static int blk_mq_do_dispatch_ctx(struct blk_mq_hw_ctx *hctx)
|
static int blk_mq_do_dispatch_ctx(struct blk_mq_hw_ctx *hctx)
|
||||||
{
|
{
|
||||||
@ -161,10 +233,9 @@ static int blk_mq_do_dispatch_ctx(struct blk_mq_hw_ctx *hctx)
|
|||||||
LIST_HEAD(rq_list);
|
LIST_HEAD(rq_list);
|
||||||
struct blk_mq_ctx *ctx = READ_ONCE(hctx->dispatch_from);
|
struct blk_mq_ctx *ctx = READ_ONCE(hctx->dispatch_from);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct request *rq;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
struct request *rq;
|
|
||||||
|
|
||||||
if (!list_empty_careful(&hctx->dispatch)) {
|
if (!list_empty_careful(&hctx->dispatch)) {
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
break;
|
break;
|
||||||
@ -173,12 +244,12 @@ static int blk_mq_do_dispatch_ctx(struct blk_mq_hw_ctx *hctx)
|
|||||||
if (!sbitmap_any_bit_set(&hctx->ctx_map))
|
if (!sbitmap_any_bit_set(&hctx->ctx_map))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!blk_mq_get_dispatch_budget(hctx))
|
if (!blk_mq_get_dispatch_budget(q))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
rq = blk_mq_dequeue_from_ctx(hctx, ctx);
|
rq = blk_mq_dequeue_from_ctx(hctx, ctx);
|
||||||
if (!rq) {
|
if (!rq) {
|
||||||
blk_mq_put_dispatch_budget(hctx);
|
blk_mq_put_dispatch_budget(q);
|
||||||
/*
|
/*
|
||||||
* We're releasing without dispatching. Holding the
|
* We're releasing without dispatching. Holding the
|
||||||
* budget could have blocked any "hctx"s with the
|
* budget could have blocked any "hctx"s with the
|
||||||
@ -200,7 +271,7 @@ static int blk_mq_do_dispatch_ctx(struct blk_mq_hw_ctx *hctx)
|
|||||||
/* round robin for fair dispatch */
|
/* round robin for fair dispatch */
|
||||||
ctx = blk_mq_next_ctx(hctx, rq->mq_ctx);
|
ctx = blk_mq_next_ctx(hctx, rq->mq_ctx);
|
||||||
|
|
||||||
} while (blk_mq_dispatch_rq_list(q, &rq_list, true));
|
} while (blk_mq_dispatch_rq_list(rq->mq_hctx, &rq_list, 1));
|
||||||
|
|
||||||
WRITE_ONCE(hctx->dispatch_from, ctx);
|
WRITE_ONCE(hctx->dispatch_from, ctx);
|
||||||
return ret;
|
return ret;
|
||||||
@ -240,7 +311,7 @@ static int __blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx)
|
|||||||
*/
|
*/
|
||||||
if (!list_empty(&rq_list)) {
|
if (!list_empty(&rq_list)) {
|
||||||
blk_mq_sched_mark_restart_hctx(hctx);
|
blk_mq_sched_mark_restart_hctx(hctx);
|
||||||
if (blk_mq_dispatch_rq_list(q, &rq_list, false)) {
|
if (blk_mq_dispatch_rq_list(hctx, &rq_list, 0)) {
|
||||||
if (has_sched_dispatch)
|
if (has_sched_dispatch)
|
||||||
ret = blk_mq_do_dispatch_sched(hctx);
|
ret = blk_mq_do_dispatch_sched(hctx);
|
||||||
else
|
else
|
||||||
@ -253,7 +324,7 @@ static int __blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx)
|
|||||||
ret = blk_mq_do_dispatch_ctx(hctx);
|
ret = blk_mq_do_dispatch_ctx(hctx);
|
||||||
} else {
|
} else {
|
||||||
blk_mq_flush_busy_ctxs(hctx, &rq_list);
|
blk_mq_flush_busy_ctxs(hctx, &rq_list);
|
||||||
blk_mq_dispatch_rq_list(q, &rq_list, false);
|
blk_mq_dispatch_rq_list(hctx, &rq_list, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -56,43 +56,12 @@ void __blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx)
|
|||||||
blk_mq_tag_wakeup_all(tags, false);
|
blk_mq_tag_wakeup_all(tags, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* For shared tag users, we track the number of currently active users
|
|
||||||
* and attempt to provide a fair share of the tag depth for each of them.
|
|
||||||
*/
|
|
||||||
static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx,
|
|
||||||
struct sbitmap_queue *bt)
|
|
||||||
{
|
|
||||||
unsigned int depth, users;
|
|
||||||
|
|
||||||
if (!hctx || !(hctx->flags & BLK_MQ_F_TAG_SHARED))
|
|
||||||
return true;
|
|
||||||
if (!test_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Don't try dividing an ant
|
|
||||||
*/
|
|
||||||
if (bt->sb.depth == 1)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
users = atomic_read(&hctx->tags->active_queues);
|
|
||||||
if (!users)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allow at least some tags
|
|
||||||
*/
|
|
||||||
depth = max((bt->sb.depth + users - 1) / users, 4U);
|
|
||||||
return atomic_read(&hctx->nr_active) < depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __blk_mq_get_tag(struct blk_mq_alloc_data *data,
|
static int __blk_mq_get_tag(struct blk_mq_alloc_data *data,
|
||||||
struct sbitmap_queue *bt)
|
struct sbitmap_queue *bt)
|
||||||
{
|
{
|
||||||
if (!(data->flags & BLK_MQ_REQ_INTERNAL) &&
|
if (!data->q->elevator && !hctx_may_queue(data->hctx, bt))
|
||||||
!hctx_may_queue(data->hctx, bt))
|
|
||||||
return BLK_MQ_NO_TAG;
|
return BLK_MQ_NO_TAG;
|
||||||
|
|
||||||
if (data->shallow_depth)
|
if (data->shallow_depth)
|
||||||
return __sbitmap_queue_get_shallow(bt, data->shallow_depth);
|
return __sbitmap_queue_get_shallow(bt, data->shallow_depth);
|
||||||
else
|
else
|
||||||
@ -191,33 +160,6 @@ found_tag:
|
|||||||
return tag + tag_offset;
|
return tag + tag_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __blk_mq_get_driver_tag(struct request *rq)
|
|
||||||
{
|
|
||||||
struct sbitmap_queue *bt = &rq->mq_hctx->tags->bitmap_tags;
|
|
||||||
unsigned int tag_offset = rq->mq_hctx->tags->nr_reserved_tags;
|
|
||||||
bool shared = blk_mq_tag_busy(rq->mq_hctx);
|
|
||||||
int tag;
|
|
||||||
|
|
||||||
if (blk_mq_tag_is_reserved(rq->mq_hctx->sched_tags, rq->internal_tag)) {
|
|
||||||
bt = &rq->mq_hctx->tags->breserved_tags;
|
|
||||||
tag_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hctx_may_queue(rq->mq_hctx, bt))
|
|
||||||
return false;
|
|
||||||
tag = __sbitmap_queue_get(bt);
|
|
||||||
if (tag == BLK_MQ_NO_TAG)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
rq->tag = tag + tag_offset;
|
|
||||||
if (shared) {
|
|
||||||
rq->rq_flags |= RQF_MQ_INFLIGHT;
|
|
||||||
atomic_inc(&rq->mq_hctx->nr_active);
|
|
||||||
}
|
|
||||||
rq->mq_hctx->tags->rqs[rq->tag] = rq;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void blk_mq_put_tag(struct blk_mq_tags *tags, struct blk_mq_ctx *ctx,
|
void blk_mq_put_tag(struct blk_mq_tags *tags, struct blk_mq_ctx *ctx,
|
||||||
unsigned int tag)
|
unsigned int tag)
|
||||||
{
|
{
|
||||||
|
@ -51,14 +51,6 @@ enum {
|
|||||||
BLK_MQ_TAG_MAX = BLK_MQ_NO_TAG - 1,
|
BLK_MQ_TAG_MAX = BLK_MQ_NO_TAG - 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool __blk_mq_get_driver_tag(struct request *rq);
|
|
||||||
static inline bool blk_mq_get_driver_tag(struct request *rq)
|
|
||||||
{
|
|
||||||
if (rq->tag != BLK_MQ_NO_TAG)
|
|
||||||
return true;
|
|
||||||
return __blk_mq_get_driver_tag(rq);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern bool __blk_mq_tag_busy(struct blk_mq_hw_ctx *);
|
extern bool __blk_mq_tag_busy(struct blk_mq_hw_ctx *);
|
||||||
extern void __blk_mq_tag_idle(struct blk_mq_hw_ctx *);
|
extern void __blk_mq_tag_idle(struct blk_mq_hw_ctx *);
|
||||||
|
|
||||||
@ -79,15 +71,34 @@ static inline void blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This helper should only be used for flush request to share tag
|
* For shared tag users, we track the number of currently active users
|
||||||
* with the request cloned from, and both the two requests can't be
|
* and attempt to provide a fair share of the tag depth for each of them.
|
||||||
* in flight at the same time. The caller has to make sure the tag
|
|
||||||
* can't be freed.
|
|
||||||
*/
|
*/
|
||||||
static inline void blk_mq_tag_set_rq(struct blk_mq_hw_ctx *hctx,
|
static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx,
|
||||||
unsigned int tag, struct request *rq)
|
struct sbitmap_queue *bt)
|
||||||
{
|
{
|
||||||
hctx->tags->rqs[tag] = rq;
|
unsigned int depth, users;
|
||||||
|
|
||||||
|
if (!hctx || !(hctx->flags & BLK_MQ_F_TAG_SHARED))
|
||||||
|
return true;
|
||||||
|
if (!test_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't try dividing an ant
|
||||||
|
*/
|
||||||
|
if (bt->sb.depth == 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
users = atomic_read(&hctx->tags->active_queues);
|
||||||
|
if (!users)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allow at least some tags
|
||||||
|
*/
|
||||||
|
depth = max((bt->sb.depth + users - 1) / users, 4U);
|
||||||
|
return atomic_read(&hctx->nr_active) < depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool blk_mq_tag_is_reserved(struct blk_mq_tags *tags,
|
static inline bool blk_mq_tag_is_reserved(struct blk_mq_tags *tags,
|
||||||
|
396
block/blk-mq.c
396
block/blk-mq.c
@ -41,6 +41,8 @@
|
|||||||
#include "blk-mq-sched.h"
|
#include "blk-mq-sched.h"
|
||||||
#include "blk-rq-qos.h"
|
#include "blk-rq-qos.h"
|
||||||
|
|
||||||
|
static DEFINE_PER_CPU(struct list_head, blk_cpu_done);
|
||||||
|
|
||||||
static void blk_mq_poll_stats_start(struct request_queue *q);
|
static void blk_mq_poll_stats_start(struct request_queue *q);
|
||||||
static void blk_mq_poll_stats_fn(struct blk_stat_callback *cb);
|
static void blk_mq_poll_stats_fn(struct blk_stat_callback *cb);
|
||||||
|
|
||||||
@ -275,26 +277,20 @@ static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data,
|
|||||||
{
|
{
|
||||||
struct blk_mq_tags *tags = blk_mq_tags_from_data(data);
|
struct blk_mq_tags *tags = blk_mq_tags_from_data(data);
|
||||||
struct request *rq = tags->static_rqs[tag];
|
struct request *rq = tags->static_rqs[tag];
|
||||||
req_flags_t rq_flags = 0;
|
|
||||||
|
|
||||||
if (data->flags & BLK_MQ_REQ_INTERNAL) {
|
if (data->q->elevator) {
|
||||||
rq->tag = BLK_MQ_NO_TAG;
|
rq->tag = BLK_MQ_NO_TAG;
|
||||||
rq->internal_tag = tag;
|
rq->internal_tag = tag;
|
||||||
} else {
|
} else {
|
||||||
if (data->hctx->flags & BLK_MQ_F_TAG_SHARED) {
|
|
||||||
rq_flags = RQF_MQ_INFLIGHT;
|
|
||||||
atomic_inc(&data->hctx->nr_active);
|
|
||||||
}
|
|
||||||
rq->tag = tag;
|
rq->tag = tag;
|
||||||
rq->internal_tag = BLK_MQ_NO_TAG;
|
rq->internal_tag = BLK_MQ_NO_TAG;
|
||||||
data->hctx->tags->rqs[rq->tag] = rq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* csd/requeue_work/fifo_time is initialized before use */
|
/* csd/requeue_work/fifo_time is initialized before use */
|
||||||
rq->q = data->q;
|
rq->q = data->q;
|
||||||
rq->mq_ctx = data->ctx;
|
rq->mq_ctx = data->ctx;
|
||||||
rq->mq_hctx = data->hctx;
|
rq->mq_hctx = data->hctx;
|
||||||
rq->rq_flags = rq_flags;
|
rq->rq_flags = 0;
|
||||||
rq->cmd_flags = data->cmd_flags;
|
rq->cmd_flags = data->cmd_flags;
|
||||||
if (data->flags & BLK_MQ_REQ_PREEMPT)
|
if (data->flags & BLK_MQ_REQ_PREEMPT)
|
||||||
rq->rq_flags |= RQF_PREEMPT;
|
rq->rq_flags |= RQF_PREEMPT;
|
||||||
@ -362,8 +358,6 @@ static struct request *__blk_mq_alloc_request(struct blk_mq_alloc_data *data)
|
|||||||
data->flags |= BLK_MQ_REQ_NOWAIT;
|
data->flags |= BLK_MQ_REQ_NOWAIT;
|
||||||
|
|
||||||
if (e) {
|
if (e) {
|
||||||
data->flags |= BLK_MQ_REQ_INTERNAL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flush requests are special and go directly to the
|
* Flush requests are special and go directly to the
|
||||||
* dispatch list. Don't include reserved tags in the
|
* dispatch list. Don't include reserved tags in the
|
||||||
@ -378,7 +372,7 @@ static struct request *__blk_mq_alloc_request(struct blk_mq_alloc_data *data)
|
|||||||
retry:
|
retry:
|
||||||
data->ctx = blk_mq_get_ctx(q);
|
data->ctx = blk_mq_get_ctx(q);
|
||||||
data->hctx = blk_mq_map_queue(q, data->cmd_flags, data->ctx);
|
data->hctx = blk_mq_map_queue(q, data->cmd_flags, data->ctx);
|
||||||
if (!(data->flags & BLK_MQ_REQ_INTERNAL))
|
if (!e)
|
||||||
blk_mq_tag_busy(data->hctx);
|
blk_mq_tag_busy(data->hctx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -394,7 +388,7 @@ retry:
|
|||||||
/*
|
/*
|
||||||
* Give up the CPU and sleep for a random short time to ensure
|
* Give up the CPU and sleep for a random short time to ensure
|
||||||
* that thread using a realtime scheduling class are migrated
|
* that thread using a realtime scheduling class are migrated
|
||||||
* off the the CPU, and thus off the hctx that is going away.
|
* off the CPU, and thus off the hctx that is going away.
|
||||||
*/
|
*/
|
||||||
msleep(3);
|
msleep(3);
|
||||||
goto retry;
|
goto retry;
|
||||||
@ -474,9 +468,7 @@ struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
|
|||||||
cpu = cpumask_first_and(data.hctx->cpumask, cpu_online_mask);
|
cpu = cpumask_first_and(data.hctx->cpumask, cpu_online_mask);
|
||||||
data.ctx = __blk_mq_get_ctx(q, cpu);
|
data.ctx = __blk_mq_get_ctx(q, cpu);
|
||||||
|
|
||||||
if (q->elevator)
|
if (!q->elevator)
|
||||||
data.flags |= BLK_MQ_REQ_INTERNAL;
|
|
||||||
else
|
|
||||||
blk_mq_tag_busy(data.hctx);
|
blk_mq_tag_busy(data.hctx);
|
||||||
|
|
||||||
ret = -EWOULDBLOCK;
|
ret = -EWOULDBLOCK;
|
||||||
@ -552,8 +544,7 @@ inline void __blk_mq_end_request(struct request *rq, blk_status_t error)
|
|||||||
blk_stat_add(rq, now);
|
blk_stat_add(rq, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rq->internal_tag != BLK_MQ_NO_TAG)
|
blk_mq_sched_completed_request(rq, now);
|
||||||
blk_mq_sched_completed_request(rq, now);
|
|
||||||
|
|
||||||
blk_account_io_done(rq, now);
|
blk_account_io_done(rq, now);
|
||||||
|
|
||||||
@ -574,71 +565,139 @@ void blk_mq_end_request(struct request *rq, blk_status_t error)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(blk_mq_end_request);
|
EXPORT_SYMBOL(blk_mq_end_request);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Softirq action handler - move entries to local list and loop over them
|
||||||
|
* while passing them to the queue registered handler.
|
||||||
|
*/
|
||||||
|
static __latent_entropy void blk_done_softirq(struct softirq_action *h)
|
||||||
|
{
|
||||||
|
struct list_head *cpu_list, local_list;
|
||||||
|
|
||||||
|
local_irq_disable();
|
||||||
|
cpu_list = this_cpu_ptr(&blk_cpu_done);
|
||||||
|
list_replace_init(cpu_list, &local_list);
|
||||||
|
local_irq_enable();
|
||||||
|
|
||||||
|
while (!list_empty(&local_list)) {
|
||||||
|
struct request *rq;
|
||||||
|
|
||||||
|
rq = list_entry(local_list.next, struct request, ipi_list);
|
||||||
|
list_del_init(&rq->ipi_list);
|
||||||
|
rq->q->mq_ops->complete(rq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blk_mq_trigger_softirq(struct request *rq)
|
||||||
|
{
|
||||||
|
struct list_head *list;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
|
list = this_cpu_ptr(&blk_cpu_done);
|
||||||
|
list_add_tail(&rq->ipi_list, list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the list only contains our just added request, signal a raise of
|
||||||
|
* the softirq. If there are already entries there, someone already
|
||||||
|
* raised the irq but it hasn't run yet.
|
||||||
|
*/
|
||||||
|
if (list->next == &rq->ipi_list)
|
||||||
|
raise_softirq_irqoff(BLOCK_SOFTIRQ);
|
||||||
|
local_irq_restore(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int blk_softirq_cpu_dead(unsigned int cpu)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If a CPU goes away, splice its entries to the current CPU
|
||||||
|
* and trigger a run of the softirq
|
||||||
|
*/
|
||||||
|
local_irq_disable();
|
||||||
|
list_splice_init(&per_cpu(blk_cpu_done, cpu),
|
||||||
|
this_cpu_ptr(&blk_cpu_done));
|
||||||
|
raise_softirq_irqoff(BLOCK_SOFTIRQ);
|
||||||
|
local_irq_enable();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void __blk_mq_complete_request_remote(void *data)
|
static void __blk_mq_complete_request_remote(void *data)
|
||||||
{
|
{
|
||||||
struct request *rq = data;
|
struct request *rq = data;
|
||||||
struct request_queue *q = rq->q;
|
|
||||||
|
|
||||||
q->mq_ops->complete(rq);
|
/*
|
||||||
|
* For most of single queue controllers, there is only one irq vector
|
||||||
|
* for handling I/O completion, and the only irq's affinity is set
|
||||||
|
* to all possible CPUs. On most of ARCHs, this affinity means the irq
|
||||||
|
* is handled on one specific CPU.
|
||||||
|
*
|
||||||
|
* So complete I/O requests in softirq context in case of single queue
|
||||||
|
* devices to avoid degrading I/O performance due to irqsoff latency.
|
||||||
|
*/
|
||||||
|
if (rq->q->nr_hw_queues == 1)
|
||||||
|
blk_mq_trigger_softirq(rq);
|
||||||
|
else
|
||||||
|
rq->q->mq_ops->complete(rq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static inline bool blk_mq_complete_need_ipi(struct request *rq)
|
||||||
* blk_mq_force_complete_rq() - Force complete the request, bypassing any error
|
|
||||||
* injection that could drop the completion.
|
|
||||||
* @rq: Request to be force completed
|
|
||||||
*
|
|
||||||
* Drivers should use blk_mq_complete_request() to complete requests in their
|
|
||||||
* normal IO path. For timeout error recovery, drivers may call this forced
|
|
||||||
* completion routine after they've reclaimed timed out requests to bypass
|
|
||||||
* potentially subsequent fake timeouts.
|
|
||||||
*/
|
|
||||||
void blk_mq_force_complete_rq(struct request *rq)
|
|
||||||
{
|
{
|
||||||
struct blk_mq_ctx *ctx = rq->mq_ctx;
|
int cpu = raw_smp_processor_id();
|
||||||
struct request_queue *q = rq->q;
|
|
||||||
bool shared = false;
|
|
||||||
int cpu;
|
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_SMP) ||
|
||||||
|
!test_bit(QUEUE_FLAG_SAME_COMP, &rq->q->queue_flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* same CPU or cache domain? Complete locally */
|
||||||
|
if (cpu == rq->mq_ctx->cpu ||
|
||||||
|
(!test_bit(QUEUE_FLAG_SAME_FORCE, &rq->q->queue_flags) &&
|
||||||
|
cpus_share_cache(cpu, rq->mq_ctx->cpu)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* don't try to IPI to an offline CPU */
|
||||||
|
return cpu_online(rq->mq_ctx->cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blk_mq_complete_request_remote(struct request *rq)
|
||||||
|
{
|
||||||
WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
|
WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
|
||||||
/*
|
|
||||||
* Most of single queue controllers, there is only one irq vector
|
|
||||||
* for handling IO completion, and the only irq's affinity is set
|
|
||||||
* as all possible CPUs. On most of ARCHs, this affinity means the
|
|
||||||
* irq is handled on one specific CPU.
|
|
||||||
*
|
|
||||||
* So complete IO reqeust in softirq context in case of single queue
|
|
||||||
* for not degrading IO performance by irqsoff latency.
|
|
||||||
*/
|
|
||||||
if (q->nr_hw_queues == 1) {
|
|
||||||
__blk_complete_request(rq);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For a polled request, always complete locallly, it's pointless
|
* For a polled request, always complete locallly, it's pointless
|
||||||
* to redirect the completion.
|
* to redirect the completion.
|
||||||
*/
|
*/
|
||||||
if ((rq->cmd_flags & REQ_HIPRI) ||
|
if (rq->cmd_flags & REQ_HIPRI)
|
||||||
!test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags)) {
|
return false;
|
||||||
q->mq_ops->complete(rq);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu = get_cpu();
|
if (blk_mq_complete_need_ipi(rq)) {
|
||||||
if (!test_bit(QUEUE_FLAG_SAME_FORCE, &q->queue_flags))
|
|
||||||
shared = cpus_share_cache(cpu, ctx->cpu);
|
|
||||||
|
|
||||||
if (cpu != ctx->cpu && !shared && cpu_online(ctx->cpu)) {
|
|
||||||
rq->csd.func = __blk_mq_complete_request_remote;
|
rq->csd.func = __blk_mq_complete_request_remote;
|
||||||
rq->csd.info = rq;
|
rq->csd.info = rq;
|
||||||
rq->csd.flags = 0;
|
rq->csd.flags = 0;
|
||||||
smp_call_function_single_async(ctx->cpu, &rq->csd);
|
smp_call_function_single_async(rq->mq_ctx->cpu, &rq->csd);
|
||||||
} else {
|
} else {
|
||||||
q->mq_ops->complete(rq);
|
if (rq->q->nr_hw_queues > 1)
|
||||||
|
return false;
|
||||||
|
blk_mq_trigger_softirq(rq);
|
||||||
}
|
}
|
||||||
put_cpu();
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(blk_mq_force_complete_rq);
|
EXPORT_SYMBOL_GPL(blk_mq_complete_request_remote);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* blk_mq_complete_request - end I/O on a request
|
||||||
|
* @rq: the request being processed
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Complete a request by scheduling the ->complete_rq operation.
|
||||||
|
**/
|
||||||
|
void blk_mq_complete_request(struct request *rq)
|
||||||
|
{
|
||||||
|
if (!blk_mq_complete_request_remote(rq))
|
||||||
|
rq->q->mq_ops->complete(rq);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(blk_mq_complete_request);
|
||||||
|
|
||||||
static void hctx_unlock(struct blk_mq_hw_ctx *hctx, int srcu_idx)
|
static void hctx_unlock(struct blk_mq_hw_ctx *hctx, int srcu_idx)
|
||||||
__releases(hctx->srcu)
|
__releases(hctx->srcu)
|
||||||
@ -660,23 +719,6 @@ static void hctx_lock(struct blk_mq_hw_ctx *hctx, int *srcu_idx)
|
|||||||
*srcu_idx = srcu_read_lock(hctx->srcu);
|
*srcu_idx = srcu_read_lock(hctx->srcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* blk_mq_complete_request - end I/O on a request
|
|
||||||
* @rq: the request being processed
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Ends all I/O on a request. It does not handle partial completions.
|
|
||||||
* The actual completion happens out-of-order, through a IPI handler.
|
|
||||||
**/
|
|
||||||
bool blk_mq_complete_request(struct request *rq)
|
|
||||||
{
|
|
||||||
if (unlikely(blk_should_fake_timeout(rq->q)))
|
|
||||||
return false;
|
|
||||||
blk_mq_force_complete_rq(rq);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(blk_mq_complete_request);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* blk_mq_start_request - Start processing a request
|
* blk_mq_start_request - Start processing a request
|
||||||
* @rq: Pointer to request to be started
|
* @rq: Pointer to request to be started
|
||||||
@ -1052,6 +1094,45 @@ static inline unsigned int queued_to_index(unsigned int queued)
|
|||||||
return min(BLK_MQ_MAX_DISPATCH_ORDER - 1, ilog2(queued) + 1);
|
return min(BLK_MQ_MAX_DISPATCH_ORDER - 1, ilog2(queued) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool __blk_mq_get_driver_tag(struct request *rq)
|
||||||
|
{
|
||||||
|
struct sbitmap_queue *bt = &rq->mq_hctx->tags->bitmap_tags;
|
||||||
|
unsigned int tag_offset = rq->mq_hctx->tags->nr_reserved_tags;
|
||||||
|
int tag;
|
||||||
|
|
||||||
|
blk_mq_tag_busy(rq->mq_hctx);
|
||||||
|
|
||||||
|
if (blk_mq_tag_is_reserved(rq->mq_hctx->sched_tags, rq->internal_tag)) {
|
||||||
|
bt = &rq->mq_hctx->tags->breserved_tags;
|
||||||
|
tag_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hctx_may_queue(rq->mq_hctx, bt))
|
||||||
|
return false;
|
||||||
|
tag = __sbitmap_queue_get(bt);
|
||||||
|
if (tag == BLK_MQ_NO_TAG)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rq->tag = tag + tag_offset;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool blk_mq_get_driver_tag(struct request *rq)
|
||||||
|
{
|
||||||
|
struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
|
||||||
|
|
||||||
|
if (rq->tag == BLK_MQ_NO_TAG && !__blk_mq_get_driver_tag(rq))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((hctx->flags & BLK_MQ_F_TAG_SHARED) &&
|
||||||
|
!(rq->rq_flags & RQF_MQ_INFLIGHT)) {
|
||||||
|
rq->rq_flags |= RQF_MQ_INFLIGHT;
|
||||||
|
atomic_inc(&hctx->nr_active);
|
||||||
|
}
|
||||||
|
hctx->tags->rqs[rq->tag] = rq;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static int blk_mq_dispatch_wake(wait_queue_entry_t *wait, unsigned mode,
|
static int blk_mq_dispatch_wake(wait_queue_entry_t *wait, unsigned mode,
|
||||||
int flags, void *key)
|
int flags, void *key)
|
||||||
{
|
{
|
||||||
@ -1204,25 +1285,70 @@ static void blk_mq_handle_zone_resource(struct request *rq,
|
|||||||
__blk_mq_requeue_request(rq);
|
__blk_mq_requeue_request(rq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum prep_dispatch {
|
||||||
|
PREP_DISPATCH_OK,
|
||||||
|
PREP_DISPATCH_NO_TAG,
|
||||||
|
PREP_DISPATCH_NO_BUDGET,
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum prep_dispatch blk_mq_prep_dispatch_rq(struct request *rq,
|
||||||
|
bool need_budget)
|
||||||
|
{
|
||||||
|
struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
|
||||||
|
|
||||||
|
if (need_budget && !blk_mq_get_dispatch_budget(rq->q)) {
|
||||||
|
blk_mq_put_driver_tag(rq);
|
||||||
|
return PREP_DISPATCH_NO_BUDGET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blk_mq_get_driver_tag(rq)) {
|
||||||
|
/*
|
||||||
|
* The initial allocation attempt failed, so we need to
|
||||||
|
* rerun the hardware queue when a tag is freed. The
|
||||||
|
* waitqueue takes care of that. If the queue is run
|
||||||
|
* before we add this entry back on the dispatch list,
|
||||||
|
* we'll re-run it below.
|
||||||
|
*/
|
||||||
|
if (!blk_mq_mark_tag_wait(hctx, rq)) {
|
||||||
|
/*
|
||||||
|
* All budgets not got from this function will be put
|
||||||
|
* together during handling partial dispatch
|
||||||
|
*/
|
||||||
|
if (need_budget)
|
||||||
|
blk_mq_put_dispatch_budget(rq->q);
|
||||||
|
return PREP_DISPATCH_NO_TAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PREP_DISPATCH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release all allocated budgets before calling to blk_mq_dispatch_rq_list */
|
||||||
|
static void blk_mq_release_budgets(struct request_queue *q,
|
||||||
|
unsigned int nr_budgets)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < nr_budgets; i++)
|
||||||
|
blk_mq_put_dispatch_budget(q);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns true if we did some work AND can potentially do more.
|
* Returns true if we did some work AND can potentially do more.
|
||||||
*/
|
*/
|
||||||
bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
|
bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *list,
|
||||||
bool got_budget)
|
unsigned int nr_budgets)
|
||||||
{
|
{
|
||||||
struct blk_mq_hw_ctx *hctx;
|
enum prep_dispatch prep;
|
||||||
|
struct request_queue *q = hctx->queue;
|
||||||
struct request *rq, *nxt;
|
struct request *rq, *nxt;
|
||||||
bool no_tag = false;
|
|
||||||
int errors, queued;
|
int errors, queued;
|
||||||
blk_status_t ret = BLK_STS_OK;
|
blk_status_t ret = BLK_STS_OK;
|
||||||
bool no_budget_avail = false;
|
|
||||||
LIST_HEAD(zone_list);
|
LIST_HEAD(zone_list);
|
||||||
|
|
||||||
if (list_empty(list))
|
if (list_empty(list))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
WARN_ON(!list_is_singular(list) && got_budget);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now process all the entries, sending them to the driver.
|
* Now process all the entries, sending them to the driver.
|
||||||
*/
|
*/
|
||||||
@ -1232,32 +1358,10 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
|
|||||||
|
|
||||||
rq = list_first_entry(list, struct request, queuelist);
|
rq = list_first_entry(list, struct request, queuelist);
|
||||||
|
|
||||||
hctx = rq->mq_hctx;
|
WARN_ON_ONCE(hctx != rq->mq_hctx);
|
||||||
if (!got_budget && !blk_mq_get_dispatch_budget(hctx)) {
|
prep = blk_mq_prep_dispatch_rq(rq, !nr_budgets);
|
||||||
blk_mq_put_driver_tag(rq);
|
if (prep != PREP_DISPATCH_OK)
|
||||||
no_budget_avail = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (!blk_mq_get_driver_tag(rq)) {
|
|
||||||
/*
|
|
||||||
* The initial allocation attempt failed, so we need to
|
|
||||||
* rerun the hardware queue when a tag is freed. The
|
|
||||||
* waitqueue takes care of that. If the queue is run
|
|
||||||
* before we add this entry back on the dispatch list,
|
|
||||||
* we'll re-run it below.
|
|
||||||
*/
|
|
||||||
if (!blk_mq_mark_tag_wait(hctx, rq)) {
|
|
||||||
blk_mq_put_dispatch_budget(hctx);
|
|
||||||
/*
|
|
||||||
* For non-shared tags, the RESTART check
|
|
||||||
* will suffice.
|
|
||||||
*/
|
|
||||||
if (hctx->flags & BLK_MQ_F_TAG_SHARED)
|
|
||||||
no_tag = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list_del_init(&rq->queuelist);
|
list_del_init(&rq->queuelist);
|
||||||
|
|
||||||
@ -1274,31 +1378,35 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
|
|||||||
bd.last = !blk_mq_get_driver_tag(nxt);
|
bd.last = !blk_mq_get_driver_tag(nxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* once the request is queued to lld, no need to cover the
|
||||||
|
* budget any more
|
||||||
|
*/
|
||||||
|
if (nr_budgets)
|
||||||
|
nr_budgets--;
|
||||||
ret = q->mq_ops->queue_rq(hctx, &bd);
|
ret = q->mq_ops->queue_rq(hctx, &bd);
|
||||||
if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE) {
|
switch (ret) {
|
||||||
blk_mq_handle_dev_resource(rq, list);
|
case BLK_STS_OK:
|
||||||
|
queued++;
|
||||||
break;
|
break;
|
||||||
} else if (ret == BLK_STS_ZONE_RESOURCE) {
|
case BLK_STS_RESOURCE:
|
||||||
|
case BLK_STS_DEV_RESOURCE:
|
||||||
|
blk_mq_handle_dev_resource(rq, list);
|
||||||
|
goto out;
|
||||||
|
case BLK_STS_ZONE_RESOURCE:
|
||||||
/*
|
/*
|
||||||
* Move the request to zone_list and keep going through
|
* Move the request to zone_list and keep going through
|
||||||
* the dispatch list to find more requests the drive can
|
* the dispatch list to find more requests the drive can
|
||||||
* accept.
|
* accept.
|
||||||
*/
|
*/
|
||||||
blk_mq_handle_zone_resource(rq, &zone_list);
|
blk_mq_handle_zone_resource(rq, &zone_list);
|
||||||
if (list_empty(list))
|
break;
|
||||||
break;
|
default:
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unlikely(ret != BLK_STS_OK)) {
|
|
||||||
errors++;
|
errors++;
|
||||||
blk_mq_end_request(rq, BLK_STS_IOERR);
|
blk_mq_end_request(rq, BLK_STS_IOERR);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queued++;
|
|
||||||
} while (!list_empty(list));
|
} while (!list_empty(list));
|
||||||
|
out:
|
||||||
if (!list_empty(&zone_list))
|
if (!list_empty(&zone_list))
|
||||||
list_splice_tail_init(&zone_list, list);
|
list_splice_tail_init(&zone_list, list);
|
||||||
|
|
||||||
@ -1310,6 +1418,12 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
|
|||||||
*/
|
*/
|
||||||
if (!list_empty(list)) {
|
if (!list_empty(list)) {
|
||||||
bool needs_restart;
|
bool needs_restart;
|
||||||
|
/* For non-shared tags, the RESTART check will suffice */
|
||||||
|
bool no_tag = prep == PREP_DISPATCH_NO_TAG &&
|
||||||
|
(hctx->flags & BLK_MQ_F_TAG_SHARED);
|
||||||
|
bool no_budget_avail = prep == PREP_DISPATCH_NO_BUDGET;
|
||||||
|
|
||||||
|
blk_mq_release_budgets(q, nr_budgets);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we didn't flush the entire list, we could have told
|
* If we didn't flush the entire list, we could have told
|
||||||
@ -1361,13 +1475,6 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
|
|||||||
} else
|
} else
|
||||||
blk_mq_update_dispatch_busy(hctx, false);
|
blk_mq_update_dispatch_busy(hctx, false);
|
||||||
|
|
||||||
/*
|
|
||||||
* If the host/device is unable to accept more work, inform the
|
|
||||||
* caller of that.
|
|
||||||
*/
|
|
||||||
if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return (queued + errors) != 0;
|
return (queued + errors) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1896,11 +2003,11 @@ static blk_status_t __blk_mq_try_issue_directly(struct blk_mq_hw_ctx *hctx,
|
|||||||
if (q->elevator && !bypass_insert)
|
if (q->elevator && !bypass_insert)
|
||||||
goto insert;
|
goto insert;
|
||||||
|
|
||||||
if (!blk_mq_get_dispatch_budget(hctx))
|
if (!blk_mq_get_dispatch_budget(q))
|
||||||
goto insert;
|
goto insert;
|
||||||
|
|
||||||
if (!blk_mq_get_driver_tag(rq)) {
|
if (!blk_mq_get_driver_tag(rq)) {
|
||||||
blk_mq_put_dispatch_budget(hctx);
|
blk_mq_put_dispatch_budget(q);
|
||||||
goto insert;
|
goto insert;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2005,8 +2112,7 @@ static void blk_add_rq_to_plug(struct blk_plug *plug, struct request *rq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* blk_mq_make_request - Create and send a request to block device.
|
* blk_mq_submit_bio - Create and send a request to block device.
|
||||||
* @q: Request queue pointer.
|
|
||||||
* @bio: Bio pointer.
|
* @bio: Bio pointer.
|
||||||
*
|
*
|
||||||
* Builds up a request structure from @q and @bio and send to the device. The
|
* Builds up a request structure from @q and @bio and send to the device. The
|
||||||
@ -2020,8 +2126,9 @@ static void blk_add_rq_to_plug(struct blk_plug *plug, struct request *rq)
|
|||||||
*
|
*
|
||||||
* Returns: Request queue cookie.
|
* Returns: Request queue cookie.
|
||||||
*/
|
*/
|
||||||
blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio)
|
blk_qc_t blk_mq_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
|
struct request_queue *q = bio->bi_disk->queue;
|
||||||
const int is_sync = op_is_sync(bio->bi_opf);
|
const int is_sync = op_is_sync(bio->bi_opf);
|
||||||
const int is_flush_fua = op_is_flush(bio->bi_opf);
|
const int is_flush_fua = op_is_flush(bio->bi_opf);
|
||||||
struct blk_mq_alloc_data data = {
|
struct blk_mq_alloc_data data = {
|
||||||
@ -2035,7 +2142,7 @@ blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio)
|
|||||||
blk_status_t ret;
|
blk_status_t ret;
|
||||||
|
|
||||||
blk_queue_bounce(q, &bio);
|
blk_queue_bounce(q, &bio);
|
||||||
__blk_queue_split(q, &bio, &nr_segs);
|
__blk_queue_split(&bio, &nr_segs);
|
||||||
|
|
||||||
if (!bio_integrity_prep(bio))
|
if (!bio_integrity_prep(bio))
|
||||||
goto queue_exit;
|
goto queue_exit;
|
||||||
@ -2146,7 +2253,7 @@ queue_exit:
|
|||||||
blk_queue_exit(q);
|
blk_queue_exit(q);
|
||||||
return BLK_QC_T_NONE;
|
return BLK_QC_T_NONE;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(blk_mq_make_request); /* only for request based dm */
|
EXPORT_SYMBOL_GPL(blk_mq_submit_bio); /* only for request based dm */
|
||||||
|
|
||||||
void blk_mq_free_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
|
void blk_mq_free_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
|
||||||
unsigned int hctx_idx)
|
unsigned int hctx_idx)
|
||||||
@ -2792,7 +2899,7 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q)
|
|||||||
struct blk_mq_tag_set *set = q->tag_set;
|
struct blk_mq_tag_set *set = q->tag_set;
|
||||||
|
|
||||||
mutex_lock(&set->tag_list_lock);
|
mutex_lock(&set->tag_list_lock);
|
||||||
list_del_rcu(&q->tag_set_list);
|
list_del(&q->tag_set_list);
|
||||||
if (list_is_singular(&set->tag_list)) {
|
if (list_is_singular(&set->tag_list)) {
|
||||||
/* just transitioned to unshared */
|
/* just transitioned to unshared */
|
||||||
set->flags &= ~BLK_MQ_F_TAG_SHARED;
|
set->flags &= ~BLK_MQ_F_TAG_SHARED;
|
||||||
@ -2819,7 +2926,7 @@ static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set,
|
|||||||
}
|
}
|
||||||
if (set->flags & BLK_MQ_F_TAG_SHARED)
|
if (set->flags & BLK_MQ_F_TAG_SHARED)
|
||||||
queue_set_hctx_shared(q, true);
|
queue_set_hctx_shared(q, true);
|
||||||
list_add_tail_rcu(&q->tag_set_list, &set->tag_list);
|
list_add_tail(&q->tag_set_list, &set->tag_list);
|
||||||
|
|
||||||
mutex_unlock(&set->tag_list_lock);
|
mutex_unlock(&set->tag_list_lock);
|
||||||
}
|
}
|
||||||
@ -2886,7 +2993,7 @@ struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set,
|
|||||||
{
|
{
|
||||||
struct request_queue *uninit_q, *q;
|
struct request_queue *uninit_q, *q;
|
||||||
|
|
||||||
uninit_q = __blk_alloc_queue(set->numa_node);
|
uninit_q = blk_alloc_queue(set->numa_node);
|
||||||
if (!uninit_q)
|
if (!uninit_q)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
uninit_q->queuedata = queuedata;
|
uninit_q->queuedata = queuedata;
|
||||||
@ -3760,6 +3867,15 @@ EXPORT_SYMBOL(blk_mq_rq_cpu);
|
|||||||
|
|
||||||
static int __init blk_mq_init(void)
|
static int __init blk_mq_init(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for_each_possible_cpu(i)
|
||||||
|
INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
|
||||||
|
open_softirq(BLOCK_SOFTIRQ, blk_done_softirq);
|
||||||
|
|
||||||
|
cpuhp_setup_state_nocalls(CPUHP_BLOCK_SOFTIRQ_DEAD,
|
||||||
|
"block/softirq:dead", NULL,
|
||||||
|
blk_softirq_cpu_dead);
|
||||||
cpuhp_setup_state_multi(CPUHP_BLK_MQ_DEAD, "block/mq:dead", NULL,
|
cpuhp_setup_state_multi(CPUHP_BLK_MQ_DEAD, "block/mq:dead", NULL,
|
||||||
blk_mq_hctx_notify_dead);
|
blk_mq_hctx_notify_dead);
|
||||||
cpuhp_setup_state_multi(CPUHP_AP_BLK_MQ_ONLINE, "block/mq:online",
|
cpuhp_setup_state_multi(CPUHP_AP_BLK_MQ_ONLINE, "block/mq:online",
|
||||||
|
@ -40,7 +40,8 @@ struct blk_mq_ctx {
|
|||||||
void blk_mq_exit_queue(struct request_queue *q);
|
void blk_mq_exit_queue(struct request_queue *q);
|
||||||
int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr);
|
int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr);
|
||||||
void blk_mq_wake_waiters(struct request_queue *q);
|
void blk_mq_wake_waiters(struct request_queue *q);
|
||||||
bool blk_mq_dispatch_rq_list(struct request_queue *, struct list_head *, bool);
|
bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *,
|
||||||
|
unsigned int);
|
||||||
void blk_mq_add_to_requeue_list(struct request *rq, bool at_head,
|
void blk_mq_add_to_requeue_list(struct request *rq, bool at_head,
|
||||||
bool kick_requeue_list);
|
bool kick_requeue_list);
|
||||||
void blk_mq_flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list);
|
void blk_mq_flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list);
|
||||||
@ -159,7 +160,7 @@ struct blk_mq_alloc_data {
|
|||||||
|
|
||||||
static inline struct blk_mq_tags *blk_mq_tags_from_data(struct blk_mq_alloc_data *data)
|
static inline struct blk_mq_tags *blk_mq_tags_from_data(struct blk_mq_alloc_data *data)
|
||||||
{
|
{
|
||||||
if (data->flags & BLK_MQ_REQ_INTERNAL)
|
if (data->q->elevator)
|
||||||
return data->hctx->sched_tags;
|
return data->hctx->sched_tags;
|
||||||
|
|
||||||
return data->hctx->tags;
|
return data->hctx->tags;
|
||||||
@ -179,20 +180,16 @@ unsigned int blk_mq_in_flight(struct request_queue *q, struct hd_struct *part);
|
|||||||
void blk_mq_in_flight_rw(struct request_queue *q, struct hd_struct *part,
|
void blk_mq_in_flight_rw(struct request_queue *q, struct hd_struct *part,
|
||||||
unsigned int inflight[2]);
|
unsigned int inflight[2]);
|
||||||
|
|
||||||
static inline void blk_mq_put_dispatch_budget(struct blk_mq_hw_ctx *hctx)
|
static inline void blk_mq_put_dispatch_budget(struct request_queue *q)
|
||||||
{
|
{
|
||||||
struct request_queue *q = hctx->queue;
|
|
||||||
|
|
||||||
if (q->mq_ops->put_budget)
|
if (q->mq_ops->put_budget)
|
||||||
q->mq_ops->put_budget(hctx);
|
q->mq_ops->put_budget(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool blk_mq_get_dispatch_budget(struct blk_mq_hw_ctx *hctx)
|
static inline bool blk_mq_get_dispatch_budget(struct request_queue *q)
|
||||||
{
|
{
|
||||||
struct request_queue *q = hctx->queue;
|
|
||||||
|
|
||||||
if (q->mq_ops->get_budget)
|
if (q->mq_ops->get_budget)
|
||||||
return q->mq_ops->get_budget(hctx);
|
return q->mq_ops->get_budget(q);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,156 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
|
||||||
/*
|
|
||||||
* Functions related to softirq rq completions
|
|
||||||
*/
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/bio.h>
|
|
||||||
#include <linux/blkdev.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/cpu.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/sched/topology.h>
|
|
||||||
|
|
||||||
#include "blk.h"
|
|
||||||
|
|
||||||
static DEFINE_PER_CPU(struct list_head, blk_cpu_done);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Softirq action handler - move entries to local list and loop over them
|
|
||||||
* while passing them to the queue registered handler.
|
|
||||||
*/
|
|
||||||
static __latent_entropy void blk_done_softirq(struct softirq_action *h)
|
|
||||||
{
|
|
||||||
struct list_head *cpu_list, local_list;
|
|
||||||
|
|
||||||
local_irq_disable();
|
|
||||||
cpu_list = this_cpu_ptr(&blk_cpu_done);
|
|
||||||
list_replace_init(cpu_list, &local_list);
|
|
||||||
local_irq_enable();
|
|
||||||
|
|
||||||
while (!list_empty(&local_list)) {
|
|
||||||
struct request *rq;
|
|
||||||
|
|
||||||
rq = list_entry(local_list.next, struct request, ipi_list);
|
|
||||||
list_del_init(&rq->ipi_list);
|
|
||||||
rq->q->mq_ops->complete(rq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
static void trigger_softirq(void *data)
|
|
||||||
{
|
|
||||||
struct request *rq = data;
|
|
||||||
struct list_head *list;
|
|
||||||
|
|
||||||
list = this_cpu_ptr(&blk_cpu_done);
|
|
||||||
list_add_tail(&rq->ipi_list, list);
|
|
||||||
|
|
||||||
if (list->next == &rq->ipi_list)
|
|
||||||
raise_softirq_irqoff(BLOCK_SOFTIRQ);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Setup and invoke a run of 'trigger_softirq' on the given cpu.
|
|
||||||
*/
|
|
||||||
static int raise_blk_irq(int cpu, struct request *rq)
|
|
||||||
{
|
|
||||||
if (cpu_online(cpu)) {
|
|
||||||
call_single_data_t *data = &rq->csd;
|
|
||||||
|
|
||||||
data->func = trigger_softirq;
|
|
||||||
data->info = rq;
|
|
||||||
data->flags = 0;
|
|
||||||
|
|
||||||
smp_call_function_single_async(cpu, data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#else /* CONFIG_SMP */
|
|
||||||
static int raise_blk_irq(int cpu, struct request *rq)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int blk_softirq_cpu_dead(unsigned int cpu)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If a CPU goes away, splice its entries to the current CPU
|
|
||||||
* and trigger a run of the softirq
|
|
||||||
*/
|
|
||||||
local_irq_disable();
|
|
||||||
list_splice_init(&per_cpu(blk_cpu_done, cpu),
|
|
||||||
this_cpu_ptr(&blk_cpu_done));
|
|
||||||
raise_softirq_irqoff(BLOCK_SOFTIRQ);
|
|
||||||
local_irq_enable();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __blk_complete_request(struct request *req)
|
|
||||||
{
|
|
||||||
struct request_queue *q = req->q;
|
|
||||||
int cpu, ccpu = req->mq_ctx->cpu;
|
|
||||||
unsigned long flags;
|
|
||||||
bool shared = false;
|
|
||||||
|
|
||||||
BUG_ON(!q->mq_ops->complete);
|
|
||||||
|
|
||||||
local_irq_save(flags);
|
|
||||||
cpu = smp_processor_id();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Select completion CPU
|
|
||||||
*/
|
|
||||||
if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags) && ccpu != -1) {
|
|
||||||
if (!test_bit(QUEUE_FLAG_SAME_FORCE, &q->queue_flags))
|
|
||||||
shared = cpus_share_cache(cpu, ccpu);
|
|
||||||
} else
|
|
||||||
ccpu = cpu;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If current CPU and requested CPU share a cache, run the softirq on
|
|
||||||
* the current CPU. One might concern this is just like
|
|
||||||
* QUEUE_FLAG_SAME_FORCE, but actually not. blk_complete_request() is
|
|
||||||
* running in interrupt handler, and currently I/O controller doesn't
|
|
||||||
* support multiple interrupts, so current CPU is unique actually. This
|
|
||||||
* avoids IPI sending from current CPU to the first CPU of a group.
|
|
||||||
*/
|
|
||||||
if (ccpu == cpu || shared) {
|
|
||||||
struct list_head *list;
|
|
||||||
do_local:
|
|
||||||
list = this_cpu_ptr(&blk_cpu_done);
|
|
||||||
list_add_tail(&req->ipi_list, list);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if the list only contains our just added request,
|
|
||||||
* signal a raise of the softirq. If there are already
|
|
||||||
* entries there, someone already raised the irq but it
|
|
||||||
* hasn't run yet.
|
|
||||||
*/
|
|
||||||
if (list->next == &req->ipi_list)
|
|
||||||
raise_softirq_irqoff(BLOCK_SOFTIRQ);
|
|
||||||
} else if (raise_blk_irq(ccpu, req))
|
|
||||||
goto do_local;
|
|
||||||
|
|
||||||
local_irq_restore(flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __init int blk_softirq_init(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for_each_possible_cpu(i)
|
|
||||||
INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
|
|
||||||
|
|
||||||
open_softirq(BLOCK_SOFTIRQ, blk_done_softirq);
|
|
||||||
cpuhp_setup_state_nocalls(CPUHP_BLOCK_SOFTIRQ_DEAD,
|
|
||||||
"block/softirq:dead", NULL,
|
|
||||||
blk_softirq_cpu_dead);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
subsys_initcall(blk_softirq_init);
|
|
@ -11,6 +11,7 @@
|
|||||||
#include <linux/blktrace_api.h>
|
#include <linux/blktrace_api.h>
|
||||||
#include <linux/blk-mq.h>
|
#include <linux/blk-mq.h>
|
||||||
#include <linux/blk-cgroup.h>
|
#include <linux/blk-cgroup.h>
|
||||||
|
#include <linux/debugfs.h>
|
||||||
|
|
||||||
#include "blk.h"
|
#include "blk.h"
|
||||||
#include "blk-mq.h"
|
#include "blk-mq.h"
|
||||||
@ -873,22 +874,32 @@ static void blk_exit_queue(struct request_queue *q)
|
|||||||
bdi_put(q->backing_dev_info);
|
bdi_put(q->backing_dev_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __blk_release_queue - release a request queue
|
* blk_release_queue - releases all allocated resources of the request_queue
|
||||||
* @work: pointer to the release_work member of the request queue to be released
|
* @kobj: pointer to a kobject, whose container is a request_queue
|
||||||
*
|
*
|
||||||
* Description:
|
* This function releases all allocated resources of the request queue.
|
||||||
* This function is called when a block device is being unregistered. The
|
*
|
||||||
* process of releasing a request queue starts with blk_cleanup_queue, which
|
* The struct request_queue refcount is incremented with blk_get_queue() and
|
||||||
* set the appropriate flags and then calls blk_put_queue, that decrements
|
* decremented with blk_put_queue(). Once the refcount reaches 0 this function
|
||||||
* the reference counter of the request queue. Once the reference counter
|
* is called.
|
||||||
* of the request queue reaches zero, blk_release_queue is called to release
|
*
|
||||||
* all allocated resources of the request queue.
|
* For drivers that have a request_queue on a gendisk and added with
|
||||||
|
* __device_add_disk() the refcount to request_queue will reach 0 with
|
||||||
|
* the last put_disk() called by the driver. For drivers which don't use
|
||||||
|
* __device_add_disk() this happens with blk_cleanup_queue().
|
||||||
|
*
|
||||||
|
* Drivers exist which depend on the release of the request_queue to be
|
||||||
|
* synchronous, it should not be deferred.
|
||||||
|
*
|
||||||
|
* Context: can sleep
|
||||||
*/
|
*/
|
||||||
static void __blk_release_queue(struct work_struct *work)
|
static void blk_release_queue(struct kobject *kobj)
|
||||||
{
|
{
|
||||||
struct request_queue *q = container_of(work, typeof(*q), release_work);
|
struct request_queue *q =
|
||||||
|
container_of(kobj, struct request_queue, kobj);
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
if (test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags))
|
if (test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags))
|
||||||
blk_stat_remove_callback(q, q->poll_cb);
|
blk_stat_remove_callback(q, q->poll_cb);
|
||||||
@ -907,6 +918,9 @@ static void __blk_release_queue(struct work_struct *work)
|
|||||||
blk_mq_release(q);
|
blk_mq_release(q);
|
||||||
|
|
||||||
blk_trace_shutdown(q);
|
blk_trace_shutdown(q);
|
||||||
|
mutex_lock(&q->debugfs_mutex);
|
||||||
|
debugfs_remove_recursive(q->debugfs_dir);
|
||||||
|
mutex_unlock(&q->debugfs_mutex);
|
||||||
|
|
||||||
if (queue_is_mq(q))
|
if (queue_is_mq(q))
|
||||||
blk_mq_debugfs_unregister(q);
|
blk_mq_debugfs_unregister(q);
|
||||||
@ -917,15 +931,6 @@ static void __blk_release_queue(struct work_struct *work)
|
|||||||
call_rcu(&q->rcu_head, blk_free_queue_rcu);
|
call_rcu(&q->rcu_head, blk_free_queue_rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void blk_release_queue(struct kobject *kobj)
|
|
||||||
{
|
|
||||||
struct request_queue *q =
|
|
||||||
container_of(kobj, struct request_queue, kobj);
|
|
||||||
|
|
||||||
INIT_WORK(&q->release_work, __blk_release_queue);
|
|
||||||
schedule_work(&q->release_work);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct sysfs_ops queue_sysfs_ops = {
|
static const struct sysfs_ops queue_sysfs_ops = {
|
||||||
.show = queue_attr_show,
|
.show = queue_attr_show,
|
||||||
.store = queue_attr_store,
|
.store = queue_attr_store,
|
||||||
@ -988,6 +993,11 @@ int blk_register_queue(struct gendisk *disk)
|
|||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&q->debugfs_mutex);
|
||||||
|
q->debugfs_dir = debugfs_create_dir(kobject_name(q->kobj.parent),
|
||||||
|
blk_debugfs_root);
|
||||||
|
mutex_unlock(&q->debugfs_mutex);
|
||||||
|
|
||||||
if (queue_is_mq(q)) {
|
if (queue_is_mq(q)) {
|
||||||
__blk_mq_register_dev(dev, q);
|
__blk_mq_register_dev(dev, q);
|
||||||
blk_mq_debugfs_register(q);
|
blk_mq_debugfs_register(q);
|
||||||
|
@ -1339,8 +1339,8 @@ static void blk_throtl_dispatch_work_fn(struct work_struct *work)
|
|||||||
|
|
||||||
if (!bio_list_empty(&bio_list_on_stack)) {
|
if (!bio_list_empty(&bio_list_on_stack)) {
|
||||||
blk_start_plug(&plug);
|
blk_start_plug(&plug);
|
||||||
while((bio = bio_list_pop(&bio_list_on_stack)))
|
while ((bio = bio_list_pop(&bio_list_on_stack)))
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
blk_finish_plug(&plug);
|
blk_finish_plug(&plug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2158,17 +2158,18 @@ static inline void throtl_update_latency_buckets(struct throtl_data *td)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool blk_throtl_bio(struct request_queue *q, struct blkcg_gq *blkg,
|
bool blk_throtl_bio(struct bio *bio)
|
||||||
struct bio *bio)
|
|
||||||
{
|
{
|
||||||
|
struct request_queue *q = bio->bi_disk->queue;
|
||||||
|
struct blkcg_gq *blkg = bio->bi_blkg;
|
||||||
struct throtl_qnode *qn = NULL;
|
struct throtl_qnode *qn = NULL;
|
||||||
struct throtl_grp *tg = blkg_to_tg(blkg ?: q->root_blkg);
|
struct throtl_grp *tg = blkg_to_tg(blkg);
|
||||||
struct throtl_service_queue *sq;
|
struct throtl_service_queue *sq;
|
||||||
bool rw = bio_data_dir(bio);
|
bool rw = bio_data_dir(bio);
|
||||||
bool throttled = false;
|
bool throttled = false;
|
||||||
struct throtl_data *td = tg->td;
|
struct throtl_data *td = tg->td;
|
||||||
|
|
||||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
rcu_read_lock();
|
||||||
|
|
||||||
/* see throtl_charge_bio() */
|
/* see throtl_charge_bio() */
|
||||||
if (bio_flagged(bio, BIO_THROTTLED))
|
if (bio_flagged(bio, BIO_THROTTLED))
|
||||||
@ -2273,6 +2274,7 @@ out:
|
|||||||
if (throttled || !td->track_bio_latency)
|
if (throttled || !td->track_bio_latency)
|
||||||
bio->bi_issue.value |= BIO_ISSUE_THROTL_SKIP_LATENCY;
|
bio->bi_issue.value |= BIO_ISSUE_THROTL_SKIP_LATENCY;
|
||||||
#endif
|
#endif
|
||||||
|
rcu_read_unlock();
|
||||||
return throttled;
|
return throttled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,13 +20,11 @@ static int __init setup_fail_io_timeout(char *str)
|
|||||||
}
|
}
|
||||||
__setup("fail_io_timeout=", setup_fail_io_timeout);
|
__setup("fail_io_timeout=", setup_fail_io_timeout);
|
||||||
|
|
||||||
int blk_should_fake_timeout(struct request_queue *q)
|
bool __blk_should_fake_timeout(struct request_queue *q)
|
||||||
{
|
{
|
||||||
if (!test_bit(QUEUE_FLAG_FAIL_IO, &q->queue_flags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return should_fail(&fail_io_timeout, 1);
|
return should_fail(&fail_io_timeout, 1);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(__blk_should_fake_timeout);
|
||||||
|
|
||||||
static int __init fail_io_timeout_debugfs(void)
|
static int __init fail_io_timeout_debugfs(void)
|
||||||
{
|
{
|
||||||
@ -70,7 +68,7 @@ ssize_t part_timeout_store(struct device *dev, struct device_attribute *attr,
|
|||||||
#endif /* CONFIG_FAIL_IO_TIMEOUT */
|
#endif /* CONFIG_FAIL_IO_TIMEOUT */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* blk_abort_request -- Request request recovery for the specified command
|
* blk_abort_request - Request recovery for the specified command
|
||||||
* @req: pointer to the request of interest
|
* @req: pointer to the request of interest
|
||||||
*
|
*
|
||||||
* This function requests that the block layer start recovery for the
|
* This function requests that the block layer start recovery for the
|
||||||
@ -90,11 +88,29 @@ void blk_abort_request(struct request *req)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(blk_abort_request);
|
EXPORT_SYMBOL_GPL(blk_abort_request);
|
||||||
|
|
||||||
|
static unsigned long blk_timeout_mask __read_mostly;
|
||||||
|
|
||||||
|
static int __init blk_timeout_init(void)
|
||||||
|
{
|
||||||
|
blk_timeout_mask = roundup_pow_of_two(HZ) - 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
late_initcall(blk_timeout_init);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Just a rough estimate, we don't care about specific values for timeouts.
|
||||||
|
*/
|
||||||
|
static inline unsigned long blk_round_jiffies(unsigned long j)
|
||||||
|
{
|
||||||
|
return (j + blk_timeout_mask) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long blk_rq_timeout(unsigned long timeout)
|
unsigned long blk_rq_timeout(unsigned long timeout)
|
||||||
{
|
{
|
||||||
unsigned long maxt;
|
unsigned long maxt;
|
||||||
|
|
||||||
maxt = round_jiffies_up(jiffies + BLK_MAX_TIMEOUT);
|
maxt = blk_round_jiffies(jiffies + BLK_MAX_TIMEOUT);
|
||||||
if (time_after(timeout, maxt))
|
if (time_after(timeout, maxt))
|
||||||
timeout = maxt;
|
timeout = maxt;
|
||||||
|
|
||||||
@ -131,7 +147,7 @@ void blk_add_timer(struct request *req)
|
|||||||
* than an existing one, modify the timer. Round up to next nearest
|
* than an existing one, modify the timer. Round up to next nearest
|
||||||
* second.
|
* second.
|
||||||
*/
|
*/
|
||||||
expiry = blk_rq_timeout(round_jiffies_up(expiry));
|
expiry = blk_rq_timeout(blk_round_jiffies(expiry));
|
||||||
|
|
||||||
if (!timer_pending(&q->timeout) ||
|
if (!timer_pending(&q->timeout) ||
|
||||||
time_before(expiry, q->timeout.expires)) {
|
time_before(expiry, q->timeout.expires)) {
|
||||||
|
37
block/blk.h
37
block/blk.h
@ -14,9 +14,7 @@
|
|||||||
/* Max future timer expiry for timeouts */
|
/* Max future timer expiry for timeouts */
|
||||||
#define BLK_MAX_TIMEOUT (5 * HZ)
|
#define BLK_MAX_TIMEOUT (5 * HZ)
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
|
||||||
extern struct dentry *blk_debugfs_root;
|
extern struct dentry *blk_debugfs_root;
|
||||||
#endif
|
|
||||||
|
|
||||||
struct blk_flush_queue {
|
struct blk_flush_queue {
|
||||||
unsigned int flush_pending_idx:1;
|
unsigned int flush_pending_idx:1;
|
||||||
@ -27,11 +25,6 @@ struct blk_flush_queue {
|
|||||||
struct list_head flush_data_in_flight;
|
struct list_head flush_data_in_flight;
|
||||||
struct request *flush_rq;
|
struct request *flush_rq;
|
||||||
|
|
||||||
/*
|
|
||||||
* flush_rq shares tag with this rq, both can't be active
|
|
||||||
* at the same time
|
|
||||||
*/
|
|
||||||
struct request *orig_rq;
|
|
||||||
struct lock_class_key key;
|
struct lock_class_key key;
|
||||||
spinlock_t mq_flush_lock;
|
spinlock_t mq_flush_lock;
|
||||||
};
|
};
|
||||||
@ -223,21 +216,11 @@ ssize_t part_fail_show(struct device *dev, struct device_attribute *attr,
|
|||||||
char *buf);
|
char *buf);
|
||||||
ssize_t part_fail_store(struct device *dev, struct device_attribute *attr,
|
ssize_t part_fail_store(struct device *dev, struct device_attribute *attr,
|
||||||
const char *buf, size_t count);
|
const char *buf, size_t count);
|
||||||
|
|
||||||
#ifdef CONFIG_FAIL_IO_TIMEOUT
|
|
||||||
int blk_should_fake_timeout(struct request_queue *);
|
|
||||||
ssize_t part_timeout_show(struct device *, struct device_attribute *, char *);
|
ssize_t part_timeout_show(struct device *, struct device_attribute *, char *);
|
||||||
ssize_t part_timeout_store(struct device *, struct device_attribute *,
|
ssize_t part_timeout_store(struct device *, struct device_attribute *,
|
||||||
const char *, size_t);
|
const char *, size_t);
|
||||||
#else
|
|
||||||
static inline int blk_should_fake_timeout(struct request_queue *q)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void __blk_queue_split(struct request_queue *q, struct bio **bio,
|
void __blk_queue_split(struct bio **bio, unsigned int *nr_segs);
|
||||||
unsigned int *nr_segs);
|
|
||||||
int ll_back_merge_fn(struct request *req, struct bio *bio,
|
int ll_back_merge_fn(struct request *req, struct bio *bio,
|
||||||
unsigned int nr_segs);
|
unsigned int nr_segs);
|
||||||
int ll_front_merge_fn(struct request *req, struct bio *bio,
|
int ll_front_merge_fn(struct request *req, struct bio *bio,
|
||||||
@ -281,6 +264,20 @@ static inline unsigned int bio_allowed_max_sectors(struct request_queue *q)
|
|||||||
return round_down(UINT_MAX, queue_logical_block_size(q)) >> 9;
|
return round_down(UINT_MAX, queue_logical_block_size(q)) >> 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The max bio size which is aligned to q->limits.discard_granularity. This
|
||||||
|
* is a hint to split large discard bio in generic block layer, then if device
|
||||||
|
* driver needs to split the discard bio into smaller ones, their bi_size can
|
||||||
|
* be very probably and easily aligned to discard_granularity of the device's
|
||||||
|
* queue.
|
||||||
|
*/
|
||||||
|
static inline unsigned int bio_aligned_discard_max_sectors(
|
||||||
|
struct request_queue *q)
|
||||||
|
{
|
||||||
|
return round_down(UINT_MAX, q->limits.discard_granularity) >>
|
||||||
|
SECTOR_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal io_context interface
|
* Internal io_context interface
|
||||||
*/
|
*/
|
||||||
@ -299,10 +296,12 @@ int create_task_io_context(struct task_struct *task, gfp_t gfp_mask, int node);
|
|||||||
extern int blk_throtl_init(struct request_queue *q);
|
extern int blk_throtl_init(struct request_queue *q);
|
||||||
extern void blk_throtl_exit(struct request_queue *q);
|
extern void blk_throtl_exit(struct request_queue *q);
|
||||||
extern void blk_throtl_register_queue(struct request_queue *q);
|
extern void blk_throtl_register_queue(struct request_queue *q);
|
||||||
|
bool blk_throtl_bio(struct bio *bio);
|
||||||
#else /* CONFIG_BLK_DEV_THROTTLING */
|
#else /* CONFIG_BLK_DEV_THROTTLING */
|
||||||
static inline int blk_throtl_init(struct request_queue *q) { return 0; }
|
static inline int blk_throtl_init(struct request_queue *q) { return 0; }
|
||||||
static inline void blk_throtl_exit(struct request_queue *q) { }
|
static inline void blk_throtl_exit(struct request_queue *q) { }
|
||||||
static inline void blk_throtl_register_queue(struct request_queue *q) { }
|
static inline void blk_throtl_register_queue(struct request_queue *q) { }
|
||||||
|
static inline bool blk_throtl_bio(struct bio *bio) { return false; }
|
||||||
#endif /* CONFIG_BLK_DEV_THROTTLING */
|
#endif /* CONFIG_BLK_DEV_THROTTLING */
|
||||||
#ifdef CONFIG_BLK_DEV_THROTTLING_LOW
|
#ifdef CONFIG_BLK_DEV_THROTTLING_LOW
|
||||||
extern ssize_t blk_throtl_sample_time_show(struct request_queue *q, char *page);
|
extern ssize_t blk_throtl_sample_time_show(struct request_queue *q, char *page);
|
||||||
@ -434,8 +433,6 @@ static inline void part_nr_sects_write(struct hd_struct *part, sector_t size)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct request_queue *__blk_alloc_queue(int node_id);
|
|
||||||
|
|
||||||
int bio_add_hw_page(struct request_queue *q, struct bio *bio,
|
int bio_add_hw_page(struct request_queue *q, struct bio *bio,
|
||||||
struct page *page, unsigned int len, unsigned int offset,
|
struct page *page, unsigned int len, unsigned int offset,
|
||||||
unsigned int max_sectors, bool *same_page);
|
unsigned int max_sectors, bool *same_page);
|
||||||
|
@ -309,7 +309,7 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
|
|||||||
if (!passthrough && sectors < bio_sectors(*bio_orig)) {
|
if (!passthrough && sectors < bio_sectors(*bio_orig)) {
|
||||||
bio = bio_split(*bio_orig, sectors, GFP_NOIO, &bounce_bio_split);
|
bio = bio_split(*bio_orig, sectors, GFP_NOIO, &bounce_bio_split);
|
||||||
bio_chain(bio, *bio_orig);
|
bio_chain(bio, *bio_orig);
|
||||||
generic_make_request(*bio_orig);
|
submit_bio_noacct(*bio_orig);
|
||||||
*bio_orig = bio;
|
*bio_orig = bio;
|
||||||
}
|
}
|
||||||
bio = bounce_clone_bio(*bio_orig, GFP_NOIO, passthrough ? NULL :
|
bio = bounce_clone_bio(*bio_orig, GFP_NOIO, passthrough ? NULL :
|
||||||
|
@ -181,9 +181,12 @@ EXPORT_SYMBOL_GPL(bsg_job_get);
|
|||||||
void bsg_job_done(struct bsg_job *job, int result,
|
void bsg_job_done(struct bsg_job *job, int result,
|
||||||
unsigned int reply_payload_rcv_len)
|
unsigned int reply_payload_rcv_len)
|
||||||
{
|
{
|
||||||
|
struct request *rq = blk_mq_rq_from_pdu(job);
|
||||||
|
|
||||||
job->result = result;
|
job->result = result;
|
||||||
job->reply_payload_rcv_len = reply_payload_rcv_len;
|
job->reply_payload_rcv_len = reply_payload_rcv_len;
|
||||||
blk_mq_complete_request(blk_mq_rq_from_pdu(job));
|
if (likely(!blk_should_fake_timeout(rq->q)))
|
||||||
|
blk_mq_complete_request(rq);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(bsg_job_done);
|
EXPORT_SYMBOL_GPL(bsg_job_done);
|
||||||
|
|
||||||
|
@ -95,8 +95,8 @@ static inline bool elv_support_features(unsigned int elv_features,
|
|||||||
* @name: Elevator name to test
|
* @name: Elevator name to test
|
||||||
* @required_features: Features that the elevator must provide
|
* @required_features: Features that the elevator must provide
|
||||||
*
|
*
|
||||||
* Return true is the elevator @e name matches @name and if @e provides all the
|
* Return true if the elevator @e name matches @name and if @e provides all
|
||||||
* the feratures spcified by @required_features.
|
* the features specified by @required_features.
|
||||||
*/
|
*/
|
||||||
static bool elevator_match(const struct elevator_type *e, const char *name,
|
static bool elevator_match(const struct elevator_type *e, const char *name,
|
||||||
unsigned int required_features)
|
unsigned int required_features)
|
||||||
|
@ -38,8 +38,6 @@ static struct kobject *block_depr;
|
|||||||
static DEFINE_SPINLOCK(ext_devt_lock);
|
static DEFINE_SPINLOCK(ext_devt_lock);
|
||||||
static DEFINE_IDR(ext_devt_idr);
|
static DEFINE_IDR(ext_devt_idr);
|
||||||
|
|
||||||
static const struct device_type disk_type;
|
|
||||||
|
|
||||||
static void disk_check_events(struct disk_events *ev,
|
static void disk_check_events(struct disk_events *ev,
|
||||||
unsigned int *clearing_ptr);
|
unsigned int *clearing_ptr);
|
||||||
static void disk_alloc_events(struct gendisk *disk);
|
static void disk_alloc_events(struct gendisk *disk);
|
||||||
@ -876,11 +874,32 @@ static void invalidate_partition(struct gendisk *disk, int partno)
|
|||||||
bdput(bdev);
|
bdput(bdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* del_gendisk - remove the gendisk
|
||||||
|
* @disk: the struct gendisk to remove
|
||||||
|
*
|
||||||
|
* Removes the gendisk and all its associated resources. This deletes the
|
||||||
|
* partitions associated with the gendisk, and unregisters the associated
|
||||||
|
* request_queue.
|
||||||
|
*
|
||||||
|
* This is the counter to the respective __device_add_disk() call.
|
||||||
|
*
|
||||||
|
* The final removal of the struct gendisk happens when its refcount reaches 0
|
||||||
|
* with put_disk(), which should be called after del_gendisk(), if
|
||||||
|
* __device_add_disk() was used.
|
||||||
|
*
|
||||||
|
* Drivers exist which depend on the release of the gendisk to be synchronous,
|
||||||
|
* it should not be deferred.
|
||||||
|
*
|
||||||
|
* Context: can sleep
|
||||||
|
*/
|
||||||
void del_gendisk(struct gendisk *disk)
|
void del_gendisk(struct gendisk *disk)
|
||||||
{
|
{
|
||||||
struct disk_part_iter piter;
|
struct disk_part_iter piter;
|
||||||
struct hd_struct *part;
|
struct hd_struct *part;
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
blk_integrity_del(disk);
|
blk_integrity_del(disk);
|
||||||
disk_del_events(disk);
|
disk_del_events(disk);
|
||||||
|
|
||||||
@ -971,11 +990,15 @@ static ssize_t disk_badblocks_store(struct device *dev,
|
|||||||
*
|
*
|
||||||
* This function gets the structure containing partitioning
|
* This function gets the structure containing partitioning
|
||||||
* information for the given device @devt.
|
* information for the given device @devt.
|
||||||
|
*
|
||||||
|
* Context: can sleep
|
||||||
*/
|
*/
|
||||||
struct gendisk *get_gendisk(dev_t devt, int *partno)
|
struct gendisk *get_gendisk(dev_t devt, int *partno)
|
||||||
{
|
{
|
||||||
struct gendisk *disk = NULL;
|
struct gendisk *disk = NULL;
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
if (MAJOR(devt) != BLOCK_EXT_MAJOR) {
|
if (MAJOR(devt) != BLOCK_EXT_MAJOR) {
|
||||||
struct kobject *kobj;
|
struct kobject *kobj;
|
||||||
|
|
||||||
@ -1514,10 +1537,31 @@ int disk_expand_part_tbl(struct gendisk *disk, int partno)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* disk_release - releases all allocated resources of the gendisk
|
||||||
|
* @dev: the device representing this disk
|
||||||
|
*
|
||||||
|
* This function releases all allocated resources of the gendisk.
|
||||||
|
*
|
||||||
|
* The struct gendisk refcount is incremented with get_gendisk() or
|
||||||
|
* get_disk_and_module(), and its refcount is decremented with
|
||||||
|
* put_disk_and_module() or put_disk(). Once the refcount reaches 0 this
|
||||||
|
* function is called.
|
||||||
|
*
|
||||||
|
* Drivers which used __device_add_disk() have a gendisk with a request_queue
|
||||||
|
* assigned. Since the request_queue sits on top of the gendisk for these
|
||||||
|
* drivers we also call blk_put_queue() for them, and we expect the
|
||||||
|
* request_queue refcount to reach 0 at this point, and so the request_queue
|
||||||
|
* will also be freed prior to the disk.
|
||||||
|
*
|
||||||
|
* Context: can sleep
|
||||||
|
*/
|
||||||
static void disk_release(struct device *dev)
|
static void disk_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct gendisk *disk = dev_to_disk(dev);
|
struct gendisk *disk = dev_to_disk(dev);
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
blk_free_devt(dev->devt);
|
blk_free_devt(dev->devt);
|
||||||
disk_release_events(disk);
|
disk_release_events(disk);
|
||||||
kfree(disk->random);
|
kfree(disk->random);
|
||||||
@ -1541,7 +1585,7 @@ static char *block_devnode(struct device *dev, umode_t *mode,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct device_type disk_type = {
|
const struct device_type disk_type = {
|
||||||
.name = "disk",
|
.name = "disk",
|
||||||
.groups = disk_attr_groups,
|
.groups = disk_attr_groups,
|
||||||
.release = disk_release,
|
.release = disk_release,
|
||||||
@ -1727,6 +1771,15 @@ struct gendisk *__alloc_disk_node(int minors, int node_id)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__alloc_disk_node);
|
EXPORT_SYMBOL(__alloc_disk_node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get_disk_and_module - increments the gendisk and gendisk fops module refcount
|
||||||
|
* @disk: the struct gendisk to increment the refcount for
|
||||||
|
*
|
||||||
|
* This increments the refcount for the struct gendisk, and the gendisk's
|
||||||
|
* fops module owner.
|
||||||
|
*
|
||||||
|
* Context: Any context.
|
||||||
|
*/
|
||||||
struct kobject *get_disk_and_module(struct gendisk *disk)
|
struct kobject *get_disk_and_module(struct gendisk *disk)
|
||||||
{
|
{
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
@ -1747,6 +1800,16 @@ struct kobject *get_disk_and_module(struct gendisk *disk)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(get_disk_and_module);
|
EXPORT_SYMBOL(get_disk_and_module);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* put_disk - decrements the gendisk refcount
|
||||||
|
* @disk: the struct gendisk to decrement the refcount for
|
||||||
|
*
|
||||||
|
* This decrements the refcount for the struct gendisk. When this reaches 0
|
||||||
|
* we'll have disk_release() called.
|
||||||
|
*
|
||||||
|
* Context: Any context, but the last reference must not be dropped from
|
||||||
|
* atomic context.
|
||||||
|
*/
|
||||||
void put_disk(struct gendisk *disk)
|
void put_disk(struct gendisk *disk)
|
||||||
{
|
{
|
||||||
if (disk)
|
if (disk)
|
||||||
@ -1754,9 +1817,15 @@ void put_disk(struct gendisk *disk)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(put_disk);
|
EXPORT_SYMBOL(put_disk);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* put_disk_and_module - decrements the module and gendisk refcount
|
||||||
|
* @disk: the struct gendisk to decrement the refcount for
|
||||||
|
*
|
||||||
* This is a counterpart of get_disk_and_module() and thus also of
|
* This is a counterpart of get_disk_and_module() and thus also of
|
||||||
* get_gendisk().
|
* get_gendisk().
|
||||||
|
*
|
||||||
|
* Context: Any context, but the last reference must not be dropped from
|
||||||
|
* atomic context.
|
||||||
*/
|
*/
|
||||||
void put_disk_and_module(struct gendisk *disk)
|
void put_disk_and_module(struct gendisk *disk)
|
||||||
{
|
{
|
||||||
@ -1985,18 +2054,12 @@ void disk_flush_events(struct gendisk *disk, unsigned int mask)
|
|||||||
*/
|
*/
|
||||||
unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
|
unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
|
||||||
{
|
{
|
||||||
const struct block_device_operations *bdops = disk->fops;
|
|
||||||
struct disk_events *ev = disk->ev;
|
struct disk_events *ev = disk->ev;
|
||||||
unsigned int pending;
|
unsigned int pending;
|
||||||
unsigned int clearing = mask;
|
unsigned int clearing = mask;
|
||||||
|
|
||||||
if (!ev) {
|
if (!ev)
|
||||||
/* for drivers still using the old ->media_changed method */
|
|
||||||
if ((mask & DISK_EVENT_MEDIA_CHANGE) &&
|
|
||||||
bdops->media_changed && bdops->media_changed(disk))
|
|
||||||
return DISK_EVENT_MEDIA_CHANGE;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
disk_block_events(disk);
|
disk_block_events(disk);
|
||||||
|
|
||||||
|
@ -619,8 +619,6 @@ int blk_drop_partitions(struct block_device *bdev)
|
|||||||
struct disk_part_iter piter;
|
struct disk_part_iter piter;
|
||||||
struct hd_struct *part;
|
struct hd_struct *part;
|
||||||
|
|
||||||
if (!disk_part_scan_enabled(bdev->bd_disk))
|
|
||||||
return 0;
|
|
||||||
if (bdev->bd_part_count)
|
if (bdev->bd_part_count)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio)
|
static blk_qc_t brd_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct brd_device *brd = bio->bi_disk->private_data;
|
struct brd_device *brd = bio->bi_disk->private_data;
|
||||||
struct bio_vec bvec;
|
struct bio_vec bvec;
|
||||||
@ -330,6 +330,7 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector,
|
|||||||
|
|
||||||
static const struct block_device_operations brd_fops = {
|
static const struct block_device_operations brd_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = brd_submit_bio,
|
||||||
.rw_page = brd_rw_page,
|
.rw_page = brd_rw_page,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -381,7 +382,7 @@ static struct brd_device *brd_alloc(int i)
|
|||||||
spin_lock_init(&brd->brd_lock);
|
spin_lock_init(&brd->brd_lock);
|
||||||
INIT_RADIX_TREE(&brd->brd_pages, GFP_ATOMIC);
|
INIT_RADIX_TREE(&brd->brd_pages, GFP_ATOMIC);
|
||||||
|
|
||||||
brd->brd_queue = blk_alloc_queue(brd_make_request, NUMA_NO_NODE);
|
brd->brd_queue = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (!brd->brd_queue)
|
if (!brd->brd_queue)
|
||||||
goto out_free_dev;
|
goto out_free_dev;
|
||||||
|
|
||||||
|
@ -1451,7 +1451,7 @@ extern void conn_free_crypto(struct drbd_connection *connection);
|
|||||||
/* drbd_req */
|
/* drbd_req */
|
||||||
extern void do_submit(struct work_struct *ws);
|
extern void do_submit(struct work_struct *ws);
|
||||||
extern void __drbd_make_request(struct drbd_device *, struct bio *, unsigned long);
|
extern void __drbd_make_request(struct drbd_device *, struct bio *, unsigned long);
|
||||||
extern blk_qc_t drbd_make_request(struct request_queue *q, struct bio *bio);
|
extern blk_qc_t drbd_submit_bio(struct bio *bio);
|
||||||
extern int drbd_read_remote(struct drbd_device *device, struct drbd_request *req);
|
extern int drbd_read_remote(struct drbd_device *device, struct drbd_request *req);
|
||||||
extern int is_valid_ar_handle(struct drbd_request *, sector_t);
|
extern int is_valid_ar_handle(struct drbd_request *, sector_t);
|
||||||
|
|
||||||
@ -1576,12 +1576,12 @@ void drbd_set_my_capacity(struct drbd_device *device, sector_t size);
|
|||||||
/*
|
/*
|
||||||
* used to submit our private bio
|
* used to submit our private bio
|
||||||
*/
|
*/
|
||||||
static inline void drbd_generic_make_request(struct drbd_device *device,
|
static inline void drbd_submit_bio_noacct(struct drbd_device *device,
|
||||||
int fault_type, struct bio *bio)
|
int fault_type, struct bio *bio)
|
||||||
{
|
{
|
||||||
__release(local);
|
__release(local);
|
||||||
if (!bio->bi_disk) {
|
if (!bio->bi_disk) {
|
||||||
drbd_err(device, "drbd_generic_make_request: bio->bi_disk == NULL\n");
|
drbd_err(device, "drbd_submit_bio_noacct: bio->bi_disk == NULL\n");
|
||||||
bio->bi_status = BLK_STS_IOERR;
|
bio->bi_status = BLK_STS_IOERR;
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
return;
|
return;
|
||||||
@ -1590,7 +1590,7 @@ static inline void drbd_generic_make_request(struct drbd_device *device,
|
|||||||
if (drbd_insert_fault(device, fault_type))
|
if (drbd_insert_fault(device, fault_type))
|
||||||
bio_io_error(bio);
|
bio_io_error(bio);
|
||||||
else
|
else
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drbd_bump_write_ordering(struct drbd_resource *resource, struct drbd_backing_dev *bdev,
|
void drbd_bump_write_ordering(struct drbd_resource *resource, struct drbd_backing_dev *bdev,
|
||||||
|
@ -132,9 +132,10 @@ wait_queue_head_t drbd_pp_wait;
|
|||||||
DEFINE_RATELIMIT_STATE(drbd_ratelimit_state, 5 * HZ, 5);
|
DEFINE_RATELIMIT_STATE(drbd_ratelimit_state, 5 * HZ, 5);
|
||||||
|
|
||||||
static const struct block_device_operations drbd_ops = {
|
static const struct block_device_operations drbd_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = drbd_open,
|
.submit_bio = drbd_submit_bio,
|
||||||
.release = drbd_release,
|
.open = drbd_open,
|
||||||
|
.release = drbd_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bio *bio_alloc_drbd(gfp_t gfp_mask)
|
struct bio *bio_alloc_drbd(gfp_t gfp_mask)
|
||||||
@ -2324,7 +2325,7 @@ static void do_retry(struct work_struct *ws)
|
|||||||
* workqueues instead.
|
* workqueues instead.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* We are not just doing generic_make_request(),
|
/* We are not just doing submit_bio_noacct(),
|
||||||
* as we want to keep the start_time information. */
|
* as we want to keep the start_time information. */
|
||||||
inc_ap_bio(device);
|
inc_ap_bio(device);
|
||||||
__drbd_make_request(device, bio, start_jif);
|
__drbd_make_request(device, bio, start_jif);
|
||||||
@ -2414,62 +2415,6 @@ static void drbd_cleanup(void)
|
|||||||
pr_info("module cleanup done.\n");
|
pr_info("module cleanup done.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* drbd_congested() - Callback for the flusher thread
|
|
||||||
* @congested_data: User data
|
|
||||||
* @bdi_bits: Bits the BDI flusher thread is currently interested in
|
|
||||||
*
|
|
||||||
* Returns 1<<WB_async_congested and/or 1<<WB_sync_congested if we are congested.
|
|
||||||
*/
|
|
||||||
static int drbd_congested(void *congested_data, int bdi_bits)
|
|
||||||
{
|
|
||||||
struct drbd_device *device = congested_data;
|
|
||||||
struct request_queue *q;
|
|
||||||
char reason = '-';
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
if (!may_inc_ap_bio(device)) {
|
|
||||||
/* DRBD has frozen IO */
|
|
||||||
r = bdi_bits;
|
|
||||||
reason = 'd';
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (test_bit(CALLBACK_PENDING, &first_peer_device(device)->connection->flags)) {
|
|
||||||
r |= (1 << WB_async_congested);
|
|
||||||
/* Without good local data, we would need to read from remote,
|
|
||||||
* and that would need the worker thread as well, which is
|
|
||||||
* currently blocked waiting for that usermode helper to
|
|
||||||
* finish.
|
|
||||||
*/
|
|
||||||
if (!get_ldev_if_state(device, D_UP_TO_DATE))
|
|
||||||
r |= (1 << WB_sync_congested);
|
|
||||||
else
|
|
||||||
put_ldev(device);
|
|
||||||
r &= bdi_bits;
|
|
||||||
reason = 'c';
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_ldev(device)) {
|
|
||||||
q = bdev_get_queue(device->ldev->backing_bdev);
|
|
||||||
r = bdi_congested(q->backing_dev_info, bdi_bits);
|
|
||||||
put_ldev(device);
|
|
||||||
if (r)
|
|
||||||
reason = 'b';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bdi_bits & (1 << WB_async_congested) &&
|
|
||||||
test_bit(NET_CONGESTED, &first_peer_device(device)->connection->flags)) {
|
|
||||||
r |= (1 << WB_async_congested);
|
|
||||||
reason = reason == 'b' ? 'a' : 'n';
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
device->congestion_reason = reason;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drbd_init_workqueue(struct drbd_work_queue* wq)
|
static void drbd_init_workqueue(struct drbd_work_queue* wq)
|
||||||
{
|
{
|
||||||
spin_lock_init(&wq->q_lock);
|
spin_lock_init(&wq->q_lock);
|
||||||
@ -2801,11 +2746,10 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
|
|||||||
|
|
||||||
drbd_init_set_defaults(device);
|
drbd_init_set_defaults(device);
|
||||||
|
|
||||||
q = blk_alloc_queue(drbd_make_request, NUMA_NO_NODE);
|
q = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (!q)
|
if (!q)
|
||||||
goto out_no_q;
|
goto out_no_q;
|
||||||
device->rq_queue = q;
|
device->rq_queue = q;
|
||||||
q->queuedata = device;
|
|
||||||
|
|
||||||
disk = alloc_disk(1);
|
disk = alloc_disk(1);
|
||||||
if (!disk)
|
if (!disk)
|
||||||
@ -2825,9 +2769,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
|
|||||||
/* we have no partitions. we contain only ourselves. */
|
/* we have no partitions. we contain only ourselves. */
|
||||||
device->this_bdev->bd_contains = device->this_bdev;
|
device->this_bdev->bd_contains = device->this_bdev;
|
||||||
|
|
||||||
q->backing_dev_info->congested_fn = drbd_congested;
|
|
||||||
q->backing_dev_info->congested_data = device;
|
|
||||||
|
|
||||||
blk_queue_write_cache(q, true, true);
|
blk_queue_write_cache(q, true, true);
|
||||||
/* Setting the max_hw_sectors to an odd value of 8kibyte here
|
/* Setting the max_hw_sectors to an odd value of 8kibyte here
|
||||||
This triggers a max_bio_size message upon first attach or connect */
|
This triggers a max_bio_size message upon first attach or connect */
|
||||||
|
@ -265,7 +265,6 @@ int drbd_seq_show(struct seq_file *seq, void *v)
|
|||||||
seq_printf(seq, "%2d: cs:Unconfigured\n", i);
|
seq_printf(seq, "%2d: cs:Unconfigured\n", i);
|
||||||
} else {
|
} else {
|
||||||
/* reset device->congestion_reason */
|
/* reset device->congestion_reason */
|
||||||
bdi_rw_congested(device->rq_queue->backing_dev_info);
|
|
||||||
|
|
||||||
nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
|
nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
|
||||||
wp = nc ? nc->wire_protocol - DRBD_PROT_A + 'A' : ' ';
|
wp = nc ? nc->wire_protocol - DRBD_PROT_A + 'A' : ' ';
|
||||||
|
@ -1723,7 +1723,7 @@ next_bio:
|
|||||||
bios = bios->bi_next;
|
bios = bios->bi_next;
|
||||||
bio->bi_next = NULL;
|
bio->bi_next = NULL;
|
||||||
|
|
||||||
drbd_generic_make_request(device, fault_type, bio);
|
drbd_submit_bio_noacct(device, fault_type, bio);
|
||||||
} while (bios);
|
} while (bios);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1164,7 +1164,7 @@ drbd_submit_req_private_bio(struct drbd_request *req)
|
|||||||
else if (bio_op(bio) == REQ_OP_DISCARD)
|
else if (bio_op(bio) == REQ_OP_DISCARD)
|
||||||
drbd_process_discard_or_zeroes_req(req, EE_TRIM);
|
drbd_process_discard_or_zeroes_req(req, EE_TRIM);
|
||||||
else
|
else
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
put_ldev(device);
|
put_ldev(device);
|
||||||
} else
|
} else
|
||||||
bio_io_error(bio);
|
bio_io_error(bio);
|
||||||
@ -1593,12 +1593,12 @@ void do_submit(struct work_struct *ws)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blk_qc_t drbd_make_request(struct request_queue *q, struct bio *bio)
|
blk_qc_t drbd_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct drbd_device *device = (struct drbd_device *) q->queuedata;
|
struct drbd_device *device = bio->bi_disk->private_data;
|
||||||
unsigned long start_jif;
|
unsigned long start_jif;
|
||||||
|
|
||||||
blk_queue_split(q, &bio);
|
blk_queue_split(&bio);
|
||||||
|
|
||||||
start_jif = jiffies;
|
start_jif = jiffies;
|
||||||
|
|
||||||
|
@ -1525,7 +1525,7 @@ int w_restart_disk_io(struct drbd_work *w, int cancel)
|
|||||||
|
|
||||||
drbd_req_make_private_bio(req, req->master_bio);
|
drbd_req_make_private_bio(req, req->master_bio);
|
||||||
bio_set_dev(req->private_bio, device->ldev->backing_bdev);
|
bio_set_dev(req->private_bio, device->ldev->backing_bdev);
|
||||||
generic_make_request(req->private_bio);
|
submit_bio_noacct(req->private_bio);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4205,7 +4205,6 @@ static int __floppy_read_block_0(struct block_device *bdev, int drive)
|
|||||||
struct bio_vec bio_vec;
|
struct bio_vec bio_vec;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
struct rb0_cbdata cbdata;
|
struct rb0_cbdata cbdata;
|
||||||
size_t size;
|
|
||||||
|
|
||||||
page = alloc_page(GFP_NOIO);
|
page = alloc_page(GFP_NOIO);
|
||||||
if (!page) {
|
if (!page) {
|
||||||
@ -4213,15 +4212,11 @@ static int __floppy_read_block_0(struct block_device *bdev, int drive)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = bdev->bd_block_size;
|
|
||||||
if (!size)
|
|
||||||
size = 1024;
|
|
||||||
|
|
||||||
cbdata.drive = drive;
|
cbdata.drive = drive;
|
||||||
|
|
||||||
bio_init(&bio, &bio_vec, 1);
|
bio_init(&bio, &bio_vec, 1);
|
||||||
bio_set_dev(&bio, bdev);
|
bio_set_dev(&bio, bdev);
|
||||||
bio_add_page(&bio, page, size, 0);
|
bio_add_page(&bio, page, block_size(bdev), 0);
|
||||||
|
|
||||||
bio.bi_iter.bi_sector = 0;
|
bio.bi_iter.bi_sector = 0;
|
||||||
bio.bi_flags |= (1 << BIO_QUIET);
|
bio.bi_flags |= (1 << BIO_QUIET);
|
||||||
|
@ -509,7 +509,8 @@ static void lo_rw_aio_do_completion(struct loop_cmd *cmd)
|
|||||||
return;
|
return;
|
||||||
kfree(cmd->bvec);
|
kfree(cmd->bvec);
|
||||||
cmd->bvec = NULL;
|
cmd->bvec = NULL;
|
||||||
blk_mq_complete_request(rq);
|
if (likely(!blk_should_fake_timeout(rq->q)))
|
||||||
|
blk_mq_complete_request(rq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lo_rw_aio_complete(struct kiocb *iocb, long ret, long ret2)
|
static void lo_rw_aio_complete(struct kiocb *iocb, long ret, long ret2)
|
||||||
@ -1089,11 +1090,10 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
|
|||||||
* here to avoid changing device under exclusive owner.
|
* here to avoid changing device under exclusive owner.
|
||||||
*/
|
*/
|
||||||
if (!(mode & FMODE_EXCL)) {
|
if (!(mode & FMODE_EXCL)) {
|
||||||
claimed_bdev = bd_start_claiming(bdev, loop_configure);
|
claimed_bdev = bdev->bd_contains;
|
||||||
if (IS_ERR(claimed_bdev)) {
|
error = bd_prepare_to_claim(bdev, claimed_bdev, loop_configure);
|
||||||
error = PTR_ERR(claimed_bdev);
|
if (error)
|
||||||
goto out_putf;
|
goto out_putf;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error = mutex_lock_killable(&loop_ctl_mutex);
|
error = mutex_lock_killable(&loop_ctl_mutex);
|
||||||
@ -2048,7 +2048,8 @@ static void loop_handle_cmd(struct loop_cmd *cmd)
|
|||||||
cmd->ret = ret;
|
cmd->ret = ret;
|
||||||
else
|
else
|
||||||
cmd->ret = ret ? -EIO : 0;
|
cmd->ret = ret ? -EIO : 0;
|
||||||
blk_mq_complete_request(rq);
|
if (likely(!blk_should_fake_timeout(rq->q)))
|
||||||
|
blk_mq_complete_request(rq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2402,6 +2403,8 @@ static void __exit loop_exit(void)
|
|||||||
|
|
||||||
range = max_loop ? max_loop << part_shift : 1UL << MINORBITS;
|
range = max_loop ? max_loop << part_shift : 1UL << MINORBITS;
|
||||||
|
|
||||||
|
mutex_lock(&loop_ctl_mutex);
|
||||||
|
|
||||||
idr_for_each(&loop_index_idr, &loop_exit_cb, NULL);
|
idr_for_each(&loop_index_idr, &loop_exit_cb, NULL);
|
||||||
idr_destroy(&loop_index_idr);
|
idr_destroy(&loop_index_idr);
|
||||||
|
|
||||||
@ -2409,6 +2412,8 @@ static void __exit loop_exit(void)
|
|||||||
unregister_blkdev(LOOP_MAJOR, "loop");
|
unregister_blkdev(LOOP_MAJOR, "loop");
|
||||||
|
|
||||||
misc_deregister(&loop_misc);
|
misc_deregister(&loop_misc);
|
||||||
|
|
||||||
|
mutex_unlock(&loop_ctl_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(loop_init);
|
module_init(loop_init);
|
||||||
|
@ -492,7 +492,8 @@ static void mtip_complete_command(struct mtip_cmd *cmd, blk_status_t status)
|
|||||||
struct request *req = blk_mq_rq_from_pdu(cmd);
|
struct request *req = blk_mq_rq_from_pdu(cmd);
|
||||||
|
|
||||||
cmd->status = status;
|
cmd->status = status;
|
||||||
blk_mq_complete_request(req);
|
if (likely(!blk_should_fake_timeout(req->q)))
|
||||||
|
blk_mq_complete_request(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -784,6 +784,7 @@ static void recv_work(struct work_struct *work)
|
|||||||
struct nbd_device *nbd = args->nbd;
|
struct nbd_device *nbd = args->nbd;
|
||||||
struct nbd_config *config = nbd->config;
|
struct nbd_config *config = nbd->config;
|
||||||
struct nbd_cmd *cmd;
|
struct nbd_cmd *cmd;
|
||||||
|
struct request *rq;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
cmd = nbd_read_stat(nbd, args->index);
|
cmd = nbd_read_stat(nbd, args->index);
|
||||||
@ -796,7 +797,9 @@ static void recv_work(struct work_struct *work)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
blk_mq_complete_request(blk_mq_rq_from_pdu(cmd));
|
rq = blk_mq_rq_from_pdu(cmd);
|
||||||
|
if (likely(!blk_should_fake_timeout(rq->q)))
|
||||||
|
blk_mq_complete_request(rq);
|
||||||
}
|
}
|
||||||
atomic_dec(&config->recv_threads);
|
atomic_dec(&config->recv_threads);
|
||||||
wake_up(&config->recv_wq);
|
wake_up(&config->recv_wq);
|
||||||
|
@ -1283,7 +1283,8 @@ static inline void nullb_complete_cmd(struct nullb_cmd *cmd)
|
|||||||
case NULL_IRQ_SOFTIRQ:
|
case NULL_IRQ_SOFTIRQ:
|
||||||
switch (cmd->nq->dev->queue_mode) {
|
switch (cmd->nq->dev->queue_mode) {
|
||||||
case NULL_Q_MQ:
|
case NULL_Q_MQ:
|
||||||
blk_mq_complete_request(cmd->rq);
|
if (likely(!blk_should_fake_timeout(cmd->rq->q)))
|
||||||
|
blk_mq_complete_request(cmd->rq);
|
||||||
break;
|
break;
|
||||||
case NULL_Q_BIO:
|
case NULL_Q_BIO:
|
||||||
/*
|
/*
|
||||||
@ -1387,11 +1388,11 @@ static struct nullb_queue *nullb_to_queue(struct nullb *nullb)
|
|||||||
return &nullb->queues[index];
|
return &nullb->queues[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t null_queue_bio(struct request_queue *q, struct bio *bio)
|
static blk_qc_t null_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
sector_t sector = bio->bi_iter.bi_sector;
|
sector_t sector = bio->bi_iter.bi_sector;
|
||||||
sector_t nr_sectors = bio_sectors(bio);
|
sector_t nr_sectors = bio_sectors(bio);
|
||||||
struct nullb *nullb = q->queuedata;
|
struct nullb *nullb = bio->bi_disk->private_data;
|
||||||
struct nullb_queue *nq = nullb_to_queue(nullb);
|
struct nullb_queue *nq = nullb_to_queue(nullb);
|
||||||
struct nullb_cmd *cmd;
|
struct nullb_cmd *cmd;
|
||||||
|
|
||||||
@ -1423,7 +1424,7 @@ static bool should_requeue_request(struct request *rq)
|
|||||||
static enum blk_eh_timer_return null_timeout_rq(struct request *rq, bool res)
|
static enum blk_eh_timer_return null_timeout_rq(struct request *rq, bool res)
|
||||||
{
|
{
|
||||||
pr_info("rq %p timed out\n", rq);
|
pr_info("rq %p timed out\n", rq);
|
||||||
blk_mq_force_complete_rq(rq);
|
blk_mq_complete_request(rq);
|
||||||
return BLK_EH_DONE;
|
return BLK_EH_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1574,7 +1575,13 @@ static void null_config_discard(struct nullb *nullb)
|
|||||||
blk_queue_flag_set(QUEUE_FLAG_DISCARD, nullb->q);
|
blk_queue_flag_set(QUEUE_FLAG_DISCARD, nullb->q);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct block_device_operations null_ops = {
|
static const struct block_device_operations null_bio_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = null_submit_bio,
|
||||||
|
.report_zones = null_report_zones,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct block_device_operations null_rq_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.report_zones = null_report_zones,
|
.report_zones = null_report_zones,
|
||||||
};
|
};
|
||||||
@ -1646,7 +1653,10 @@ static int null_gendisk_register(struct nullb *nullb)
|
|||||||
disk->flags |= GENHD_FL_EXT_DEVT | GENHD_FL_SUPPRESS_PARTITION_INFO;
|
disk->flags |= GENHD_FL_EXT_DEVT | GENHD_FL_SUPPRESS_PARTITION_INFO;
|
||||||
disk->major = null_major;
|
disk->major = null_major;
|
||||||
disk->first_minor = nullb->index;
|
disk->first_minor = nullb->index;
|
||||||
disk->fops = &null_ops;
|
if (queue_is_mq(nullb->q))
|
||||||
|
disk->fops = &null_rq_ops;
|
||||||
|
else
|
||||||
|
disk->fops = &null_bio_ops;
|
||||||
disk->private_data = nullb;
|
disk->private_data = nullb;
|
||||||
disk->queue = nullb->q;
|
disk->queue = nullb->q;
|
||||||
strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
|
strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
|
||||||
@ -1791,7 +1801,7 @@ static int null_add_dev(struct nullb_device *dev)
|
|||||||
goto out_cleanup_tags;
|
goto out_cleanup_tags;
|
||||||
}
|
}
|
||||||
} else if (dev->queue_mode == NULL_Q_BIO) {
|
} else if (dev->queue_mode == NULL_Q_BIO) {
|
||||||
nullb->q = blk_alloc_queue(null_queue_bio, dev->home_node);
|
nullb->q = blk_alloc_queue(dev->home_node);
|
||||||
if (!nullb->q) {
|
if (!nullb->q) {
|
||||||
rv = -ENOMEM;
|
rv = -ENOMEM;
|
||||||
goto out_cleanup_queues;
|
goto out_cleanup_queues;
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
* block device, assembling the pieces to full packets and queuing them to the
|
* block device, assembling the pieces to full packets and queuing them to the
|
||||||
* packet I/O scheduler.
|
* packet I/O scheduler.
|
||||||
*
|
*
|
||||||
* At the top layer there is a custom make_request_fn function that forwards
|
* At the top layer there is a custom ->submit_bio function that forwards
|
||||||
* read requests directly to the iosched queue and puts write requests in the
|
* read requests directly to the iosched queue and puts write requests in the
|
||||||
* unaligned write queue. A kernel thread performs the necessary read
|
* unaligned write queue. A kernel thread performs the necessary read
|
||||||
* gathering to convert the unaligned writes to aligned writes and then feeds
|
* gathering to convert the unaligned writes to aligned writes and then feeds
|
||||||
@ -913,7 +913,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_inc(&pd->cdrw.pending_bios);
|
atomic_inc(&pd->cdrw.pending_bios);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2428,15 +2428,15 @@ static void pkt_make_request_write(struct request_queue *q, struct bio *bio)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t pkt_make_request(struct request_queue *q, struct bio *bio)
|
static blk_qc_t pkt_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct pktcdvd_device *pd;
|
struct pktcdvd_device *pd;
|
||||||
char b[BDEVNAME_SIZE];
|
char b[BDEVNAME_SIZE];
|
||||||
struct bio *split;
|
struct bio *split;
|
||||||
|
|
||||||
blk_queue_split(q, &bio);
|
blk_queue_split(&bio);
|
||||||
|
|
||||||
pd = q->queuedata;
|
pd = bio->bi_disk->queue->queuedata;
|
||||||
if (!pd) {
|
if (!pd) {
|
||||||
pr_err("%s incorrect request queue\n", bio_devname(bio, b));
|
pr_err("%s incorrect request queue\n", bio_devname(bio, b));
|
||||||
goto end_io;
|
goto end_io;
|
||||||
@ -2480,7 +2480,7 @@ static blk_qc_t pkt_make_request(struct request_queue *q, struct bio *bio)
|
|||||||
split = bio;
|
split = bio;
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt_make_request_write(q, split);
|
pkt_make_request_write(bio->bi_disk->queue, split);
|
||||||
} while (split != bio);
|
} while (split != bio);
|
||||||
|
|
||||||
return BLK_QC_T_NONE;
|
return BLK_QC_T_NONE;
|
||||||
@ -2685,6 +2685,7 @@ static char *pkt_devnode(struct gendisk *disk, umode_t *mode)
|
|||||||
|
|
||||||
static const struct block_device_operations pktcdvd_ops = {
|
static const struct block_device_operations pktcdvd_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = pkt_submit_bio,
|
||||||
.open = pkt_open,
|
.open = pkt_open,
|
||||||
.release = pkt_close,
|
.release = pkt_close,
|
||||||
.ioctl = pkt_ioctl,
|
.ioctl = pkt_ioctl,
|
||||||
@ -2749,7 +2750,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
|
|||||||
disk->flags = GENHD_FL_REMOVABLE;
|
disk->flags = GENHD_FL_REMOVABLE;
|
||||||
strcpy(disk->disk_name, pd->name);
|
strcpy(disk->disk_name, pd->name);
|
||||||
disk->private_data = pd;
|
disk->private_data = pd;
|
||||||
disk->queue = blk_alloc_queue(pkt_make_request, NUMA_NO_NODE);
|
disk->queue = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (!disk->queue)
|
if (!disk->queue)
|
||||||
goto out_mem2;
|
goto out_mem2;
|
||||||
|
|
||||||
|
@ -90,12 +90,6 @@ struct ps3vram_priv {
|
|||||||
|
|
||||||
static int ps3vram_major;
|
static int ps3vram_major;
|
||||||
|
|
||||||
|
|
||||||
static const struct block_device_operations ps3vram_fops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */
|
#define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */
|
||||||
#define DMA_NOTIFIER_OFFSET_BASE 0x1000 /* first DMA notifier offset */
|
#define DMA_NOTIFIER_OFFSET_BASE 0x1000 /* first DMA notifier offset */
|
||||||
#define DMA_NOTIFIER_SIZE 0x40
|
#define DMA_NOTIFIER_SIZE 0x40
|
||||||
@ -585,15 +579,15 @@ out:
|
|||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t ps3vram_make_request(struct request_queue *q, struct bio *bio)
|
static blk_qc_t ps3vram_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct ps3_system_bus_device *dev = q->queuedata;
|
struct ps3_system_bus_device *dev = bio->bi_disk->private_data;
|
||||||
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
|
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
|
||||||
int busy;
|
int busy;
|
||||||
|
|
||||||
dev_dbg(&dev->core, "%s\n", __func__);
|
dev_dbg(&dev->core, "%s\n", __func__);
|
||||||
|
|
||||||
blk_queue_split(q, &bio);
|
blk_queue_split(&bio);
|
||||||
|
|
||||||
spin_lock_irq(&priv->lock);
|
spin_lock_irq(&priv->lock);
|
||||||
busy = !bio_list_empty(&priv->list);
|
busy = !bio_list_empty(&priv->list);
|
||||||
@ -610,6 +604,11 @@ static blk_qc_t ps3vram_make_request(struct request_queue *q, struct bio *bio)
|
|||||||
return BLK_QC_T_NONE;
|
return BLK_QC_T_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct block_device_operations ps3vram_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = ps3vram_submit_bio,
|
||||||
|
};
|
||||||
|
|
||||||
static int ps3vram_probe(struct ps3_system_bus_device *dev)
|
static int ps3vram_probe(struct ps3_system_bus_device *dev)
|
||||||
{
|
{
|
||||||
struct ps3vram_priv *priv;
|
struct ps3vram_priv *priv;
|
||||||
@ -737,7 +736,7 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev)
|
|||||||
|
|
||||||
ps3vram_proc_init(dev);
|
ps3vram_proc_init(dev);
|
||||||
|
|
||||||
queue = blk_alloc_queue(ps3vram_make_request, NUMA_NO_NODE);
|
queue = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (!queue) {
|
if (!queue) {
|
||||||
dev_err(&dev->core, "blk_alloc_queue failed\n");
|
dev_err(&dev->core, "blk_alloc_queue failed\n");
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
@ -745,7 +744,6 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
priv->queue = queue;
|
priv->queue = queue;
|
||||||
queue->queuedata = dev;
|
|
||||||
blk_queue_max_segments(queue, BLK_MAX_SEGMENTS);
|
blk_queue_max_segments(queue, BLK_MAX_SEGMENTS);
|
||||||
blk_queue_max_segment_size(queue, BLK_MAX_SEGMENT_SIZE);
|
blk_queue_max_segment_size(queue, BLK_MAX_SEGMENT_SIZE);
|
||||||
blk_queue_max_hw_sectors(queue, BLK_SAFE_MAX_SECTORS);
|
blk_queue_max_hw_sectors(queue, BLK_SAFE_MAX_SECTORS);
|
||||||
|
@ -50,6 +50,8 @@ struct rsxx_bio_meta {
|
|||||||
|
|
||||||
static struct kmem_cache *bio_meta_pool;
|
static struct kmem_cache *bio_meta_pool;
|
||||||
|
|
||||||
|
static blk_qc_t rsxx_submit_bio(struct bio *bio);
|
||||||
|
|
||||||
/*----------------- Block Device Operations -----------------*/
|
/*----------------- Block Device Operations -----------------*/
|
||||||
static int rsxx_blkdev_ioctl(struct block_device *bdev,
|
static int rsxx_blkdev_ioctl(struct block_device *bdev,
|
||||||
fmode_t mode,
|
fmode_t mode,
|
||||||
@ -92,6 +94,7 @@ static int rsxx_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
|||||||
|
|
||||||
static const struct block_device_operations rsxx_fops = {
|
static const struct block_device_operations rsxx_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = rsxx_submit_bio,
|
||||||
.getgeo = rsxx_getgeo,
|
.getgeo = rsxx_getgeo,
|
||||||
.ioctl = rsxx_blkdev_ioctl,
|
.ioctl = rsxx_blkdev_ioctl,
|
||||||
};
|
};
|
||||||
@ -117,13 +120,13 @@ static void bio_dma_done_cb(struct rsxx_cardinfo *card,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t rsxx_make_request(struct request_queue *q, struct bio *bio)
|
static blk_qc_t rsxx_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct rsxx_cardinfo *card = q->queuedata;
|
struct rsxx_cardinfo *card = bio->bi_disk->private_data;
|
||||||
struct rsxx_bio_meta *bio_meta;
|
struct rsxx_bio_meta *bio_meta;
|
||||||
blk_status_t st = BLK_STS_IOERR;
|
blk_status_t st = BLK_STS_IOERR;
|
||||||
|
|
||||||
blk_queue_split(q, &bio);
|
blk_queue_split(&bio);
|
||||||
|
|
||||||
might_sleep();
|
might_sleep();
|
||||||
|
|
||||||
@ -233,7 +236,7 @@ int rsxx_setup_dev(struct rsxx_cardinfo *card)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
card->queue = blk_alloc_queue(rsxx_make_request, NUMA_NO_NODE);
|
card->queue = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (!card->queue) {
|
if (!card->queue) {
|
||||||
dev_err(CARD_TO_DEV(card), "Failed queue alloc\n");
|
dev_err(CARD_TO_DEV(card), "Failed queue alloc\n");
|
||||||
unregister_blkdev(card->major, DRIVER_NAME);
|
unregister_blkdev(card->major, DRIVER_NAME);
|
||||||
@ -267,8 +270,6 @@ int rsxx_setup_dev(struct rsxx_cardinfo *card)
|
|||||||
card->queue->limits.discard_alignment = RSXX_HW_BLK_SIZE;
|
card->queue->limits.discard_alignment = RSXX_HW_BLK_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
card->queue->queuedata = card;
|
|
||||||
|
|
||||||
snprintf(card->gendisk->disk_name, sizeof(card->gendisk->disk_name),
|
snprintf(card->gendisk->disk_name, sizeof(card->gendisk->disk_name),
|
||||||
"rsxx%d", card->disk_id);
|
"rsxx%d", card->disk_id);
|
||||||
card->gendisk->major = card->major;
|
card->gendisk->major = card->major;
|
||||||
@ -289,7 +290,6 @@ void rsxx_destroy_dev(struct rsxx_cardinfo *card)
|
|||||||
card->gendisk = NULL;
|
card->gendisk = NULL;
|
||||||
|
|
||||||
blk_cleanup_queue(card->queue);
|
blk_cleanup_queue(card->queue);
|
||||||
card->queue->queuedata = NULL;
|
|
||||||
unregister_blkdev(card->major, DRIVER_NAME);
|
unregister_blkdev(card->major, DRIVER_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1417,7 +1417,8 @@ static void skd_resolve_req_exception(struct skd_device *skdev,
|
|||||||
case SKD_CHECK_STATUS_REPORT_GOOD:
|
case SKD_CHECK_STATUS_REPORT_GOOD:
|
||||||
case SKD_CHECK_STATUS_REPORT_SMART_ALERT:
|
case SKD_CHECK_STATUS_REPORT_SMART_ALERT:
|
||||||
skreq->status = BLK_STS_OK;
|
skreq->status = BLK_STS_OK;
|
||||||
blk_mq_complete_request(req);
|
if (likely(!blk_should_fake_timeout(req->q)))
|
||||||
|
blk_mq_complete_request(req);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SKD_CHECK_STATUS_BUSY_IMMINENT:
|
case SKD_CHECK_STATUS_BUSY_IMMINENT:
|
||||||
@ -1440,7 +1441,8 @@ static void skd_resolve_req_exception(struct skd_device *skdev,
|
|||||||
case SKD_CHECK_STATUS_REPORT_ERROR:
|
case SKD_CHECK_STATUS_REPORT_ERROR:
|
||||||
default:
|
default:
|
||||||
skreq->status = BLK_STS_IOERR;
|
skreq->status = BLK_STS_IOERR;
|
||||||
blk_mq_complete_request(req);
|
if (likely(!blk_should_fake_timeout(req->q)))
|
||||||
|
blk_mq_complete_request(req);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1560,7 +1562,8 @@ static int skd_isr_completion_posted(struct skd_device *skdev,
|
|||||||
*/
|
*/
|
||||||
if (likely(cmp_status == SAM_STAT_GOOD)) {
|
if (likely(cmp_status == SAM_STAT_GOOD)) {
|
||||||
skreq->status = BLK_STS_OK;
|
skreq->status = BLK_STS_OK;
|
||||||
blk_mq_complete_request(rq);
|
if (likely(!blk_should_fake_timeout(rq->q)))
|
||||||
|
blk_mq_complete_request(rq);
|
||||||
} else {
|
} else {
|
||||||
skd_resolve_req_exception(skdev, skreq, rq);
|
skd_resolve_req_exception(skdev, skreq, rq);
|
||||||
}
|
}
|
||||||
|
@ -519,14 +519,15 @@ static int mm_check_plugged(struct cardinfo *card)
|
|||||||
return !!blk_check_plugged(mm_unplug, card, sizeof(struct blk_plug_cb));
|
return !!blk_check_plugged(mm_unplug, card, sizeof(struct blk_plug_cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t mm_make_request(struct request_queue *q, struct bio *bio)
|
static blk_qc_t mm_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct cardinfo *card = q->queuedata;
|
struct cardinfo *card = bio->bi_disk->private_data;
|
||||||
|
|
||||||
pr_debug("mm_make_request %llu %u\n",
|
pr_debug("mm_make_request %llu %u\n",
|
||||||
(unsigned long long)bio->bi_iter.bi_sector,
|
(unsigned long long)bio->bi_iter.bi_sector,
|
||||||
bio->bi_iter.bi_size);
|
bio->bi_iter.bi_size);
|
||||||
|
|
||||||
blk_queue_split(q, &bio);
|
blk_queue_split(&bio);
|
||||||
|
|
||||||
spin_lock_irq(&card->lock);
|
spin_lock_irq(&card->lock);
|
||||||
*card->biotail = bio;
|
*card->biotail = bio;
|
||||||
@ -778,6 +779,7 @@ static int mm_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
|||||||
|
|
||||||
static const struct block_device_operations mm_fops = {
|
static const struct block_device_operations mm_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = mm_submit_bio,
|
||||||
.getgeo = mm_getgeo,
|
.getgeo = mm_getgeo,
|
||||||
.revalidate_disk = mm_revalidate,
|
.revalidate_disk = mm_revalidate,
|
||||||
};
|
};
|
||||||
@ -885,10 +887,9 @@ static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||||||
card->biotail = &card->bio;
|
card->biotail = &card->bio;
|
||||||
spin_lock_init(&card->lock);
|
spin_lock_init(&card->lock);
|
||||||
|
|
||||||
card->queue = blk_alloc_queue(mm_make_request, NUMA_NO_NODE);
|
card->queue = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (!card->queue)
|
if (!card->queue)
|
||||||
goto failed_alloc;
|
goto failed_alloc;
|
||||||
card->queue->queuedata = card;
|
|
||||||
|
|
||||||
tasklet_init(&card->tasklet, process_page, (unsigned long)card);
|
tasklet_init(&card->tasklet, process_page, (unsigned long)card);
|
||||||
|
|
||||||
|
@ -171,7 +171,8 @@ static void virtblk_done(struct virtqueue *vq)
|
|||||||
while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) {
|
while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) {
|
||||||
struct request *req = blk_mq_rq_from_pdu(vbr);
|
struct request *req = blk_mq_rq_from_pdu(vbr);
|
||||||
|
|
||||||
blk_mq_complete_request(req);
|
if (likely(!blk_should_fake_timeout(req->q)))
|
||||||
|
blk_mq_complete_request(req);
|
||||||
req_done = true;
|
req_done = true;
|
||||||
}
|
}
|
||||||
if (unlikely(virtqueue_is_broken(vq)))
|
if (unlikely(virtqueue_is_broken(vq)))
|
||||||
|
@ -1655,7 +1655,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
|||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
blk_mq_complete_request(req);
|
if (likely(!blk_should_fake_timeout(req->q)))
|
||||||
|
blk_mq_complete_request(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
rinfo->ring.rsp_cons = i;
|
rinfo->ring.rsp_cons = i;
|
||||||
|
@ -793,9 +793,9 @@ static void zram_sync_read(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Block layer want one ->make_request_fn to be active at a time
|
* Block layer want one ->submit_bio to be active at a time, so if we use
|
||||||
* so if we use chained IO with parent IO in same context,
|
* chained IO with parent IO in same context, it's a deadlock. To avoid that,
|
||||||
* it's a deadlock. To avoid, it, it uses worker thread context.
|
* use a worker thread context.
|
||||||
*/
|
*/
|
||||||
static int read_from_bdev_sync(struct zram *zram, struct bio_vec *bvec,
|
static int read_from_bdev_sync(struct zram *zram, struct bio_vec *bvec,
|
||||||
unsigned long entry, struct bio *bio)
|
unsigned long entry, struct bio *bio)
|
||||||
@ -1584,9 +1584,9 @@ static void __zram_make_request(struct zram *zram, struct bio *bio)
|
|||||||
/*
|
/*
|
||||||
* Handler function for all zram I/O requests.
|
* Handler function for all zram I/O requests.
|
||||||
*/
|
*/
|
||||||
static blk_qc_t zram_make_request(struct request_queue *queue, struct bio *bio)
|
static blk_qc_t zram_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct zram *zram = queue->queuedata;
|
struct zram *zram = bio->bi_disk->private_data;
|
||||||
|
|
||||||
if (!valid_io_request(zram, bio->bi_iter.bi_sector,
|
if (!valid_io_request(zram, bio->bi_iter.bi_sector,
|
||||||
bio->bi_iter.bi_size)) {
|
bio->bi_iter.bi_size)) {
|
||||||
@ -1813,6 +1813,7 @@ static int zram_open(struct block_device *bdev, fmode_t mode)
|
|||||||
|
|
||||||
static const struct block_device_operations zram_devops = {
|
static const struct block_device_operations zram_devops = {
|
||||||
.open = zram_open,
|
.open = zram_open,
|
||||||
|
.submit_bio = zram_submit_bio,
|
||||||
.swap_slot_free_notify = zram_slot_free_notify,
|
.swap_slot_free_notify = zram_slot_free_notify,
|
||||||
.rw_page = zram_rw_page,
|
.rw_page = zram_rw_page,
|
||||||
.owner = THIS_MODULE
|
.owner = THIS_MODULE
|
||||||
@ -1891,7 +1892,7 @@ static int zram_add(void)
|
|||||||
#ifdef CONFIG_ZRAM_WRITEBACK
|
#ifdef CONFIG_ZRAM_WRITEBACK
|
||||||
spin_lock_init(&zram->wb_limit_lock);
|
spin_lock_init(&zram->wb_limit_lock);
|
||||||
#endif
|
#endif
|
||||||
queue = blk_alloc_queue(zram_make_request, NUMA_NO_NODE);
|
queue = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (!queue) {
|
if (!queue) {
|
||||||
pr_err("Error allocating disk queue for device %d\n",
|
pr_err("Error allocating disk queue for device %d\n",
|
||||||
device_id);
|
device_id);
|
||||||
@ -1912,7 +1913,6 @@ static int zram_add(void)
|
|||||||
zram->disk->first_minor = device_id;
|
zram->disk->first_minor = device_id;
|
||||||
zram->disk->fops = &zram_devops;
|
zram->disk->fops = &zram_devops;
|
||||||
zram->disk->queue = queue;
|
zram->disk->queue = queue;
|
||||||
zram->disk->queue->queuedata = zram;
|
|
||||||
zram->disk->private_data = zram;
|
zram->disk->private_data = zram;
|
||||||
snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
|
snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
|
||||||
|
|
||||||
|
@ -605,7 +605,7 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi)
|
|||||||
disk->cdi = cdi;
|
disk->cdi = cdi;
|
||||||
|
|
||||||
ENSURE(cdo, drive_status, CDC_DRIVE_STATUS);
|
ENSURE(cdo, drive_status, CDC_DRIVE_STATUS);
|
||||||
if (cdo->check_events == NULL && cdo->media_changed == NULL)
|
if (cdo->check_events == NULL)
|
||||||
WARN_ON_ONCE(cdo->capability & (CDC_MEDIA_CHANGED | CDC_SELECT_DISC));
|
WARN_ON_ONCE(cdo->capability & (CDC_MEDIA_CHANGED | CDC_SELECT_DISC));
|
||||||
ENSURE(cdo, tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
|
ENSURE(cdo, tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
|
||||||
ENSURE(cdo, lock_door, CDC_LOCK);
|
ENSURE(cdo, lock_door, CDC_LOCK);
|
||||||
@ -1419,8 +1419,6 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
|
|||||||
|
|
||||||
if (cdi->ops->check_events)
|
if (cdi->ops->check_events)
|
||||||
cdi->ops->check_events(cdi, 0, slot);
|
cdi->ops->check_events(cdi, 0, slot);
|
||||||
else
|
|
||||||
cdi->ops->media_changed(cdi, slot);
|
|
||||||
|
|
||||||
if (slot == CDSL_NONE) {
|
if (slot == CDSL_NONE) {
|
||||||
/* set media changed bits, on both queues */
|
/* set media changed bits, on both queues */
|
||||||
@ -1517,13 +1515,10 @@ int media_changed(struct cdrom_device_info *cdi, int queue)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* changed since last call? */
|
/* changed since last call? */
|
||||||
if (cdi->ops->check_events) {
|
BUG_ON(!queue); /* shouldn't be called from VFS path */
|
||||||
BUG_ON(!queue); /* shouldn't be called from VFS path */
|
cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE);
|
||||||
cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE);
|
changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE;
|
||||||
changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE;
|
cdi->ioctl_events = 0;
|
||||||
cdi->ioctl_events = 0;
|
|
||||||
} else
|
|
||||||
changed = cdi->ops->media_changed(cdi, CDSL_CURRENT);
|
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
cdi->mc_flags = 0x3; /* set bit on both queues */
|
cdi->mc_flags = 0x3; /* set bit on both queues */
|
||||||
@ -1535,18 +1530,6 @@ int media_changed(struct cdrom_device_info *cdi, int queue)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cdrom_media_changed(struct cdrom_device_info *cdi)
|
|
||||||
{
|
|
||||||
/* This talks to the VFS, which doesn't like errors - just 1 or 0.
|
|
||||||
* Returning "0" is always safe (media hasn't been changed). Do that
|
|
||||||
* if the low-level cdrom driver dosn't support media changed. */
|
|
||||||
if (cdi == NULL || cdi->ops->media_changed == NULL)
|
|
||||||
return 0;
|
|
||||||
if (!CDROM_CAN(CDC_MEDIA_CHANGED))
|
|
||||||
return 0;
|
|
||||||
return media_changed(cdi, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Requests to the low-level drivers will /always/ be done in the
|
/* Requests to the low-level drivers will /always/ be done in the
|
||||||
following format convention:
|
following format convention:
|
||||||
|
|
||||||
@ -3464,7 +3447,6 @@ EXPORT_SYMBOL(unregister_cdrom);
|
|||||||
EXPORT_SYMBOL(cdrom_open);
|
EXPORT_SYMBOL(cdrom_open);
|
||||||
EXPORT_SYMBOL(cdrom_release);
|
EXPORT_SYMBOL(cdrom_release);
|
||||||
EXPORT_SYMBOL(cdrom_ioctl);
|
EXPORT_SYMBOL(cdrom_ioctl);
|
||||||
EXPORT_SYMBOL(cdrom_media_changed);
|
|
||||||
EXPORT_SYMBOL(cdrom_number_of_slots);
|
EXPORT_SYMBOL(cdrom_number_of_slots);
|
||||||
EXPORT_SYMBOL(cdrom_mode_select);
|
EXPORT_SYMBOL(cdrom_mode_select);
|
||||||
EXPORT_SYMBOL(cdrom_mode_sense);
|
EXPORT_SYMBOL(cdrom_mode_sense);
|
||||||
|
@ -59,7 +59,7 @@ EXPORT_SYMBOL(bdev_dax_pgoff);
|
|||||||
#if IS_ENABLED(CONFIG_FS_DAX)
|
#if IS_ENABLED(CONFIG_FS_DAX)
|
||||||
struct dax_device *fs_dax_get_by_bdev(struct block_device *bdev)
|
struct dax_device *fs_dax_get_by_bdev(struct block_device *bdev)
|
||||||
{
|
{
|
||||||
if (!blk_queue_dax(bdev->bd_queue))
|
if (!blk_queue_dax(bdev->bd_disk->queue))
|
||||||
return NULL;
|
return NULL;
|
||||||
return dax_get_by_host(bdev->bd_disk->disk_name);
|
return dax_get_by_host(bdev->bd_disk->disk_name);
|
||||||
}
|
}
|
||||||
|
@ -236,10 +236,6 @@ err_dev:
|
|||||||
return tgt_dev;
|
return tgt_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct block_device_operations nvm_fops = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct nvm_tgt_type *__nvm_find_target_type(const char *name)
|
static struct nvm_tgt_type *__nvm_find_target_type(const char *name)
|
||||||
{
|
{
|
||||||
struct nvm_tgt_type *tt;
|
struct nvm_tgt_type *tt;
|
||||||
@ -380,7 +376,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
|
|||||||
goto err_dev;
|
goto err_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
tqueue = blk_alloc_queue(tt->make_rq, dev->q->node);
|
tqueue = blk_alloc_queue(dev->q->node);
|
||||||
if (!tqueue) {
|
if (!tqueue) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_disk;
|
goto err_disk;
|
||||||
@ -390,7 +386,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
|
|||||||
tdisk->flags = GENHD_FL_EXT_DEVT;
|
tdisk->flags = GENHD_FL_EXT_DEVT;
|
||||||
tdisk->major = 0;
|
tdisk->major = 0;
|
||||||
tdisk->first_minor = 0;
|
tdisk->first_minor = 0;
|
||||||
tdisk->fops = &nvm_fops;
|
tdisk->fops = tt->bops;
|
||||||
tdisk->queue = tqueue;
|
tdisk->queue = tqueue;
|
||||||
|
|
||||||
targetdata = tt->init(tgt_dev, tdisk, create->flags);
|
targetdata = tt->init(tgt_dev, tdisk, create->flags);
|
||||||
|
@ -47,9 +47,9 @@ static struct pblk_global_caches pblk_caches = {
|
|||||||
|
|
||||||
struct bio_set pblk_bio_set;
|
struct bio_set pblk_bio_set;
|
||||||
|
|
||||||
static blk_qc_t pblk_make_rq(struct request_queue *q, struct bio *bio)
|
static blk_qc_t pblk_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct pblk *pblk = q->queuedata;
|
struct pblk *pblk = bio->bi_disk->queue->queuedata;
|
||||||
|
|
||||||
if (bio_op(bio) == REQ_OP_DISCARD) {
|
if (bio_op(bio) == REQ_OP_DISCARD) {
|
||||||
pblk_discard(pblk, bio);
|
pblk_discard(pblk, bio);
|
||||||
@ -63,7 +63,7 @@ static blk_qc_t pblk_make_rq(struct request_queue *q, struct bio *bio)
|
|||||||
* constraint. Writes can be of arbitrary size.
|
* constraint. Writes can be of arbitrary size.
|
||||||
*/
|
*/
|
||||||
if (bio_data_dir(bio) == READ) {
|
if (bio_data_dir(bio) == READ) {
|
||||||
blk_queue_split(q, &bio);
|
blk_queue_split(&bio);
|
||||||
pblk_submit_read(pblk, bio);
|
pblk_submit_read(pblk, bio);
|
||||||
} else {
|
} else {
|
||||||
/* Prevent deadlock in the case of a modest LUN configuration
|
/* Prevent deadlock in the case of a modest LUN configuration
|
||||||
@ -71,7 +71,7 @@ static blk_qc_t pblk_make_rq(struct request_queue *q, struct bio *bio)
|
|||||||
* leaves at least 256KB available for user I/O.
|
* leaves at least 256KB available for user I/O.
|
||||||
*/
|
*/
|
||||||
if (pblk_get_secs(bio) > pblk_rl_max_io(&pblk->rl))
|
if (pblk_get_secs(bio) > pblk_rl_max_io(&pblk->rl))
|
||||||
blk_queue_split(q, &bio);
|
blk_queue_split(&bio);
|
||||||
|
|
||||||
pblk_write_to_cache(pblk, bio, PBLK_IOTYPE_USER);
|
pblk_write_to_cache(pblk, bio, PBLK_IOTYPE_USER);
|
||||||
}
|
}
|
||||||
@ -79,6 +79,12 @@ static blk_qc_t pblk_make_rq(struct request_queue *q, struct bio *bio)
|
|||||||
return BLK_QC_T_NONE;
|
return BLK_QC_T_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct block_device_operations pblk_bops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = pblk_submit_bio,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static size_t pblk_trans_map_size(struct pblk *pblk)
|
static size_t pblk_trans_map_size(struct pblk *pblk)
|
||||||
{
|
{
|
||||||
int entry_size = 8;
|
int entry_size = 8;
|
||||||
@ -1280,7 +1286,7 @@ static struct nvm_tgt_type tt_pblk = {
|
|||||||
.name = "pblk",
|
.name = "pblk",
|
||||||
.version = {1, 0, 0},
|
.version = {1, 0, 0},
|
||||||
|
|
||||||
.make_rq = pblk_make_rq,
|
.bops = &pblk_bops,
|
||||||
.capacity = pblk_capacity,
|
.capacity = pblk_capacity,
|
||||||
|
|
||||||
.init = pblk_init,
|
.init = pblk_init,
|
||||||
|
@ -320,7 +320,7 @@ split_retry:
|
|||||||
split_bio = bio_split(bio, nr_secs * NR_PHY_IN_LOG, GFP_KERNEL,
|
split_bio = bio_split(bio, nr_secs * NR_PHY_IN_LOG, GFP_KERNEL,
|
||||||
&pblk_bio_set);
|
&pblk_bio_set);
|
||||||
bio_chain(split_bio, bio);
|
bio_chain(split_bio, bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
|
|
||||||
/* New bio contains first N sectors of the previous one, so
|
/* New bio contains first N sectors of the previous one, so
|
||||||
* we can continue to use existing rqd, but we need to shrink
|
* we can continue to use existing rqd, but we need to shrink
|
||||||
|
@ -929,7 +929,7 @@ static inline void closure_bio_submit(struct cache_set *c,
|
|||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -959,7 +959,7 @@ err:
|
|||||||
* bch_btree_node_get - find a btree node in the cache and lock it, reading it
|
* bch_btree_node_get - find a btree node in the cache and lock it, reading it
|
||||||
* in from disk if necessary.
|
* in from disk if necessary.
|
||||||
*
|
*
|
||||||
* If IO is necessary and running under generic_make_request, returns -EAGAIN.
|
* If IO is necessary and running under submit_bio_noacct, returns -EAGAIN.
|
||||||
*
|
*
|
||||||
* The btree node will have either a read or a write lock held, depending on
|
* The btree node will have either a read or a write lock held, depending on
|
||||||
* level and op->lock.
|
* level and op->lock.
|
||||||
|
@ -1115,7 +1115,7 @@ static void detached_dev_do_request(struct bcache_device *d, struct bio *bio)
|
|||||||
!blk_queue_discard(bdev_get_queue(dc->bdev)))
|
!blk_queue_discard(bdev_get_queue(dc->bdev)))
|
||||||
bio->bi_end_io(bio);
|
bio->bi_end_io(bio);
|
||||||
else
|
else
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quit_max_writeback_rate(struct cache_set *c,
|
static void quit_max_writeback_rate(struct cache_set *c,
|
||||||
@ -1158,7 +1158,7 @@ static void quit_max_writeback_rate(struct cache_set *c,
|
|||||||
|
|
||||||
/* Cached devices - read & write stuff */
|
/* Cached devices - read & write stuff */
|
||||||
|
|
||||||
blk_qc_t cached_dev_make_request(struct request_queue *q, struct bio *bio)
|
blk_qc_t cached_dev_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct search *s;
|
struct search *s;
|
||||||
struct bcache_device *d = bio->bi_disk->private_data;
|
struct bcache_device *d = bio->bi_disk->private_data;
|
||||||
@ -1197,7 +1197,7 @@ blk_qc_t cached_dev_make_request(struct request_queue *q, struct bio *bio)
|
|||||||
if (!bio->bi_iter.bi_size) {
|
if (!bio->bi_iter.bi_size) {
|
||||||
/*
|
/*
|
||||||
* can't call bch_journal_meta from under
|
* can't call bch_journal_meta from under
|
||||||
* generic_make_request
|
* submit_bio_noacct
|
||||||
*/
|
*/
|
||||||
continue_at_nobarrier(&s->cl,
|
continue_at_nobarrier(&s->cl,
|
||||||
cached_dev_nodata,
|
cached_dev_nodata,
|
||||||
@ -1228,36 +1228,8 @@ static int cached_dev_ioctl(struct bcache_device *d, fmode_t mode,
|
|||||||
return __blkdev_driver_ioctl(dc->bdev, mode, cmd, arg);
|
return __blkdev_driver_ioctl(dc->bdev, mode, cmd, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cached_dev_congested(void *data, int bits)
|
|
||||||
{
|
|
||||||
struct bcache_device *d = data;
|
|
||||||
struct cached_dev *dc = container_of(d, struct cached_dev, disk);
|
|
||||||
struct request_queue *q = bdev_get_queue(dc->bdev);
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (bdi_congested(q->backing_dev_info, bits))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (cached_dev_get(dc)) {
|
|
||||||
unsigned int i;
|
|
||||||
struct cache *ca;
|
|
||||||
|
|
||||||
for_each_cache(ca, d->c, i) {
|
|
||||||
q = bdev_get_queue(ca->bdev);
|
|
||||||
ret |= bdi_congested(q->backing_dev_info, bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
cached_dev_put(dc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bch_cached_dev_request_init(struct cached_dev *dc)
|
void bch_cached_dev_request_init(struct cached_dev *dc)
|
||||||
{
|
{
|
||||||
struct gendisk *g = dc->disk.disk;
|
|
||||||
|
|
||||||
g->queue->backing_dev_info->congested_fn = cached_dev_congested;
|
|
||||||
dc->disk.cache_miss = cached_dev_cache_miss;
|
dc->disk.cache_miss = cached_dev_cache_miss;
|
||||||
dc->disk.ioctl = cached_dev_ioctl;
|
dc->disk.ioctl = cached_dev_ioctl;
|
||||||
}
|
}
|
||||||
@ -1291,7 +1263,7 @@ static void flash_dev_nodata(struct closure *cl)
|
|||||||
continue_at(cl, search_free, NULL);
|
continue_at(cl, search_free, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
blk_qc_t flash_dev_make_request(struct request_queue *q, struct bio *bio)
|
blk_qc_t flash_dev_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct search *s;
|
struct search *s;
|
||||||
struct closure *cl;
|
struct closure *cl;
|
||||||
@ -1311,8 +1283,7 @@ blk_qc_t flash_dev_make_request(struct request_queue *q, struct bio *bio)
|
|||||||
|
|
||||||
if (!bio->bi_iter.bi_size) {
|
if (!bio->bi_iter.bi_size) {
|
||||||
/*
|
/*
|
||||||
* can't call bch_journal_meta from under
|
* can't call bch_journal_meta from under submit_bio_noacct
|
||||||
* generic_make_request
|
|
||||||
*/
|
*/
|
||||||
continue_at_nobarrier(&s->cl,
|
continue_at_nobarrier(&s->cl,
|
||||||
flash_dev_nodata,
|
flash_dev_nodata,
|
||||||
@ -1342,27 +1313,8 @@ static int flash_dev_ioctl(struct bcache_device *d, fmode_t mode,
|
|||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flash_dev_congested(void *data, int bits)
|
|
||||||
{
|
|
||||||
struct bcache_device *d = data;
|
|
||||||
struct request_queue *q;
|
|
||||||
struct cache *ca;
|
|
||||||
unsigned int i;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
for_each_cache(ca, d->c, i) {
|
|
||||||
q = bdev_get_queue(ca->bdev);
|
|
||||||
ret |= bdi_congested(q->backing_dev_info, bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bch_flash_dev_request_init(struct bcache_device *d)
|
void bch_flash_dev_request_init(struct bcache_device *d)
|
||||||
{
|
{
|
||||||
struct gendisk *g = d->disk;
|
|
||||||
|
|
||||||
g->queue->backing_dev_info->congested_fn = flash_dev_congested;
|
|
||||||
d->cache_miss = flash_dev_cache_miss;
|
d->cache_miss = flash_dev_cache_miss;
|
||||||
d->ioctl = flash_dev_ioctl;
|
d->ioctl = flash_dev_ioctl;
|
||||||
}
|
}
|
||||||
|
@ -37,10 +37,10 @@ unsigned int bch_get_congested(const struct cache_set *c);
|
|||||||
void bch_data_insert(struct closure *cl);
|
void bch_data_insert(struct closure *cl);
|
||||||
|
|
||||||
void bch_cached_dev_request_init(struct cached_dev *dc);
|
void bch_cached_dev_request_init(struct cached_dev *dc);
|
||||||
blk_qc_t cached_dev_make_request(struct request_queue *q, struct bio *bio);
|
blk_qc_t cached_dev_submit_bio(struct bio *bio);
|
||||||
|
|
||||||
void bch_flash_dev_request_init(struct bcache_device *d);
|
void bch_flash_dev_request_init(struct bcache_device *d);
|
||||||
blk_qc_t flash_dev_make_request(struct request_queue *q, struct bio *bio);
|
blk_qc_t flash_dev_submit_bio(struct bio *bio);
|
||||||
|
|
||||||
extern struct kmem_cache *bch_search_cache;
|
extern struct kmem_cache *bch_search_cache;
|
||||||
|
|
||||||
|
@ -680,7 +680,16 @@ static int ioctl_dev(struct block_device *b, fmode_t mode,
|
|||||||
return d->ioctl(d, mode, cmd, arg);
|
return d->ioctl(d, mode, cmd, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct block_device_operations bcache_ops = {
|
static const struct block_device_operations bcache_cached_ops = {
|
||||||
|
.submit_bio = cached_dev_submit_bio,
|
||||||
|
.open = open_dev,
|
||||||
|
.release = release_dev,
|
||||||
|
.ioctl = ioctl_dev,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct block_device_operations bcache_flash_ops = {
|
||||||
|
.submit_bio = flash_dev_submit_bio,
|
||||||
.open = open_dev,
|
.open = open_dev,
|
||||||
.release = release_dev,
|
.release = release_dev,
|
||||||
.ioctl = ioctl_dev,
|
.ioctl = ioctl_dev,
|
||||||
@ -820,8 +829,8 @@ static void bcache_device_free(struct bcache_device *d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
|
static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
|
||||||
sector_t sectors, make_request_fn make_request_fn,
|
sector_t sectors, struct block_device *cached_bdev,
|
||||||
struct block_device *cached_bdev)
|
const struct block_device_operations *ops)
|
||||||
{
|
{
|
||||||
struct request_queue *q;
|
struct request_queue *q;
|
||||||
const size_t max_stripes = min_t(size_t, INT_MAX,
|
const size_t max_stripes = min_t(size_t, INT_MAX,
|
||||||
@ -868,16 +877,14 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
|
|||||||
|
|
||||||
d->disk->major = bcache_major;
|
d->disk->major = bcache_major;
|
||||||
d->disk->first_minor = idx_to_first_minor(idx);
|
d->disk->first_minor = idx_to_first_minor(idx);
|
||||||
d->disk->fops = &bcache_ops;
|
d->disk->fops = ops;
|
||||||
d->disk->private_data = d;
|
d->disk->private_data = d;
|
||||||
|
|
||||||
q = blk_alloc_queue(make_request_fn, NUMA_NO_NODE);
|
q = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (!q)
|
if (!q)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
d->disk->queue = q;
|
d->disk->queue = q;
|
||||||
q->queuedata = d;
|
|
||||||
q->backing_dev_info->congested_data = d;
|
|
||||||
q->limits.max_hw_sectors = UINT_MAX;
|
q->limits.max_hw_sectors = UINT_MAX;
|
||||||
q->limits.max_sectors = UINT_MAX;
|
q->limits.max_sectors = UINT_MAX;
|
||||||
q->limits.max_segment_size = UINT_MAX;
|
q->limits.max_segment_size = UINT_MAX;
|
||||||
@ -1356,7 +1363,7 @@ static int cached_dev_init(struct cached_dev *dc, unsigned int block_size)
|
|||||||
|
|
||||||
ret = bcache_device_init(&dc->disk, block_size,
|
ret = bcache_device_init(&dc->disk, block_size,
|
||||||
dc->bdev->bd_part->nr_sects - dc->sb.data_offset,
|
dc->bdev->bd_part->nr_sects - dc->sb.data_offset,
|
||||||
cached_dev_make_request, dc->bdev);
|
dc->bdev, &bcache_cached_ops);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -1469,7 +1476,7 @@ static int flash_dev_run(struct cache_set *c, struct uuid_entry *u)
|
|||||||
kobject_init(&d->kobj, &bch_flash_dev_ktype);
|
kobject_init(&d->kobj, &bch_flash_dev_ktype);
|
||||||
|
|
||||||
if (bcache_device_init(d, block_bytes(c), u->sectors,
|
if (bcache_device_init(d, block_bytes(c), u->sectors,
|
||||||
flash_dev_make_request, NULL))
|
NULL, &bcache_flash_ops))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
bcache_device_attach(d, c, u - c->uuids);
|
bcache_device_attach(d, c, u - c->uuids);
|
||||||
|
@ -421,8 +421,6 @@ struct cache {
|
|||||||
|
|
||||||
struct rw_semaphore quiesce_lock;
|
struct rw_semaphore quiesce_lock;
|
||||||
|
|
||||||
struct dm_target_callbacks callbacks;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* origin_blocks entries, discarded if set.
|
* origin_blocks entries, discarded if set.
|
||||||
*/
|
*/
|
||||||
@ -886,7 +884,7 @@ static void accounted_complete(struct cache *cache, struct bio *bio)
|
|||||||
static void accounted_request(struct cache *cache, struct bio *bio)
|
static void accounted_request(struct cache *cache, struct bio *bio)
|
||||||
{
|
{
|
||||||
accounted_begin(cache, bio);
|
accounted_begin(cache, bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void issue_op(struct bio *bio, void *context)
|
static void issue_op(struct bio *bio, void *context)
|
||||||
@ -1792,7 +1790,7 @@ static bool process_bio(struct cache *cache, struct bio *bio)
|
|||||||
bool commit_needed;
|
bool commit_needed;
|
||||||
|
|
||||||
if (map_bio(cache, bio, get_bio_block(cache, bio), &commit_needed) == DM_MAPIO_REMAPPED)
|
if (map_bio(cache, bio, get_bio_block(cache, bio), &commit_needed) == DM_MAPIO_REMAPPED)
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
|
|
||||||
return commit_needed;
|
return commit_needed;
|
||||||
}
|
}
|
||||||
@ -1858,7 +1856,7 @@ static bool process_discard_bio(struct cache *cache, struct bio *bio)
|
|||||||
|
|
||||||
if (cache->features.discard_passdown) {
|
if (cache->features.discard_passdown) {
|
||||||
remap_to_origin(cache, bio);
|
remap_to_origin(cache, bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
} else
|
} else
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
|
|
||||||
@ -2423,20 +2421,6 @@ static void set_cache_size(struct cache *cache, dm_cblock_t size)
|
|||||||
cache->cache_size = size;
|
cache->cache_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_congested(struct dm_dev *dev, int bdi_bits)
|
|
||||||
{
|
|
||||||
struct request_queue *q = bdev_get_queue(dev->bdev);
|
|
||||||
return bdi_congested(q->backing_dev_info, bdi_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cache_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
|
|
||||||
{
|
|
||||||
struct cache *cache = container_of(cb, struct cache, callbacks);
|
|
||||||
|
|
||||||
return is_congested(cache->origin_dev, bdi_bits) ||
|
|
||||||
is_congested(cache->cache_dev, bdi_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DEFAULT_MIGRATION_THRESHOLD 2048
|
#define DEFAULT_MIGRATION_THRESHOLD 2048
|
||||||
|
|
||||||
static int cache_create(struct cache_args *ca, struct cache **result)
|
static int cache_create(struct cache_args *ca, struct cache **result)
|
||||||
@ -2471,9 +2455,6 @@ static int cache_create(struct cache_args *ca, struct cache **result)
|
|||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache->callbacks.congested_fn = cache_is_congested;
|
|
||||||
dm_table_add_target_callbacks(ti->table, &cache->callbacks);
|
|
||||||
|
|
||||||
cache->metadata_dev = ca->metadata_dev;
|
cache->metadata_dev = ca->metadata_dev;
|
||||||
cache->origin_dev = ca->origin_dev;
|
cache->origin_dev = ca->origin_dev;
|
||||||
cache->cache_dev = ca->cache_dev;
|
cache->cache_dev = ca->cache_dev;
|
||||||
|
@ -68,7 +68,6 @@ struct hash_table_bucket;
|
|||||||
|
|
||||||
struct clone {
|
struct clone {
|
||||||
struct dm_target *ti;
|
struct dm_target *ti;
|
||||||
struct dm_target_callbacks callbacks;
|
|
||||||
|
|
||||||
struct dm_dev *metadata_dev;
|
struct dm_dev *metadata_dev;
|
||||||
struct dm_dev *dest_dev;
|
struct dm_dev *dest_dev;
|
||||||
@ -330,7 +329,7 @@ static void submit_bios(struct bio_list *bios)
|
|||||||
blk_start_plug(&plug);
|
blk_start_plug(&plug);
|
||||||
|
|
||||||
while ((bio = bio_list_pop(bios)))
|
while ((bio = bio_list_pop(bios)))
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
|
|
||||||
blk_finish_plug(&plug);
|
blk_finish_plug(&plug);
|
||||||
}
|
}
|
||||||
@ -346,7 +345,7 @@ static void submit_bios(struct bio_list *bios)
|
|||||||
static void issue_bio(struct clone *clone, struct bio *bio)
|
static void issue_bio(struct clone *clone, struct bio *bio)
|
||||||
{
|
{
|
||||||
if (!bio_triggers_commit(clone, bio)) {
|
if (!bio_triggers_commit(clone, bio)) {
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,7 +472,7 @@ static void complete_discard_bio(struct clone *clone, struct bio *bio, bool succ
|
|||||||
bio_region_range(clone, bio, &rs, &nr_regions);
|
bio_region_range(clone, bio, &rs, &nr_regions);
|
||||||
trim_bio(bio, region_to_sector(clone, rs),
|
trim_bio(bio, region_to_sector(clone, rs),
|
||||||
nr_regions << clone->region_shift);
|
nr_regions << clone->region_shift);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
} else
|
} else
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
}
|
}
|
||||||
@ -865,7 +864,7 @@ static void hydration_overwrite(struct dm_clone_region_hydration *hd, struct bio
|
|||||||
bio->bi_private = hd;
|
bio->bi_private = hd;
|
||||||
|
|
||||||
atomic_inc(&hd->clone->hydrations_in_flight);
|
atomic_inc(&hd->clone->hydrations_in_flight);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1281,7 +1280,7 @@ static void process_deferred_flush_bios(struct clone *clone)
|
|||||||
*/
|
*/
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
} else {
|
} else {
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1518,18 +1517,6 @@ error:
|
|||||||
DMEMIT("Error");
|
DMEMIT("Error");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int clone_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
|
|
||||||
{
|
|
||||||
struct request_queue *dest_q, *source_q;
|
|
||||||
struct clone *clone = container_of(cb, struct clone, callbacks);
|
|
||||||
|
|
||||||
source_q = bdev_get_queue(clone->source_dev->bdev);
|
|
||||||
dest_q = bdev_get_queue(clone->dest_dev->bdev);
|
|
||||||
|
|
||||||
return (bdi_congested(dest_q->backing_dev_info, bdi_bits) |
|
|
||||||
bdi_congested(source_q->backing_dev_info, bdi_bits));
|
|
||||||
}
|
|
||||||
|
|
||||||
static sector_t get_dev_size(struct dm_dev *dev)
|
static sector_t get_dev_size(struct dm_dev *dev)
|
||||||
{
|
{
|
||||||
return i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT;
|
return i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT;
|
||||||
@ -1930,8 +1917,6 @@ static int clone_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
|||||||
goto out_with_mempool;
|
goto out_with_mempool;
|
||||||
|
|
||||||
mutex_init(&clone->commit_lock);
|
mutex_init(&clone->commit_lock);
|
||||||
clone->callbacks.congested_fn = clone_is_congested;
|
|
||||||
dm_table_add_target_callbacks(ti->table, &clone->callbacks);
|
|
||||||
|
|
||||||
/* Enable flushes */
|
/* Enable flushes */
|
||||||
ti->num_flush_bios = 1;
|
ti->num_flush_bios = 1;
|
||||||
|
@ -1789,7 +1789,7 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
generic_make_request(clone);
|
submit_bio_noacct(clone);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1815,7 +1815,7 @@ static void kcryptd_io_write(struct dm_crypt_io *io)
|
|||||||
{
|
{
|
||||||
struct bio *clone = io->ctx.bio_out;
|
struct bio *clone = io->ctx.bio_out;
|
||||||
|
|
||||||
generic_make_request(clone);
|
submit_bio_noacct(clone);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define crypt_io_from_node(node) rb_entry((node), struct dm_crypt_io, rb_node)
|
#define crypt_io_from_node(node) rb_entry((node), struct dm_crypt_io, rb_node)
|
||||||
@ -1893,7 +1893,7 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
|
|||||||
clone->bi_iter.bi_sector = cc->start + io->sector;
|
clone->bi_iter.bi_sector = cc->start + io->sector;
|
||||||
|
|
||||||
if (likely(!async) && test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags)) {
|
if (likely(!async) && test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags)) {
|
||||||
generic_make_request(clone);
|
submit_bio_noacct(clone);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ static void flush_bios(struct bio *bio)
|
|||||||
while (bio) {
|
while (bio) {
|
||||||
n = bio->bi_next;
|
n = bio->bi_next;
|
||||||
bio->bi_next = NULL;
|
bio->bi_next = NULL;
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
bio = n;
|
bio = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1137,7 +1137,6 @@ static int metadata_get_stats(struct era_metadata *md, void *ptr)
|
|||||||
|
|
||||||
struct era {
|
struct era {
|
||||||
struct dm_target *ti;
|
struct dm_target *ti;
|
||||||
struct dm_target_callbacks callbacks;
|
|
||||||
|
|
||||||
struct dm_dev *metadata_dev;
|
struct dm_dev *metadata_dev;
|
||||||
struct dm_dev *origin_dev;
|
struct dm_dev *origin_dev;
|
||||||
@ -1265,7 +1264,7 @@ static void process_deferred_bios(struct era *era)
|
|||||||
bio_io_error(bio);
|
bio_io_error(bio);
|
||||||
else
|
else
|
||||||
while ((bio = bio_list_pop(&marked_bios)))
|
while ((bio = bio_list_pop(&marked_bios)))
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_rpc_calls(struct era *era)
|
static void process_rpc_calls(struct era *era)
|
||||||
@ -1375,18 +1374,6 @@ static void stop_worker(struct era *era)
|
|||||||
/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
||||||
* Target methods
|
* Target methods
|
||||||
*--------------------------------------------------------------*/
|
*--------------------------------------------------------------*/
|
||||||
static int dev_is_congested(struct dm_dev *dev, int bdi_bits)
|
|
||||||
{
|
|
||||||
struct request_queue *q = bdev_get_queue(dev->bdev);
|
|
||||||
return bdi_congested(q->backing_dev_info, bdi_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int era_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
|
|
||||||
{
|
|
||||||
struct era *era = container_of(cb, struct era, callbacks);
|
|
||||||
return dev_is_congested(era->origin_dev, bdi_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void era_destroy(struct era *era)
|
static void era_destroy(struct era *era)
|
||||||
{
|
{
|
||||||
if (era->md)
|
if (era->md)
|
||||||
@ -1514,8 +1501,6 @@ static int era_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|||||||
ti->flush_supported = true;
|
ti->flush_supported = true;
|
||||||
|
|
||||||
ti->num_discard_bios = 1;
|
ti->num_discard_bios = 1;
|
||||||
era->callbacks.congested_fn = era_is_congested;
|
|
||||||
dm_table_add_target_callbacks(ti->table, &era->callbacks);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2115,12 +2115,12 @@ offload_to_thread:
|
|||||||
dio->in_flight = (atomic_t)ATOMIC_INIT(1);
|
dio->in_flight = (atomic_t)ATOMIC_INIT(1);
|
||||||
dio->completion = NULL;
|
dio->completion = NULL;
|
||||||
|
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
|
|
||||||
if (need_sync_io) {
|
if (need_sync_io) {
|
||||||
wait_for_completion_io(&read_comp);
|
wait_for_completion_io(&read_comp);
|
||||||
|
@ -677,7 +677,7 @@ static void process_queued_bios(struct work_struct *work)
|
|||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
break;
|
break;
|
||||||
case DM_MAPIO_REMAPPED:
|
case DM_MAPIO_REMAPPED:
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
break;
|
break;
|
||||||
case DM_MAPIO_SUBMITTED:
|
case DM_MAPIO_SUBMITTED:
|
||||||
break;
|
break;
|
||||||
|
@ -242,7 +242,6 @@ struct raid_set {
|
|||||||
|
|
||||||
struct mddev md;
|
struct mddev md;
|
||||||
struct raid_type *raid_type;
|
struct raid_type *raid_type;
|
||||||
struct dm_target_callbacks callbacks;
|
|
||||||
|
|
||||||
sector_t array_sectors;
|
sector_t array_sectors;
|
||||||
sector_t dev_sectors;
|
sector_t dev_sectors;
|
||||||
@ -1705,13 +1704,6 @@ static void do_table_event(struct work_struct *ws)
|
|||||||
dm_table_event(rs->ti->table);
|
dm_table_event(rs->ti->table);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raid_is_congested(struct dm_target_callbacks *cb, int bits)
|
|
||||||
{
|
|
||||||
struct raid_set *rs = container_of(cb, struct raid_set, callbacks);
|
|
||||||
|
|
||||||
return mddev_congested(&rs->md, bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure a valid takover (level switch) is being requested on @rs
|
* Make sure a valid takover (level switch) is being requested on @rs
|
||||||
*
|
*
|
||||||
@ -3248,9 +3240,6 @@ size_check:
|
|||||||
goto bad_md_start;
|
goto bad_md_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
rs->callbacks.congested_fn = raid_is_congested;
|
|
||||||
dm_table_add_target_callbacks(ti->table, &rs->callbacks);
|
|
||||||
|
|
||||||
/* If raid4/5/6 journal mode explicitly requested (only possible with journal dev) -> set it */
|
/* If raid4/5/6 journal mode explicitly requested (only possible with journal dev) -> set it */
|
||||||
if (test_bit(__CTR_FLAG_JOURNAL_MODE, &rs->ctr_flags)) {
|
if (test_bit(__CTR_FLAG_JOURNAL_MODE, &rs->ctr_flags)) {
|
||||||
r = r5c_journal_mode_set(&rs->md, rs->journal_dev.mode);
|
r = r5c_journal_mode_set(&rs->md, rs->journal_dev.mode);
|
||||||
@ -3310,7 +3299,6 @@ static void raid_dtr(struct dm_target *ti)
|
|||||||
{
|
{
|
||||||
struct raid_set *rs = ti->private;
|
struct raid_set *rs = ti->private;
|
||||||
|
|
||||||
list_del_init(&rs->callbacks.list);
|
|
||||||
md_stop(&rs->md);
|
md_stop(&rs->md);
|
||||||
raid_set_free(rs);
|
raid_set_free(rs);
|
||||||
}
|
}
|
||||||
|
@ -779,7 +779,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
|
|||||||
wakeup_mirrord(ms);
|
wakeup_mirrord(ms);
|
||||||
} else {
|
} else {
|
||||||
map_bio(get_default_mirror(ms), bio);
|
map_bio(get_default_mirror(ms), bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,7 +284,8 @@ static void dm_complete_request(struct request *rq, blk_status_t error)
|
|||||||
struct dm_rq_target_io *tio = tio_from_request(rq);
|
struct dm_rq_target_io *tio = tio_from_request(rq);
|
||||||
|
|
||||||
tio->error = error;
|
tio->error = error;
|
||||||
blk_mq_complete_request(rq);
|
if (likely(!blk_should_fake_timeout(rq->q)))
|
||||||
|
blk_mq_complete_request(rq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -252,7 +252,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int op,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Issue the synchronous I/O from a different thread
|
* Issue the synchronous I/O from a different thread
|
||||||
* to avoid generic_make_request recursion.
|
* to avoid submit_bio_noacct recursion.
|
||||||
*/
|
*/
|
||||||
INIT_WORK_ONSTACK(&req.work, do_metadata);
|
INIT_WORK_ONSTACK(&req.work, do_metadata);
|
||||||
queue_work(ps->metadata_wq, &req.work);
|
queue_work(ps->metadata_wq, &req.work);
|
||||||
|
@ -1568,7 +1568,7 @@ static void flush_bios(struct bio *bio)
|
|||||||
while (bio) {
|
while (bio) {
|
||||||
n = bio->bi_next;
|
n = bio->bi_next;
|
||||||
bio->bi_next = NULL;
|
bio->bi_next = NULL;
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
bio = n;
|
bio = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1588,7 +1588,7 @@ static void retry_origin_bios(struct dm_snapshot *s, struct bio *bio)
|
|||||||
bio->bi_next = NULL;
|
bio->bi_next = NULL;
|
||||||
r = do_origin(s->origin, bio, false);
|
r = do_origin(s->origin, bio, false);
|
||||||
if (r == DM_MAPIO_REMAPPED)
|
if (r == DM_MAPIO_REMAPPED)
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
bio = n;
|
bio = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1829,7 +1829,7 @@ static void start_full_bio(struct dm_snap_pending_exception *pe,
|
|||||||
bio->bi_end_io = full_bio_end_io;
|
bio->bi_end_io = full_bio_end_io;
|
||||||
bio->bi_private = callback_data;
|
bio->bi_private = callback_data;
|
||||||
|
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dm_snap_pending_exception *
|
static struct dm_snap_pending_exception *
|
||||||
|
@ -64,8 +64,6 @@ struct dm_table {
|
|||||||
void *event_context;
|
void *event_context;
|
||||||
|
|
||||||
struct dm_md_mempools *mempools;
|
struct dm_md_mempools *mempools;
|
||||||
|
|
||||||
struct list_head target_callbacks;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -190,7 +188,6 @@ int dm_table_create(struct dm_table **result, fmode_t mode,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&t->devices);
|
INIT_LIST_HEAD(&t->devices);
|
||||||
INIT_LIST_HEAD(&t->target_callbacks);
|
|
||||||
|
|
||||||
if (!num_targets)
|
if (!num_targets)
|
||||||
num_targets = KEYS_PER_NODE;
|
num_targets = KEYS_PER_NODE;
|
||||||
@ -361,7 +358,7 @@ static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev,
|
|||||||
* This upgrades the mode on an already open dm_dev, being
|
* This upgrades the mode on an already open dm_dev, being
|
||||||
* careful to leave things as they were if we fail to reopen the
|
* careful to leave things as they were if we fail to reopen the
|
||||||
* device and not to touch the existing bdev field in case
|
* device and not to touch the existing bdev field in case
|
||||||
* it is accessed concurrently inside dm_table_any_congested().
|
* it is accessed concurrently.
|
||||||
*/
|
*/
|
||||||
static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
|
static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
|
||||||
struct mapped_device *md)
|
struct mapped_device *md)
|
||||||
@ -2052,38 +2049,6 @@ int dm_table_resume_targets(struct dm_table *t)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dm_table_add_target_callbacks(struct dm_table *t, struct dm_target_callbacks *cb)
|
|
||||||
{
|
|
||||||
list_add(&cb->list, &t->target_callbacks);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(dm_table_add_target_callbacks);
|
|
||||||
|
|
||||||
int dm_table_any_congested(struct dm_table *t, int bdi_bits)
|
|
||||||
{
|
|
||||||
struct dm_dev_internal *dd;
|
|
||||||
struct list_head *devices = dm_table_get_devices(t);
|
|
||||||
struct dm_target_callbacks *cb;
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
list_for_each_entry(dd, devices, list) {
|
|
||||||
struct request_queue *q = bdev_get_queue(dd->dm_dev->bdev);
|
|
||||||
char b[BDEVNAME_SIZE];
|
|
||||||
|
|
||||||
if (likely(q))
|
|
||||||
r |= bdi_congested(q->backing_dev_info, bdi_bits);
|
|
||||||
else
|
|
||||||
DMWARN_LIMIT("%s: any_congested: nonexistent device %s",
|
|
||||||
dm_device_name(t->md),
|
|
||||||
bdevname(dd->dm_dev->bdev, b));
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(cb, &t->target_callbacks, list)
|
|
||||||
if (cb->congested_fn)
|
|
||||||
r |= cb->congested_fn(cb, bdi_bits);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mapped_device *dm_table_get_md(struct dm_table *t)
|
struct mapped_device *dm_table_get_md(struct dm_table *t)
|
||||||
{
|
{
|
||||||
return t->md;
|
return t->md;
|
||||||
|
@ -326,7 +326,6 @@ struct pool_c {
|
|||||||
struct pool *pool;
|
struct pool *pool;
|
||||||
struct dm_dev *data_dev;
|
struct dm_dev *data_dev;
|
||||||
struct dm_dev *metadata_dev;
|
struct dm_dev *metadata_dev;
|
||||||
struct dm_target_callbacks callbacks;
|
|
||||||
|
|
||||||
dm_block_t low_water_blocks;
|
dm_block_t low_water_blocks;
|
||||||
struct pool_features requested_pf; /* Features requested during table load */
|
struct pool_features requested_pf; /* Features requested during table load */
|
||||||
@ -758,7 +757,7 @@ static void issue(struct thin_c *tc, struct bio *bio)
|
|||||||
struct pool *pool = tc->pool;
|
struct pool *pool = tc->pool;
|
||||||
|
|
||||||
if (!bio_triggers_commit(tc, bio)) {
|
if (!bio_triggers_commit(tc, bio)) {
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2394,7 +2393,7 @@ static void process_deferred_bios(struct pool *pool)
|
|||||||
if (bio->bi_opf & REQ_PREFLUSH)
|
if (bio->bi_opf & REQ_PREFLUSH)
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
else
|
else
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2796,18 +2795,6 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pool_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
|
|
||||||
{
|
|
||||||
struct pool_c *pt = container_of(cb, struct pool_c, callbacks);
|
|
||||||
struct request_queue *q;
|
|
||||||
|
|
||||||
if (get_pool_mode(pt->pool) == PM_OUT_OF_DATA_SPACE)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
q = bdev_get_queue(pt->data_dev->bdev);
|
|
||||||
return bdi_congested(q->backing_dev_info, bdi_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void requeue_bios(struct pool *pool)
|
static void requeue_bios(struct pool *pool)
|
||||||
{
|
{
|
||||||
struct thin_c *tc;
|
struct thin_c *tc;
|
||||||
@ -3420,9 +3407,6 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|||||||
dm_pool_register_pre_commit_callback(pool->pmd,
|
dm_pool_register_pre_commit_callback(pool->pmd,
|
||||||
metadata_pre_commit_callback, pool);
|
metadata_pre_commit_callback, pool);
|
||||||
|
|
||||||
pt->callbacks.congested_fn = pool_is_congested;
|
|
||||||
dm_table_add_target_callbacks(ti->table, &pt->callbacks);
|
|
||||||
|
|
||||||
mutex_unlock(&dm_thin_pool_table.mutex);
|
mutex_unlock(&dm_thin_pool_table.mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -681,7 +681,7 @@ static int verity_map(struct dm_target *ti, struct bio *bio)
|
|||||||
|
|
||||||
verity_submit_prefetch(v, io);
|
verity_submit_prefetch(v, io);
|
||||||
|
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
|
|
||||||
return DM_MAPIO_SUBMITTED;
|
return DM_MAPIO_SUBMITTED;
|
||||||
}
|
}
|
||||||
|
@ -1244,7 +1244,7 @@ static int writecache_flush_thread(void *data)
|
|||||||
bio_end_sector(bio));
|
bio_end_sector(bio));
|
||||||
wc_unlock(wc);
|
wc_unlock(wc);
|
||||||
bio_set_dev(bio, wc->dev->bdev);
|
bio_set_dev(bio, wc->dev->bdev);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
} else {
|
} else {
|
||||||
writecache_flush(wc);
|
writecache_flush(wc);
|
||||||
wc_unlock(wc);
|
wc_unlock(wc);
|
||||||
|
@ -140,7 +140,7 @@ static int dmz_submit_bio(struct dmz_target *dmz, struct dm_zone *zone,
|
|||||||
bio_advance(bio, clone->bi_iter.bi_size);
|
bio_advance(bio, clone->bi_iter.bi_size);
|
||||||
|
|
||||||
refcount_inc(&bioctx->ref);
|
refcount_inc(&bioctx->ref);
|
||||||
generic_make_request(clone);
|
submit_bio_noacct(clone);
|
||||||
|
|
||||||
if (bio_op(bio) == REQ_OP_WRITE && dmz_is_seq(zone))
|
if (bio_op(bio) == REQ_OP_WRITE && dmz_is_seq(zone))
|
||||||
zone->wp_block += nr_blocks;
|
zone->wp_block += nr_blocks;
|
||||||
|
@ -1273,7 +1273,6 @@ static blk_qc_t __map_bio(struct dm_target_io *tio)
|
|||||||
sector_t sector;
|
sector_t sector;
|
||||||
struct bio *clone = &tio->clone;
|
struct bio *clone = &tio->clone;
|
||||||
struct dm_io *io = tio->io;
|
struct dm_io *io = tio->io;
|
||||||
struct mapped_device *md = io->md;
|
|
||||||
struct dm_target *ti = tio->ti;
|
struct dm_target *ti = tio->ti;
|
||||||
blk_qc_t ret = BLK_QC_T_NONE;
|
blk_qc_t ret = BLK_QC_T_NONE;
|
||||||
|
|
||||||
@ -1295,10 +1294,7 @@ static blk_qc_t __map_bio(struct dm_target_io *tio)
|
|||||||
/* the bio has been remapped so dispatch it */
|
/* the bio has been remapped so dispatch it */
|
||||||
trace_block_bio_remap(clone->bi_disk->queue, clone,
|
trace_block_bio_remap(clone->bi_disk->queue, clone,
|
||||||
bio_dev(io->orig_bio), sector);
|
bio_dev(io->orig_bio), sector);
|
||||||
if (md->type == DM_TYPE_NVME_BIO_BASED)
|
ret = submit_bio_noacct(clone);
|
||||||
ret = direct_make_request(clone);
|
|
||||||
else
|
|
||||||
ret = generic_make_request(clone);
|
|
||||||
break;
|
break;
|
||||||
case DM_MAPIO_KILL:
|
case DM_MAPIO_KILL:
|
||||||
free_tio(tio);
|
free_tio(tio);
|
||||||
@ -1645,7 +1641,7 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md,
|
|||||||
error = __split_and_process_non_flush(&ci);
|
error = __split_and_process_non_flush(&ci);
|
||||||
if (current->bio_list && ci.sector_count && !error) {
|
if (current->bio_list && ci.sector_count && !error) {
|
||||||
/*
|
/*
|
||||||
* Remainder must be passed to generic_make_request()
|
* Remainder must be passed to submit_bio_noacct()
|
||||||
* so that it gets handled *after* bios already submitted
|
* so that it gets handled *after* bios already submitted
|
||||||
* have been completely processed.
|
* have been completely processed.
|
||||||
* We take a clone of the original to store in
|
* We take a clone of the original to store in
|
||||||
@ -1670,7 +1666,7 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md,
|
|||||||
|
|
||||||
bio_chain(b, bio);
|
bio_chain(b, bio);
|
||||||
trace_block_split(md->queue, b, bio->bi_iter.bi_sector);
|
trace_block_split(md->queue, b, bio->bi_iter.bi_sector);
|
||||||
ret = generic_make_request(bio);
|
ret = submit_bio_noacct(bio);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1738,7 +1734,7 @@ static void dm_queue_split(struct mapped_device *md, struct dm_target *ti, struc
|
|||||||
|
|
||||||
bio_chain(split, *bio);
|
bio_chain(split, *bio);
|
||||||
trace_block_split(md->queue, split, (*bio)->bi_iter.bi_sector);
|
trace_block_split(md->queue, split, (*bio)->bi_iter.bi_sector);
|
||||||
generic_make_request(*bio);
|
submit_bio_noacct(*bio);
|
||||||
*bio = split;
|
*bio = split;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1763,13 +1759,13 @@ static blk_qc_t dm_process_bio(struct mapped_device *md,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If in ->make_request_fn we need to use blk_queue_split(), otherwise
|
* If in ->queue_bio we need to use blk_queue_split(), otherwise
|
||||||
* queue_limits for abnormal requests (e.g. discard, writesame, etc)
|
* queue_limits for abnormal requests (e.g. discard, writesame, etc)
|
||||||
* won't be imposed.
|
* won't be imposed.
|
||||||
*/
|
*/
|
||||||
if (current->bio_list) {
|
if (current->bio_list) {
|
||||||
if (is_abnormal_io(bio))
|
if (is_abnormal_io(bio))
|
||||||
blk_queue_split(md->queue, &bio);
|
blk_queue_split(&bio);
|
||||||
else
|
else
|
||||||
dm_queue_split(md, ti, &bio);
|
dm_queue_split(md, ti, &bio);
|
||||||
}
|
}
|
||||||
@ -1780,9 +1776,9 @@ static blk_qc_t dm_process_bio(struct mapped_device *md,
|
|||||||
return __split_and_process_bio(md, map, bio);
|
return __split_and_process_bio(md, map, bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t dm_make_request(struct request_queue *q, struct bio *bio)
|
static blk_qc_t dm_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct mapped_device *md = q->queuedata;
|
struct mapped_device *md = bio->bi_disk->private_data;
|
||||||
blk_qc_t ret = BLK_QC_T_NONE;
|
blk_qc_t ret = BLK_QC_T_NONE;
|
||||||
int srcu_idx;
|
int srcu_idx;
|
||||||
struct dm_table *map;
|
struct dm_table *map;
|
||||||
@ -1791,12 +1787,12 @@ static blk_qc_t dm_make_request(struct request_queue *q, struct bio *bio)
|
|||||||
/*
|
/*
|
||||||
* We are called with a live reference on q_usage_counter, but
|
* We are called with a live reference on q_usage_counter, but
|
||||||
* that one will be released as soon as we return. Grab an
|
* that one will be released as soon as we return. Grab an
|
||||||
* extra one as blk_mq_make_request expects to be able to
|
* extra one as blk_mq_submit_bio expects to be able to consume
|
||||||
* consume a reference (which lives until the request is freed
|
* a reference (which lives until the request is freed in case a
|
||||||
* in case a request is allocated).
|
* request is allocated).
|
||||||
*/
|
*/
|
||||||
percpu_ref_get(&q->q_usage_counter);
|
percpu_ref_get(&bio->bi_disk->queue->q_usage_counter);
|
||||||
return blk_mq_make_request(q, bio);
|
return blk_mq_submit_bio(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
map = dm_get_live_table(md, &srcu_idx);
|
map = dm_get_live_table(md, &srcu_idx);
|
||||||
@ -1818,31 +1814,6 @@ static blk_qc_t dm_make_request(struct request_queue *q, struct bio *bio)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dm_any_congested(void *congested_data, int bdi_bits)
|
|
||||||
{
|
|
||||||
int r = bdi_bits;
|
|
||||||
struct mapped_device *md = congested_data;
|
|
||||||
struct dm_table *map;
|
|
||||||
|
|
||||||
if (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) {
|
|
||||||
if (dm_request_based(md)) {
|
|
||||||
/*
|
|
||||||
* With request-based DM we only need to check the
|
|
||||||
* top-level queue for congestion.
|
|
||||||
*/
|
|
||||||
struct backing_dev_info *bdi = md->queue->backing_dev_info;
|
|
||||||
r = bdi->wb.congested->state & bdi_bits;
|
|
||||||
} else {
|
|
||||||
map = dm_get_live_table_fast(md);
|
|
||||||
if (map)
|
|
||||||
r = dm_table_any_congested(map, bdi_bits);
|
|
||||||
dm_put_live_table_fast(md);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
* An IDR is used to keep track of allocated minor numbers.
|
* An IDR is used to keep track of allocated minor numbers.
|
||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
@ -1981,14 +1952,13 @@ static struct mapped_device *alloc_dev(int minor)
|
|||||||
spin_lock_init(&md->uevent_lock);
|
spin_lock_init(&md->uevent_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* default to bio-based required ->make_request_fn until DM
|
* default to bio-based until DM table is loaded and md->type
|
||||||
* table is loaded and md->type established. If request-based
|
* established. If request-based table is loaded: blk-mq will
|
||||||
* table is loaded: blk-mq will override accordingly.
|
* override accordingly.
|
||||||
*/
|
*/
|
||||||
md->queue = blk_alloc_queue(dm_make_request, numa_node_id);
|
md->queue = blk_alloc_queue(numa_node_id);
|
||||||
if (!md->queue)
|
if (!md->queue)
|
||||||
goto bad;
|
goto bad;
|
||||||
md->queue->queuedata = md;
|
|
||||||
|
|
||||||
md->disk = alloc_disk_node(1, md->numa_node_id);
|
md->disk = alloc_disk_node(1, md->numa_node_id);
|
||||||
if (!md->disk)
|
if (!md->disk)
|
||||||
@ -2282,12 +2252,6 @@ struct queue_limits *dm_get_queue_limits(struct mapped_device *md)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dm_get_queue_limits);
|
EXPORT_SYMBOL_GPL(dm_get_queue_limits);
|
||||||
|
|
||||||
static void dm_init_congested_fn(struct mapped_device *md)
|
|
||||||
{
|
|
||||||
md->queue->backing_dev_info->congested_data = md;
|
|
||||||
md->queue->backing_dev_info->congested_fn = dm_any_congested;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup the DM device's queue based on md's type
|
* Setup the DM device's queue based on md's type
|
||||||
*/
|
*/
|
||||||
@ -2304,12 +2268,10 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t)
|
|||||||
DMERR("Cannot initialize queue for request-based dm-mq mapped device");
|
DMERR("Cannot initialize queue for request-based dm-mq mapped device");
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
dm_init_congested_fn(md);
|
|
||||||
break;
|
break;
|
||||||
case DM_TYPE_BIO_BASED:
|
case DM_TYPE_BIO_BASED:
|
||||||
case DM_TYPE_DAX_BIO_BASED:
|
case DM_TYPE_DAX_BIO_BASED:
|
||||||
case DM_TYPE_NVME_BIO_BASED:
|
case DM_TYPE_NVME_BIO_BASED:
|
||||||
dm_init_congested_fn(md);
|
|
||||||
break;
|
break;
|
||||||
case DM_TYPE_NONE:
|
case DM_TYPE_NONE:
|
||||||
WARN_ON_ONCE(true);
|
WARN_ON_ONCE(true);
|
||||||
@ -2531,7 +2493,7 @@ static void dm_wq_work(struct work_struct *work)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (dm_request_based(md))
|
if (dm_request_based(md))
|
||||||
(void) generic_make_request(c);
|
(void) submit_bio_noacct(c);
|
||||||
else
|
else
|
||||||
(void) dm_process_bio(md, map, c);
|
(void) dm_process_bio(md, map, c);
|
||||||
}
|
}
|
||||||
@ -3286,6 +3248,7 @@ static const struct pr_ops dm_pr_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct block_device_operations dm_blk_dops = {
|
static const struct block_device_operations dm_blk_dops = {
|
||||||
|
.submit_bio = dm_submit_bio,
|
||||||
.open = dm_blk_open,
|
.open = dm_blk_open,
|
||||||
.release = dm_blk_close,
|
.release = dm_blk_close,
|
||||||
.ioctl = dm_blk_ioctl,
|
.ioctl = dm_blk_ioctl,
|
||||||
|
@ -63,7 +63,6 @@ void dm_table_presuspend_targets(struct dm_table *t);
|
|||||||
void dm_table_presuspend_undo_targets(struct dm_table *t);
|
void dm_table_presuspend_undo_targets(struct dm_table *t);
|
||||||
void dm_table_postsuspend_targets(struct dm_table *t);
|
void dm_table_postsuspend_targets(struct dm_table *t);
|
||||||
int dm_table_resume_targets(struct dm_table *t);
|
int dm_table_resume_targets(struct dm_table *t);
|
||||||
int dm_table_any_congested(struct dm_table *t, int bdi_bits);
|
|
||||||
enum dm_queue_mode dm_table_get_type(struct dm_table *t);
|
enum dm_queue_mode dm_table_get_type(struct dm_table *t);
|
||||||
struct target_type *dm_table_get_immutable_target_type(struct dm_table *t);
|
struct target_type *dm_table_get_immutable_target_type(struct dm_table *t);
|
||||||
struct dm_target *dm_table_get_immutable_target(struct dm_table *t);
|
struct dm_target *dm_table_get_immutable_target(struct dm_table *t);
|
||||||
|
@ -169,7 +169,7 @@ static bool faulty_make_request(struct mddev *mddev, struct bio *bio)
|
|||||||
if (bio_data_dir(bio) == WRITE) {
|
if (bio_data_dir(bio) == WRITE) {
|
||||||
/* write request */
|
/* write request */
|
||||||
if (atomic_read(&conf->counters[WriteAll])) {
|
if (atomic_read(&conf->counters[WriteAll])) {
|
||||||
/* special case - don't decrement, don't generic_make_request,
|
/* special case - don't decrement, don't submit_bio_noacct,
|
||||||
* just fail immediately
|
* just fail immediately
|
||||||
*/
|
*/
|
||||||
bio_io_error(bio);
|
bio_io_error(bio);
|
||||||
@ -214,7 +214,7 @@ static bool faulty_make_request(struct mddev *mddev, struct bio *bio)
|
|||||||
} else
|
} else
|
||||||
bio_set_dev(bio, conf->rdev->bdev);
|
bio_set_dev(bio, conf->rdev->bdev);
|
||||||
|
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,29 +46,6 @@ static inline struct dev_info *which_dev(struct mddev *mddev, sector_t sector)
|
|||||||
return conf->disks + lo;
|
return conf->disks + lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* In linear_congested() conf->raid_disks is used as a copy of
|
|
||||||
* mddev->raid_disks to iterate conf->disks[], because conf->raid_disks
|
|
||||||
* and conf->disks[] are created in linear_conf(), they are always
|
|
||||||
* consitent with each other, but mddev->raid_disks does not.
|
|
||||||
*/
|
|
||||||
static int linear_congested(struct mddev *mddev, int bits)
|
|
||||||
{
|
|
||||||
struct linear_conf *conf;
|
|
||||||
int i, ret = 0;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
conf = rcu_dereference(mddev->private);
|
|
||||||
|
|
||||||
for (i = 0; i < conf->raid_disks && !ret ; i++) {
|
|
||||||
struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev);
|
|
||||||
ret |= bdi_congested(q->backing_dev_info, bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static sector_t linear_size(struct mddev *mddev, sector_t sectors, int raid_disks)
|
static sector_t linear_size(struct mddev *mddev, sector_t sectors, int raid_disks)
|
||||||
{
|
{
|
||||||
struct linear_conf *conf;
|
struct linear_conf *conf;
|
||||||
@ -267,7 +244,7 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio)
|
|||||||
struct bio *split = bio_split(bio, end_sector - bio_sector,
|
struct bio *split = bio_split(bio, end_sector - bio_sector,
|
||||||
GFP_NOIO, &mddev->bio_set);
|
GFP_NOIO, &mddev->bio_set);
|
||||||
bio_chain(split, bio);
|
bio_chain(split, bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
bio = split;
|
bio = split;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +263,7 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio)
|
|||||||
bio_sector);
|
bio_sector);
|
||||||
mddev_check_writesame(mddev, bio);
|
mddev_check_writesame(mddev, bio);
|
||||||
mddev_check_write_zeroes(mddev, bio);
|
mddev_check_write_zeroes(mddev, bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -322,7 +299,6 @@ static struct md_personality linear_personality =
|
|||||||
.hot_add_disk = linear_add,
|
.hot_add_disk = linear_add,
|
||||||
.size = linear_size,
|
.size = linear_size,
|
||||||
.quiesce = linear_quiesce,
|
.quiesce = linear_quiesce,
|
||||||
.congested = linear_congested,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init linear_init (void)
|
static int __init linear_init (void)
|
||||||
|
@ -131,7 +131,7 @@ static bool multipath_make_request(struct mddev *mddev, struct bio * bio)
|
|||||||
mp_bh->bio.bi_private = mp_bh;
|
mp_bh->bio.bi_private = mp_bh;
|
||||||
mddev_check_writesame(mddev, &mp_bh->bio);
|
mddev_check_writesame(mddev, &mp_bh->bio);
|
||||||
mddev_check_write_zeroes(mddev, &mp_bh->bio);
|
mddev_check_write_zeroes(mddev, &mp_bh->bio);
|
||||||
generic_make_request(&mp_bh->bio);
|
submit_bio_noacct(&mp_bh->bio);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,28 +151,6 @@ static void multipath_status(struct seq_file *seq, struct mddev *mddev)
|
|||||||
seq_putc(seq, ']');
|
seq_putc(seq, ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
static int multipath_congested(struct mddev *mddev, int bits)
|
|
||||||
{
|
|
||||||
struct mpconf *conf = mddev->private;
|
|
||||||
int i, ret = 0;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
for (i = 0; i < mddev->raid_disks ; i++) {
|
|
||||||
struct md_rdev *rdev = rcu_dereference(conf->multipaths[i].rdev);
|
|
||||||
if (rdev && !test_bit(Faulty, &rdev->flags)) {
|
|
||||||
struct request_queue *q = bdev_get_queue(rdev->bdev);
|
|
||||||
|
|
||||||
ret |= bdi_congested(q->backing_dev_info, bits);
|
|
||||||
/* Just like multipath_map, we just check the
|
|
||||||
* first available device
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Careful, this can execute in IRQ contexts as well!
|
* Careful, this can execute in IRQ contexts as well!
|
||||||
*/
|
*/
|
||||||
@ -348,7 +326,7 @@ static void multipathd(struct md_thread *thread)
|
|||||||
bio->bi_opf |= REQ_FAILFAST_TRANSPORT;
|
bio->bi_opf |= REQ_FAILFAST_TRANSPORT;
|
||||||
bio->bi_end_io = multipath_end_request;
|
bio->bi_end_io = multipath_end_request;
|
||||||
bio->bi_private = mp_bh;
|
bio->bi_private = mp_bh;
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&conf->device_lock, flags);
|
spin_unlock_irqrestore(&conf->device_lock, flags);
|
||||||
@ -478,7 +456,6 @@ static struct md_personality multipath_personality =
|
|||||||
.hot_add_disk = multipath_add_disk,
|
.hot_add_disk = multipath_add_disk,
|
||||||
.hot_remove_disk= multipath_remove_disk,
|
.hot_remove_disk= multipath_remove_disk,
|
||||||
.size = multipath_size,
|
.size = multipath_size,
|
||||||
.congested = multipath_congested,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init multipath_init (void)
|
static int __init multipath_init (void)
|
||||||
|
@ -199,7 +199,7 @@ static int rdevs_init_serial(struct mddev *mddev)
|
|||||||
static int rdev_need_serial(struct md_rdev *rdev)
|
static int rdev_need_serial(struct md_rdev *rdev)
|
||||||
{
|
{
|
||||||
return (rdev && rdev->mddev->bitmap_info.max_write_behind > 0 &&
|
return (rdev && rdev->mddev->bitmap_info.max_write_behind > 0 &&
|
||||||
rdev->bdev->bd_queue->nr_hw_queues != 1 &&
|
rdev->bdev->bd_disk->queue->nr_hw_queues != 1 &&
|
||||||
test_bit(WriteMostly, &rdev->flags));
|
test_bit(WriteMostly, &rdev->flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,7 +463,7 @@ check_suspended:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(md_handle_request);
|
EXPORT_SYMBOL(md_handle_request);
|
||||||
|
|
||||||
static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
|
static blk_qc_t md_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
const int rw = bio_data_dir(bio);
|
const int rw = bio_data_dir(bio);
|
||||||
const int sgrp = op_stat_group(bio_op(bio));
|
const int sgrp = op_stat_group(bio_op(bio));
|
||||||
@ -475,7 +475,7 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
|
|||||||
return BLK_QC_T_NONE;
|
return BLK_QC_T_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
blk_queue_split(q, &bio);
|
blk_queue_split(&bio);
|
||||||
|
|
||||||
if (mddev == NULL || mddev->pers == NULL) {
|
if (mddev == NULL || mddev->pers == NULL) {
|
||||||
bio_io_error(bio);
|
bio_io_error(bio);
|
||||||
@ -549,26 +549,6 @@ void mddev_resume(struct mddev *mddev)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mddev_resume);
|
EXPORT_SYMBOL_GPL(mddev_resume);
|
||||||
|
|
||||||
int mddev_congested(struct mddev *mddev, int bits)
|
|
||||||
{
|
|
||||||
struct md_personality *pers = mddev->pers;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
if (mddev->suspended)
|
|
||||||
ret = 1;
|
|
||||||
else if (pers && pers->congested)
|
|
||||||
ret = pers->congested(mddev, bits);
|
|
||||||
rcu_read_unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(mddev_congested);
|
|
||||||
static int md_congested(void *data, int bits)
|
|
||||||
{
|
|
||||||
struct mddev *mddev = data;
|
|
||||||
return mddev_congested(mddev, bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic flush handling for md
|
* Generic flush handling for md
|
||||||
*/
|
*/
|
||||||
@ -5641,7 +5621,7 @@ static int md_alloc(dev_t dev, char *name)
|
|||||||
mddev->hold_active = UNTIL_STOP;
|
mddev->hold_active = UNTIL_STOP;
|
||||||
|
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
mddev->queue = blk_alloc_queue(md_make_request, NUMA_NO_NODE);
|
mddev->queue = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (!mddev->queue)
|
if (!mddev->queue)
|
||||||
goto abort;
|
goto abort;
|
||||||
|
|
||||||
@ -5670,6 +5650,7 @@ static int md_alloc(dev_t dev, char *name)
|
|||||||
* remove it now.
|
* remove it now.
|
||||||
*/
|
*/
|
||||||
disk->flags |= GENHD_FL_EXT_DEVT;
|
disk->flags |= GENHD_FL_EXT_DEVT;
|
||||||
|
disk->events |= DISK_EVENT_MEDIA_CHANGE;
|
||||||
mddev->gendisk = disk;
|
mddev->gendisk = disk;
|
||||||
/* As soon as we call add_disk(), another thread could get
|
/* As soon as we call add_disk(), another thread could get
|
||||||
* through to md_open, so make sure it doesn't get too far
|
* through to md_open, so make sure it doesn't get too far
|
||||||
@ -5964,8 +5945,6 @@ int md_run(struct mddev *mddev)
|
|||||||
blk_queue_flag_set(QUEUE_FLAG_NONROT, mddev->queue);
|
blk_queue_flag_set(QUEUE_FLAG_NONROT, mddev->queue);
|
||||||
else
|
else
|
||||||
blk_queue_flag_clear(QUEUE_FLAG_NONROT, mddev->queue);
|
blk_queue_flag_clear(QUEUE_FLAG_NONROT, mddev->queue);
|
||||||
mddev->queue->backing_dev_info->congested_data = mddev;
|
|
||||||
mddev->queue->backing_dev_info->congested_fn = md_congested;
|
|
||||||
}
|
}
|
||||||
if (pers->sync_request) {
|
if (pers->sync_request) {
|
||||||
if (mddev->kobj.sd &&
|
if (mddev->kobj.sd &&
|
||||||
@ -6350,7 +6329,6 @@ static int do_md_stop(struct mddev *mddev, int mode,
|
|||||||
|
|
||||||
__md_stop_writes(mddev);
|
__md_stop_writes(mddev);
|
||||||
__md_stop(mddev);
|
__md_stop(mddev);
|
||||||
mddev->queue->backing_dev_info->congested_fn = NULL;
|
|
||||||
|
|
||||||
/* tell userspace to handle 'inactive' */
|
/* tell userspace to handle 'inactive' */
|
||||||
sysfs_notify_dirent_safe(mddev->sysfs_state);
|
sysfs_notify_dirent_safe(mddev->sysfs_state);
|
||||||
@ -7806,23 +7784,21 @@ static void md_release(struct gendisk *disk, fmode_t mode)
|
|||||||
mddev_put(mddev);
|
mddev_put(mddev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int md_media_changed(struct gendisk *disk)
|
static unsigned int md_check_events(struct gendisk *disk, unsigned int clearing)
|
||||||
{
|
|
||||||
struct mddev *mddev = disk->private_data;
|
|
||||||
|
|
||||||
return mddev->changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int md_revalidate(struct gendisk *disk)
|
|
||||||
{
|
{
|
||||||
struct mddev *mddev = disk->private_data;
|
struct mddev *mddev = disk->private_data;
|
||||||
|
unsigned int ret = 0;
|
||||||
|
|
||||||
|
if (mddev->changed)
|
||||||
|
ret = DISK_EVENT_MEDIA_CHANGE;
|
||||||
mddev->changed = 0;
|
mddev->changed = 0;
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct block_device_operations md_fops =
|
static const struct block_device_operations md_fops =
|
||||||
{
|
{
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = md_submit_bio,
|
||||||
.open = md_open,
|
.open = md_open,
|
||||||
.release = md_release,
|
.release = md_release,
|
||||||
.ioctl = md_ioctl,
|
.ioctl = md_ioctl,
|
||||||
@ -7830,8 +7806,7 @@ static const struct block_device_operations md_fops =
|
|||||||
.compat_ioctl = md_compat_ioctl,
|
.compat_ioctl = md_compat_ioctl,
|
||||||
#endif
|
#endif
|
||||||
.getgeo = md_getgeo,
|
.getgeo = md_getgeo,
|
||||||
.media_changed = md_media_changed,
|
.check_events = md_check_events,
|
||||||
.revalidate_disk= md_revalidate,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int md_thread(void *arg)
|
static int md_thread(void *arg)
|
||||||
|
@ -597,9 +597,6 @@ struct md_personality
|
|||||||
* array.
|
* array.
|
||||||
*/
|
*/
|
||||||
void *(*takeover) (struct mddev *mddev);
|
void *(*takeover) (struct mddev *mddev);
|
||||||
/* congested implements bdi.congested_fn().
|
|
||||||
* Will not be called while array is 'suspended' */
|
|
||||||
int (*congested)(struct mddev *mddev, int bits);
|
|
||||||
/* Changes the consistency policy of an active array. */
|
/* Changes the consistency policy of an active array. */
|
||||||
int (*change_consistency_policy)(struct mddev *mddev, const char *buf);
|
int (*change_consistency_policy)(struct mddev *mddev, const char *buf);
|
||||||
};
|
};
|
||||||
@ -710,7 +707,6 @@ extern void md_done_sync(struct mddev *mddev, int blocks, int ok);
|
|||||||
extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
|
extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
|
||||||
extern void md_finish_reshape(struct mddev *mddev);
|
extern void md_finish_reshape(struct mddev *mddev);
|
||||||
|
|
||||||
extern int mddev_congested(struct mddev *mddev, int bits);
|
|
||||||
extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
|
extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
|
||||||
extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
|
extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
|
||||||
sector_t sector, int size, struct page *page);
|
sector_t sector, int size, struct page *page);
|
||||||
|
@ -29,21 +29,6 @@ module_param(default_layout, int, 0644);
|
|||||||
(1L << MD_HAS_PPL) | \
|
(1L << MD_HAS_PPL) | \
|
||||||
(1L << MD_HAS_MULTIPLE_PPLS))
|
(1L << MD_HAS_MULTIPLE_PPLS))
|
||||||
|
|
||||||
static int raid0_congested(struct mddev *mddev, int bits)
|
|
||||||
{
|
|
||||||
struct r0conf *conf = mddev->private;
|
|
||||||
struct md_rdev **devlist = conf->devlist;
|
|
||||||
int raid_disks = conf->strip_zone[0].nb_dev;
|
|
||||||
int i, ret = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < raid_disks && !ret ; i++) {
|
|
||||||
struct request_queue *q = bdev_get_queue(devlist[i]->bdev);
|
|
||||||
|
|
||||||
ret |= bdi_congested(q->backing_dev_info, bits);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* inform the user of the raid configuration
|
* inform the user of the raid configuration
|
||||||
*/
|
*/
|
||||||
@ -495,7 +480,7 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
|
|||||||
zone->zone_end - bio->bi_iter.bi_sector, GFP_NOIO,
|
zone->zone_end - bio->bi_iter.bi_sector, GFP_NOIO,
|
||||||
&mddev->bio_set);
|
&mddev->bio_set);
|
||||||
bio_chain(split, bio);
|
bio_chain(split, bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
bio = split;
|
bio = split;
|
||||||
end = zone->zone_end;
|
end = zone->zone_end;
|
||||||
} else
|
} else
|
||||||
@ -559,7 +544,7 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
|
|||||||
trace_block_bio_remap(bdev_get_queue(rdev->bdev),
|
trace_block_bio_remap(bdev_get_queue(rdev->bdev),
|
||||||
discard_bio, disk_devt(mddev->gendisk),
|
discard_bio, disk_devt(mddev->gendisk),
|
||||||
bio->bi_iter.bi_sector);
|
bio->bi_iter.bi_sector);
|
||||||
generic_make_request(discard_bio);
|
submit_bio_noacct(discard_bio);
|
||||||
}
|
}
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
}
|
}
|
||||||
@ -600,7 +585,7 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
|
|||||||
struct bio *split = bio_split(bio, sectors, GFP_NOIO,
|
struct bio *split = bio_split(bio, sectors, GFP_NOIO,
|
||||||
&mddev->bio_set);
|
&mddev->bio_set);
|
||||||
bio_chain(split, bio);
|
bio_chain(split, bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
bio = split;
|
bio = split;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -633,7 +618,7 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
|
|||||||
disk_devt(mddev->gendisk), bio_sector);
|
disk_devt(mddev->gendisk), bio_sector);
|
||||||
mddev_check_writesame(mddev, bio);
|
mddev_check_writesame(mddev, bio);
|
||||||
mddev_check_write_zeroes(mddev, bio);
|
mddev_check_write_zeroes(mddev, bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -818,7 +803,6 @@ static struct md_personality raid0_personality=
|
|||||||
.size = raid0_size,
|
.size = raid0_size,
|
||||||
.takeover = raid0_takeover,
|
.takeover = raid0_takeover,
|
||||||
.quiesce = raid0_quiesce,
|
.quiesce = raid0_quiesce,
|
||||||
.congested = raid0_congested,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init raid0_init (void)
|
static int __init raid0_init (void)
|
||||||
|
@ -786,36 +786,6 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
|
|||||||
return best_disk;
|
return best_disk;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raid1_congested(struct mddev *mddev, int bits)
|
|
||||||
{
|
|
||||||
struct r1conf *conf = mddev->private;
|
|
||||||
int i, ret = 0;
|
|
||||||
|
|
||||||
if ((bits & (1 << WB_async_congested)) &&
|
|
||||||
conf->pending_count >= max_queued_requests)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
for (i = 0; i < conf->raid_disks * 2; i++) {
|
|
||||||
struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
|
|
||||||
if (rdev && !test_bit(Faulty, &rdev->flags)) {
|
|
||||||
struct request_queue *q = bdev_get_queue(rdev->bdev);
|
|
||||||
|
|
||||||
BUG_ON(!q);
|
|
||||||
|
|
||||||
/* Note the '|| 1' - when read_balance prefers
|
|
||||||
* non-congested targets, it can be removed
|
|
||||||
*/
|
|
||||||
if ((bits & (1 << WB_async_congested)) || 1)
|
|
||||||
ret |= bdi_congested(q->backing_dev_info, bits);
|
|
||||||
else
|
|
||||||
ret &= bdi_congested(q->backing_dev_info, bits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void flush_bio_list(struct r1conf *conf, struct bio *bio)
|
static void flush_bio_list(struct r1conf *conf, struct bio *bio)
|
||||||
{
|
{
|
||||||
/* flush any pending bitmap writes to disk before proceeding w/ I/O */
|
/* flush any pending bitmap writes to disk before proceeding w/ I/O */
|
||||||
@ -834,7 +804,7 @@ static void flush_bio_list(struct r1conf *conf, struct bio *bio)
|
|||||||
/* Just ignore it */
|
/* Just ignore it */
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
else
|
else
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
bio = next;
|
bio = next;
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
@ -1312,7 +1282,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
|
|||||||
struct bio *split = bio_split(bio, max_sectors,
|
struct bio *split = bio_split(bio, max_sectors,
|
||||||
gfp, &conf->bio_split);
|
gfp, &conf->bio_split);
|
||||||
bio_chain(split, bio);
|
bio_chain(split, bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
bio = split;
|
bio = split;
|
||||||
r1_bio->master_bio = bio;
|
r1_bio->master_bio = bio;
|
||||||
r1_bio->sectors = max_sectors;
|
r1_bio->sectors = max_sectors;
|
||||||
@ -1338,7 +1308,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
|
|||||||
trace_block_bio_remap(read_bio->bi_disk->queue, read_bio,
|
trace_block_bio_remap(read_bio->bi_disk->queue, read_bio,
|
||||||
disk_devt(mddev->gendisk), r1_bio->sector);
|
disk_devt(mddev->gendisk), r1_bio->sector);
|
||||||
|
|
||||||
generic_make_request(read_bio);
|
submit_bio_noacct(read_bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||||
@ -1483,7 +1453,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
|||||||
struct bio *split = bio_split(bio, max_sectors,
|
struct bio *split = bio_split(bio, max_sectors,
|
||||||
GFP_NOIO, &conf->bio_split);
|
GFP_NOIO, &conf->bio_split);
|
||||||
bio_chain(split, bio);
|
bio_chain(split, bio);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
bio = split;
|
bio = split;
|
||||||
r1_bio->master_bio = bio;
|
r1_bio->master_bio = bio;
|
||||||
r1_bio->sectors = max_sectors;
|
r1_bio->sectors = max_sectors;
|
||||||
@ -2240,7 +2210,7 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio)
|
|||||||
atomic_inc(&r1_bio->remaining);
|
atomic_inc(&r1_bio->remaining);
|
||||||
md_sync_acct(conf->mirrors[i].rdev->bdev, bio_sectors(wbio));
|
md_sync_acct(conf->mirrors[i].rdev->bdev, bio_sectors(wbio));
|
||||||
|
|
||||||
generic_make_request(wbio);
|
submit_bio_noacct(wbio);
|
||||||
}
|
}
|
||||||
|
|
||||||
put_sync_write_buf(r1_bio, 1);
|
put_sync_write_buf(r1_bio, 1);
|
||||||
@ -2926,7 +2896,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
|
|||||||
md_sync_acct_bio(bio, nr_sectors);
|
md_sync_acct_bio(bio, nr_sectors);
|
||||||
if (read_targets == 1)
|
if (read_targets == 1)
|
||||||
bio->bi_opf &= ~MD_FAILFAST;
|
bio->bi_opf &= ~MD_FAILFAST;
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2935,7 +2905,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
|
|||||||
md_sync_acct_bio(bio, nr_sectors);
|
md_sync_acct_bio(bio, nr_sectors);
|
||||||
if (read_targets == 1)
|
if (read_targets == 1)
|
||||||
bio->bi_opf &= ~MD_FAILFAST;
|
bio->bi_opf &= ~MD_FAILFAST;
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
return nr_sectors;
|
return nr_sectors;
|
||||||
}
|
}
|
||||||
@ -3396,7 +3366,6 @@ static struct md_personality raid1_personality =
|
|||||||
.check_reshape = raid1_reshape,
|
.check_reshape = raid1_reshape,
|
||||||
.quiesce = raid1_quiesce,
|
.quiesce = raid1_quiesce,
|
||||||
.takeover = raid1_takeover,
|
.takeover = raid1_takeover,
|
||||||
.congested = raid1_congested,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init raid_init(void)
|
static int __init raid_init(void)
|
||||||
|
@ -848,31 +848,6 @@ static struct md_rdev *read_balance(struct r10conf *conf,
|
|||||||
return rdev;
|
return rdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raid10_congested(struct mddev *mddev, int bits)
|
|
||||||
{
|
|
||||||
struct r10conf *conf = mddev->private;
|
|
||||||
int i, ret = 0;
|
|
||||||
|
|
||||||
if ((bits & (1 << WB_async_congested)) &&
|
|
||||||
conf->pending_count >= max_queued_requests)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
for (i = 0;
|
|
||||||
(i < conf->geo.raid_disks || i < conf->prev.raid_disks)
|
|
||||||
&& ret == 0;
|
|
||||||
i++) {
|
|
||||||
struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
|
|
||||||
if (rdev && !test_bit(Faulty, &rdev->flags)) {
|
|
||||||
struct request_queue *q = bdev_get_queue(rdev->bdev);
|
|
||||||
|
|
||||||
ret |= bdi_congested(q->backing_dev_info, bits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void flush_pending_writes(struct r10conf *conf)
|
static void flush_pending_writes(struct r10conf *conf)
|
||||||
{
|
{
|
||||||
/* Any writes that have been queued but are awaiting
|
/* Any writes that have been queued but are awaiting
|
||||||
@ -917,7 +892,7 @@ static void flush_pending_writes(struct r10conf *conf)
|
|||||||
/* Just ignore it */
|
/* Just ignore it */
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
else
|
else
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
bio = next;
|
bio = next;
|
||||||
}
|
}
|
||||||
blk_finish_plug(&plug);
|
blk_finish_plug(&plug);
|
||||||
@ -1102,7 +1077,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
|
|||||||
/* Just ignore it */
|
/* Just ignore it */
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
else
|
else
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
bio = next;
|
bio = next;
|
||||||
}
|
}
|
||||||
kfree(plug);
|
kfree(plug);
|
||||||
@ -1194,7 +1169,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
|
|||||||
gfp, &conf->bio_split);
|
gfp, &conf->bio_split);
|
||||||
bio_chain(split, bio);
|
bio_chain(split, bio);
|
||||||
allow_barrier(conf);
|
allow_barrier(conf);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
wait_barrier(conf);
|
wait_barrier(conf);
|
||||||
bio = split;
|
bio = split;
|
||||||
r10_bio->master_bio = bio;
|
r10_bio->master_bio = bio;
|
||||||
@ -1221,7 +1196,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
|
|||||||
trace_block_bio_remap(read_bio->bi_disk->queue,
|
trace_block_bio_remap(read_bio->bi_disk->queue,
|
||||||
read_bio, disk_devt(mddev->gendisk),
|
read_bio, disk_devt(mddev->gendisk),
|
||||||
r10_bio->sector);
|
r10_bio->sector);
|
||||||
generic_make_request(read_bio);
|
submit_bio_noacct(read_bio);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1479,7 +1454,7 @@ retry_write:
|
|||||||
GFP_NOIO, &conf->bio_split);
|
GFP_NOIO, &conf->bio_split);
|
||||||
bio_chain(split, bio);
|
bio_chain(split, bio);
|
||||||
allow_barrier(conf);
|
allow_barrier(conf);
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
wait_barrier(conf);
|
wait_barrier(conf);
|
||||||
bio = split;
|
bio = split;
|
||||||
r10_bio->master_bio = bio;
|
r10_bio->master_bio = bio;
|
||||||
@ -2099,7 +2074,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
|
|||||||
tbio->bi_opf |= MD_FAILFAST;
|
tbio->bi_opf |= MD_FAILFAST;
|
||||||
tbio->bi_iter.bi_sector += conf->mirrors[d].rdev->data_offset;
|
tbio->bi_iter.bi_sector += conf->mirrors[d].rdev->data_offset;
|
||||||
bio_set_dev(tbio, conf->mirrors[d].rdev->bdev);
|
bio_set_dev(tbio, conf->mirrors[d].rdev->bdev);
|
||||||
generic_make_request(tbio);
|
submit_bio_noacct(tbio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now write out to any replacement devices
|
/* Now write out to any replacement devices
|
||||||
@ -2118,7 +2093,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
|
|||||||
atomic_inc(&r10_bio->remaining);
|
atomic_inc(&r10_bio->remaining);
|
||||||
md_sync_acct(conf->mirrors[d].replacement->bdev,
|
md_sync_acct(conf->mirrors[d].replacement->bdev,
|
||||||
bio_sectors(tbio));
|
bio_sectors(tbio));
|
||||||
generic_make_request(tbio);
|
submit_bio_noacct(tbio);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
@ -2241,7 +2216,7 @@ static void recovery_request_write(struct mddev *mddev, struct r10bio *r10_bio)
|
|||||||
wbio = r10_bio->devs[1].bio;
|
wbio = r10_bio->devs[1].bio;
|
||||||
wbio2 = r10_bio->devs[1].repl_bio;
|
wbio2 = r10_bio->devs[1].repl_bio;
|
||||||
/* Need to test wbio2->bi_end_io before we call
|
/* Need to test wbio2->bi_end_io before we call
|
||||||
* generic_make_request as if the former is NULL,
|
* submit_bio_noacct as if the former is NULL,
|
||||||
* the latter is free to free wbio2.
|
* the latter is free to free wbio2.
|
||||||
*/
|
*/
|
||||||
if (wbio2 && !wbio2->bi_end_io)
|
if (wbio2 && !wbio2->bi_end_io)
|
||||||
@ -2249,13 +2224,13 @@ static void recovery_request_write(struct mddev *mddev, struct r10bio *r10_bio)
|
|||||||
if (wbio->bi_end_io) {
|
if (wbio->bi_end_io) {
|
||||||
atomic_inc(&conf->mirrors[d].rdev->nr_pending);
|
atomic_inc(&conf->mirrors[d].rdev->nr_pending);
|
||||||
md_sync_acct(conf->mirrors[d].rdev->bdev, bio_sectors(wbio));
|
md_sync_acct(conf->mirrors[d].rdev->bdev, bio_sectors(wbio));
|
||||||
generic_make_request(wbio);
|
submit_bio_noacct(wbio);
|
||||||
}
|
}
|
||||||
if (wbio2) {
|
if (wbio2) {
|
||||||
atomic_inc(&conf->mirrors[d].replacement->nr_pending);
|
atomic_inc(&conf->mirrors[d].replacement->nr_pending);
|
||||||
md_sync_acct(conf->mirrors[d].replacement->bdev,
|
md_sync_acct(conf->mirrors[d].replacement->bdev,
|
||||||
bio_sectors(wbio2));
|
bio_sectors(wbio2));
|
||||||
generic_make_request(wbio2);
|
submit_bio_noacct(wbio2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2889,7 +2864,7 @@ static void raid10_set_cluster_sync_high(struct r10conf *conf)
|
|||||||
* a number of r10_bio structures, one for each out-of-sync device.
|
* a number of r10_bio structures, one for each out-of-sync device.
|
||||||
* As we setup these structures, we collect all bio's together into a list
|
* As we setup these structures, we collect all bio's together into a list
|
||||||
* which we then process collectively to add pages, and then process again
|
* which we then process collectively to add pages, and then process again
|
||||||
* to pass to generic_make_request.
|
* to pass to submit_bio_noacct.
|
||||||
*
|
*
|
||||||
* The r10_bio structures are linked using a borrowed master_bio pointer.
|
* The r10_bio structures are linked using a borrowed master_bio pointer.
|
||||||
* This link is counted in ->remaining. When the r10_bio that points to NULL
|
* This link is counted in ->remaining. When the r10_bio that points to NULL
|
||||||
@ -3496,7 +3471,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
|
|||||||
if (bio->bi_end_io == end_sync_read) {
|
if (bio->bi_end_io == end_sync_read) {
|
||||||
md_sync_acct_bio(bio, nr_sectors);
|
md_sync_acct_bio(bio, nr_sectors);
|
||||||
bio->bi_status = 0;
|
bio->bi_status = 0;
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4654,7 +4629,7 @@ read_more:
|
|||||||
md_sync_acct_bio(read_bio, r10_bio->sectors);
|
md_sync_acct_bio(read_bio, r10_bio->sectors);
|
||||||
atomic_inc(&r10_bio->remaining);
|
atomic_inc(&r10_bio->remaining);
|
||||||
read_bio->bi_next = NULL;
|
read_bio->bi_next = NULL;
|
||||||
generic_make_request(read_bio);
|
submit_bio_noacct(read_bio);
|
||||||
sectors_done += nr_sectors;
|
sectors_done += nr_sectors;
|
||||||
if (sector_nr <= last)
|
if (sector_nr <= last)
|
||||||
goto read_more;
|
goto read_more;
|
||||||
@ -4717,7 +4692,7 @@ static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio)
|
|||||||
md_sync_acct_bio(b, r10_bio->sectors);
|
md_sync_acct_bio(b, r10_bio->sectors);
|
||||||
atomic_inc(&r10_bio->remaining);
|
atomic_inc(&r10_bio->remaining);
|
||||||
b->bi_next = NULL;
|
b->bi_next = NULL;
|
||||||
generic_make_request(b);
|
submit_bio_noacct(b);
|
||||||
}
|
}
|
||||||
end_reshape_request(r10_bio);
|
end_reshape_request(r10_bio);
|
||||||
}
|
}
|
||||||
@ -4929,7 +4904,6 @@ static struct md_personality raid10_personality =
|
|||||||
.start_reshape = raid10_start_reshape,
|
.start_reshape = raid10_start_reshape,
|
||||||
.finish_reshape = raid10_finish_reshape,
|
.finish_reshape = raid10_finish_reshape,
|
||||||
.update_reshape_pos = raid10_update_reshape_pos,
|
.update_reshape_pos = raid10_update_reshape_pos,
|
||||||
.congested = raid10_congested,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init raid_init(void)
|
static int __init raid_init(void)
|
||||||
|
@ -873,7 +873,7 @@ static void dispatch_bio_list(struct bio_list *tmp)
|
|||||||
struct bio *bio;
|
struct bio *bio;
|
||||||
|
|
||||||
while ((bio = bio_list_pop(tmp)))
|
while ((bio = bio_list_pop(tmp)))
|
||||||
generic_make_request(bio);
|
submit_bio_noacct(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmp_stripe(void *priv, struct list_head *a, struct list_head *b)
|
static int cmp_stripe(void *priv, struct list_head *a, struct list_head *b)
|
||||||
@ -1151,7 +1151,7 @@ again:
|
|||||||
if (should_defer && op_is_write(op))
|
if (should_defer && op_is_write(op))
|
||||||
bio_list_add(&pending_bios, bi);
|
bio_list_add(&pending_bios, bi);
|
||||||
else
|
else
|
||||||
generic_make_request(bi);
|
submit_bio_noacct(bi);
|
||||||
}
|
}
|
||||||
if (rrdev) {
|
if (rrdev) {
|
||||||
if (s->syncing || s->expanding || s->expanded
|
if (s->syncing || s->expanding || s->expanded
|
||||||
@ -1201,7 +1201,7 @@ again:
|
|||||||
if (should_defer && op_is_write(op))
|
if (should_defer && op_is_write(op))
|
||||||
bio_list_add(&pending_bios, rbi);
|
bio_list_add(&pending_bios, rbi);
|
||||||
else
|
else
|
||||||
generic_make_request(rbi);
|
submit_bio_noacct(rbi);
|
||||||
}
|
}
|
||||||
if (!rdev && !rrdev) {
|
if (!rdev && !rrdev) {
|
||||||
if (op_is_write(op))
|
if (op_is_write(op))
|
||||||
@ -5099,28 +5099,6 @@ static void activate_bit_delay(struct r5conf *conf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raid5_congested(struct mddev *mddev, int bits)
|
|
||||||
{
|
|
||||||
struct r5conf *conf = mddev->private;
|
|
||||||
|
|
||||||
/* No difference between reads and writes. Just check
|
|
||||||
* how busy the stripe_cache is
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (test_bit(R5_INACTIVE_BLOCKED, &conf->cache_state))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* Also checks whether there is pressure on r5cache log space */
|
|
||||||
if (test_bit(R5C_LOG_TIGHT, &conf->cache_state))
|
|
||||||
return 1;
|
|
||||||
if (conf->quiesce)
|
|
||||||
return 1;
|
|
||||||
if (atomic_read(&conf->empty_inactive_list_nr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int in_chunk_boundary(struct mddev *mddev, struct bio *bio)
|
static int in_chunk_boundary(struct mddev *mddev, struct bio *bio)
|
||||||
{
|
{
|
||||||
struct r5conf *conf = mddev->private;
|
struct r5conf *conf = mddev->private;
|
||||||
@ -5289,7 +5267,7 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio)
|
|||||||
trace_block_bio_remap(align_bi->bi_disk->queue,
|
trace_block_bio_remap(align_bi->bi_disk->queue,
|
||||||
align_bi, disk_devt(mddev->gendisk),
|
align_bi, disk_devt(mddev->gendisk),
|
||||||
raid_bio->bi_iter.bi_sector);
|
raid_bio->bi_iter.bi_sector);
|
||||||
generic_make_request(align_bi);
|
submit_bio_noacct(align_bi);
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
@ -5309,7 +5287,7 @@ static struct bio *chunk_aligned_read(struct mddev *mddev, struct bio *raid_bio)
|
|||||||
struct r5conf *conf = mddev->private;
|
struct r5conf *conf = mddev->private;
|
||||||
split = bio_split(raid_bio, sectors, GFP_NOIO, &conf->bio_split);
|
split = bio_split(raid_bio, sectors, GFP_NOIO, &conf->bio_split);
|
||||||
bio_chain(split, raid_bio);
|
bio_chain(split, raid_bio);
|
||||||
generic_make_request(raid_bio);
|
submit_bio_noacct(raid_bio);
|
||||||
raid_bio = split;
|
raid_bio = split;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8427,7 +8405,6 @@ static struct md_personality raid6_personality =
|
|||||||
.finish_reshape = raid5_finish_reshape,
|
.finish_reshape = raid5_finish_reshape,
|
||||||
.quiesce = raid5_quiesce,
|
.quiesce = raid5_quiesce,
|
||||||
.takeover = raid6_takeover,
|
.takeover = raid6_takeover,
|
||||||
.congested = raid5_congested,
|
|
||||||
.change_consistency_policy = raid5_change_consistency_policy,
|
.change_consistency_policy = raid5_change_consistency_policy,
|
||||||
};
|
};
|
||||||
static struct md_personality raid5_personality =
|
static struct md_personality raid5_personality =
|
||||||
@ -8452,7 +8429,6 @@ static struct md_personality raid5_personality =
|
|||||||
.finish_reshape = raid5_finish_reshape,
|
.finish_reshape = raid5_finish_reshape,
|
||||||
.quiesce = raid5_quiesce,
|
.quiesce = raid5_quiesce,
|
||||||
.takeover = raid5_takeover,
|
.takeover = raid5_takeover,
|
||||||
.congested = raid5_congested,
|
|
||||||
.change_consistency_policy = raid5_change_consistency_policy,
|
.change_consistency_policy = raid5_change_consistency_policy,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -8478,7 +8454,6 @@ static struct md_personality raid4_personality =
|
|||||||
.finish_reshape = raid5_finish_reshape,
|
.finish_reshape = raid5_finish_reshape,
|
||||||
.quiesce = raid5_quiesce,
|
.quiesce = raid5_quiesce,
|
||||||
.takeover = raid4_takeover,
|
.takeover = raid4_takeover,
|
||||||
.congested = raid5_congested,
|
|
||||||
.change_consistency_policy = raid5_change_consistency_policy,
|
.change_consistency_policy = raid5_change_consistency_policy,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -312,10 +312,7 @@ static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
|
|||||||
|
|
||||||
mutex_lock(&block_mutex);
|
mutex_lock(&block_mutex);
|
||||||
if (md) {
|
if (md) {
|
||||||
if (md->usage == 2)
|
|
||||||
check_disk_change(bdev);
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
if ((mode & FMODE_WRITE) && md->read_only) {
|
if ((mode & FMODE_WRITE) && md->read_only) {
|
||||||
mmc_blk_put(md);
|
mmc_blk_put(md);
|
||||||
ret = -EROFS;
|
ret = -EROFS;
|
||||||
@ -1446,7 +1443,7 @@ static void mmc_blk_cqe_req_done(struct mmc_request *mrq)
|
|||||||
*/
|
*/
|
||||||
if (mq->in_recovery)
|
if (mq->in_recovery)
|
||||||
mmc_blk_cqe_complete_rq(mq, req);
|
mmc_blk_cqe_complete_rq(mq, req);
|
||||||
else
|
else if (likely(!blk_should_fake_timeout(req->q)))
|
||||||
blk_mq_complete_request(req);
|
blk_mq_complete_request(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1926,7 +1923,7 @@ static void mmc_blk_hsq_req_done(struct mmc_request *mrq)
|
|||||||
*/
|
*/
|
||||||
if (mq->in_recovery)
|
if (mq->in_recovery)
|
||||||
mmc_blk_cqe_complete_rq(mq, req);
|
mmc_blk_cqe_complete_rq(mq, req);
|
||||||
else
|
else if (likely(!blk_should_fake_timeout(req->q)))
|
||||||
blk_mq_complete_request(req);
|
blk_mq_complete_request(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1936,7 +1933,7 @@ void mmc_blk_mq_complete(struct request *req)
|
|||||||
|
|
||||||
if (mq->use_cqe)
|
if (mq->use_cqe)
|
||||||
mmc_blk_cqe_complete_rq(mq, req);
|
mmc_blk_cqe_complete_rq(mq, req);
|
||||||
else
|
else if (likely(!blk_should_fake_timeout(req->q)))
|
||||||
mmc_blk_mq_complete_rq(mq, req);
|
mmc_blk_mq_complete_rq(mq, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1988,7 +1985,7 @@ static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req)
|
|||||||
*/
|
*/
|
||||||
if (mq->in_recovery)
|
if (mq->in_recovery)
|
||||||
mmc_blk_mq_complete_rq(mq, req);
|
mmc_blk_mq_complete_rq(mq, req);
|
||||||
else
|
else if (likely(!blk_should_fake_timeout(req->q)))
|
||||||
blk_mq_complete_request(req);
|
blk_mq_complete_request(req);
|
||||||
|
|
||||||
mmc_blk_mq_dec_in_flight(mq, req);
|
mmc_blk_mq_dec_in_flight(mq, req);
|
||||||
|
@ -162,7 +162,7 @@ static int nsblk_do_bvec(struct nd_namespace_blk *nsblk,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio)
|
static blk_qc_t nd_blk_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct bio_integrity_payload *bip;
|
struct bio_integrity_payload *bip;
|
||||||
struct nd_namespace_blk *nsblk = bio->bi_disk->private_data;
|
struct nd_namespace_blk *nsblk = bio->bi_disk->private_data;
|
||||||
@ -225,6 +225,7 @@ static int nsblk_rw_bytes(struct nd_namespace_common *ndns,
|
|||||||
|
|
||||||
static const struct block_device_operations nd_blk_fops = {
|
static const struct block_device_operations nd_blk_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = nd_blk_submit_bio,
|
||||||
.revalidate_disk = nvdimm_revalidate_disk,
|
.revalidate_disk = nvdimm_revalidate_disk,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -250,7 +251,7 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
|
|||||||
internal_nlba = div_u64(nsblk->size, nsblk_internal_lbasize(nsblk));
|
internal_nlba = div_u64(nsblk->size, nsblk_internal_lbasize(nsblk));
|
||||||
available_disk_size = internal_nlba * nsblk_sector_size(nsblk);
|
available_disk_size = internal_nlba * nsblk_sector_size(nsblk);
|
||||||
|
|
||||||
q = blk_alloc_queue(nd_blk_make_request, NUMA_NO_NODE);
|
q = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (!q)
|
if (!q)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
if (devm_add_action_or_reset(dev, nd_blk_release_queue, q))
|
if (devm_add_action_or_reset(dev, nd_blk_release_queue, q))
|
||||||
|
@ -1439,7 +1439,7 @@ static int btt_do_bvec(struct btt *btt, struct bio_integrity_payload *bip,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t btt_make_request(struct request_queue *q, struct bio *bio)
|
static blk_qc_t btt_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||||
struct btt *btt = bio->bi_disk->private_data;
|
struct btt *btt = bio->bi_disk->private_data;
|
||||||
@ -1512,6 +1512,7 @@ static int btt_getgeo(struct block_device *bd, struct hd_geometry *geo)
|
|||||||
|
|
||||||
static const struct block_device_operations btt_fops = {
|
static const struct block_device_operations btt_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = btt_submit_bio,
|
||||||
.rw_page = btt_rw_page,
|
.rw_page = btt_rw_page,
|
||||||
.getgeo = btt_getgeo,
|
.getgeo = btt_getgeo,
|
||||||
.revalidate_disk = nvdimm_revalidate_disk,
|
.revalidate_disk = nvdimm_revalidate_disk,
|
||||||
@ -1523,7 +1524,7 @@ static int btt_blk_init(struct btt *btt)
|
|||||||
struct nd_namespace_common *ndns = nd_btt->ndns;
|
struct nd_namespace_common *ndns = nd_btt->ndns;
|
||||||
|
|
||||||
/* create a new disk and request queue for btt */
|
/* create a new disk and request queue for btt */
|
||||||
btt->btt_queue = blk_alloc_queue(btt_make_request, NUMA_NO_NODE);
|
btt->btt_queue = blk_alloc_queue(NUMA_NO_NODE);
|
||||||
if (!btt->btt_queue)
|
if (!btt->btt_queue)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ static blk_status_t pmem_do_write(struct pmem_device *pmem,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
|
static blk_qc_t pmem_submit_bio(struct bio *bio)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
blk_status_t rc = 0;
|
blk_status_t rc = 0;
|
||||||
@ -281,6 +281,7 @@ __weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
|
|||||||
|
|
||||||
static const struct block_device_operations pmem_fops = {
|
static const struct block_device_operations pmem_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.submit_bio = pmem_submit_bio,
|
||||||
.rw_page = pmem_rw_page,
|
.rw_page = pmem_rw_page,
|
||||||
.revalidate_disk = nvdimm_revalidate_disk,
|
.revalidate_disk = nvdimm_revalidate_disk,
|
||||||
};
|
};
|
||||||
@ -423,7 +424,7 @@ static int pmem_attach_disk(struct device *dev,
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
q = blk_alloc_queue(pmem_make_request, dev_to_node(dev));
|
q = blk_alloc_queue(dev_to_node(dev));
|
||||||
if (!q)
|
if (!q)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user