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:
Linus Torvalds 2020-08-03 11:57:03 -07:00
commit 382625d0d4
157 changed files with 1839 additions and 2648 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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");

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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",

View File

@ -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(&current->bio_list[0], bio); bio_list_add(&current->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;
} }

View File

@ -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;
} }

View File

@ -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.
* *

View File

@ -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);

View File

@ -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);
} }

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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)
{ {

View File

@ -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,

View File

@ -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",

View File

@ -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;
} }

View File

@ -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);

View File

@ -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);

View File

@ -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;
} }

View File

@ -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)) {

View File

@ -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);

View File

@ -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 :

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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 */

View File

@ -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' : ' ';

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }

View File

@ -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);

View File

@ -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);

View File

@ -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);
} }
/* /*

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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);

View File

@ -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)))

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);
} }

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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);
} }
/* /*

View File

@ -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.

View File

@ -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;
} }

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;
} }
} }

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;

View File

@ -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);
} }

View File

@ -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);
} }
} }
} }

View File

@ -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);
} }
/* /*

View File

@ -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);

View File

@ -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 *

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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;
} }

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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,
}; };

View File

@ -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);

View File

@ -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))

View File

@ -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;

View File

@ -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