You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-3.18/core' of git://git.kernel.dk/linux-block
Pull core block layer changes from Jens Axboe:
"This is the core block IO pull request for 3.18. Apart from the new
and improved flush machinery for blk-mq, this is all mostly bug fixes
and cleanups.
- blk-mq timeout updates and fixes from Christoph.
- Removal of REQ_END, also from Christoph. We pass it through the
->queue_rq() hook for blk-mq instead, freeing up one of the request
bits. The space was overly tight on 32-bit, so Martin also killed
REQ_KERNEL since it's no longer used.
- blk integrity updates and fixes from Martin and Gu Zheng.
- Update to the flush machinery for blk-mq from Ming Lei. Now we
have a per hardware context flush request, which both cleans up the
code should scale better for flush intensive workloads on blk-mq.
- Improve the error printing, from Rob Elliott.
- Backing device improvements and cleanups from Tejun.
- Fixup of a misplaced rq_complete() tracepoint from Hannes.
- Make blk_get_request() return error pointers, fixing up issues
where we NULL deref when a device goes bad or missing. From Joe
Lawrence.
- Prep work for drastically reducing the memory consumption of dm
devices from Junichi Nomura. This allows creating clone bio sets
without preallocating a lot of memory.
- Fix a blk-mq hang on certain combinations of queue depths and
hardware queues from me.
- Limit memory consumption for blk-mq devices for crash dump
scenarios and drivers that use crazy high depths (certain SCSI
shared tag setups). We now just use a single queue and limited
depth for that"
* 'for-3.18/core' of git://git.kernel.dk/linux-block: (58 commits)
block: Remove REQ_KERNEL
blk-mq: allocate cpumask on the home node
bio-integrity: remove the needless fail handle of bip_slab creating
block: include func name in __get_request prints
block: make blk_update_request print prefix match ratelimited prefix
blk-merge: don't compute bi_phys_segments from bi_vcnt for cloned bio
block: fix alignment_offset math that assumes io_min is a power-of-2
blk-mq: Make bt_clear_tag() easier to read
blk-mq: fix potential hang if rolling wakeup depth is too high
block: add bioset_create_nobvec()
block: use bio_clone_fast() in blk_rq_prep_clone()
block: misplaced rq_complete tracepoint
sd: Honor block layer integrity handling flags
block: Replace strnicmp with strncasecmp
block: Add T10 Protection Information functions
block: Don't merge requests if integrity flags differ
block: Integrity checksum flag
block: Relocate bio integrity flags
block: Add a disk flag to block integrity profile
block: Add prefix to block integrity profile flags
...
This commit is contained in:
@@ -53,6 +53,14 @@ Description:
|
||||
512 bytes of data.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/device_is_integrity_capable
|
||||
Date: July 2014
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Indicates whether a storage device is capable of storing
|
||||
integrity metadata. Set if the device is T10 PI-capable.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/write_generate
|
||||
Date: June 2008
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
|
||||
@@ -129,11 +129,11 @@ interface for this is being worked on.
|
||||
4.1 BIO
|
||||
|
||||
The data integrity patches add a new field to struct bio when
|
||||
CONFIG_BLK_DEV_INTEGRITY is enabled. bio->bi_integrity is a pointer
|
||||
to a struct bip which contains the bio integrity payload. Essentially
|
||||
a bip is a trimmed down struct bio which holds a bio_vec containing
|
||||
the integrity metadata and the required housekeeping information (bvec
|
||||
pool, vector count, etc.)
|
||||
CONFIG_BLK_DEV_INTEGRITY is enabled. bio_integrity(bio) returns a
|
||||
pointer to a struct bip which contains the bio integrity payload.
|
||||
Essentially a bip is a trimmed down struct bio which holds a bio_vec
|
||||
containing the integrity metadata and the required housekeeping
|
||||
information (bvec pool, vector count, etc.)
|
||||
|
||||
A kernel subsystem can enable data integrity protection on a bio by
|
||||
calling bio_integrity_alloc(bio). This will allocate and attach the
|
||||
@@ -192,16 +192,6 @@ will require extra work due to the application tag.
|
||||
supported by the block device.
|
||||
|
||||
|
||||
int bdev_integrity_enabled(block_device, int rw);
|
||||
|
||||
bdev_integrity_enabled() will return 1 if the block device
|
||||
supports integrity metadata transfer for the data direction
|
||||
specified in 'rw'.
|
||||
|
||||
bdev_integrity_enabled() honors the write_generate and
|
||||
read_verify flags in sysfs and will respond accordingly.
|
||||
|
||||
|
||||
int bio_integrity_prep(bio);
|
||||
|
||||
To generate IMD for WRITE and to set up buffers for READ, the
|
||||
@@ -216,36 +206,6 @@ will require extra work due to the application tag.
|
||||
bio_integrity_enabled() returned 1.
|
||||
|
||||
|
||||
int bio_integrity_tag_size(bio);
|
||||
|
||||
If the filesystem wants to use the application tag space it will
|
||||
first have to find out how much storage space is available.
|
||||
Because tag space is generally limited (usually 2 bytes per
|
||||
sector regardless of sector size), the integrity framework
|
||||
supports interleaving the information between the sectors in an
|
||||
I/O.
|
||||
|
||||
Filesystems can call bio_integrity_tag_size(bio) to find out how
|
||||
many bytes of storage are available for that particular bio.
|
||||
|
||||
Another option is bdev_get_tag_size(block_device) which will
|
||||
return the number of available bytes per hardware sector.
|
||||
|
||||
|
||||
int bio_integrity_set_tag(bio, void *tag_buf, len);
|
||||
|
||||
After a successful return from bio_integrity_prep(),
|
||||
bio_integrity_set_tag() can be used to attach an opaque tag
|
||||
buffer to a bio. Obviously this only makes sense if the I/O is
|
||||
a WRITE.
|
||||
|
||||
|
||||
int bio_integrity_get_tag(bio, void *tag_buf, len);
|
||||
|
||||
Similarly, at READ I/O completion time the filesystem can
|
||||
retrieve the tag buffer using bio_integrity_get_tag().
|
||||
|
||||
|
||||
5.3 PASSING EXISTING INTEGRITY METADATA
|
||||
|
||||
Filesystems that either generate their own integrity metadata or
|
||||
@@ -298,8 +258,6 @@ will require extra work due to the application tag.
|
||||
.name = "STANDARDSBODY-TYPE-VARIANT-CSUM",
|
||||
.generate_fn = my_generate_fn,
|
||||
.verify_fn = my_verify_fn,
|
||||
.get_tag_fn = my_get_tag_fn,
|
||||
.set_tag_fn = my_set_tag_fn,
|
||||
.tuple_size = sizeof(struct my_tuple_size),
|
||||
.tag_size = <tag bytes per hw sector>,
|
||||
};
|
||||
@@ -321,7 +279,5 @@ will require extra work due to the application tag.
|
||||
are available per hardware sector. For DIF this is either 2 or
|
||||
0 depending on the value of the Control Mode Page ATO bit.
|
||||
|
||||
See 6.2 for a description of get_tag_fn and set_tag_fn.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
2007-12-24 Martin K. Petersen <martin.petersen@oracle.com>
|
||||
|
||||
@@ -77,6 +77,7 @@ config BLK_DEV_BSGLIB
|
||||
|
||||
config BLK_DEV_INTEGRITY
|
||||
bool "Block layer data integrity support"
|
||||
select CRC_T10DIF if BLK_DEV_INTEGRITY
|
||||
---help---
|
||||
Some storage devices allow extra information to be
|
||||
stored/retrieved to help protect the data. The block layer
|
||||
|
||||
+2
-2
@@ -20,6 +20,6 @@ obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o
|
||||
obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o
|
||||
|
||||
obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o
|
||||
obj-$(CONFIG_BLK_DEV_INTEGRITY) += blk-integrity.o
|
||||
obj-$(CONFIG_BLK_CMDLINE_PARSER) += cmdline-parser.o
|
||||
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o
|
||||
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o t10-pi.o
|
||||
|
||||
|
||||
+67
-202
@@ -79,6 +79,7 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
|
||||
bip->bip_slab = idx;
|
||||
bip->bip_bio = bio;
|
||||
bio->bi_integrity = bip;
|
||||
bio->bi_rw |= REQ_INTEGRITY;
|
||||
|
||||
return bip;
|
||||
err:
|
||||
@@ -96,11 +97,12 @@ EXPORT_SYMBOL(bio_integrity_alloc);
|
||||
*/
|
||||
void bio_integrity_free(struct bio *bio)
|
||||
{
|
||||
struct bio_integrity_payload *bip = bio->bi_integrity;
|
||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||
struct bio_set *bs = bio->bi_pool;
|
||||
|
||||
if (bip->bip_owns_buf)
|
||||
kfree(bip->bip_buf);
|
||||
if (bip->bip_flags & BIP_BLOCK_INTEGRITY)
|
||||
kfree(page_address(bip->bip_vec->bv_page) +
|
||||
bip->bip_vec->bv_offset);
|
||||
|
||||
if (bs) {
|
||||
if (bip->bip_slab != BIO_POOL_NONE)
|
||||
@@ -128,7 +130,7 @@ EXPORT_SYMBOL(bio_integrity_free);
|
||||
int bio_integrity_add_page(struct bio *bio, struct page *page,
|
||||
unsigned int len, unsigned int offset)
|
||||
{
|
||||
struct bio_integrity_payload *bip = bio->bi_integrity;
|
||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||
struct bio_vec *iv;
|
||||
|
||||
if (bip->bip_vcnt >= bip->bip_max_vcnt) {
|
||||
@@ -147,24 +149,6 @@ int bio_integrity_add_page(struct bio *bio, struct page *page,
|
||||
}
|
||||
EXPORT_SYMBOL(bio_integrity_add_page);
|
||||
|
||||
static int bdev_integrity_enabled(struct block_device *bdev, int rw)
|
||||
{
|
||||
struct blk_integrity *bi = bdev_get_integrity(bdev);
|
||||
|
||||
if (bi == NULL)
|
||||
return 0;
|
||||
|
||||
if (rw == READ && bi->verify_fn != NULL &&
|
||||
(bi->flags & INTEGRITY_FLAG_READ))
|
||||
return 1;
|
||||
|
||||
if (rw == WRITE && bi->generate_fn != NULL &&
|
||||
(bi->flags & INTEGRITY_FLAG_WRITE))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* bio_integrity_enabled - Check whether integrity can be passed
|
||||
* @bio: bio to check
|
||||
@@ -174,199 +158,92 @@ static int bdev_integrity_enabled(struct block_device *bdev, int rw)
|
||||
* set prior to calling. The functions honors the write_generate and
|
||||
* read_verify flags in sysfs.
|
||||
*/
|
||||
int bio_integrity_enabled(struct bio *bio)
|
||||
bool bio_integrity_enabled(struct bio *bio)
|
||||
{
|
||||
struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
|
||||
|
||||
if (!bio_is_rw(bio))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
/* Already protected? */
|
||||
if (bio_integrity(bio))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
return bdev_integrity_enabled(bio->bi_bdev, bio_data_dir(bio));
|
||||
if (bi == NULL)
|
||||
return false;
|
||||
|
||||
if (bio_data_dir(bio) == READ && bi->verify_fn != NULL &&
|
||||
(bi->flags & BLK_INTEGRITY_VERIFY))
|
||||
return true;
|
||||
|
||||
if (bio_data_dir(bio) == WRITE && bi->generate_fn != NULL &&
|
||||
(bi->flags & BLK_INTEGRITY_GENERATE))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(bio_integrity_enabled);
|
||||
|
||||
/**
|
||||
* bio_integrity_hw_sectors - Convert 512b sectors to hardware ditto
|
||||
* bio_integrity_intervals - Return number of integrity intervals for a bio
|
||||
* @bi: blk_integrity profile for device
|
||||
* @sectors: Number of 512 sectors to convert
|
||||
* @sectors: Size of the bio in 512-byte sectors
|
||||
*
|
||||
* Description: The block layer calculates everything in 512 byte
|
||||
* sectors but integrity metadata is done in terms of the hardware
|
||||
* sector size of the storage device. Convert the block layer sectors
|
||||
* to physical sectors.
|
||||
* sectors but integrity metadata is done in terms of the data integrity
|
||||
* interval size of the storage device. Convert the block layer sectors
|
||||
* to the appropriate number of integrity intervals.
|
||||
*/
|
||||
static inline unsigned int bio_integrity_hw_sectors(struct blk_integrity *bi,
|
||||
unsigned int sectors)
|
||||
static inline unsigned int bio_integrity_intervals(struct blk_integrity *bi,
|
||||
unsigned int sectors)
|
||||
{
|
||||
/* At this point there are only 512b or 4096b DIF/EPP devices */
|
||||
if (bi->sector_size == 4096)
|
||||
return sectors >>= 3;
|
||||
|
||||
return sectors;
|
||||
return sectors >> (ilog2(bi->interval) - 9);
|
||||
}
|
||||
|
||||
static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
|
||||
unsigned int sectors)
|
||||
{
|
||||
return bio_integrity_hw_sectors(bi, sectors) * bi->tuple_size;
|
||||
return bio_integrity_intervals(bi, sectors) * bi->tuple_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* bio_integrity_tag_size - Retrieve integrity tag space
|
||||
* @bio: bio to inspect
|
||||
*
|
||||
* Description: Returns the maximum number of tag bytes that can be
|
||||
* attached to this bio. Filesystems can use this to determine how
|
||||
* much metadata to attach to an I/O.
|
||||
*/
|
||||
unsigned int bio_integrity_tag_size(struct bio *bio)
|
||||
{
|
||||
struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
|
||||
|
||||
BUG_ON(bio->bi_iter.bi_size == 0);
|
||||
|
||||
return bi->tag_size * (bio->bi_iter.bi_size / bi->sector_size);
|
||||
}
|
||||
EXPORT_SYMBOL(bio_integrity_tag_size);
|
||||
|
||||
static int bio_integrity_tag(struct bio *bio, void *tag_buf, unsigned int len,
|
||||
int set)
|
||||
{
|
||||
struct bio_integrity_payload *bip = bio->bi_integrity;
|
||||
struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
|
||||
unsigned int nr_sectors;
|
||||
|
||||
BUG_ON(bip->bip_buf == NULL);
|
||||
|
||||
if (bi->tag_size == 0)
|
||||
return -1;
|
||||
|
||||
nr_sectors = bio_integrity_hw_sectors(bi,
|
||||
DIV_ROUND_UP(len, bi->tag_size));
|
||||
|
||||
if (nr_sectors * bi->tuple_size > bip->bip_iter.bi_size) {
|
||||
printk(KERN_ERR "%s: tag too big for bio: %u > %u\n", __func__,
|
||||
nr_sectors * bi->tuple_size, bip->bip_iter.bi_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (set)
|
||||
bi->set_tag_fn(bip->bip_buf, tag_buf, nr_sectors);
|
||||
else
|
||||
bi->get_tag_fn(bip->bip_buf, tag_buf, nr_sectors);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* bio_integrity_set_tag - Attach a tag buffer to a bio
|
||||
* @bio: bio to attach buffer to
|
||||
* @tag_buf: Pointer to a buffer containing tag data
|
||||
* @len: Length of the included buffer
|
||||
*
|
||||
* Description: Use this function to tag a bio by leveraging the extra
|
||||
* space provided by devices formatted with integrity protection. The
|
||||
* size of the integrity buffer must be <= to the size reported by
|
||||
* bio_integrity_tag_size().
|
||||
*/
|
||||
int bio_integrity_set_tag(struct bio *bio, void *tag_buf, unsigned int len)
|
||||
{
|
||||
BUG_ON(bio_data_dir(bio) != WRITE);
|
||||
|
||||
return bio_integrity_tag(bio, tag_buf, len, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(bio_integrity_set_tag);
|
||||
|
||||
/**
|
||||
* bio_integrity_get_tag - Retrieve a tag buffer from a bio
|
||||
* @bio: bio to retrieve buffer from
|
||||
* @tag_buf: Pointer to a buffer for the tag data
|
||||
* @len: Length of the target buffer
|
||||
*
|
||||
* Description: Use this function to retrieve the tag buffer from a
|
||||
* completed I/O. The size of the integrity buffer must be <= to the
|
||||
* size reported by bio_integrity_tag_size().
|
||||
*/
|
||||
int bio_integrity_get_tag(struct bio *bio, void *tag_buf, unsigned int len)
|
||||
{
|
||||
BUG_ON(bio_data_dir(bio) != READ);
|
||||
|
||||
return bio_integrity_tag(bio, tag_buf, len, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(bio_integrity_get_tag);
|
||||
|
||||
/**
|
||||
* bio_integrity_generate_verify - Generate/verify integrity metadata for a bio
|
||||
* bio_integrity_process - Process integrity metadata for a bio
|
||||
* @bio: bio to generate/verify integrity metadata for
|
||||
* @operate: operate number, 1 for generate, 0 for verify
|
||||
* @proc_fn: Pointer to the relevant processing function
|
||||
*/
|
||||
static int bio_integrity_generate_verify(struct bio *bio, int operate)
|
||||
static int bio_integrity_process(struct bio *bio,
|
||||
integrity_processing_fn *proc_fn)
|
||||
{
|
||||
struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
|
||||
struct blk_integrity_exchg bix;
|
||||
struct blk_integrity_iter iter;
|
||||
struct bio_vec *bv;
|
||||
sector_t sector;
|
||||
unsigned int sectors, ret = 0, i;
|
||||
void *prot_buf = bio->bi_integrity->bip_buf;
|
||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||
unsigned int i, ret = 0;
|
||||
void *prot_buf = page_address(bip->bip_vec->bv_page) +
|
||||
bip->bip_vec->bv_offset;
|
||||
|
||||
if (operate)
|
||||
sector = bio->bi_iter.bi_sector;
|
||||
else
|
||||
sector = bio->bi_integrity->bip_iter.bi_sector;
|
||||
|
||||
bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
|
||||
bix.sector_size = bi->sector_size;
|
||||
iter.disk_name = bio->bi_bdev->bd_disk->disk_name;
|
||||
iter.interval = bi->interval;
|
||||
iter.seed = bip_get_seed(bip);
|
||||
iter.prot_buf = prot_buf;
|
||||
|
||||
bio_for_each_segment_all(bv, bio, i) {
|
||||
void *kaddr = kmap_atomic(bv->bv_page);
|
||||
bix.data_buf = kaddr + bv->bv_offset;
|
||||
bix.data_size = bv->bv_len;
|
||||
bix.prot_buf = prot_buf;
|
||||
bix.sector = sector;
|
||||
|
||||
if (operate)
|
||||
bi->generate_fn(&bix);
|
||||
else {
|
||||
ret = bi->verify_fn(&bix);
|
||||
if (ret) {
|
||||
kunmap_atomic(kaddr);
|
||||
return ret;
|
||||
}
|
||||
iter.data_buf = kaddr + bv->bv_offset;
|
||||
iter.data_size = bv->bv_len;
|
||||
|
||||
ret = proc_fn(&iter);
|
||||
if (ret) {
|
||||
kunmap_atomic(kaddr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sectors = bv->bv_len / bi->sector_size;
|
||||
sector += sectors;
|
||||
prot_buf += sectors * bi->tuple_size;
|
||||
|
||||
kunmap_atomic(kaddr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* bio_integrity_generate - Generate integrity metadata for a bio
|
||||
* @bio: bio to generate integrity metadata for
|
||||
*
|
||||
* Description: Generates integrity metadata for a bio by calling the
|
||||
* block device's generation callback function. The bio must have a
|
||||
* bip attached with enough room to accommodate the generated
|
||||
* integrity metadata.
|
||||
*/
|
||||
static void bio_integrity_generate(struct bio *bio)
|
||||
{
|
||||
bio_integrity_generate_verify(bio, 1);
|
||||
}
|
||||
|
||||
static inline unsigned short blk_integrity_tuple_size(struct blk_integrity *bi)
|
||||
{
|
||||
if (bi)
|
||||
return bi->tuple_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* bio_integrity_prep - Prepare bio for integrity I/O
|
||||
* @bio: bio to prepare
|
||||
@@ -387,17 +264,17 @@ int bio_integrity_prep(struct bio *bio)
|
||||
unsigned long start, end;
|
||||
unsigned int len, nr_pages;
|
||||
unsigned int bytes, offset, i;
|
||||
unsigned int sectors;
|
||||
unsigned int intervals;
|
||||
|
||||
bi = bdev_get_integrity(bio->bi_bdev);
|
||||
q = bdev_get_queue(bio->bi_bdev);
|
||||
BUG_ON(bi == NULL);
|
||||
BUG_ON(bio_integrity(bio));
|
||||
|
||||
sectors = bio_integrity_hw_sectors(bi, bio_sectors(bio));
|
||||
intervals = bio_integrity_intervals(bi, bio_sectors(bio));
|
||||
|
||||
/* Allocate kernel buffer for protection data */
|
||||
len = sectors * blk_integrity_tuple_size(bi);
|
||||
len = intervals * bi->tuple_size;
|
||||
buf = kmalloc(len, GFP_NOIO | q->bounce_gfp);
|
||||
if (unlikely(buf == NULL)) {
|
||||
printk(KERN_ERR "could not allocate integrity buffer\n");
|
||||
@@ -416,10 +293,12 @@ int bio_integrity_prep(struct bio *bio)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
bip->bip_owns_buf = 1;
|
||||
bip->bip_buf = buf;
|
||||
bip->bip_flags |= BIP_BLOCK_INTEGRITY;
|
||||
bip->bip_iter.bi_size = len;
|
||||
bip->bip_iter.bi_sector = bio->bi_iter.bi_sector;
|
||||
bip_set_seed(bip, bio->bi_iter.bi_sector);
|
||||
|
||||
if (bi->flags & BLK_INTEGRITY_IP_CHECKSUM)
|
||||
bip->bip_flags |= BIP_IP_CHECKSUM;
|
||||
|
||||
/* Map it */
|
||||
offset = offset_in_page(buf);
|
||||
@@ -455,25 +334,12 @@ int bio_integrity_prep(struct bio *bio)
|
||||
|
||||
/* Auto-generate integrity metadata if this is a write */
|
||||
if (bio_data_dir(bio) == WRITE)
|
||||
bio_integrity_generate(bio);
|
||||
bio_integrity_process(bio, bi->generate_fn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(bio_integrity_prep);
|
||||
|
||||
/**
|
||||
* bio_integrity_verify - Verify integrity metadata for a bio
|
||||
* @bio: bio to verify
|
||||
*
|
||||
* Description: This function is called to verify the integrity of a
|
||||
* bio. The data in the bio io_vec is compared to the integrity
|
||||
* metadata returned by the HBA.
|
||||
*/
|
||||
static int bio_integrity_verify(struct bio *bio)
|
||||
{
|
||||
return bio_integrity_generate_verify(bio, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* bio_integrity_verify_fn - Integrity I/O completion worker
|
||||
* @work: Work struct stored in bio to be verified
|
||||
@@ -487,9 +353,10 @@ static void bio_integrity_verify_fn(struct work_struct *work)
|
||||
struct bio_integrity_payload *bip =
|
||||
container_of(work, struct bio_integrity_payload, bip_work);
|
||||
struct bio *bio = bip->bip_bio;
|
||||
struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
|
||||
int error;
|
||||
|
||||
error = bio_integrity_verify(bio);
|
||||
error = bio_integrity_process(bio, bi->verify_fn);
|
||||
|
||||
/* Restore original bio completion handler */
|
||||
bio->bi_end_io = bip->bip_end_io;
|
||||
@@ -510,7 +377,7 @@ static void bio_integrity_verify_fn(struct work_struct *work)
|
||||
*/
|
||||
void bio_integrity_endio(struct bio *bio, int error)
|
||||
{
|
||||
struct bio_integrity_payload *bip = bio->bi_integrity;
|
||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||
|
||||
BUG_ON(bip->bip_bio != bio);
|
||||
|
||||
@@ -541,7 +408,7 @@ EXPORT_SYMBOL(bio_integrity_endio);
|
||||
*/
|
||||
void bio_integrity_advance(struct bio *bio, unsigned int bytes_done)
|
||||
{
|
||||
struct bio_integrity_payload *bip = bio->bi_integrity;
|
||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||
struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
|
||||
unsigned bytes = bio_integrity_bytes(bi, bytes_done >> 9);
|
||||
|
||||
@@ -563,7 +430,7 @@ EXPORT_SYMBOL(bio_integrity_advance);
|
||||
void bio_integrity_trim(struct bio *bio, unsigned int offset,
|
||||
unsigned int sectors)
|
||||
{
|
||||
struct bio_integrity_payload *bip = bio->bi_integrity;
|
||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||
struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
|
||||
|
||||
bio_integrity_advance(bio, offset << 9);
|
||||
@@ -582,7 +449,7 @@ EXPORT_SYMBOL(bio_integrity_trim);
|
||||
int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
struct bio_integrity_payload *bip_src = bio_src->bi_integrity;
|
||||
struct bio_integrity_payload *bip_src = bio_integrity(bio_src);
|
||||
struct bio_integrity_payload *bip;
|
||||
|
||||
BUG_ON(bip_src == NULL);
|
||||
@@ -646,6 +513,4 @@ void __init bio_integrity_init(void)
|
||||
sizeof(struct bio_integrity_payload) +
|
||||
sizeof(struct bio_vec) * BIP_INLINE_VECS,
|
||||
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
|
||||
if (!bip_slab)
|
||||
panic("Failed to create slab\n");
|
||||
}
|
||||
|
||||
+44
-17
@@ -428,6 +428,9 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
|
||||
front_pad = 0;
|
||||
inline_vecs = nr_iovecs;
|
||||
} else {
|
||||
/* should not use nobvec bioset for nr_iovecs > 0 */
|
||||
if (WARN_ON_ONCE(!bs->bvec_pool && nr_iovecs > 0))
|
||||
return NULL;
|
||||
/*
|
||||
* generic_make_request() converts recursion to iteration; this
|
||||
* means if we're running beneath it, any bios we allocate and
|
||||
@@ -1900,20 +1903,9 @@ void bioset_free(struct bio_set *bs)
|
||||
}
|
||||
EXPORT_SYMBOL(bioset_free);
|
||||
|
||||
/**
|
||||
* bioset_create - Create a bio_set
|
||||
* @pool_size: Number of bio and bio_vecs to cache in the mempool
|
||||
* @front_pad: Number of bytes to allocate in front of the returned bio
|
||||
*
|
||||
* Description:
|
||||
* Set up a bio_set to be used with @bio_alloc_bioset. Allows the caller
|
||||
* to ask for a number of bytes to be allocated in front of the bio.
|
||||
* Front pad allocation is useful for embedding the bio inside
|
||||
* another structure, to avoid allocating extra data to go with the bio.
|
||||
* Note that the bio must be embedded at the END of that structure always,
|
||||
* or things will break badly.
|
||||
*/
|
||||
struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad)
|
||||
static struct bio_set *__bioset_create(unsigned int pool_size,
|
||||
unsigned int front_pad,
|
||||
bool create_bvec_pool)
|
||||
{
|
||||
unsigned int back_pad = BIO_INLINE_VECS * sizeof(struct bio_vec);
|
||||
struct bio_set *bs;
|
||||
@@ -1938,9 +1930,11 @@ struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad)
|
||||
if (!bs->bio_pool)
|
||||
goto bad;
|
||||
|
||||
bs->bvec_pool = biovec_create_pool(pool_size);
|
||||
if (!bs->bvec_pool)
|
||||
goto bad;
|
||||
if (create_bvec_pool) {
|
||||
bs->bvec_pool = biovec_create_pool(pool_size);
|
||||
if (!bs->bvec_pool)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
bs->rescue_workqueue = alloc_workqueue("bioset", WQ_MEM_RECLAIM, 0);
|
||||
if (!bs->rescue_workqueue)
|
||||
@@ -1951,8 +1945,41 @@ bad:
|
||||
bioset_free(bs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* bioset_create - Create a bio_set
|
||||
* @pool_size: Number of bio and bio_vecs to cache in the mempool
|
||||
* @front_pad: Number of bytes to allocate in front of the returned bio
|
||||
*
|
||||
* Description:
|
||||
* Set up a bio_set to be used with @bio_alloc_bioset. Allows the caller
|
||||
* to ask for a number of bytes to be allocated in front of the bio.
|
||||
* Front pad allocation is useful for embedding the bio inside
|
||||
* another structure, to avoid allocating extra data to go with the bio.
|
||||
* Note that the bio must be embedded at the END of that structure always,
|
||||
* or things will break badly.
|
||||
*/
|
||||
struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad)
|
||||
{
|
||||
return __bioset_create(pool_size, front_pad, true);
|
||||
}
|
||||
EXPORT_SYMBOL(bioset_create);
|
||||
|
||||
/**
|
||||
* bioset_create_nobvec - Create a bio_set without bio_vec mempool
|
||||
* @pool_size: Number of bio to cache in the mempool
|
||||
* @front_pad: Number of bytes to allocate in front of the returned bio
|
||||
*
|
||||
* Description:
|
||||
* Same functionality as bioset_create() except that mempool is not
|
||||
* created for bio_vecs. Saving some memory for bio_clone_fast() users.
|
||||
*/
|
||||
struct bio_set *bioset_create_nobvec(unsigned int pool_size, unsigned int front_pad)
|
||||
{
|
||||
return __bioset_create(pool_size, front_pad, false);
|
||||
}
|
||||
EXPORT_SYMBOL(bioset_create_nobvec);
|
||||
|
||||
#ifdef CONFIG_BLK_CGROUP
|
||||
/**
|
||||
* bio_associate_current - associate a bio with %current
|
||||
|
||||
@@ -822,7 +822,6 @@ static void blkcg_css_free(struct cgroup_subsys_state *css)
|
||||
static struct cgroup_subsys_state *
|
||||
blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
|
||||
{
|
||||
static atomic64_t id_seq = ATOMIC64_INIT(0);
|
||||
struct blkcg *blkcg;
|
||||
|
||||
if (!parent_css) {
|
||||
@@ -836,7 +835,6 @@ blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
|
||||
|
||||
blkcg->cfq_weight = CFQ_WEIGHT_DEFAULT;
|
||||
blkcg->cfq_leaf_weight = CFQ_WEIGHT_DEFAULT;
|
||||
blkcg->id = atomic64_inc_return(&id_seq); /* root is 0, start from 1 */
|
||||
done:
|
||||
spin_lock_init(&blkcg->lock);
|
||||
INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_ATOMIC);
|
||||
|
||||
@@ -50,9 +50,6 @@ struct blkcg {
|
||||
struct blkcg_gq *blkg_hint;
|
||||
struct hlist_head blkg_list;
|
||||
|
||||
/* for policies to test whether associated blkcg has changed */
|
||||
uint64_t id;
|
||||
|
||||
/* TODO: per-policy storage in blkcg */
|
||||
unsigned int cfq_weight; /* belongs to cfq */
|
||||
unsigned int cfq_leaf_weight;
|
||||
|
||||
+31
-36
@@ -83,18 +83,14 @@ void blk_queue_congestion_threshold(struct request_queue *q)
|
||||
* @bdev: device
|
||||
*
|
||||
* Locates the passed device's request queue and returns the address of its
|
||||
* backing_dev_info
|
||||
*
|
||||
* Will return NULL if the request queue cannot be located.
|
||||
* backing_dev_info. This function can only be called if @bdev is opened
|
||||
* and the return value is never NULL.
|
||||
*/
|
||||
struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
|
||||
{
|
||||
struct backing_dev_info *ret = NULL;
|
||||
struct request_queue *q = bdev_get_queue(bdev);
|
||||
|
||||
if (q)
|
||||
ret = &q->backing_dev_info;
|
||||
return ret;
|
||||
return &q->backing_dev_info;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_get_backing_dev_info);
|
||||
|
||||
@@ -394,11 +390,13 @@ static void __blk_drain_queue(struct request_queue *q, bool drain_all)
|
||||
* be drained. Check all the queues and counters.
|
||||
*/
|
||||
if (drain_all) {
|
||||
struct blk_flush_queue *fq = blk_get_flush_queue(q, NULL);
|
||||
drain |= !list_empty(&q->queue_head);
|
||||
for (i = 0; i < 2; i++) {
|
||||
drain |= q->nr_rqs[i];
|
||||
drain |= q->in_flight[i];
|
||||
drain |= !list_empty(&q->flush_queue[i]);
|
||||
if (fq)
|
||||
drain |= !list_empty(&fq->flush_queue[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,9 +602,6 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
|
||||
#ifdef CONFIG_BLK_CGROUP
|
||||
INIT_LIST_HEAD(&q->blkg_list);
|
||||
#endif
|
||||
INIT_LIST_HEAD(&q->flush_queue[0]);
|
||||
INIT_LIST_HEAD(&q->flush_queue[1]);
|
||||
INIT_LIST_HEAD(&q->flush_data_in_flight);
|
||||
INIT_DELAYED_WORK(&q->delay_work, blk_delay_work);
|
||||
|
||||
kobject_init(&q->kobj, &blk_queue_ktype);
|
||||
@@ -709,8 +704,8 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
|
||||
if (!q)
|
||||
return NULL;
|
||||
|
||||
q->flush_rq = kzalloc(sizeof(struct request), GFP_KERNEL);
|
||||
if (!q->flush_rq)
|
||||
q->fq = blk_alloc_flush_queue(q, NUMA_NO_NODE, 0);
|
||||
if (!q->fq)
|
||||
return NULL;
|
||||
|
||||
if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
|
||||
@@ -746,7 +741,7 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
|
||||
return q;
|
||||
|
||||
fail:
|
||||
kfree(q->flush_rq);
|
||||
blk_free_flush_queue(q->fq);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_init_allocated_queue);
|
||||
@@ -934,8 +929,8 @@ static struct io_context *rq_ioc(struct bio *bio)
|
||||
* pressure or if @q is dead.
|
||||
*
|
||||
* Must be called with @q->queue_lock held and,
|
||||
* Returns %NULL on failure, with @q->queue_lock held.
|
||||
* Returns !%NULL on success, with @q->queue_lock *not held*.
|
||||
* Returns ERR_PTR on failure, with @q->queue_lock held.
|
||||
* Returns request pointer on success, with @q->queue_lock *not held*.
|
||||
*/
|
||||
static struct request *__get_request(struct request_list *rl, int rw_flags,
|
||||
struct bio *bio, gfp_t gfp_mask)
|
||||
@@ -949,7 +944,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
|
||||
int may_queue;
|
||||
|
||||
if (unlikely(blk_queue_dying(q)))
|
||||
return NULL;
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
may_queue = elv_may_queue(q, rw_flags);
|
||||
if (may_queue == ELV_MQUEUE_NO)
|
||||
@@ -974,7 +969,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
|
||||
* process is not a "batcher", and not
|
||||
* exempted by the IO scheduler
|
||||
*/
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -992,7 +987,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
|
||||
* allocated with any setting of ->nr_requests
|
||||
*/
|
||||
if (rl->count[is_sync] >= (3 * q->nr_requests / 2))
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
q->nr_rqs[is_sync]++;
|
||||
rl->count[is_sync]++;
|
||||
@@ -1065,8 +1060,8 @@ fail_elvpriv:
|
||||
* shouldn't stall IO. Treat this request as !elvpriv. This will
|
||||
* disturb iosched and blkcg but weird is bettern than dead.
|
||||
*/
|
||||
printk_ratelimited(KERN_WARNING "%s: request aux data allocation failed, iosched may be disturbed\n",
|
||||
dev_name(q->backing_dev_info.dev));
|
||||
printk_ratelimited(KERN_WARNING "%s: dev %s: request aux data allocation failed, iosched may be disturbed\n",
|
||||
__func__, dev_name(q->backing_dev_info.dev));
|
||||
|
||||
rq->cmd_flags &= ~REQ_ELVPRIV;
|
||||
rq->elv.icq = NULL;
|
||||
@@ -1097,7 +1092,7 @@ fail_alloc:
|
||||
rq_starved:
|
||||
if (unlikely(rl->count[is_sync] == 0))
|
||||
rl->starved[is_sync] = 1;
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1111,8 +1106,8 @@ rq_starved:
|
||||
* function keeps retrying under memory pressure and fails iff @q is dead.
|
||||
*
|
||||
* Must be called with @q->queue_lock held and,
|
||||
* Returns %NULL on failure, with @q->queue_lock held.
|
||||
* Returns !%NULL on success, with @q->queue_lock *not held*.
|
||||
* Returns ERR_PTR on failure, with @q->queue_lock held.
|
||||
* Returns request pointer on success, with @q->queue_lock *not held*.
|
||||
*/
|
||||
static struct request *get_request(struct request_queue *q, int rw_flags,
|
||||
struct bio *bio, gfp_t gfp_mask)
|
||||
@@ -1125,12 +1120,12 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
|
||||
rl = blk_get_rl(q, bio); /* transferred to @rq on success */
|
||||
retry:
|
||||
rq = __get_request(rl, rw_flags, bio, gfp_mask);
|
||||
if (rq)
|
||||
if (!IS_ERR(rq))
|
||||
return rq;
|
||||
|
||||
if (!(gfp_mask & __GFP_WAIT) || unlikely(blk_queue_dying(q))) {
|
||||
blk_put_rl(rl);
|
||||
return NULL;
|
||||
return rq;
|
||||
}
|
||||
|
||||
/* wait on @rl and retry */
|
||||
@@ -1167,7 +1162,7 @@ static struct request *blk_old_get_request(struct request_queue *q, int rw,
|
||||
|
||||
spin_lock_irq(q->queue_lock);
|
||||
rq = get_request(q, rw, NULL, gfp_mask);
|
||||
if (!rq)
|
||||
if (IS_ERR(rq))
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
/* q->queue_lock is unlocked at this point */
|
||||
|
||||
@@ -1219,8 +1214,8 @@ struct request *blk_make_request(struct request_queue *q, struct bio *bio,
|
||||
{
|
||||
struct request *rq = blk_get_request(q, bio_data_dir(bio), gfp_mask);
|
||||
|
||||
if (unlikely(!rq))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (IS_ERR(rq))
|
||||
return rq;
|
||||
|
||||
blk_rq_set_block_pc(rq);
|
||||
|
||||
@@ -1614,8 +1609,8 @@ get_rq:
|
||||
* Returns with the queue unlocked.
|
||||
*/
|
||||
req = get_request(q, rw_flags, bio, GFP_NOIO);
|
||||
if (unlikely(!req)) {
|
||||
bio_endio(bio, -ENODEV); /* @q is dead */
|
||||
if (IS_ERR(req)) {
|
||||
bio_endio(bio, PTR_ERR(req)); /* @q is dead */
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
@@ -2405,11 +2400,11 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
|
||||
{
|
||||
int total_bytes;
|
||||
|
||||
trace_block_rq_complete(req->q, req, nr_bytes);
|
||||
|
||||
if (!req->bio)
|
||||
return false;
|
||||
|
||||
trace_block_rq_complete(req->q, req, nr_bytes);
|
||||
|
||||
/*
|
||||
* For fs requests, rq is just carrier of independent bio's
|
||||
* and each partial completion should be handled separately.
|
||||
@@ -2449,8 +2444,8 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
|
||||
error_type = "I/O";
|
||||
break;
|
||||
}
|
||||
printk_ratelimited(KERN_ERR "end_request: %s error, dev %s, sector %llu\n",
|
||||
error_type, req->rq_disk ?
|
||||
printk_ratelimited(KERN_ERR "%s: %s error, dev %s, sector %llu\n",
|
||||
__func__, error_type, req->rq_disk ?
|
||||
req->rq_disk->disk_name : "?",
|
||||
(unsigned long long)blk_rq_pos(req));
|
||||
|
||||
@@ -2931,7 +2926,7 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
|
||||
blk_rq_init(NULL, rq);
|
||||
|
||||
__rq_for_each_bio(bio_src, rq_src) {
|
||||
bio = bio_clone_bioset(bio_src, gfp_mask, bs);
|
||||
bio = bio_clone_fast(bio_src, gfp_mask, bs);
|
||||
if (!bio)
|
||||
goto free_and_out;
|
||||
|
||||
|
||||
+98
-49
@@ -28,7 +28,7 @@
|
||||
*
|
||||
* The actual execution of flush is double buffered. Whenever a request
|
||||
* needs to execute PRE or POSTFLUSH, it queues at
|
||||
* q->flush_queue[q->flush_pending_idx]. Once certain criteria are met, a
|
||||
* fq->flush_queue[fq->flush_pending_idx]. Once certain criteria are met, a
|
||||
* flush is issued and the pending_idx is toggled. When the flush
|
||||
* completes, all the requests which were pending are proceeded to the next
|
||||
* step. This allows arbitrary merging of different types of FLUSH/FUA
|
||||
@@ -91,7 +91,8 @@ enum {
|
||||
FLUSH_PENDING_TIMEOUT = 5 * HZ,
|
||||
};
|
||||
|
||||
static bool blk_kick_flush(struct request_queue *q);
|
||||
static bool blk_kick_flush(struct request_queue *q,
|
||||
struct blk_flush_queue *fq);
|
||||
|
||||
static unsigned int blk_flush_policy(unsigned int fflags, struct request *rq)
|
||||
{
|
||||
@@ -126,8 +127,6 @@ static void blk_flush_restore_request(struct request *rq)
|
||||
/* make @rq a normal request */
|
||||
rq->cmd_flags &= ~REQ_FLUSH_SEQ;
|
||||
rq->end_io = rq->flush.saved_end_io;
|
||||
|
||||
blk_clear_rq_complete(rq);
|
||||
}
|
||||
|
||||
static bool blk_flush_queue_rq(struct request *rq, bool add_front)
|
||||
@@ -150,6 +149,7 @@ static bool blk_flush_queue_rq(struct request *rq, bool add_front)
|
||||
/**
|
||||
* blk_flush_complete_seq - complete flush sequence
|
||||
* @rq: FLUSH/FUA request being sequenced
|
||||
* @fq: flush queue
|
||||
* @seq: sequences to complete (mask of %REQ_FSEQ_*, can be zero)
|
||||
* @error: whether an error occurred
|
||||
*
|
||||
@@ -157,16 +157,17 @@ static bool blk_flush_queue_rq(struct request *rq, bool add_front)
|
||||
* completion and trigger the next step.
|
||||
*
|
||||
* CONTEXT:
|
||||
* spin_lock_irq(q->queue_lock or q->mq_flush_lock)
|
||||
* spin_lock_irq(q->queue_lock or fq->mq_flush_lock)
|
||||
*
|
||||
* RETURNS:
|
||||
* %true if requests were added to the dispatch queue, %false otherwise.
|
||||
*/
|
||||
static bool blk_flush_complete_seq(struct request *rq, unsigned int seq,
|
||||
int error)
|
||||
static bool blk_flush_complete_seq(struct request *rq,
|
||||
struct blk_flush_queue *fq,
|
||||
unsigned int seq, int error)
|
||||
{
|
||||
struct request_queue *q = rq->q;
|
||||
struct list_head *pending = &q->flush_queue[q->flush_pending_idx];
|
||||
struct list_head *pending = &fq->flush_queue[fq->flush_pending_idx];
|
||||
bool queued = false, kicked;
|
||||
|
||||
BUG_ON(rq->flush.seq & seq);
|
||||
@@ -182,12 +183,12 @@ static bool blk_flush_complete_seq(struct request *rq, unsigned int seq,
|
||||
case REQ_FSEQ_POSTFLUSH:
|
||||
/* queue for flush */
|
||||
if (list_empty(pending))
|
||||
q->flush_pending_since = jiffies;
|
||||
fq->flush_pending_since = jiffies;
|
||||
list_move_tail(&rq->flush.list, pending);
|
||||
break;
|
||||
|
||||
case REQ_FSEQ_DATA:
|
||||
list_move_tail(&rq->flush.list, &q->flush_data_in_flight);
|
||||
list_move_tail(&rq->flush.list, &fq->flush_data_in_flight);
|
||||
queued = blk_flush_queue_rq(rq, true);
|
||||
break;
|
||||
|
||||
@@ -202,7 +203,7 @@ static bool blk_flush_complete_seq(struct request *rq, unsigned int seq,
|
||||
list_del_init(&rq->flush.list);
|
||||
blk_flush_restore_request(rq);
|
||||
if (q->mq_ops)
|
||||
blk_mq_end_io(rq, error);
|
||||
blk_mq_end_request(rq, error);
|
||||
else
|
||||
__blk_end_request_all(rq, error);
|
||||
break;
|
||||
@@ -211,7 +212,7 @@ static bool blk_flush_complete_seq(struct request *rq, unsigned int seq,
|
||||
BUG();
|
||||
}
|
||||
|
||||
kicked = blk_kick_flush(q);
|
||||
kicked = blk_kick_flush(q, fq);
|
||||
return kicked | queued;
|
||||
}
|
||||
|
||||
@@ -222,17 +223,18 @@ static void flush_end_io(struct request *flush_rq, int error)
|
||||
bool queued = false;
|
||||
struct request *rq, *n;
|
||||
unsigned long flags = 0;
|
||||
struct blk_flush_queue *fq = blk_get_flush_queue(q, flush_rq->mq_ctx);
|
||||
|
||||
if (q->mq_ops) {
|
||||
spin_lock_irqsave(&q->mq_flush_lock, flags);
|
||||
q->flush_rq->tag = -1;
|
||||
spin_lock_irqsave(&fq->mq_flush_lock, flags);
|
||||
flush_rq->tag = -1;
|
||||
}
|
||||
|
||||
running = &q->flush_queue[q->flush_running_idx];
|
||||
BUG_ON(q->flush_pending_idx == q->flush_running_idx);
|
||||
running = &fq->flush_queue[fq->flush_running_idx];
|
||||
BUG_ON(fq->flush_pending_idx == fq->flush_running_idx);
|
||||
|
||||
/* account completion of the flush request */
|
||||
q->flush_running_idx ^= 1;
|
||||
fq->flush_running_idx ^= 1;
|
||||
|
||||
if (!q->mq_ops)
|
||||
elv_completed_request(q, flush_rq);
|
||||
@@ -242,7 +244,7 @@ static void flush_end_io(struct request *flush_rq, int error)
|
||||
unsigned int seq = blk_flush_cur_seq(rq);
|
||||
|
||||
BUG_ON(seq != REQ_FSEQ_PREFLUSH && seq != REQ_FSEQ_POSTFLUSH);
|
||||
queued |= blk_flush_complete_seq(rq, seq, error);
|
||||
queued |= blk_flush_complete_seq(rq, fq, seq, error);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -256,71 +258,81 @@ static void flush_end_io(struct request *flush_rq, int error)
|
||||
* directly into request_fn may confuse the driver. Always use
|
||||
* kblockd.
|
||||
*/
|
||||
if (queued || q->flush_queue_delayed) {
|
||||
if (queued || fq->flush_queue_delayed) {
|
||||
WARN_ON(q->mq_ops);
|
||||
blk_run_queue_async(q);
|
||||
}
|
||||
q->flush_queue_delayed = 0;
|
||||
fq->flush_queue_delayed = 0;
|
||||
if (q->mq_ops)
|
||||
spin_unlock_irqrestore(&q->mq_flush_lock, flags);
|
||||
spin_unlock_irqrestore(&fq->mq_flush_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* blk_kick_flush - consider issuing flush request
|
||||
* @q: request_queue being kicked
|
||||
* @fq: flush queue
|
||||
*
|
||||
* Flush related states of @q have changed, consider issuing flush request.
|
||||
* Please read the comment at the top of this file for more info.
|
||||
*
|
||||
* CONTEXT:
|
||||
* spin_lock_irq(q->queue_lock or q->mq_flush_lock)
|
||||
* spin_lock_irq(q->queue_lock or fq->mq_flush_lock)
|
||||
*
|
||||
* RETURNS:
|
||||
* %true if flush was issued, %false otherwise.
|
||||
*/
|
||||
static bool blk_kick_flush(struct request_queue *q)
|
||||
static bool blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq)
|
||||
{
|
||||
struct list_head *pending = &q->flush_queue[q->flush_pending_idx];
|
||||
struct list_head *pending = &fq->flush_queue[fq->flush_pending_idx];
|
||||
struct request *first_rq =
|
||||
list_first_entry(pending, struct request, flush.list);
|
||||
struct request *flush_rq = fq->flush_rq;
|
||||
|
||||
/* C1 described at the top of this file */
|
||||
if (q->flush_pending_idx != q->flush_running_idx || list_empty(pending))
|
||||
if (fq->flush_pending_idx != fq->flush_running_idx || list_empty(pending))
|
||||
return false;
|
||||
|
||||
/* C2 and C3 */
|
||||
if (!list_empty(&q->flush_data_in_flight) &&
|
||||
if (!list_empty(&fq->flush_data_in_flight) &&
|
||||
time_before(jiffies,
|
||||
q->flush_pending_since + FLUSH_PENDING_TIMEOUT))
|
||||
fq->flush_pending_since + FLUSH_PENDING_TIMEOUT))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Issue flush and toggle pending_idx. This makes pending_idx
|
||||
* different from running_idx, which means flush is in flight.
|
||||
*/
|
||||
q->flush_pending_idx ^= 1;
|
||||
fq->flush_pending_idx ^= 1;
|
||||
|
||||
blk_rq_init(q, q->flush_rq);
|
||||
if (q->mq_ops)
|
||||
blk_mq_clone_flush_request(q->flush_rq, first_rq);
|
||||
blk_rq_init(q, flush_rq);
|
||||
|
||||
q->flush_rq->cmd_type = REQ_TYPE_FS;
|
||||
q->flush_rq->cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ;
|
||||
q->flush_rq->rq_disk = first_rq->rq_disk;
|
||||
q->flush_rq->end_io = flush_end_io;
|
||||
/*
|
||||
* Borrow tag from the first request since they can't
|
||||
* be in flight at the same time.
|
||||
*/
|
||||
if (q->mq_ops) {
|
||||
flush_rq->mq_ctx = first_rq->mq_ctx;
|
||||
flush_rq->tag = first_rq->tag;
|
||||
}
|
||||
|
||||
return blk_flush_queue_rq(q->flush_rq, false);
|
||||
flush_rq->cmd_type = REQ_TYPE_FS;
|
||||
flush_rq->cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ;
|
||||
flush_rq->rq_disk = first_rq->rq_disk;
|
||||
flush_rq->end_io = flush_end_io;
|
||||
|
||||
return blk_flush_queue_rq(flush_rq, false);
|
||||
}
|
||||
|
||||
static void flush_data_end_io(struct request *rq, int error)
|
||||
{
|
||||
struct request_queue *q = rq->q;
|
||||
struct blk_flush_queue *fq = blk_get_flush_queue(q, NULL);
|
||||
|
||||
/*
|
||||
* After populating an empty queue, kick it to avoid stall. Read
|
||||
* the comment in flush_end_io().
|
||||
*/
|
||||
if (blk_flush_complete_seq(rq, REQ_FSEQ_DATA, error))
|
||||
if (blk_flush_complete_seq(rq, fq, REQ_FSEQ_DATA, error))
|
||||
blk_run_queue_async(q);
|
||||
}
|
||||
|
||||
@@ -328,20 +340,20 @@ static void mq_flush_data_end_io(struct request *rq, int error)
|
||||
{
|
||||
struct request_queue *q = rq->q;
|
||||
struct blk_mq_hw_ctx *hctx;
|
||||
struct blk_mq_ctx *ctx;
|
||||
struct blk_mq_ctx *ctx = rq->mq_ctx;
|
||||
unsigned long flags;
|
||||
struct blk_flush_queue *fq = blk_get_flush_queue(q, ctx);
|
||||
|
||||
ctx = rq->mq_ctx;
|
||||
hctx = q->mq_ops->map_queue(q, ctx->cpu);
|
||||
|
||||
/*
|
||||
* After populating an empty queue, kick it to avoid stall. Read
|
||||
* the comment in flush_end_io().
|
||||
*/
|
||||
spin_lock_irqsave(&q->mq_flush_lock, flags);
|
||||
if (blk_flush_complete_seq(rq, REQ_FSEQ_DATA, error))
|
||||
spin_lock_irqsave(&fq->mq_flush_lock, flags);
|
||||
if (blk_flush_complete_seq(rq, fq, REQ_FSEQ_DATA, error))
|
||||
blk_mq_run_hw_queue(hctx, true);
|
||||
spin_unlock_irqrestore(&q->mq_flush_lock, flags);
|
||||
spin_unlock_irqrestore(&fq->mq_flush_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -361,6 +373,7 @@ void blk_insert_flush(struct request *rq)
|
||||
struct request_queue *q = rq->q;
|
||||
unsigned int fflags = q->flush_flags; /* may change, cache */
|
||||
unsigned int policy = blk_flush_policy(fflags, rq);
|
||||
struct blk_flush_queue *fq = blk_get_flush_queue(q, rq->mq_ctx);
|
||||
|
||||
/*
|
||||
* @policy now records what operations need to be done. Adjust
|
||||
@@ -378,7 +391,7 @@ void blk_insert_flush(struct request *rq)
|
||||
*/
|
||||
if (!policy) {
|
||||
if (q->mq_ops)
|
||||
blk_mq_end_io(rq, 0);
|
||||
blk_mq_end_request(rq, 0);
|
||||
else
|
||||
__blk_end_bidi_request(rq, 0, 0, 0);
|
||||
return;
|
||||
@@ -411,14 +424,14 @@ void blk_insert_flush(struct request *rq)
|
||||
if (q->mq_ops) {
|
||||
rq->end_io = mq_flush_data_end_io;
|
||||
|
||||
spin_lock_irq(&q->mq_flush_lock);
|
||||
blk_flush_complete_seq(rq, REQ_FSEQ_ACTIONS & ~policy, 0);
|
||||
spin_unlock_irq(&q->mq_flush_lock);
|
||||
spin_lock_irq(&fq->mq_flush_lock);
|
||||
blk_flush_complete_seq(rq, fq, REQ_FSEQ_ACTIONS & ~policy, 0);
|
||||
spin_unlock_irq(&fq->mq_flush_lock);
|
||||
return;
|
||||
}
|
||||
rq->end_io = flush_data_end_io;
|
||||
|
||||
blk_flush_complete_seq(rq, REQ_FSEQ_ACTIONS & ~policy, 0);
|
||||
blk_flush_complete_seq(rq, fq, REQ_FSEQ_ACTIONS & ~policy, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -474,7 +487,43 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask,
|
||||
}
|
||||
EXPORT_SYMBOL(blkdev_issue_flush);
|
||||
|
||||
void blk_mq_init_flush(struct request_queue *q)
|
||||
struct blk_flush_queue *blk_alloc_flush_queue(struct request_queue *q,
|
||||
int node, int cmd_size)
|
||||
{
|
||||
spin_lock_init(&q->mq_flush_lock);
|
||||
struct blk_flush_queue *fq;
|
||||
int rq_sz = sizeof(struct request);
|
||||
|
||||
fq = kzalloc_node(sizeof(*fq), GFP_KERNEL, node);
|
||||
if (!fq)
|
||||
goto fail;
|
||||
|
||||
if (q->mq_ops) {
|
||||
spin_lock_init(&fq->mq_flush_lock);
|
||||
rq_sz = round_up(rq_sz + cmd_size, cache_line_size());
|
||||
}
|
||||
|
||||
fq->flush_rq = kzalloc_node(rq_sz, GFP_KERNEL, node);
|
||||
if (!fq->flush_rq)
|
||||
goto fail_rq;
|
||||
|
||||
INIT_LIST_HEAD(&fq->flush_queue[0]);
|
||||
INIT_LIST_HEAD(&fq->flush_queue[1]);
|
||||
INIT_LIST_HEAD(&fq->flush_data_in_flight);
|
||||
|
||||
return fq;
|
||||
|
||||
fail_rq:
|
||||
kfree(fq);
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void blk_free_flush_queue(struct blk_flush_queue *fq)
|
||||
{
|
||||
/* bio based request queue hasn't flush queue */
|
||||
if (!fq)
|
||||
return;
|
||||
|
||||
kfree(fq->flush_rq);
|
||||
kfree(fq);
|
||||
}
|
||||
|
||||
+65
-38
@@ -154,10 +154,10 @@ int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
|
||||
if (!b1 || !b2)
|
||||
return -1;
|
||||
|
||||
if (b1->sector_size != b2->sector_size) {
|
||||
printk(KERN_ERR "%s: %s/%s sector sz %u != %u\n", __func__,
|
||||
gd1->disk_name, gd2->disk_name,
|
||||
b1->sector_size, b2->sector_size);
|
||||
if (b1->interval != b2->interval) {
|
||||
pr_err("%s: %s/%s protection interval %u != %u\n",
|
||||
__func__, gd1->disk_name, gd2->disk_name,
|
||||
b1->interval, b2->interval);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -186,37 +186,53 @@ int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
|
||||
}
|
||||
EXPORT_SYMBOL(blk_integrity_compare);
|
||||
|
||||
int blk_integrity_merge_rq(struct request_queue *q, struct request *req,
|
||||
struct request *next)
|
||||
bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
|
||||
struct request *next)
|
||||
{
|
||||
if (blk_integrity_rq(req) != blk_integrity_rq(next))
|
||||
return -1;
|
||||
if (blk_integrity_rq(req) == 0 && blk_integrity_rq(next) == 0)
|
||||
return true;
|
||||
|
||||
if (blk_integrity_rq(req) == 0 || blk_integrity_rq(next) == 0)
|
||||
return false;
|
||||
|
||||
if (bio_integrity(req->bio)->bip_flags !=
|
||||
bio_integrity(next->bio)->bip_flags)
|
||||
return false;
|
||||
|
||||
if (req->nr_integrity_segments + next->nr_integrity_segments >
|
||||
q->limits.max_integrity_segments)
|
||||
return -1;
|
||||
return false;
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_integrity_merge_rq);
|
||||
|
||||
int blk_integrity_merge_bio(struct request_queue *q, struct request *req,
|
||||
struct bio *bio)
|
||||
bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
|
||||
struct bio *bio)
|
||||
{
|
||||
int nr_integrity_segs;
|
||||
struct bio *next = bio->bi_next;
|
||||
|
||||
if (blk_integrity_rq(req) == 0 && bio_integrity(bio) == NULL)
|
||||
return true;
|
||||
|
||||
if (blk_integrity_rq(req) == 0 || bio_integrity(bio) == NULL)
|
||||
return false;
|
||||
|
||||
if (bio_integrity(req->bio)->bip_flags != bio_integrity(bio)->bip_flags)
|
||||
return false;
|
||||
|
||||
bio->bi_next = NULL;
|
||||
nr_integrity_segs = blk_rq_count_integrity_sg(q, bio);
|
||||
bio->bi_next = next;
|
||||
|
||||
if (req->nr_integrity_segments + nr_integrity_segs >
|
||||
q->limits.max_integrity_segments)
|
||||
return -1;
|
||||
return false;
|
||||
|
||||
req->nr_integrity_segments += nr_integrity_segs;
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_integrity_merge_bio);
|
||||
|
||||
@@ -269,42 +285,48 @@ static ssize_t integrity_tag_size_show(struct blk_integrity *bi, char *page)
|
||||
return sprintf(page, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t integrity_read_store(struct blk_integrity *bi,
|
||||
const char *page, size_t count)
|
||||
static ssize_t integrity_verify_store(struct blk_integrity *bi,
|
||||
const char *page, size_t count)
|
||||
{
|
||||
char *p = (char *) page;
|
||||
unsigned long val = simple_strtoul(p, &p, 10);
|
||||
|
||||
if (val)
|
||||
bi->flags |= INTEGRITY_FLAG_READ;
|
||||
bi->flags |= BLK_INTEGRITY_VERIFY;
|
||||
else
|
||||
bi->flags &= ~INTEGRITY_FLAG_READ;
|
||||
bi->flags &= ~BLK_INTEGRITY_VERIFY;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t integrity_read_show(struct blk_integrity *bi, char *page)
|
||||
static ssize_t integrity_verify_show(struct blk_integrity *bi, char *page)
|
||||
{
|
||||
return sprintf(page, "%d\n", (bi->flags & INTEGRITY_FLAG_READ) != 0);
|
||||
return sprintf(page, "%d\n", (bi->flags & BLK_INTEGRITY_VERIFY) != 0);
|
||||
}
|
||||
|
||||
static ssize_t integrity_write_store(struct blk_integrity *bi,
|
||||
const char *page, size_t count)
|
||||
static ssize_t integrity_generate_store(struct blk_integrity *bi,
|
||||
const char *page, size_t count)
|
||||
{
|
||||
char *p = (char *) page;
|
||||
unsigned long val = simple_strtoul(p, &p, 10);
|
||||
|
||||
if (val)
|
||||
bi->flags |= INTEGRITY_FLAG_WRITE;
|
||||
bi->flags |= BLK_INTEGRITY_GENERATE;
|
||||
else
|
||||
bi->flags &= ~INTEGRITY_FLAG_WRITE;
|
||||
bi->flags &= ~BLK_INTEGRITY_GENERATE;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t integrity_write_show(struct blk_integrity *bi, char *page)
|
||||
static ssize_t integrity_generate_show(struct blk_integrity *bi, char *page)
|
||||
{
|
||||
return sprintf(page, "%d\n", (bi->flags & INTEGRITY_FLAG_WRITE) != 0);
|
||||
return sprintf(page, "%d\n", (bi->flags & BLK_INTEGRITY_GENERATE) != 0);
|
||||
}
|
||||
|
||||
static ssize_t integrity_device_show(struct blk_integrity *bi, char *page)
|
||||
{
|
||||
return sprintf(page, "%u\n",
|
||||
(bi->flags & BLK_INTEGRITY_DEVICE_CAPABLE) != 0);
|
||||
}
|
||||
|
||||
static struct integrity_sysfs_entry integrity_format_entry = {
|
||||
@@ -317,23 +339,29 @@ static struct integrity_sysfs_entry integrity_tag_size_entry = {
|
||||
.show = integrity_tag_size_show,
|
||||
};
|
||||
|
||||
static struct integrity_sysfs_entry integrity_read_entry = {
|
||||
static struct integrity_sysfs_entry integrity_verify_entry = {
|
||||
.attr = { .name = "read_verify", .mode = S_IRUGO | S_IWUSR },
|
||||
.show = integrity_read_show,
|
||||
.store = integrity_read_store,
|
||||
.show = integrity_verify_show,
|
||||
.store = integrity_verify_store,
|
||||
};
|
||||
|
||||
static struct integrity_sysfs_entry integrity_write_entry = {
|
||||
static struct integrity_sysfs_entry integrity_generate_entry = {
|
||||
.attr = { .name = "write_generate", .mode = S_IRUGO | S_IWUSR },
|
||||
.show = integrity_write_show,
|
||||
.store = integrity_write_store,
|
||||
.show = integrity_generate_show,
|
||||
.store = integrity_generate_store,
|
||||
};
|
||||
|
||||
static struct integrity_sysfs_entry integrity_device_entry = {
|
||||
.attr = { .name = "device_is_integrity_capable", .mode = S_IRUGO },
|
||||
.show = integrity_device_show,
|
||||
};
|
||||
|
||||
static struct attribute *integrity_attrs[] = {
|
||||
&integrity_format_entry.attr,
|
||||
&integrity_tag_size_entry.attr,
|
||||
&integrity_read_entry.attr,
|
||||
&integrity_write_entry.attr,
|
||||
&integrity_verify_entry.attr,
|
||||
&integrity_generate_entry.attr,
|
||||
&integrity_device_entry.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -406,8 +434,8 @@ int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
|
||||
|
||||
kobject_uevent(&bi->kobj, KOBJ_ADD);
|
||||
|
||||
bi->flags |= INTEGRITY_FLAG_READ | INTEGRITY_FLAG_WRITE;
|
||||
bi->sector_size = queue_logical_block_size(disk->queue);
|
||||
bi->flags |= BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE;
|
||||
bi->interval = queue_logical_block_size(disk->queue);
|
||||
disk->integrity = bi;
|
||||
} else
|
||||
bi = disk->integrity;
|
||||
@@ -418,9 +446,8 @@ int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
|
||||
bi->generate_fn = template->generate_fn;
|
||||
bi->verify_fn = template->verify_fn;
|
||||
bi->tuple_size = template->tuple_size;
|
||||
bi->set_tag_fn = template->set_tag_fn;
|
||||
bi->get_tag_fn = template->get_tag_fn;
|
||||
bi->tag_size = template->tag_size;
|
||||
bi->flags |= template->flags;
|
||||
} else
|
||||
bi->name = bi_unsupported_name;
|
||||
|
||||
|
||||
+9
-5
@@ -97,14 +97,18 @@ void blk_recalc_rq_segments(struct request *rq)
|
||||
|
||||
void blk_recount_segments(struct request_queue *q, struct bio *bio)
|
||||
{
|
||||
if (test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags) &&
|
||||
bool no_sg_merge = !!test_bit(QUEUE_FLAG_NO_SG_MERGE,
|
||||
&q->queue_flags);
|
||||
|
||||
if (no_sg_merge && !bio_flagged(bio, BIO_CLONED) &&
|
||||
bio->bi_vcnt < queue_max_segments(q))
|
||||
bio->bi_phys_segments = bio->bi_vcnt;
|
||||
else {
|
||||
struct bio *nxt = bio->bi_next;
|
||||
|
||||
bio->bi_next = NULL;
|
||||
bio->bi_phys_segments = __blk_recalc_rq_segments(q, bio, false);
|
||||
bio->bi_phys_segments = __blk_recalc_rq_segments(q, bio,
|
||||
no_sg_merge);
|
||||
bio->bi_next = nxt;
|
||||
}
|
||||
|
||||
@@ -313,7 +317,7 @@ static inline int ll_new_hw_segment(struct request_queue *q,
|
||||
if (req->nr_phys_segments + nr_phys_segs > queue_max_segments(q))
|
||||
goto no_merge;
|
||||
|
||||
if (bio_integrity(bio) && blk_integrity_merge_bio(q, req, bio))
|
||||
if (blk_integrity_merge_bio(q, req, bio) == false)
|
||||
goto no_merge;
|
||||
|
||||
/*
|
||||
@@ -410,7 +414,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
|
||||
if (total_phys_segments > queue_max_segments(q))
|
||||
return 0;
|
||||
|
||||
if (blk_integrity_rq(req) && blk_integrity_merge_rq(q, req, next))
|
||||
if (blk_integrity_merge_rq(q, req, next) == false)
|
||||
return 0;
|
||||
|
||||
/* Merge is OK... */
|
||||
@@ -590,7 +594,7 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
|
||||
return false;
|
||||
|
||||
/* only merge integrity protected bio into ditto rq */
|
||||
if (bio_integrity(bio) != blk_integrity_rq(rq))
|
||||
if (blk_integrity_merge_bio(rq->q, rq, bio) == false)
|
||||
return false;
|
||||
|
||||
/* must be using the same buffer */
|
||||
|
||||
+22
-33
@@ -351,15 +351,12 @@ static void bt_clear_tag(struct blk_mq_bitmap_tags *bt, unsigned int tag)
|
||||
return;
|
||||
|
||||
wait_cnt = atomic_dec_return(&bs->wait_cnt);
|
||||
if (unlikely(wait_cnt < 0))
|
||||
wait_cnt = atomic_inc_return(&bs->wait_cnt);
|
||||
if (wait_cnt == 0) {
|
||||
wake:
|
||||
atomic_add(bt->wake_cnt, &bs->wait_cnt);
|
||||
bt_index_atomic_inc(&bt->wake_index);
|
||||
wake_up(&bs->wait);
|
||||
} else if (wait_cnt < 0) {
|
||||
wait_cnt = atomic_inc_return(&bs->wait_cnt);
|
||||
if (!wait_cnt)
|
||||
goto wake;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,45 +389,37 @@ void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, unsigned int tag,
|
||||
__blk_mq_put_reserved_tag(tags, tag);
|
||||
}
|
||||
|
||||
static void bt_for_each_free(struct blk_mq_bitmap_tags *bt,
|
||||
unsigned long *free_map, unsigned int off)
|
||||
static void bt_for_each(struct blk_mq_hw_ctx *hctx,
|
||||
struct blk_mq_bitmap_tags *bt, unsigned int off,
|
||||
busy_iter_fn *fn, void *data, bool reserved)
|
||||
{
|
||||
int i;
|
||||
struct request *rq;
|
||||
int bit, i;
|
||||
|
||||
for (i = 0; i < bt->map_nr; i++) {
|
||||
struct blk_align_bitmap *bm = &bt->map[i];
|
||||
int bit = 0;
|
||||
|
||||
do {
|
||||
bit = find_next_zero_bit(&bm->word, bm->depth, bit);
|
||||
if (bit >= bm->depth)
|
||||
break;
|
||||
|
||||
__set_bit(bit + off, free_map);
|
||||
bit++;
|
||||
} while (1);
|
||||
for (bit = find_first_bit(&bm->word, bm->depth);
|
||||
bit < bm->depth;
|
||||
bit = find_next_bit(&bm->word, bm->depth, bit + 1)) {
|
||||
rq = blk_mq_tag_to_rq(hctx->tags, off + bit);
|
||||
if (rq->q == hctx->queue)
|
||||
fn(hctx, rq, data, reserved);
|
||||
}
|
||||
|
||||
off += (1 << bt->bits_per_word);
|
||||
}
|
||||
}
|
||||
|
||||
void blk_mq_tag_busy_iter(struct blk_mq_tags *tags,
|
||||
void (*fn)(void *, unsigned long *), void *data)
|
||||
void blk_mq_tag_busy_iter(struct blk_mq_hw_ctx *hctx, busy_iter_fn *fn,
|
||||
void *priv)
|
||||
{
|
||||
unsigned long *tag_map;
|
||||
size_t map_size;
|
||||
struct blk_mq_tags *tags = hctx->tags;
|
||||
|
||||
map_size = ALIGN(tags->nr_tags, BITS_PER_LONG) / BITS_PER_LONG;
|
||||
tag_map = kzalloc(map_size * sizeof(unsigned long), GFP_ATOMIC);
|
||||
if (!tag_map)
|
||||
return;
|
||||
|
||||
bt_for_each_free(&tags->bitmap_tags, tag_map, tags->nr_reserved_tags);
|
||||
if (tags->nr_reserved_tags)
|
||||
bt_for_each_free(&tags->breserved_tags, tag_map, 0);
|
||||
|
||||
fn(data, tag_map);
|
||||
kfree(tag_map);
|
||||
bt_for_each(hctx, &tags->breserved_tags, 0, fn, priv, true);
|
||||
bt_for_each(hctx, &tags->bitmap_tags, tags->nr_reserved_tags, fn, priv,
|
||||
false);
|
||||
}
|
||||
EXPORT_SYMBOL(blk_mq_tag_busy_iter);
|
||||
|
||||
@@ -463,8 +452,8 @@ static void bt_update_count(struct blk_mq_bitmap_tags *bt,
|
||||
}
|
||||
|
||||
bt->wake_cnt = BT_WAIT_BATCH;
|
||||
if (bt->wake_cnt > depth / 4)
|
||||
bt->wake_cnt = max(1U, depth / 4);
|
||||
if (bt->wake_cnt > depth / BT_WAIT_QUEUES)
|
||||
bt->wake_cnt = max(1U, depth / BT_WAIT_QUEUES);
|
||||
|
||||
bt->depth = depth;
|
||||
}
|
||||
|
||||
+189
-179
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -27,7 +27,6 @@ struct blk_mq_ctx {
|
||||
|
||||
void __blk_mq_complete_request(struct request *rq);
|
||||
void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
|
||||
void blk_mq_init_flush(struct request_queue *q);
|
||||
void blk_mq_freeze_queue(struct request_queue *q);
|
||||
void blk_mq_free_queue(struct request_queue *q);
|
||||
void blk_mq_clone_flush_request(struct request *flush_rq,
|
||||
@@ -60,6 +59,8 @@ extern int blk_mq_hw_queue_to_node(unsigned int *map, unsigned int);
|
||||
extern int blk_mq_sysfs_register(struct request_queue *q);
|
||||
extern void blk_mq_sysfs_unregister(struct request_queue *q);
|
||||
|
||||
extern void blk_mq_rq_timed_out(struct request *req, bool reserved);
|
||||
|
||||
/*
|
||||
* Basic implementation of sparser bitmap, allowing the user to spread
|
||||
* the bits over more cachelines.
|
||||
|
||||
@@ -574,7 +574,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
|
||||
bottom = max(b->physical_block_size, b->io_min) + alignment;
|
||||
|
||||
/* Verify that top and bottom intervals line up */
|
||||
if (max(top, bottom) & (min(top, bottom) - 1)) {
|
||||
if (max(top, bottom) % min(top, bottom)) {
|
||||
t->misaligned = 1;
|
||||
ret = -1;
|
||||
}
|
||||
@@ -619,7 +619,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
|
||||
|
||||
/* Find lowest common alignment_offset */
|
||||
t->alignment_offset = lcm(t->alignment_offset, alignment)
|
||||
& (max(t->physical_block_size, t->io_min) - 1);
|
||||
% max(t->physical_block_size, t->io_min);
|
||||
|
||||
/* Verify that new alignment_offset is on a logical block boundary */
|
||||
if (t->alignment_offset & (t->logical_block_size - 1)) {
|
||||
|
||||
+2
-2
@@ -519,8 +519,8 @@ static void blk_release_queue(struct kobject *kobj)
|
||||
|
||||
if (q->mq_ops)
|
||||
blk_mq_free_queue(q);
|
||||
|
||||
kfree(q->flush_rq);
|
||||
else
|
||||
blk_free_flush_queue(q->fq);
|
||||
|
||||
blk_trace_shutdown(q);
|
||||
|
||||
|
||||
+8
-7
@@ -90,10 +90,7 @@ static void blk_rq_timed_out(struct request *req)
|
||||
switch (ret) {
|
||||
case BLK_EH_HANDLED:
|
||||
/* Can we use req->errors here? */
|
||||
if (q->mq_ops)
|
||||
__blk_mq_complete_request(req);
|
||||
else
|
||||
__blk_complete_request(req);
|
||||
__blk_complete_request(req);
|
||||
break;
|
||||
case BLK_EH_RESET_TIMER:
|
||||
blk_add_timer(req);
|
||||
@@ -113,7 +110,7 @@ static void blk_rq_timed_out(struct request *req)
|
||||
}
|
||||
}
|
||||
|
||||
void blk_rq_check_expired(struct request *rq, unsigned long *next_timeout,
|
||||
static void blk_rq_check_expired(struct request *rq, unsigned long *next_timeout,
|
||||
unsigned int *next_set)
|
||||
{
|
||||
if (time_after_eq(jiffies, rq->deadline)) {
|
||||
@@ -162,7 +159,10 @@ void blk_abort_request(struct request *req)
|
||||
if (blk_mark_rq_complete(req))
|
||||
return;
|
||||
blk_delete_timer(req);
|
||||
blk_rq_timed_out(req);
|
||||
if (req->q->mq_ops)
|
||||
blk_mq_rq_timed_out(req, false);
|
||||
else
|
||||
blk_rq_timed_out(req);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blk_abort_request);
|
||||
|
||||
@@ -190,7 +190,8 @@ void blk_add_timer(struct request *req)
|
||||
struct request_queue *q = req->q;
|
||||
unsigned long expiry;
|
||||
|
||||
if (!q->rq_timed_out_fn)
|
||||
/* blk-mq has its own handler, so we don't need ->rq_timed_out_fn */
|
||||
if (!q->mq_ops && !q->rq_timed_out_fn)
|
||||
return;
|
||||
|
||||
BUG_ON(!list_empty(&req->timeout_list));
|
||||
|
||||
+33
-4
@@ -2,6 +2,8 @@
|
||||
#define BLK_INTERNAL_H
|
||||
|
||||
#include <linux/idr.h>
|
||||
#include <linux/blk-mq.h>
|
||||
#include "blk-mq.h"
|
||||
|
||||
/* Amount of time in which a process may batch requests */
|
||||
#define BLK_BATCH_TIME (HZ/50UL)
|
||||
@@ -12,16 +14,44 @@
|
||||
/* Max future timer expiry for timeouts */
|
||||
#define BLK_MAX_TIMEOUT (5 * HZ)
|
||||
|
||||
struct blk_flush_queue {
|
||||
unsigned int flush_queue_delayed:1;
|
||||
unsigned int flush_pending_idx:1;
|
||||
unsigned int flush_running_idx:1;
|
||||
unsigned long flush_pending_since;
|
||||
struct list_head flush_queue[2];
|
||||
struct list_head flush_data_in_flight;
|
||||
struct request *flush_rq;
|
||||
spinlock_t mq_flush_lock;
|
||||
};
|
||||
|
||||
extern struct kmem_cache *blk_requestq_cachep;
|
||||
extern struct kmem_cache *request_cachep;
|
||||
extern struct kobj_type blk_queue_ktype;
|
||||
extern struct ida blk_queue_ida;
|
||||
|
||||
static inline struct blk_flush_queue *blk_get_flush_queue(
|
||||
struct request_queue *q, struct blk_mq_ctx *ctx)
|
||||
{
|
||||
struct blk_mq_hw_ctx *hctx;
|
||||
|
||||
if (!q->mq_ops)
|
||||
return q->fq;
|
||||
|
||||
hctx = q->mq_ops->map_queue(q, ctx->cpu);
|
||||
|
||||
return hctx->fq;
|
||||
}
|
||||
|
||||
static inline void __blk_get_queue(struct request_queue *q)
|
||||
{
|
||||
kobject_get(&q->kobj);
|
||||
}
|
||||
|
||||
struct blk_flush_queue *blk_alloc_flush_queue(struct request_queue *q,
|
||||
int node, int cmd_size);
|
||||
void blk_free_flush_queue(struct blk_flush_queue *q);
|
||||
|
||||
int blk_init_rl(struct request_list *rl, struct request_queue *q,
|
||||
gfp_t gfp_mask);
|
||||
void blk_exit_rl(struct request_list *rl);
|
||||
@@ -38,8 +68,6 @@ bool __blk_end_bidi_request(struct request *rq, int error,
|
||||
unsigned int nr_bytes, unsigned int bidi_bytes);
|
||||
|
||||
void blk_rq_timed_out_timer(unsigned long data);
|
||||
void blk_rq_check_expired(struct request *rq, unsigned long *next_timeout,
|
||||
unsigned int *next_set);
|
||||
unsigned long blk_rq_timeout(unsigned long timeout);
|
||||
void blk_add_timer(struct request *req);
|
||||
void blk_delete_timer(struct request *);
|
||||
@@ -88,6 +116,7 @@ void blk_insert_flush(struct request *rq);
|
||||
static inline struct request *__elv_next_request(struct request_queue *q)
|
||||
{
|
||||
struct request *rq;
|
||||
struct blk_flush_queue *fq = blk_get_flush_queue(q, NULL);
|
||||
|
||||
while (1) {
|
||||
if (!list_empty(&q->queue_head)) {
|
||||
@@ -110,9 +139,9 @@ static inline struct request *__elv_next_request(struct request_queue *q)
|
||||
* should be restarted later. Please see flush_end_io() for
|
||||
* details.
|
||||
*/
|
||||
if (q->flush_pending_idx != q->flush_running_idx &&
|
||||
if (fq->flush_pending_idx != fq->flush_running_idx &&
|
||||
!queue_flush_queueable(q)) {
|
||||
q->flush_queue_delayed = 1;
|
||||
fq->flush_queue_delayed = 1;
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(blk_queue_bypass(q)) ||
|
||||
|
||||
+5
-4
@@ -270,8 +270,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
|
||||
* map scatter-gather elements separately and string them to request
|
||||
*/
|
||||
rq = blk_get_request(q, rw, GFP_KERNEL);
|
||||
if (!rq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (IS_ERR(rq))
|
||||
return rq;
|
||||
blk_rq_set_block_pc(rq);
|
||||
|
||||
ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd, has_write_perm);
|
||||
@@ -285,8 +285,9 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
|
||||
}
|
||||
|
||||
next_rq = blk_get_request(q, READ, GFP_KERNEL);
|
||||
if (!next_rq) {
|
||||
ret = -ENOMEM;
|
||||
if (IS_ERR(next_rq)) {
|
||||
ret = PTR_ERR(next_rq);
|
||||
next_rq = NULL;
|
||||
goto out;
|
||||
}
|
||||
rq->next_rq = next_rq;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user