Skip to content

Commit c6e56cf

Browse files
Christoph Hellwigaxboe
authored andcommitted
block: move integrity information into queue_limits
Move the integrity information into the queue limits so that it can be set atomically with other queue limits, and that the sysfs changes to the read_verify and write_generate flags are properly synchronized. This also allows to provide a more useful helper to stack the integrity fields, although it still is separate from the main stacking function as not all stackable devices want to inherit the integrity settings. Even with that it greatly simplifies the code in md and dm. Note that the integrity field is moved as-is into the queue limits. While there are good arguments for removing the separate blk_integrity structure, this would cause a lot of churn and might better be done at a later time if desired. However the integrity field in the queue_limits structure is now unconditional so that various ifdefs can be avoided or replaced with IS_ENABLED(). Given that tiny size of it that seems like a worthwhile trade off. Signed-off-by: Christoph Hellwig <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Reviewed-by: Martin K. Petersen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 9f4aa46 commit c6e56cf

File tree

21 files changed

+289
-497
lines changed

21 files changed

+289
-497
lines changed

Documentation/block/data-integrity.rst

Lines changed: 3 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -153,18 +153,11 @@ bio_free() will automatically free the bip.
153153
4.2 Block Device
154154
----------------
155155

156-
Because the format of the protection data is tied to the physical
157-
disk, each block device has been extended with a block integrity
158-
profile (struct blk_integrity). This optional profile is registered
159-
with the block layer using blk_integrity_register().
160-
161-
The profile contains callback functions for generating and verifying
162-
the protection data, as well as getting and setting application tags.
163-
The profile also contains a few constants to aid in completing,
164-
merging and splitting the integrity metadata.
156+
Block devices can set up the integrity information in the integrity
157+
sub-struture of the queue_limits structure.
165158

166159
Layered block devices will need to pick a profile that's appropriate
167-
for all subdevices. blk_integrity_compare() can help with that. DM
160+
for all subdevices. queue_limits_stack_integrity() can help with that. DM
168161
and MD linear, RAID0 and RAID1 are currently supported. RAID4/5/6
169162
will require extra work due to the application tag.
170163

@@ -250,42 +243,6 @@ will require extra work due to the application tag.
250243
integrity upon completion.
251244

252245

253-
5.4 Registering A Block Device As Capable Of Exchanging Integrity Metadata
254-
--------------------------------------------------------------------------
255-
256-
To enable integrity exchange on a block device the gendisk must be
257-
registered as capable:
258-
259-
`int blk_integrity_register(gendisk, blk_integrity);`
260-
261-
The blk_integrity struct is a template and should contain the
262-
following::
263-
264-
static struct blk_integrity my_profile = {
265-
.name = "STANDARDSBODY-TYPE-VARIANT-CSUM",
266-
.generate_fn = my_generate_fn,
267-
.verify_fn = my_verify_fn,
268-
.tuple_size = sizeof(struct my_tuple_size),
269-
.tag_size = <tag bytes per hw sector>,
270-
};
271-
272-
'name' is a text string which will be visible in sysfs. This is
273-
part of the userland API so chose it carefully and never change
274-
it. The format is standards body-type-variant.
275-
E.g. T10-DIF-TYPE1-IP or T13-EPP-0-CRC.
276-
277-
'generate_fn' generates appropriate integrity metadata (for WRITE).
278-
279-
'verify_fn' verifies that the data buffer matches the integrity
280-
metadata.
281-
282-
'tuple_size' must be set to match the size of the integrity
283-
metadata per sector. I.e. 8 for DIF and EPP.
284-
285-
'tag_size' must be set to identify how many bytes of tag space
286-
are available per hardware sector. For DIF this is either 2 or
287-
0 depending on the value of the Control Mode Page ATO bit.
288-
289246
----------------------------------------------------------------------
290247

291248
2007-12-24 Martin K. Petersen <[email protected]>

block/blk-integrity.c

Lines changed: 13 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -107,63 +107,6 @@ int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio,
107107
}
108108
EXPORT_SYMBOL(blk_rq_map_integrity_sg);
109109

110-
/**
111-
* blk_integrity_compare - Compare integrity profile of two disks
112-
* @gd1: Disk to compare
113-
* @gd2: Disk to compare
114-
*
115-
* Description: Meta-devices like DM and MD need to verify that all
116-
* sub-devices use the same integrity format before advertising to
117-
* upper layers that they can send/receive integrity metadata. This
118-
* function can be used to check whether two gendisk devices have
119-
* compatible integrity formats.
120-
*/
121-
int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
122-
{
123-
struct blk_integrity *b1 = &gd1->queue->integrity;
124-
struct blk_integrity *b2 = &gd2->queue->integrity;
125-
126-
if (!b1->tuple_size && !b2->tuple_size)
127-
return 0;
128-
129-
if (!b1->tuple_size || !b2->tuple_size)
130-
return -1;
131-
132-
if (b1->interval_exp != b2->interval_exp) {
133-
pr_err("%s: %s/%s protection interval %u != %u\n",
134-
__func__, gd1->disk_name, gd2->disk_name,
135-
1 << b1->interval_exp, 1 << b2->interval_exp);
136-
return -1;
137-
}
138-
139-
if (b1->tuple_size != b2->tuple_size) {
140-
pr_err("%s: %s/%s tuple sz %u != %u\n", __func__,
141-
gd1->disk_name, gd2->disk_name,
142-
b1->tuple_size, b2->tuple_size);
143-
return -1;
144-
}
145-
146-
if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) {
147-
pr_err("%s: %s/%s tag sz %u != %u\n", __func__,
148-
gd1->disk_name, gd2->disk_name,
149-
b1->tag_size, b2->tag_size);
150-
return -1;
151-
}
152-
153-
if (b1->csum_type != b2->csum_type ||
154-
(b1->flags & BLK_INTEGRITY_REF_TAG) !=
155-
(b2->flags & BLK_INTEGRITY_REF_TAG)) {
156-
pr_err("%s: %s/%s type %s != %s\n", __func__,
157-
gd1->disk_name, gd2->disk_name,
158-
blk_integrity_profile_name(b1),
159-
blk_integrity_profile_name(b2));
160-
return -1;
161-
}
162-
163-
return 0;
164-
}
165-
EXPORT_SYMBOL(blk_integrity_compare);
166-
167110
bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
168111
struct request *next)
169112
{
@@ -217,7 +160,7 @@ bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
217160

218161
static inline struct blk_integrity *dev_to_bi(struct device *dev)
219162
{
220-
return &dev_to_disk(dev)->queue->integrity;
163+
return &dev_to_disk(dev)->queue->limits.integrity;
221164
}
222165

223166
const char *blk_integrity_profile_name(struct blk_integrity *bi)
@@ -246,19 +189,27 @@ EXPORT_SYMBOL_GPL(blk_integrity_profile_name);
246189
static ssize_t flag_store(struct device *dev, struct device_attribute *attr,
247190
const char *page, size_t count, unsigned char flag)
248191
{
249-
struct blk_integrity *bi = dev_to_bi(dev);
192+
struct request_queue *q = dev_to_disk(dev)->queue;
193+
struct queue_limits lim;
250194
unsigned long val;
251195
int err;
252196

253197
err = kstrtoul(page, 10, &val);
254198
if (err)
255199
return err;
256200

257-
/* the flags are inverted vs the values in the sysfs files */
201+
/* note that the flags are inverted vs the values in the sysfs files */
202+
lim = queue_limits_start_update(q);
258203
if (val)
259-
bi->flags &= ~flag;
204+
lim.integrity.flags &= ~flag;
260205
else
261-
bi->flags |= flag;
206+
lim.integrity.flags |= flag;
207+
208+
blk_mq_freeze_queue(q);
209+
err = queue_limits_commit_update(q, &lim);
210+
blk_mq_unfreeze_queue(q);
211+
if (err)
212+
return err;
262213
return count;
263214
}
264215

@@ -355,52 +306,3 @@ const struct attribute_group blk_integrity_attr_group = {
355306
.name = "integrity",
356307
.attrs = integrity_attrs,
357308
};
358-
359-
/**
360-
* blk_integrity_register - Register a gendisk as being integrity-capable
361-
* @disk: struct gendisk pointer to make integrity-aware
362-
* @template: block integrity profile to register
363-
*
364-
* Description: When a device needs to advertise itself as being able to
365-
* send/receive integrity metadata it must use this function to register
366-
* the capability with the block layer. The template is a blk_integrity
367-
* struct with values appropriate for the underlying hardware. See
368-
* Documentation/block/data-integrity.rst.
369-
*/
370-
void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
371-
{
372-
struct blk_integrity *bi = &disk->queue->integrity;
373-
374-
bi->csum_type = template->csum_type;
375-
bi->flags = template->flags;
376-
bi->interval_exp = template->interval_exp ? :
377-
ilog2(queue_logical_block_size(disk->queue));
378-
bi->tuple_size = template->tuple_size;
379-
bi->tag_size = template->tag_size;
380-
bi->pi_offset = template->pi_offset;
381-
382-
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
383-
if (disk->queue->crypto_profile) {
384-
pr_warn("blk-integrity: Integrity and hardware inline encryption are not supported together. Disabling hardware inline encryption.\n");
385-
disk->queue->crypto_profile = NULL;
386-
}
387-
#endif
388-
}
389-
EXPORT_SYMBOL(blk_integrity_register);
390-
391-
/**
392-
* blk_integrity_unregister - Unregister block integrity profile
393-
* @disk: disk whose integrity profile to unregister
394-
*
395-
* Description: This function unregisters the integrity capability from
396-
* a block device.
397-
*/
398-
void blk_integrity_unregister(struct gendisk *disk)
399-
{
400-
struct blk_integrity *bi = &disk->queue->integrity;
401-
402-
if (!bi->tuple_size)
403-
return;
404-
memset(bi, 0, sizeof(*bi));
405-
}
406-
EXPORT_SYMBOL(blk_integrity_unregister);

block/blk-settings.c

Lines changed: 112 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include <linux/module.h>
77
#include <linux/init.h>
88
#include <linux/bio.h>
9-
#include <linux/blkdev.h>
9+
#include <linux/blk-integrity.h>
1010
#include <linux/pagemap.h>
1111
#include <linux/backing-dev-defs.h>
1212
#include <linux/gcd.h>
@@ -97,6 +97,36 @@ static int blk_validate_zoned_limits(struct queue_limits *lim)
9797
return 0;
9898
}
9999

100+
static int blk_validate_integrity_limits(struct queue_limits *lim)
101+
{
102+
struct blk_integrity *bi = &lim->integrity;
103+
104+
if (!bi->tuple_size) {
105+
if (bi->csum_type != BLK_INTEGRITY_CSUM_NONE ||
106+
bi->tag_size || ((bi->flags & BLK_INTEGRITY_REF_TAG))) {
107+
pr_warn("invalid PI settings.\n");
108+
return -EINVAL;
109+
}
110+
return 0;
111+
}
112+
113+
if (!IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY)) {
114+
pr_warn("integrity support disabled.\n");
115+
return -EINVAL;
116+
}
117+
118+
if (bi->csum_type == BLK_INTEGRITY_CSUM_NONE &&
119+
(bi->flags & BLK_INTEGRITY_REF_TAG)) {
120+
pr_warn("ref tag not support without checksum.\n");
121+
return -EINVAL;
122+
}
123+
124+
if (!bi->interval_exp)
125+
bi->interval_exp = ilog2(lim->logical_block_size);
126+
127+
return 0;
128+
}
129+
100130
/*
101131
* Check that the limits in lim are valid, initialize defaults for unset
102132
* values, and cap values based on others where needed.
@@ -105,6 +135,7 @@ static int blk_validate_limits(struct queue_limits *lim)
105135
{
106136
unsigned int max_hw_sectors;
107137
unsigned int logical_block_sectors;
138+
int err;
108139

109140
/*
110141
* Unless otherwise specified, default to 512 byte logical blocks and a
@@ -230,6 +261,9 @@ static int blk_validate_limits(struct queue_limits *lim)
230261
lim->misaligned = 0;
231262
}
232263

264+
err = blk_validate_integrity_limits(lim);
265+
if (err)
266+
return err;
233267
return blk_validate_zoned_limits(lim);
234268
}
235269

@@ -263,13 +297,24 @@ int queue_limits_commit_update(struct request_queue *q,
263297
struct queue_limits *lim)
264298
__releases(q->limits_lock)
265299
{
266-
int error = blk_validate_limits(lim);
300+
int error;
267301

268-
if (!error) {
269-
q->limits = *lim;
270-
if (q->disk)
271-
blk_apply_bdi_limits(q->disk->bdi, lim);
302+
error = blk_validate_limits(lim);
303+
if (error)
304+
goto out_unlock;
305+
306+
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
307+
if (q->crypto_profile && lim->integrity.tag_size) {
308+
pr_warn("blk-integrity: Integrity and hardware inline encryption are not supported together.\n");
309+
error = -EINVAL;
310+
goto out_unlock;
272311
}
312+
#endif
313+
314+
q->limits = *lim;
315+
if (q->disk)
316+
blk_apply_bdi_limits(q->disk->bdi, lim);
317+
out_unlock:
273318
mutex_unlock(&q->limits_lock);
274319
return error;
275320
}
@@ -575,6 +620,67 @@ void queue_limits_stack_bdev(struct queue_limits *t, struct block_device *bdev,
575620
}
576621
EXPORT_SYMBOL_GPL(queue_limits_stack_bdev);
577622

623+
/**
624+
* queue_limits_stack_integrity - stack integrity profile
625+
* @t: target queue limits
626+
* @b: base queue limits
627+
*
628+
* Check if the integrity profile in the @b can be stacked into the
629+
* target @t. Stacking is possible if either:
630+
*
631+
* a) does not have any integrity information stacked into it yet
632+
* b) the integrity profile in @b is identical to the one in @t
633+
*
634+
* If @b can be stacked into @t, return %true. Else return %false and clear the
635+
* integrity information in @t.
636+
*/
637+
bool queue_limits_stack_integrity(struct queue_limits *t,
638+
struct queue_limits *b)
639+
{
640+
struct blk_integrity *ti = &t->integrity;
641+
struct blk_integrity *bi = &b->integrity;
642+
643+
if (!IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY))
644+
return true;
645+
646+
if (!ti->tuple_size) {
647+
/* inherit the settings from the first underlying device */
648+
if (!(ti->flags & BLK_INTEGRITY_STACKED)) {
649+
ti->flags = BLK_INTEGRITY_DEVICE_CAPABLE |
650+
(bi->flags & BLK_INTEGRITY_REF_TAG);
651+
ti->csum_type = bi->csum_type;
652+
ti->tuple_size = bi->tuple_size;
653+
ti->pi_offset = bi->pi_offset;
654+
ti->interval_exp = bi->interval_exp;
655+
ti->tag_size = bi->tag_size;
656+
goto done;
657+
}
658+
if (!bi->tuple_size)
659+
goto done;
660+
}
661+
662+
if (ti->tuple_size != bi->tuple_size)
663+
goto incompatible;
664+
if (ti->interval_exp != bi->interval_exp)
665+
goto incompatible;
666+
if (ti->tag_size != bi->tag_size)
667+
goto incompatible;
668+
if (ti->csum_type != bi->csum_type)
669+
goto incompatible;
670+
if ((ti->flags & BLK_INTEGRITY_REF_TAG) !=
671+
(bi->flags & BLK_INTEGRITY_REF_TAG))
672+
goto incompatible;
673+
674+
done:
675+
ti->flags |= BLK_INTEGRITY_STACKED;
676+
return true;
677+
678+
incompatible:
679+
memset(ti, 0, sizeof(*ti));
680+
return false;
681+
}
682+
EXPORT_SYMBOL_GPL(queue_limits_stack_integrity);
683+
578684
/**
579685
* blk_queue_update_dma_pad - update pad mask
580686
* @q: the request queue for the device

0 commit comments

Comments
 (0)