mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'for-6.11/block-20240710' of git://git.kernel.dk/linux
Pull block updates from Jens Axboe:
- NVMe updates via Keith:
- Device initialization memory leak fixes (Keith)
- More constants defined (Weiwen)
- Target debugfs support (Hannes)
- PCIe subsystem reset enhancements (Keith)
- Queue-depth multipath policy (Redhat and PureStorage)
- Implement get_unique_id (Christoph)
- Authentication error fixes (Gaosheng)
- MD updates via Song
- sync_action fix and refactoring (Yu Kuai)
- Various small fixes (Christoph Hellwig, Li Nan, and Ofir Gal, Yu
Kuai, Benjamin Marzinski, Christophe JAILLET, Yang Li)
- Fix loop detach/open race (Gulam)
- Fix lower control limit for blk-throttle (Yu)
- Add module descriptions to various drivers (Jeff)
- Add support for atomic writes for block devices, and statx reporting
for same. Includes SCSI and NVMe (John, Prasad, Alan)
- Add IO priority information to block trace points (Dongliang)
- Various zone improvements and tweaks (Damien)
- mq-deadline tag reservation improvements (Bart)
- Ignore direct reclaim swap writes in writeback throttling (Baokun)
- Block integrity improvements and fixes (Anuj)
- Add basic support for rust based block drivers. Has a dummy null_blk
variant for now (Andreas)
- Series converting driver settings to queue limits, and cleanups and
fixes related to that (Christoph)
- Cleanup for poking too deeply into the bvec internals, in preparation
for DMA mapping API changes (Christoph)
- Various minor tweaks and fixes (Jiapeng, John, Kanchan, Mikulas,
Ming, Zhu, Damien, Christophe, Chaitanya)
* tag 'for-6.11/block-20240710' of git://git.kernel.dk/linux: (206 commits)
floppy: add missing MODULE_DESCRIPTION() macro
loop: add missing MODULE_DESCRIPTION() macro
ublk_drv: add missing MODULE_DESCRIPTION() macro
xen/blkback: add missing MODULE_DESCRIPTION() macro
block/rnbd: Constify struct kobj_type
block: take offset into account in blk_bvec_map_sg again
block: fix get_max_segment_size() warning
loop: Don't bother validating blocksize
virtio_blk: Don't bother validating blocksize
null_blk: Don't bother validating blocksize
block: Validate logical block size in blk_validate_limits()
virtio_blk: Fix default logical block size fallback
nvmet-auth: fix nvmet_auth hash error handling
nvme: implement ->get_unique_id
block: pass a phys_addr_t to get_max_segment_size
block: add a bvec_phys helper
blk-lib: check for kill signal in ioctl BLKZEROOUT
block: limit the Write Zeroes to manually writing zeroes fallback
block: refacto blkdev_issue_zeroout
block: move read-only and supported checks into (__)blkdev_issue_zeroout
...
This commit is contained in:
@@ -690,6 +690,7 @@ Vivien Didelot <vivien.didelot@gmail.com> <vivien.didelot@savoirfairelinux.com>
|
||||
Vlad Dogaru <ddvlad@gmail.com> <vlad.dogaru@intel.com>
|
||||
Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@parallels.com>
|
||||
Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@virtuozzo.com>
|
||||
Weiwen Hu <huweiwen@linux.alibaba.com> <sehuww@mail.scut.edu.cn>
|
||||
WeiXiong Liao <gmpy.liaowx@gmail.com> <liaoweixiong@allwinnertech.com>
|
||||
Wen Gong <quic_wgong@quicinc.com> <wgong@codeaurora.org>
|
||||
Wesley Cheng <quic_wcheng@quicinc.com> <wcheng@codeaurora.org>
|
||||
|
||||
@@ -21,6 +21,59 @@ Description:
|
||||
device is offset from the internal allocation unit's
|
||||
natural alignment.
|
||||
|
||||
What: /sys/block/<disk>/atomic_write_max_bytes
|
||||
Date: February 2024
|
||||
Contact: Himanshu Madhani <himanshu.madhani@oracle.com>
|
||||
Description:
|
||||
[RO] This parameter specifies the maximum atomic write
|
||||
size reported by the device. This parameter is relevant
|
||||
for merging of writes, where a merged atomic write
|
||||
operation must not exceed this number of bytes.
|
||||
This parameter may be greater than the value in
|
||||
atomic_write_unit_max_bytes as
|
||||
atomic_write_unit_max_bytes will be rounded down to a
|
||||
power-of-two and atomic_write_unit_max_bytes may also be
|
||||
limited by some other queue limits, such as max_segments.
|
||||
This parameter - along with atomic_write_unit_min_bytes
|
||||
and atomic_write_unit_max_bytes - will not be larger than
|
||||
max_hw_sectors_kb, but may be larger than max_sectors_kb.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/atomic_write_unit_min_bytes
|
||||
Date: February 2024
|
||||
Contact: Himanshu Madhani <himanshu.madhani@oracle.com>
|
||||
Description:
|
||||
[RO] This parameter specifies the smallest block which can
|
||||
be written atomically with an atomic write operation. All
|
||||
atomic write operations must begin at a
|
||||
atomic_write_unit_min boundary and must be multiples of
|
||||
atomic_write_unit_min. This value must be a power-of-two.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/atomic_write_unit_max_bytes
|
||||
Date: February 2024
|
||||
Contact: Himanshu Madhani <himanshu.madhani@oracle.com>
|
||||
Description:
|
||||
[RO] This parameter defines the largest block which can be
|
||||
written atomically with an atomic write operation. This
|
||||
value must be a multiple of atomic_write_unit_min and must
|
||||
be a power-of-two. This value will not be larger than
|
||||
atomic_write_max_bytes.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/atomic_write_boundary_bytes
|
||||
Date: February 2024
|
||||
Contact: Himanshu Madhani <himanshu.madhani@oracle.com>
|
||||
Description:
|
||||
[RO] A device may need to internally split an atomic write I/O
|
||||
which straddles a given logical block address boundary. This
|
||||
parameter specifies the size in bytes of the atomic boundary if
|
||||
one is reported by the device. This value must be a
|
||||
power-of-two and at least the size as in
|
||||
atomic_write_unit_max_bytes.
|
||||
Any attempt to merge atomic write I/Os must not result in a
|
||||
merged I/O which crosses this boundary (if any).
|
||||
|
||||
|
||||
What: /sys/block/<disk>/diskseq
|
||||
Date: February 2021
|
||||
|
||||
@@ -153,18 +153,11 @@ bio_free() will automatically free the bip.
|
||||
4.2 Block Device
|
||||
----------------
|
||||
|
||||
Because the format of the protection data is tied to the physical
|
||||
disk, each block device has been extended with a block integrity
|
||||
profile (struct blk_integrity). This optional profile is registered
|
||||
with the block layer using blk_integrity_register().
|
||||
|
||||
The profile contains callback functions for generating and verifying
|
||||
the protection data, as well as getting and setting application tags.
|
||||
The profile also contains a few constants to aid in completing,
|
||||
merging and splitting the integrity metadata.
|
||||
Block devices can set up the integrity information in the integrity
|
||||
sub-struture of the queue_limits structure.
|
||||
|
||||
Layered block devices will need to pick a profile that's appropriate
|
||||
for all subdevices. blk_integrity_compare() can help with that. DM
|
||||
for all subdevices. queue_limits_stack_integrity() can help with that. DM
|
||||
and MD linear, RAID0 and RAID1 are currently supported. RAID4/5/6
|
||||
will require extra work due to the application tag.
|
||||
|
||||
@@ -250,42 +243,6 @@ will require extra work due to the application tag.
|
||||
integrity upon completion.
|
||||
|
||||
|
||||
5.4 Registering A Block Device As Capable Of Exchanging Integrity Metadata
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
To enable integrity exchange on a block device the gendisk must be
|
||||
registered as capable:
|
||||
|
||||
`int blk_integrity_register(gendisk, blk_integrity);`
|
||||
|
||||
The blk_integrity struct is a template and should contain the
|
||||
following::
|
||||
|
||||
static struct blk_integrity my_profile = {
|
||||
.name = "STANDARDSBODY-TYPE-VARIANT-CSUM",
|
||||
.generate_fn = my_generate_fn,
|
||||
.verify_fn = my_verify_fn,
|
||||
.tuple_size = sizeof(struct my_tuple_size),
|
||||
.tag_size = <tag bytes per hw sector>,
|
||||
};
|
||||
|
||||
'name' is a text string which will be visible in sysfs. This is
|
||||
part of the userland API so chose it carefully and never change
|
||||
it. The format is standards body-type-variant.
|
||||
E.g. T10-DIF-TYPE1-IP or T13-EPP-0-CRC.
|
||||
|
||||
'generate_fn' generates appropriate integrity metadata (for WRITE).
|
||||
|
||||
'verify_fn' verifies that the data buffer matches the integrity
|
||||
metadata.
|
||||
|
||||
'tuple_size' must be set to match the size of the integrity
|
||||
metadata per sector. I.e. 8 for DIF and EPP.
|
||||
|
||||
'tag_size' must be set to identify how many bytes of tag space
|
||||
are available per hardware sector. For DIF this is either 2 or
|
||||
0 depending on the value of the Control Mode Page ATO bit.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
2007-12-24 Martin K. Petersen <martin.petersen@oracle.com>
|
||||
|
||||
@@ -46,41 +46,50 @@ worry if the underlying devices need any explicit cache flushing and how
|
||||
the Forced Unit Access is implemented. The REQ_PREFLUSH and REQ_FUA flags
|
||||
may both be set on a single bio.
|
||||
|
||||
|
||||
Implementation details for bio based block drivers
|
||||
--------------------------------------------------------------
|
||||
|
||||
These drivers will always see the REQ_PREFLUSH and REQ_FUA bits as they sit
|
||||
directly below the submit_bio interface. For remapping drivers the REQ_FUA
|
||||
bits need to be propagated to underlying devices, and a global flush needs
|
||||
to be implemented for bios with the REQ_PREFLUSH bit set. For real device
|
||||
drivers that do not have a volatile cache the REQ_PREFLUSH and REQ_FUA bits
|
||||
on non-empty bios can simply be ignored, and REQ_PREFLUSH requests without
|
||||
data can be completed successfully without doing any work. Drivers for
|
||||
devices with volatile caches need to implement the support for these
|
||||
flags themselves without any help from the block layer.
|
||||
|
||||
|
||||
Implementation details for request_fn based block drivers
|
||||
---------------------------------------------------------
|
||||
Feature settings for block drivers
|
||||
----------------------------------
|
||||
|
||||
For devices that do not support volatile write caches there is no driver
|
||||
support required, the block layer completes empty REQ_PREFLUSH requests before
|
||||
entering the driver and strips off the REQ_PREFLUSH and REQ_FUA bits from
|
||||
requests that have a payload. For devices with volatile write caches the
|
||||
driver needs to tell the block layer that it supports flushing caches by
|
||||
doing::
|
||||
requests that have a payload.
|
||||
|
||||
blk_queue_write_cache(sdkp->disk->queue, true, false);
|
||||
For devices with volatile write caches the driver needs to tell the block layer
|
||||
that it supports flushing caches by setting the
|
||||
|
||||
and handle empty REQ_OP_FLUSH requests in its prep_fn/request_fn. Note that
|
||||
REQ_PREFLUSH requests with a payload are automatically turned into a sequence
|
||||
of an empty REQ_OP_FLUSH request followed by the actual write by the block
|
||||
layer. For devices that also support the FUA bit the block layer needs
|
||||
to be told to pass through the REQ_FUA bit using::
|
||||
BLK_FEAT_WRITE_CACHE
|
||||
|
||||
blk_queue_write_cache(sdkp->disk->queue, true, true);
|
||||
flag in the queue_limits feature field. For devices that also support the FUA
|
||||
bit the block layer needs to be told to pass on the REQ_FUA bit by also setting
|
||||
the
|
||||
|
||||
and the driver must handle write requests that have the REQ_FUA bit set
|
||||
in prep_fn/request_fn. If the FUA bit is not natively supported the block
|
||||
layer turns it into an empty REQ_OP_FLUSH request after the actual write.
|
||||
BLK_FEAT_FUA
|
||||
|
||||
flag in the features field of the queue_limits structure.
|
||||
|
||||
Implementation details for bio based block drivers
|
||||
--------------------------------------------------
|
||||
|
||||
For bio based drivers the REQ_PREFLUSH and REQ_FUA bit are simply passed on to
|
||||
the driver if the driver sets the BLK_FEAT_WRITE_CACHE flag and the driver
|
||||
needs to handle them.
|
||||
|
||||
*NOTE*: The REQ_FUA bit also gets passed on when the BLK_FEAT_FUA flags is
|
||||
_not_ set. Any bio based driver that sets BLK_FEAT_WRITE_CACHE also needs to
|
||||
handle REQ_FUA.
|
||||
|
||||
For remapping drivers the REQ_FUA bits need to be propagated to underlying
|
||||
devices, and a global flush needs to be implemented for bios with the
|
||||
REQ_PREFLUSH bit set.
|
||||
|
||||
Implementation details for blk-mq drivers
|
||||
-----------------------------------------
|
||||
|
||||
When the BLK_FEAT_WRITE_CACHE flag is set, REQ_OP_WRITE | REQ_PREFLUSH requests
|
||||
with a payload are automatically turned into a sequence of a REQ_OP_FLUSH
|
||||
request followed by the actual write by the block layer.
|
||||
|
||||
When the BLK_FEAT_FUA flags is set, the REQ_FUA bit is simply passed on for the
|
||||
REQ_OP_WRITE request, else a REQ_OP_FLUSH request is sent by the block layer
|
||||
after the completion of the write request for bio submissions with the REQ_FUA
|
||||
bit set.
|
||||
|
||||
+14
@@ -3759,6 +3759,20 @@ F: include/linux/blk*
|
||||
F: kernel/trace/blktrace.c
|
||||
F: lib/sbitmap.c
|
||||
|
||||
BLOCK LAYER DEVICE DRIVER API [RUST]
|
||||
M: Andreas Hindborg <a.hindborg@samsung.com>
|
||||
R: Boqun Feng <boqun.feng@gmail.com>
|
||||
L: linux-block@vger.kernel.org
|
||||
L: rust-for-linux@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://rust-for-linux.com
|
||||
B: https://github.com/Rust-for-Linux/linux/issues
|
||||
C: https://rust-for-linux.zulipchat.com/#narrow/stream/Block
|
||||
T: git https://github.com/Rust-for-Linux/linux.git rust-block-next
|
||||
F: drivers/block/rnull.rs
|
||||
F: rust/kernel/block.rs
|
||||
F: rust/kernel/block/
|
||||
|
||||
BLOCK2MTD DRIVER
|
||||
M: Joern Engel <joern@lazybastard.org>
|
||||
L: linux-mtd@lists.infradead.org
|
||||
|
||||
@@ -71,7 +71,7 @@ static void nfhd_submit_bio(struct bio *bio)
|
||||
len = bvec.bv_len;
|
||||
len >>= 9;
|
||||
nfhd_read_write(dev->id, 0, dir, sec >> shift, len >> shift,
|
||||
page_to_phys(bvec.bv_page) + bvec.bv_offset);
|
||||
bvec_phys(&bvec));
|
||||
sec += len;
|
||||
}
|
||||
bio_endio(bio);
|
||||
@@ -98,6 +98,7 @@ static int __init nfhd_init_one(int id, u32 blocks, u32 bsize)
|
||||
{
|
||||
struct queue_limits lim = {
|
||||
.logical_block_size = bsize,
|
||||
.features = BLK_FEAT_ROTATIONAL,
|
||||
};
|
||||
struct nfhd_device *dev;
|
||||
int dev_id = id - NFHD_DEV_OFFSET;
|
||||
|
||||
+20
-33
@@ -447,43 +447,31 @@ static int bulk_req_safe_read(
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Called without dev->lock held, and only in interrupt context. */
|
||||
static void ubd_handler(void)
|
||||
static void ubd_end_request(struct io_thread_req *io_req)
|
||||
{
|
||||
int n;
|
||||
int count;
|
||||
|
||||
while(1){
|
||||
n = bulk_req_safe_read(
|
||||
thread_fd,
|
||||
irq_req_buffer,
|
||||
&irq_remainder,
|
||||
&irq_remainder_size,
|
||||
UBD_REQ_BUFFER_SIZE
|
||||
);
|
||||
if (n < 0) {
|
||||
if(n == -EAGAIN)
|
||||
break;
|
||||
printk(KERN_ERR "spurious interrupt in ubd_handler, "
|
||||
"err = %d\n", -n);
|
||||
return;
|
||||
}
|
||||
for (count = 0; count < n/sizeof(struct io_thread_req *); count++) {
|
||||
struct io_thread_req *io_req = (*irq_req_buffer)[count];
|
||||
|
||||
if ((io_req->error == BLK_STS_NOTSUPP) && (req_op(io_req->req) == REQ_OP_DISCARD)) {
|
||||
blk_queue_max_discard_sectors(io_req->req->q, 0);
|
||||
blk_queue_max_write_zeroes_sectors(io_req->req->q, 0);
|
||||
}
|
||||
blk_mq_end_request(io_req->req, io_req->error);
|
||||
kfree(io_req);
|
||||
}
|
||||
if (io_req->error == BLK_STS_NOTSUPP) {
|
||||
if (req_op(io_req->req) == REQ_OP_DISCARD)
|
||||
blk_queue_disable_discard(io_req->req->q);
|
||||
else if (req_op(io_req->req) == REQ_OP_WRITE_ZEROES)
|
||||
blk_queue_disable_write_zeroes(io_req->req->q);
|
||||
}
|
||||
blk_mq_end_request(io_req->req, io_req->error);
|
||||
kfree(io_req);
|
||||
}
|
||||
|
||||
static irqreturn_t ubd_intr(int irq, void *dev)
|
||||
{
|
||||
ubd_handler();
|
||||
int len, i;
|
||||
|
||||
while ((len = bulk_req_safe_read(thread_fd, irq_req_buffer,
|
||||
&irq_remainder, &irq_remainder_size,
|
||||
UBD_REQ_BUFFER_SIZE)) >= 0) {
|
||||
for (i = 0; i < len / sizeof(struct io_thread_req *); i++)
|
||||
ubd_end_request((*irq_req_buffer)[i]);
|
||||
}
|
||||
|
||||
if (len < 0 && len != -EAGAIN)
|
||||
pr_err("spurious interrupt in %s, err = %d\n", __func__, len);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -847,6 +835,7 @@ static int ubd_add(int n, char **error_out)
|
||||
struct queue_limits lim = {
|
||||
.max_segments = MAX_SG,
|
||||
.seg_boundary_mask = PAGE_SIZE - 1,
|
||||
.features = BLK_FEAT_WRITE_CACHE,
|
||||
};
|
||||
struct gendisk *disk;
|
||||
int err = 0;
|
||||
@@ -893,8 +882,6 @@ static int ubd_add(int n, char **error_out)
|
||||
goto out_cleanup_tags;
|
||||
}
|
||||
|
||||
blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue);
|
||||
blk_queue_write_cache(disk->queue, true, false);
|
||||
disk->major = UBD_MAJOR;
|
||||
disk->first_minor = n << UBD_SHIFT;
|
||||
disk->minors = 1 << UBD_SHIFT;
|
||||
|
||||
@@ -263,6 +263,9 @@ static const struct proc_ops simdisk_proc_ops = {
|
||||
static int __init simdisk_setup(struct simdisk *dev, int which,
|
||||
struct proc_dir_entry *procdir)
|
||||
{
|
||||
struct queue_limits lim = {
|
||||
.features = BLK_FEAT_ROTATIONAL,
|
||||
};
|
||||
char tmp[2] = { '0' + which, 0 };
|
||||
int err;
|
||||
|
||||
@@ -271,7 +274,7 @@ static int __init simdisk_setup(struct simdisk *dev, int which,
|
||||
spin_lock_init(&dev->lock);
|
||||
dev->users = 0;
|
||||
|
||||
dev->gd = blk_alloc_disk(NULL, NUMA_NO_NODE);
|
||||
dev->gd = blk_alloc_disk(&lim, NUMA_NO_NODE);
|
||||
if (IS_ERR(dev->gd)) {
|
||||
err = PTR_ERR(dev->gd);
|
||||
goto out;
|
||||
|
||||
+2
-6
@@ -62,6 +62,8 @@ config BLK_DEV_BSGLIB
|
||||
|
||||
config BLK_DEV_INTEGRITY
|
||||
bool "Block layer data integrity support"
|
||||
select CRC_T10DIF
|
||||
select CRC64_ROCKSOFT
|
||||
help
|
||||
Some storage devices allow extra information to be
|
||||
stored/retrieved to help protect the data. The block layer
|
||||
@@ -72,12 +74,6 @@ config BLK_DEV_INTEGRITY
|
||||
T10/SCSI Data Integrity Field or the T13/ATA External Path
|
||||
Protection. If in doubt, say N.
|
||||
|
||||
config BLK_DEV_INTEGRITY_T10
|
||||
tristate
|
||||
depends on BLK_DEV_INTEGRITY
|
||||
select CRC_T10DIF
|
||||
select CRC64_ROCKSOFT
|
||||
|
||||
config BLK_DEV_WRITE_MOUNTED
|
||||
bool "Allow writing to mounted block devices"
|
||||
default y
|
||||
|
||||
+1
-2
@@ -26,8 +26,7 @@ obj-$(CONFIG_MQ_IOSCHED_KYBER) += kyber-iosched.o
|
||||
bfq-y := bfq-iosched.o bfq-wf2q.o bfq-cgroup.o
|
||||
obj-$(CONFIG_IOSCHED_BFQ) += bfq.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o
|
||||
obj-$(CONFIG_BLK_DEV_INTEGRITY_T10) += t10-pi.o
|
||||
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o t10-pi.o
|
||||
obj-$(CONFIG_BLK_MQ_PCI) += blk-mq-pci.o
|
||||
obj-$(CONFIG_BLK_MQ_VIRTIO) += blk-mq-virtio.o
|
||||
obj-$(CONFIG_BLK_DEV_ZONED) += blk-zoned.o
|
||||
|
||||
+30
-11
@@ -385,7 +385,7 @@ static struct file_system_type bd_type = {
|
||||
};
|
||||
|
||||
struct super_block *blockdev_superblock __ro_after_init;
|
||||
struct vfsmount *blockdev_mnt __ro_after_init;
|
||||
static struct vfsmount *blockdev_mnt __ro_after_init;
|
||||
EXPORT_SYMBOL_GPL(blockdev_superblock);
|
||||
|
||||
void __init bdev_cache_init(void)
|
||||
@@ -1260,23 +1260,42 @@ void sync_bdevs(bool wait)
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle STATX_DIOALIGN for block devices.
|
||||
*
|
||||
* Note that the inode passed to this is the inode of a block device node file,
|
||||
* not the block device's internal inode. Therefore it is *not* valid to use
|
||||
* I_BDEV() here; the block device has to be looked up by i_rdev instead.
|
||||
* Handle STATX_{DIOALIGN, WRITE_ATOMIC} for block devices.
|
||||
*/
|
||||
void bdev_statx_dioalign(struct inode *inode, struct kstat *stat)
|
||||
void bdev_statx(struct path *path, struct kstat *stat,
|
||||
u32 request_mask)
|
||||
{
|
||||
struct inode *backing_inode;
|
||||
struct block_device *bdev;
|
||||
|
||||
bdev = blkdev_get_no_open(inode->i_rdev);
|
||||
if (!(request_mask & (STATX_DIOALIGN | STATX_WRITE_ATOMIC)))
|
||||
return;
|
||||
|
||||
backing_inode = d_backing_inode(path->dentry);
|
||||
|
||||
/*
|
||||
* Note that backing_inode is the inode of a block device node file,
|
||||
* not the block device's internal inode. Therefore it is *not* valid
|
||||
* to use I_BDEV() here; the block device has to be looked up by i_rdev
|
||||
* instead.
|
||||
*/
|
||||
bdev = blkdev_get_no_open(backing_inode->i_rdev);
|
||||
if (!bdev)
|
||||
return;
|
||||
|
||||
stat->dio_mem_align = bdev_dma_alignment(bdev) + 1;
|
||||
stat->dio_offset_align = bdev_logical_block_size(bdev);
|
||||
stat->result_mask |= STATX_DIOALIGN;
|
||||
if (request_mask & STATX_DIOALIGN) {
|
||||
stat->dio_mem_align = bdev_dma_alignment(bdev) + 1;
|
||||
stat->dio_offset_align = bdev_logical_block_size(bdev);
|
||||
stat->result_mask |= STATX_DIOALIGN;
|
||||
}
|
||||
|
||||
if (request_mask & STATX_WRITE_ATOMIC && bdev_can_atomic_write(bdev)) {
|
||||
struct request_queue *bd_queue = bdev->bd_queue;
|
||||
|
||||
generic_fill_statx_atomic_writes(stat,
|
||||
queue_atomic_write_unit_min_bytes(bd_queue),
|
||||
queue_atomic_write_unit_max_bytes(bd_queue));
|
||||
}
|
||||
|
||||
blkdev_put_no_open(bdev);
|
||||
}
|
||||
|
||||
@@ -797,57 +797,6 @@ void bfq_bic_update_cgroup(struct bfq_io_cq *bic, struct bio *bio)
|
||||
*/
|
||||
bfq_link_bfqg(bfqd, bfqg);
|
||||
__bfq_bic_change_cgroup(bfqd, bic, bfqg);
|
||||
/*
|
||||
* Update blkg_path for bfq_log_* functions. We cache this
|
||||
* path, and update it here, for the following
|
||||
* reasons. Operations on blkg objects in blk-cgroup are
|
||||
* protected with the request_queue lock, and not with the
|
||||
* lock that protects the instances of this scheduler
|
||||
* (bfqd->lock). This exposes BFQ to the following sort of
|
||||
* race.
|
||||
*
|
||||
* The blkg_lookup performed in bfq_get_queue, protected
|
||||
* through rcu, may happen to return the address of a copy of
|
||||
* the original blkg. If this is the case, then the
|
||||
* bfqg_and_blkg_get performed in bfq_get_queue, to pin down
|
||||
* the blkg, is useless: it does not prevent blk-cgroup code
|
||||
* from destroying both the original blkg and all objects
|
||||
* directly or indirectly referred by the copy of the
|
||||
* blkg.
|
||||
*
|
||||
* On the bright side, destroy operations on a blkg invoke, as
|
||||
* a first step, hooks of the scheduler associated with the
|
||||
* blkg. And these hooks are executed with bfqd->lock held for
|
||||
* BFQ. As a consequence, for any blkg associated with the
|
||||
* request queue this instance of the scheduler is attached
|
||||
* to, we are guaranteed that such a blkg is not destroyed, and
|
||||
* that all the pointers it contains are consistent, while we
|
||||
* are holding bfqd->lock. A blkg_lookup performed with
|
||||
* bfqd->lock held then returns a fully consistent blkg, which
|
||||
* remains consistent until this lock is held.
|
||||
*
|
||||
* Thanks to the last fact, and to the fact that: (1) bfqg has
|
||||
* been obtained through a blkg_lookup in the above
|
||||
* assignment, and (2) bfqd->lock is being held, here we can
|
||||
* safely use the policy data for the involved blkg (i.e., the
|
||||
* field bfqg->pd) to get to the blkg associated with bfqg,
|
||||
* and then we can safely use any field of blkg. After we
|
||||
* release bfqd->lock, even just getting blkg through this
|
||||
* bfqg may cause dangling references to be traversed, as
|
||||
* bfqg->pd may not exist any more.
|
||||
*
|
||||
* In view of the above facts, here we cache, in the bfqg, any
|
||||
* blkg data we may need for this bic, and for its associated
|
||||
* bfq_queue. As of now, we need to cache only the path of the
|
||||
* blkg, which is used in the bfq_log_* functions.
|
||||
*
|
||||
* Finally, note that bfqg itself needs to be protected from
|
||||
* destruction on the blkg_free of the original blkg (which
|
||||
* invokes bfq_pd_free). We use an additional private
|
||||
* refcounter for bfqg, to let it disappear only after no
|
||||
* bfq_queue refers to it any longer.
|
||||
*/
|
||||
blkg_path(bfqg_to_blkg(bfqg), bfqg->blkg_path, sizeof(bfqg->blkg_path));
|
||||
bic->blkcg_serial_nr = serial_nr;
|
||||
}
|
||||
|
||||
|
||||
+24
-22
@@ -5463,29 +5463,10 @@ static void bfq_exit_icq_bfqq(struct bfq_io_cq *bic, bool is_sync,
|
||||
}
|
||||
}
|
||||
|
||||
static void bfq_exit_icq(struct io_cq *icq)
|
||||
static void _bfq_exit_icq(struct bfq_io_cq *bic, unsigned int num_actuators)
|
||||
{
|
||||
struct bfq_io_cq *bic = icq_to_bic(icq);
|
||||
struct bfq_data *bfqd = bic_to_bfqd(bic);
|
||||
unsigned long flags;
|
||||
unsigned int act_idx;
|
||||
/*
|
||||
* If bfqd and thus bfqd->num_actuators is not available any
|
||||
* longer, then cycle over all possible per-actuator bfqqs in
|
||||
* next loop. We rely on bic being zeroed on creation, and
|
||||
* therefore on its unused per-actuator fields being NULL.
|
||||
*/
|
||||
unsigned int num_actuators = BFQ_MAX_ACTUATORS;
|
||||
struct bfq_iocq_bfqq_data *bfqq_data = bic->bfqq_data;
|
||||
|
||||
/*
|
||||
* bfqd is NULL if scheduler already exited, and in that case
|
||||
* this is the last time these queues are accessed.
|
||||
*/
|
||||
if (bfqd) {
|
||||
spin_lock_irqsave(&bfqd->lock, flags);
|
||||
num_actuators = bfqd->num_actuators;
|
||||
}
|
||||
unsigned int act_idx;
|
||||
|
||||
for (act_idx = 0; act_idx < num_actuators; act_idx++) {
|
||||
if (bfqq_data[act_idx].stable_merge_bfqq)
|
||||
@@ -5494,9 +5475,30 @@ static void bfq_exit_icq(struct io_cq *icq)
|
||||
bfq_exit_icq_bfqq(bic, true, act_idx);
|
||||
bfq_exit_icq_bfqq(bic, false, act_idx);
|
||||
}
|
||||
}
|
||||
|
||||
if (bfqd)
|
||||
static void bfq_exit_icq(struct io_cq *icq)
|
||||
{
|
||||
struct bfq_io_cq *bic = icq_to_bic(icq);
|
||||
struct bfq_data *bfqd = bic_to_bfqd(bic);
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* If bfqd and thus bfqd->num_actuators is not available any
|
||||
* longer, then cycle over all possible per-actuator bfqqs in
|
||||
* next loop. We rely on bic being zeroed on creation, and
|
||||
* therefore on its unused per-actuator fields being NULL.
|
||||
*
|
||||
* bfqd is NULL if scheduler already exited, and in that case
|
||||
* this is the last time these queues are accessed.
|
||||
*/
|
||||
if (bfqd) {
|
||||
spin_lock_irqsave(&bfqd->lock, flags);
|
||||
_bfq_exit_icq(bic, bfqd->num_actuators);
|
||||
spin_unlock_irqrestore(&bfqd->lock, flags);
|
||||
} else {
|
||||
_bfq_exit_icq(bic, BFQ_MAX_ACTUATORS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1003,9 +1003,6 @@ struct bfq_group {
|
||||
/* must be the first member */
|
||||
struct blkg_policy_data pd;
|
||||
|
||||
/* cached path for this blkg (see comments in bfq_bic_update_cgroup) */
|
||||
char blkg_path[128];
|
||||
|
||||
/* reference counter (see comments in bfq_bic_update_cgroup) */
|
||||
refcount_t ref;
|
||||
|
||||
|
||||
+37
-98
@@ -76,7 +76,7 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
|
||||
&bip->bip_max_vcnt, gfp_mask);
|
||||
if (!bip->bip_vec)
|
||||
goto err;
|
||||
} else {
|
||||
} else if (nr_vecs) {
|
||||
bip->bip_vec = bip->bip_inline_vecs;
|
||||
}
|
||||
|
||||
@@ -276,6 +276,7 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec,
|
||||
|
||||
bip->bip_flags |= BIP_INTEGRITY_USER | BIP_COPY_USER;
|
||||
bip->bip_iter.bi_sector = seed;
|
||||
bip->bip_vcnt = nr_vecs;
|
||||
return 0;
|
||||
free_bip:
|
||||
bio_integrity_free(bio);
|
||||
@@ -297,6 +298,7 @@ static int bio_integrity_init_user(struct bio *bio, struct bio_vec *bvec,
|
||||
bip->bip_flags |= BIP_INTEGRITY_USER;
|
||||
bip->bip_iter.bi_sector = seed;
|
||||
bip->bip_iter.bi_size = len;
|
||||
bip->bip_vcnt = nr_vecs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -334,7 +336,7 @@ int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes,
|
||||
u32 seed)
|
||||
{
|
||||
struct request_queue *q = bdev_get_queue(bio->bi_bdev);
|
||||
unsigned int align = q->dma_pad_mask | queue_dma_alignment(q);
|
||||
unsigned int align = blk_lim_dma_alignment_and_pad(&q->limits);
|
||||
struct page *stack_pages[UIO_FASTIOV], **pages = stack_pages;
|
||||
struct bio_vec stack_vec[UIO_FASTIOV], *bvec = stack_vec;
|
||||
unsigned int direction, nr_bvecs;
|
||||
@@ -396,44 +398,6 @@ free_bvec:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bio_integrity_map_user);
|
||||
|
||||
/**
|
||||
* bio_integrity_process - Process integrity metadata for a bio
|
||||
* @bio: bio to generate/verify integrity metadata for
|
||||
* @proc_iter: iterator to process
|
||||
* @proc_fn: Pointer to the relevant processing function
|
||||
*/
|
||||
static blk_status_t bio_integrity_process(struct bio *bio,
|
||||
struct bvec_iter *proc_iter, integrity_processing_fn *proc_fn)
|
||||
{
|
||||
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
|
||||
struct blk_integrity_iter iter;
|
||||
struct bvec_iter bviter;
|
||||
struct bio_vec bv;
|
||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||
blk_status_t ret = BLK_STS_OK;
|
||||
|
||||
iter.disk_name = bio->bi_bdev->bd_disk->disk_name;
|
||||
iter.interval = 1 << bi->interval_exp;
|
||||
iter.tuple_size = bi->tuple_size;
|
||||
iter.seed = proc_iter->bi_sector;
|
||||
iter.prot_buf = bvec_virt(bip->bip_vec);
|
||||
iter.pi_offset = bi->pi_offset;
|
||||
|
||||
__bio_for_each_segment(bv, bio, bviter, *proc_iter) {
|
||||
void *kaddr = bvec_kmap_local(&bv);
|
||||
|
||||
iter.data_buf = kaddr;
|
||||
iter.data_size = bv.bv_len;
|
||||
ret = proc_fn(&iter);
|
||||
kunmap_local(kaddr);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* bio_integrity_prep - Prepare bio for integrity I/O
|
||||
* @bio: bio to prepare
|
||||
@@ -450,17 +414,13 @@ bool bio_integrity_prep(struct bio *bio)
|
||||
{
|
||||
struct bio_integrity_payload *bip;
|
||||
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
|
||||
unsigned int len;
|
||||
void *buf;
|
||||
unsigned long start, end;
|
||||
unsigned int len, nr_pages;
|
||||
unsigned int bytes, offset, i;
|
||||
gfp_t gfp = GFP_NOIO;
|
||||
|
||||
if (!bi)
|
||||
return true;
|
||||
|
||||
if (bio_op(bio) != REQ_OP_READ && bio_op(bio) != REQ_OP_WRITE)
|
||||
return true;
|
||||
|
||||
if (!bio_sectors(bio))
|
||||
return true;
|
||||
|
||||
@@ -468,32 +428,36 @@ bool bio_integrity_prep(struct bio *bio)
|
||||
if (bio_integrity(bio))
|
||||
return true;
|
||||
|
||||
if (bio_data_dir(bio) == READ) {
|
||||
if (!bi->profile->verify_fn ||
|
||||
!(bi->flags & BLK_INTEGRITY_VERIFY))
|
||||
switch (bio_op(bio)) {
|
||||
case REQ_OP_READ:
|
||||
if (bi->flags & BLK_INTEGRITY_NOVERIFY)
|
||||
return true;
|
||||
} else {
|
||||
if (!bi->profile->generate_fn ||
|
||||
!(bi->flags & BLK_INTEGRITY_GENERATE))
|
||||
break;
|
||||
case REQ_OP_WRITE:
|
||||
if (bi->flags & BLK_INTEGRITY_NOGENERATE)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Zero the memory allocated to not leak uninitialized kernel
|
||||
* memory to disk for non-integrity metadata where nothing else
|
||||
* initializes the memory.
|
||||
*/
|
||||
if (bi->csum_type == BLK_INTEGRITY_CSUM_NONE)
|
||||
gfp |= __GFP_ZERO;
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Allocate kernel buffer for protection data */
|
||||
len = bio_integrity_bytes(bi, bio_sectors(bio));
|
||||
buf = kmalloc(len, GFP_NOIO);
|
||||
buf = kmalloc(len, gfp);
|
||||
if (unlikely(buf == NULL)) {
|
||||
printk(KERN_ERR "could not allocate integrity buffer\n");
|
||||
goto err_end_io;
|
||||
}
|
||||
|
||||
end = (((unsigned long) buf) + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
start = ((unsigned long) buf) >> PAGE_SHIFT;
|
||||
nr_pages = end - start;
|
||||
|
||||
/* Allocate bio integrity payload and integrity vectors */
|
||||
bip = bio_integrity_alloc(bio, GFP_NOIO, nr_pages);
|
||||
bip = bio_integrity_alloc(bio, GFP_NOIO, 1);
|
||||
if (IS_ERR(bip)) {
|
||||
printk(KERN_ERR "could not allocate data integrity bioset\n");
|
||||
kfree(buf);
|
||||
goto err_end_io;
|
||||
}
|
||||
@@ -501,35 +465,20 @@ bool bio_integrity_prep(struct bio *bio)
|
||||
bip->bip_flags |= BIP_BLOCK_INTEGRITY;
|
||||
bip_set_seed(bip, bio->bi_iter.bi_sector);
|
||||
|
||||
if (bi->flags & BLK_INTEGRITY_IP_CHECKSUM)
|
||||
if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
|
||||
bip->bip_flags |= BIP_IP_CHECKSUM;
|
||||
|
||||
/* Map it */
|
||||
offset = offset_in_page(buf);
|
||||
for (i = 0; i < nr_pages && len > 0; i++) {
|
||||
bytes = PAGE_SIZE - offset;
|
||||
|
||||
if (bytes > len)
|
||||
bytes = len;
|
||||
|
||||
if (bio_integrity_add_page(bio, virt_to_page(buf),
|
||||
bytes, offset) < bytes) {
|
||||
printk(KERN_ERR "could not attach integrity payload\n");
|
||||
goto err_end_io;
|
||||
}
|
||||
|
||||
buf += bytes;
|
||||
len -= bytes;
|
||||
offset = 0;
|
||||
if (bio_integrity_add_page(bio, virt_to_page(buf), len,
|
||||
offset_in_page(buf)) < len) {
|
||||
printk(KERN_ERR "could not attach integrity payload\n");
|
||||
goto err_end_io;
|
||||
}
|
||||
|
||||
/* Auto-generate integrity metadata if this is a write */
|
||||
if (bio_data_dir(bio) == WRITE) {
|
||||
bio_integrity_process(bio, &bio->bi_iter,
|
||||
bi->profile->generate_fn);
|
||||
} else {
|
||||
if (bio_data_dir(bio) == WRITE)
|
||||
blk_integrity_generate(bio);
|
||||
else
|
||||
bip->bio_iter = bio->bi_iter;
|
||||
}
|
||||
return true;
|
||||
|
||||
err_end_io:
|
||||
@@ -552,15 +501,8 @@ 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 = blk_get_integrity(bio->bi_bdev->bd_disk);
|
||||
|
||||
/*
|
||||
* At the moment verify is called bio's iterator was advanced
|
||||
* during split and completion, we need to rewind iterator to
|
||||
* it's original position.
|
||||
*/
|
||||
bio->bi_status = bio_integrity_process(bio, &bip->bio_iter,
|
||||
bi->profile->verify_fn);
|
||||
blk_integrity_verify(bio);
|
||||
bio_integrity_free(bio);
|
||||
bio_endio(bio);
|
||||
}
|
||||
@@ -582,7 +524,7 @@ bool __bio_integrity_endio(struct bio *bio)
|
||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||
|
||||
if (bio_op(bio) == REQ_OP_READ && !bio->bi_status &&
|
||||
(bip->bip_flags & BIP_BLOCK_INTEGRITY) && bi->profile->verify_fn) {
|
||||
(bip->bip_flags & BIP_BLOCK_INTEGRITY) && bi->csum_type) {
|
||||
INIT_WORK(&bip->bip_work, bio_integrity_verify_fn);
|
||||
queue_work(kintegrityd_wq, &bip->bip_work);
|
||||
return false;
|
||||
@@ -642,14 +584,11 @@ int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
|
||||
|
||||
BUG_ON(bip_src == NULL);
|
||||
|
||||
bip = bio_integrity_alloc(bio, gfp_mask, bip_src->bip_vcnt);
|
||||
bip = bio_integrity_alloc(bio, gfp_mask, 0);
|
||||
if (IS_ERR(bip))
|
||||
return PTR_ERR(bip);
|
||||
|
||||
memcpy(bip->bip_vec, bip_src->bip_vec,
|
||||
bip_src->bip_vcnt * sizeof(struct bio_vec));
|
||||
|
||||
bip->bip_vcnt = bip_src->bip_vcnt;
|
||||
bip->bip_vec = bip_src->bip_vec;
|
||||
bip->bip_iter = bip_src->bip_iter;
|
||||
bip->bip_flags = bip_src->bip_flags & ~BIP_BLOCK_INTEGRITY;
|
||||
|
||||
|
||||
+1
-1
@@ -953,7 +953,7 @@ bool bvec_try_merge_hw_page(struct request_queue *q, struct bio_vec *bv,
|
||||
bool *same_page)
|
||||
{
|
||||
unsigned long mask = queue_segment_boundary(q);
|
||||
phys_addr_t addr1 = page_to_phys(bv->bv_page) + bv->bv_offset;
|
||||
phys_addr_t addr1 = bvec_phys(bv);
|
||||
phys_addr_t addr2 = page_to_phys(page) + offset + len - 1;
|
||||
|
||||
if ((addr1 | mask) != (addr2 | mask))
|
||||
|
||||
@@ -300,19 +300,6 @@ static inline struct blkcg *cpd_to_blkcg(struct blkcg_policy_data *cpd)
|
||||
return cpd ? cpd->blkcg : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* blkg_path - format cgroup path of blkg
|
||||
* @blkg: blkg of interest
|
||||
* @buf: target buffer
|
||||
* @buflen: target buffer length
|
||||
*
|
||||
* Format the path of the cgroup of @blkg into @buf.
|
||||
*/
|
||||
static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen)
|
||||
{
|
||||
return cgroup_path(blkg->blkcg->css.cgroup, buf, buflen);
|
||||
}
|
||||
|
||||
/**
|
||||
* blkg_get - get a blkg reference
|
||||
* @blkg: blkg to get
|
||||
|
||||
+23
-22
@@ -94,20 +94,6 @@ void blk_queue_flag_clear(unsigned int flag, struct request_queue *q)
|
||||
}
|
||||
EXPORT_SYMBOL(blk_queue_flag_clear);
|
||||
|
||||
/**
|
||||
* blk_queue_flag_test_and_set - atomically test and set a queue flag
|
||||
* @flag: flag to be set
|
||||
* @q: request queue
|
||||
*
|
||||
* Returns the previous value of @flag - 0 if the flag was not set and 1 if
|
||||
* the flag was already set.
|
||||
*/
|
||||
bool blk_queue_flag_test_and_set(unsigned int flag, struct request_queue *q)
|
||||
{
|
||||
return test_and_set_bit(flag, &q->queue_flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blk_queue_flag_test_and_set);
|
||||
|
||||
#define REQ_OP_NAME(name) [REQ_OP_##name] = #name
|
||||
static const char *const blk_op_name[] = {
|
||||
REQ_OP_NAME(READ),
|
||||
@@ -174,6 +160,8 @@ static const struct {
|
||||
/* Command duration limit device-side timeout */
|
||||
[BLK_STS_DURATION_LIMIT] = { -ETIME, "duration limit exceeded" },
|
||||
|
||||
[BLK_STS_INVAL] = { -EINVAL, "invalid" },
|
||||
|
||||
/* everything else not covered above: */
|
||||
[BLK_STS_IOERR] = { -EIO, "I/O" },
|
||||
};
|
||||
@@ -739,6 +727,18 @@ void submit_bio_noacct_nocheck(struct bio *bio)
|
||||
__submit_bio_noacct(bio);
|
||||
}
|
||||
|
||||
static blk_status_t blk_validate_atomic_write_op_size(struct request_queue *q,
|
||||
struct bio *bio)
|
||||
{
|
||||
if (bio->bi_iter.bi_size > queue_atomic_write_unit_max_bytes(q))
|
||||
return BLK_STS_INVAL;
|
||||
|
||||
if (bio->bi_iter.bi_size % queue_atomic_write_unit_min_bytes(q))
|
||||
return BLK_STS_INVAL;
|
||||
|
||||
return BLK_STS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -782,7 +782,7 @@ void submit_bio_noacct(struct bio *bio)
|
||||
if (WARN_ON_ONCE(bio_op(bio) != REQ_OP_WRITE &&
|
||||
bio_op(bio) != REQ_OP_ZONE_APPEND))
|
||||
goto end_io;
|
||||
if (!test_bit(QUEUE_FLAG_WC, &q->queue_flags)) {
|
||||
if (!bdev_write_cache(bdev)) {
|
||||
bio->bi_opf &= ~(REQ_PREFLUSH | REQ_FUA);
|
||||
if (!bio_sectors(bio)) {
|
||||
status = BLK_STS_OK;
|
||||
@@ -791,12 +791,17 @@ void submit_bio_noacct(struct bio *bio)
|
||||
}
|
||||
}
|
||||
|
||||
if (!test_bit(QUEUE_FLAG_POLL, &q->queue_flags))
|
||||
if (!(q->limits.features & BLK_FEAT_POLL))
|
||||
bio_clear_polled(bio);
|
||||
|
||||
switch (bio_op(bio)) {
|
||||
case REQ_OP_READ:
|
||||
case REQ_OP_WRITE:
|
||||
if (bio->bi_opf & REQ_ATOMIC) {
|
||||
status = blk_validate_atomic_write_op_size(q, bio);
|
||||
if (status != BLK_STS_OK)
|
||||
goto end_io;
|
||||
}
|
||||
break;
|
||||
case REQ_OP_FLUSH:
|
||||
/*
|
||||
@@ -825,11 +830,8 @@ void submit_bio_noacct(struct bio *bio)
|
||||
case REQ_OP_ZONE_OPEN:
|
||||
case REQ_OP_ZONE_CLOSE:
|
||||
case REQ_OP_ZONE_FINISH:
|
||||
if (!bdev_is_zoned(bio->bi_bdev))
|
||||
goto not_supported;
|
||||
break;
|
||||
case REQ_OP_ZONE_RESET_ALL:
|
||||
if (!bdev_is_zoned(bio->bi_bdev) || !blk_queue_zone_resetall(q))
|
||||
if (!bdev_is_zoned(bio->bi_bdev))
|
||||
goto not_supported;
|
||||
break;
|
||||
case REQ_OP_DRV_IN:
|
||||
@@ -915,8 +917,7 @@ int bio_poll(struct bio *bio, struct io_comp_batch *iob, unsigned int flags)
|
||||
return 0;
|
||||
|
||||
q = bdev_get_queue(bdev);
|
||||
if (cookie == BLK_QC_T_NONE ||
|
||||
!test_bit(QUEUE_FLAG_POLL, &q->queue_flags))
|
||||
if (cookie == BLK_QC_T_NONE || !(q->limits.features & BLK_FEAT_POLL))
|
||||
return 0;
|
||||
|
||||
blk_flush_plug(current->plug, false);
|
||||
|
||||
+16
-20
@@ -100,23 +100,6 @@ blk_get_flush_queue(struct request_queue *q, struct blk_mq_ctx *ctx)
|
||||
return blk_mq_map_queue(q, REQ_OP_FLUSH, ctx)->fq;
|
||||
}
|
||||
|
||||
static unsigned int blk_flush_policy(unsigned long fflags, struct request *rq)
|
||||
{
|
||||
unsigned int policy = 0;
|
||||
|
||||
if (blk_rq_sectors(rq))
|
||||
policy |= REQ_FSEQ_DATA;
|
||||
|
||||
if (fflags & (1UL << QUEUE_FLAG_WC)) {
|
||||
if (rq->cmd_flags & REQ_PREFLUSH)
|
||||
policy |= REQ_FSEQ_PREFLUSH;
|
||||
if (!(fflags & (1UL << QUEUE_FLAG_FUA)) &&
|
||||
(rq->cmd_flags & REQ_FUA))
|
||||
policy |= REQ_FSEQ_POSTFLUSH;
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
|
||||
static unsigned int blk_flush_cur_seq(struct request *rq)
|
||||
{
|
||||
return 1 << ffz(rq->flush.seq);
|
||||
@@ -399,19 +382,32 @@ static void blk_rq_init_flush(struct request *rq)
|
||||
bool blk_insert_flush(struct request *rq)
|
||||
{
|
||||
struct request_queue *q = rq->q;
|
||||
unsigned long fflags = q->queue_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);
|
||||
bool supports_fua = q->limits.features & BLK_FEAT_FUA;
|
||||
unsigned int policy = 0;
|
||||
|
||||
/* FLUSH/FUA request must never be merged */
|
||||
WARN_ON_ONCE(rq->bio != rq->biotail);
|
||||
|
||||
if (blk_rq_sectors(rq))
|
||||
policy |= REQ_FSEQ_DATA;
|
||||
|
||||
/*
|
||||
* Check which flushes we need to sequence for this operation.
|
||||
*/
|
||||
if (blk_queue_write_cache(q)) {
|
||||
if (rq->cmd_flags & REQ_PREFLUSH)
|
||||
policy |= REQ_FSEQ_PREFLUSH;
|
||||
if ((rq->cmd_flags & REQ_FUA) && !supports_fua)
|
||||
policy |= REQ_FSEQ_POSTFLUSH;
|
||||
}
|
||||
|
||||
/*
|
||||
* @policy now records what operations need to be done. Adjust
|
||||
* REQ_PREFLUSH and FUA for the driver.
|
||||
*/
|
||||
rq->cmd_flags &= ~REQ_PREFLUSH;
|
||||
if (!(fflags & (1UL << QUEUE_FLAG_FUA)))
|
||||
if (!supports_fua)
|
||||
rq->cmd_flags &= ~REQ_FUA;
|
||||
|
||||
/*
|
||||
|
||||
+65
-163
@@ -107,60 +107,6 @@ new_segment:
|
||||
}
|
||||
EXPORT_SYMBOL(blk_rq_map_integrity_sg);
|
||||
|
||||
/**
|
||||
* blk_integrity_compare - Compare integrity profile of two disks
|
||||
* @gd1: Disk to compare
|
||||
* @gd2: Disk to compare
|
||||
*
|
||||
* Description: Meta-devices like DM and MD need to verify that all
|
||||
* sub-devices use the same integrity format before advertising to
|
||||
* upper layers that they can send/receive integrity metadata. This
|
||||
* function can be used to check whether two gendisk devices have
|
||||
* compatible integrity formats.
|
||||
*/
|
||||
int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
|
||||
{
|
||||
struct blk_integrity *b1 = &gd1->queue->integrity;
|
||||
struct blk_integrity *b2 = &gd2->queue->integrity;
|
||||
|
||||
if (!b1->profile && !b2->profile)
|
||||
return 0;
|
||||
|
||||
if (!b1->profile || !b2->profile)
|
||||
return -1;
|
||||
|
||||
if (b1->interval_exp != b2->interval_exp) {
|
||||
pr_err("%s: %s/%s protection interval %u != %u\n",
|
||||
__func__, gd1->disk_name, gd2->disk_name,
|
||||
1 << b1->interval_exp, 1 << b2->interval_exp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (b1->tuple_size != b2->tuple_size) {
|
||||
pr_err("%s: %s/%s tuple sz %u != %u\n", __func__,
|
||||
gd1->disk_name, gd2->disk_name,
|
||||
b1->tuple_size, b2->tuple_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) {
|
||||
pr_err("%s: %s/%s tag sz %u != %u\n", __func__,
|
||||
gd1->disk_name, gd2->disk_name,
|
||||
b1->tag_size, b2->tag_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (b1->profile != b2->profile) {
|
||||
pr_err("%s: %s/%s type %s != %s\n", __func__,
|
||||
gd1->disk_name, gd2->disk_name,
|
||||
b1->profile->name, b2->profile->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_integrity_compare);
|
||||
|
||||
bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
|
||||
struct request *next)
|
||||
{
|
||||
@@ -214,7 +160,64 @@ bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
|
||||
|
||||
static inline struct blk_integrity *dev_to_bi(struct device *dev)
|
||||
{
|
||||
return &dev_to_disk(dev)->queue->integrity;
|
||||
return &dev_to_disk(dev)->queue->limits.integrity;
|
||||
}
|
||||
|
||||
const char *blk_integrity_profile_name(struct blk_integrity *bi)
|
||||
{
|
||||
switch (bi->csum_type) {
|
||||
case BLK_INTEGRITY_CSUM_IP:
|
||||
if (bi->flags & BLK_INTEGRITY_REF_TAG)
|
||||
return "T10-DIF-TYPE1-IP";
|
||||
return "T10-DIF-TYPE3-IP";
|
||||
case BLK_INTEGRITY_CSUM_CRC:
|
||||
if (bi->flags & BLK_INTEGRITY_REF_TAG)
|
||||
return "T10-DIF-TYPE1-CRC";
|
||||
return "T10-DIF-TYPE3-CRC";
|
||||
case BLK_INTEGRITY_CSUM_CRC64:
|
||||
if (bi->flags & BLK_INTEGRITY_REF_TAG)
|
||||
return "EXT-DIF-TYPE1-CRC64";
|
||||
return "EXT-DIF-TYPE3-CRC64";
|
||||
case BLK_INTEGRITY_CSUM_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
return "nop";
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blk_integrity_profile_name);
|
||||
|
||||
static ssize_t flag_store(struct device *dev, const char *page, size_t count,
|
||||
unsigned char flag)
|
||||
{
|
||||
struct request_queue *q = dev_to_disk(dev)->queue;
|
||||
struct queue_limits lim;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(page, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* note that the flags are inverted vs the values in the sysfs files */
|
||||
lim = queue_limits_start_update(q);
|
||||
if (val)
|
||||
lim.integrity.flags &= ~flag;
|
||||
else
|
||||
lim.integrity.flags |= flag;
|
||||
|
||||
blk_mq_freeze_queue(q);
|
||||
err = queue_limits_commit_update(q, &lim);
|
||||
blk_mq_unfreeze_queue(q);
|
||||
if (err)
|
||||
return err;
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t flag_show(struct device *dev, char *page, unsigned char flag)
|
||||
{
|
||||
struct blk_integrity *bi = dev_to_bi(dev);
|
||||
|
||||
return sysfs_emit(page, "%d\n", !(bi->flags & flag));
|
||||
}
|
||||
|
||||
static ssize_t format_show(struct device *dev, struct device_attribute *attr,
|
||||
@@ -222,9 +225,9 @@ static ssize_t format_show(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct blk_integrity *bi = dev_to_bi(dev);
|
||||
|
||||
if (bi->profile && bi->profile->name)
|
||||
return sysfs_emit(page, "%s\n", bi->profile->name);
|
||||
return sysfs_emit(page, "none\n");
|
||||
if (!bi->tuple_size)
|
||||
return sysfs_emit(page, "none\n");
|
||||
return sysfs_emit(page, "%s\n", blk_integrity_profile_name(bi));
|
||||
}
|
||||
|
||||
static ssize_t tag_size_show(struct device *dev, struct device_attribute *attr,
|
||||
@@ -249,49 +252,26 @@ static ssize_t read_verify_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *page, size_t count)
|
||||
{
|
||||
struct blk_integrity *bi = dev_to_bi(dev);
|
||||
char *p = (char *) page;
|
||||
unsigned long val = simple_strtoul(p, &p, 10);
|
||||
|
||||
if (val)
|
||||
bi->flags |= BLK_INTEGRITY_VERIFY;
|
||||
else
|
||||
bi->flags &= ~BLK_INTEGRITY_VERIFY;
|
||||
|
||||
return count;
|
||||
return flag_store(dev, page, count, BLK_INTEGRITY_NOVERIFY);
|
||||
}
|
||||
|
||||
static ssize_t read_verify_show(struct device *dev,
|
||||
struct device_attribute *attr, char *page)
|
||||
{
|
||||
struct blk_integrity *bi = dev_to_bi(dev);
|
||||
|
||||
return sysfs_emit(page, "%d\n", !!(bi->flags & BLK_INTEGRITY_VERIFY));
|
||||
return flag_show(dev, page, BLK_INTEGRITY_NOVERIFY);
|
||||
}
|
||||
|
||||
static ssize_t write_generate_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *page, size_t count)
|
||||
{
|
||||
struct blk_integrity *bi = dev_to_bi(dev);
|
||||
|
||||
char *p = (char *) page;
|
||||
unsigned long val = simple_strtoul(p, &p, 10);
|
||||
|
||||
if (val)
|
||||
bi->flags |= BLK_INTEGRITY_GENERATE;
|
||||
else
|
||||
bi->flags &= ~BLK_INTEGRITY_GENERATE;
|
||||
|
||||
return count;
|
||||
return flag_store(dev, page, count, BLK_INTEGRITY_NOGENERATE);
|
||||
}
|
||||
|
||||
static ssize_t write_generate_show(struct device *dev,
|
||||
struct device_attribute *attr, char *page)
|
||||
{
|
||||
struct blk_integrity *bi = dev_to_bi(dev);
|
||||
|
||||
return sysfs_emit(page, "%d\n", !!(bi->flags & BLK_INTEGRITY_GENERATE));
|
||||
return flag_show(dev, page, BLK_INTEGRITY_NOGENERATE);
|
||||
}
|
||||
|
||||
static ssize_t device_is_integrity_capable_show(struct device *dev,
|
||||
@@ -325,81 +305,3 @@ const struct attribute_group blk_integrity_attr_group = {
|
||||
.name = "integrity",
|
||||
.attrs = integrity_attrs,
|
||||
};
|
||||
|
||||
static blk_status_t blk_integrity_nop_fn(struct blk_integrity_iter *iter)
|
||||
{
|
||||
return BLK_STS_OK;
|
||||
}
|
||||
|
||||
static void blk_integrity_nop_prepare(struct request *rq)
|
||||
{
|
||||
}
|
||||
|
||||
static void blk_integrity_nop_complete(struct request *rq,
|
||||
unsigned int nr_bytes)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct blk_integrity_profile nop_profile = {
|
||||
.name = "nop",
|
||||
.generate_fn = blk_integrity_nop_fn,
|
||||
.verify_fn = blk_integrity_nop_fn,
|
||||
.prepare_fn = blk_integrity_nop_prepare,
|
||||
.complete_fn = blk_integrity_nop_complete,
|
||||
};
|
||||
|
||||
/**
|
||||
* blk_integrity_register - Register a gendisk as being integrity-capable
|
||||
* @disk: struct gendisk pointer to make integrity-aware
|
||||
* @template: block integrity profile to register
|
||||
*
|
||||
* Description: When a device needs to advertise itself as being able to
|
||||
* send/receive integrity metadata it must use this function to register
|
||||
* the capability with the block layer. The template is a blk_integrity
|
||||
* struct with values appropriate for the underlying hardware. See
|
||||
* Documentation/block/data-integrity.rst.
|
||||
*/
|
||||
void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
|
||||
{
|
||||
struct blk_integrity *bi = &disk->queue->integrity;
|
||||
|
||||
bi->flags = BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE |
|
||||
template->flags;
|
||||
bi->interval_exp = template->interval_exp ? :
|
||||
ilog2(queue_logical_block_size(disk->queue));
|
||||
bi->profile = template->profile ? template->profile : &nop_profile;
|
||||
bi->tuple_size = template->tuple_size;
|
||||
bi->tag_size = template->tag_size;
|
||||
bi->pi_offset = template->pi_offset;
|
||||
|
||||
blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, disk->queue);
|
||||
|
||||
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
|
||||
if (disk->queue->crypto_profile) {
|
||||
pr_warn("blk-integrity: Integrity and hardware inline encryption are not supported together. Disabling hardware inline encryption.\n");
|
||||
disk->queue->crypto_profile = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(blk_integrity_register);
|
||||
|
||||
/**
|
||||
* blk_integrity_unregister - Unregister block integrity profile
|
||||
* @disk: disk whose integrity profile to unregister
|
||||
*
|
||||
* Description: This function unregisters the integrity capability from
|
||||
* a block device.
|
||||
*/
|
||||
void blk_integrity_unregister(struct gendisk *disk)
|
||||
{
|
||||
struct blk_integrity *bi = &disk->queue->integrity;
|
||||
|
||||
if (!bi->profile)
|
||||
return;
|
||||
|
||||
/* ensure all bios are off the integrity workqueue */
|
||||
blk_flush_integrity();
|
||||
blk_queue_flag_clear(QUEUE_FLAG_STABLE_WRITES, disk->queue);
|
||||
memset(bi, 0, sizeof(*bi));
|
||||
}
|
||||
EXPORT_SYMBOL(blk_integrity_unregister);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user