Skip to content

Commit e516791

Browse files
Christoph Hellwigaxboe
authored andcommitted
block: move the block layer auto-integrity code into a new file
The code that automatically creates a integrity payload and generates and verifies the checksums for bios that don't have submitter-provided integrity payload currently sits right in the middle of the block integrity metadata infrastructure. Split it into a separate file to make the different layers clear. Signed-off-by: Christoph Hellwig <[email protected]> Reviewed-by: Anuj Gupta <[email protected]> Reviewed-by: Kanchan Joshi <[email protected]> Reviewed-by: Martin K. Petersen <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Reviewed-by: Johannes Thumshirn <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 5fd0268 commit e516791

File tree

3 files changed

+164
-160
lines changed

3 files changed

+164
-160
lines changed

block/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ obj-$(CONFIG_MQ_IOSCHED_KYBER) += kyber-iosched.o
2626
bfq-y := bfq-iosched.o bfq-wf2q.o bfq-cgroup.o
2727
obj-$(CONFIG_IOSCHED_BFQ) += bfq.o
2828

29-
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o t10-pi.o
29+
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o t10-pi.o \
30+
bio-integrity-auto.o
3031
obj-$(CONFIG_BLK_DEV_ZONED) += blk-zoned.o
3132
obj-$(CONFIG_BLK_WBT) += blk-wbt.o
3233
obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o

block/bio-integrity-auto.c

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2007, 2008, 2009 Oracle Corporation
4+
* Written by: Martin K. Petersen <[email protected]>
5+
*
6+
* Automatically generate and verify integrity data on PI capable devices if the
7+
* bio submitter didn't provide PI itself. This ensures that kernel verifies
8+
* data integrity even if the file system (or other user of the block device) is
9+
* not aware of PI.
10+
*/
11+
#include <linux/blk-integrity.h>
12+
#include <linux/workqueue.h>
13+
#include "blk.h"
14+
15+
static struct workqueue_struct *kintegrityd_wq;
16+
17+
static void bio_integrity_verify_fn(struct work_struct *work)
18+
{
19+
struct bio_integrity_payload *bip =
20+
container_of(work, struct bio_integrity_payload, bip_work);
21+
struct bio *bio = bip->bip_bio;
22+
23+
blk_integrity_verify(bio);
24+
25+
kfree(bvec_virt(bip->bip_vec));
26+
bio_integrity_free(bio);
27+
bio_endio(bio);
28+
}
29+
30+
/**
31+
* __bio_integrity_endio - Integrity I/O completion function
32+
* @bio: Protected bio
33+
*
34+
* Normally I/O completion is done in interrupt context. However, verifying I/O
35+
* integrity is a time-consuming task which must be run in process context.
36+
*
37+
* This function postpones completion accordingly.
38+
*/
39+
bool __bio_integrity_endio(struct bio *bio)
40+
{
41+
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
42+
struct bio_integrity_payload *bip = bio_integrity(bio);
43+
44+
if (bio_op(bio) == REQ_OP_READ && !bio->bi_status && bi->csum_type) {
45+
INIT_WORK(&bip->bip_work, bio_integrity_verify_fn);
46+
queue_work(kintegrityd_wq, &bip->bip_work);
47+
return false;
48+
}
49+
50+
kfree(bvec_virt(bip->bip_vec));
51+
bio_integrity_free(bio);
52+
return true;
53+
}
54+
55+
/**
56+
* bio_integrity_prep - Prepare bio for integrity I/O
57+
* @bio: bio to prepare
58+
*
59+
* Checks if the bio already has an integrity payload attached. If it does, the
60+
* payload has been generated by another kernel subsystem, and we just pass it
61+
* through.
62+
* Otherwise allocates integrity payload and for writes the integrity metadata
63+
* will be generated. For reads, the completion handler will verify the
64+
* metadata.
65+
*/
66+
bool bio_integrity_prep(struct bio *bio)
67+
{
68+
struct bio_integrity_payload *bip;
69+
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
70+
gfp_t gfp = GFP_NOIO;
71+
unsigned int len;
72+
void *buf;
73+
74+
if (!bi)
75+
return true;
76+
77+
if (!bio_sectors(bio))
78+
return true;
79+
80+
/* Already protected? */
81+
if (bio_integrity(bio))
82+
return true;
83+
84+
switch (bio_op(bio)) {
85+
case REQ_OP_READ:
86+
if (bi->flags & BLK_INTEGRITY_NOVERIFY)
87+
return true;
88+
break;
89+
case REQ_OP_WRITE:
90+
if (bi->flags & BLK_INTEGRITY_NOGENERATE)
91+
return true;
92+
93+
/*
94+
* Zero the memory allocated to not leak uninitialized kernel
95+
* memory to disk for non-integrity metadata where nothing else
96+
* initializes the memory.
97+
*/
98+
if (bi->csum_type == BLK_INTEGRITY_CSUM_NONE)
99+
gfp |= __GFP_ZERO;
100+
break;
101+
default:
102+
return true;
103+
}
104+
105+
/* Allocate kernel buffer for protection data */
106+
len = bio_integrity_bytes(bi, bio_sectors(bio));
107+
buf = kmalloc(len, gfp);
108+
if (!buf)
109+
goto err_end_io;
110+
111+
bip = bio_integrity_alloc(bio, GFP_NOIO, 1);
112+
if (IS_ERR(bip)) {
113+
kfree(buf);
114+
goto err_end_io;
115+
}
116+
117+
bip->bip_flags |= BIP_BLOCK_INTEGRITY;
118+
bip_set_seed(bip, bio->bi_iter.bi_sector);
119+
120+
if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
121+
bip->bip_flags |= BIP_IP_CHECKSUM;
122+
if (bi->csum_type)
123+
bip->bip_flags |= BIP_CHECK_GUARD;
124+
if (bi->flags & BLK_INTEGRITY_REF_TAG)
125+
bip->bip_flags |= BIP_CHECK_REFTAG;
126+
127+
if (bio_integrity_add_page(bio, virt_to_page(buf), len,
128+
offset_in_page(buf)) < len)
129+
goto err_end_io;
130+
131+
/* Auto-generate integrity metadata if this is a write */
132+
if (bio_data_dir(bio) == WRITE)
133+
blk_integrity_generate(bio);
134+
else
135+
bip->bio_iter = bio->bi_iter;
136+
return true;
137+
138+
err_end_io:
139+
bio->bi_status = BLK_STS_RESOURCE;
140+
bio_endio(bio);
141+
return false;
142+
}
143+
EXPORT_SYMBOL(bio_integrity_prep);
144+
145+
void blk_flush_integrity(void)
146+
{
147+
flush_workqueue(kintegrityd_wq);
148+
}
149+
150+
static int __init blk_integrity_auto_init(void)
151+
{
152+
/*
153+
* kintegrityd won't block much but may burn a lot of CPU cycles.
154+
* Make it highpri CPU intensive wq with max concurrency of 1.
155+
*/
156+
kintegrityd_wq = alloc_workqueue("kintegrityd", WQ_MEM_RECLAIM |
157+
WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1);
158+
if (!kintegrityd_wq)
159+
panic("Failed to create kintegrityd\n");
160+
return 0;
161+
}
162+
subsys_initcall(blk_integrity_auto_init);

block/bio-integrity.c

Lines changed: 0 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,10 @@
1010
#include <linux/mempool.h>
1111
#include <linux/export.h>
1212
#include <linux/bio.h>
13-
#include <linux/workqueue.h>
1413
#include <linux/slab.h>
1514
#include "blk.h"
1615

1716
static struct kmem_cache *bip_slab;
18-
static struct workqueue_struct *kintegrityd_wq;
19-
20-
void blk_flush_integrity(void)
21-
{
22-
flush_workqueue(kintegrityd_wq);
23-
}
2417

2518
/**
2619
* bio_integrity_free - Free bio integrity payload
@@ -413,149 +406,6 @@ int bio_integrity_map_iter(struct bio *bio, struct uio_meta *meta)
413406
return ret;
414407
}
415408

416-
/**
417-
* bio_integrity_prep - Prepare bio for integrity I/O
418-
* @bio: bio to prepare
419-
*
420-
* Description: Checks if the bio already has an integrity payload attached.
421-
* If it does, the payload has been generated by another kernel subsystem,
422-
* and we just pass it through. Otherwise allocates integrity payload.
423-
* The bio must have data direction, target device and start sector set priot
424-
* to calling. In the WRITE case, integrity metadata will be generated using
425-
* the block device's integrity function. In the READ case, the buffer
426-
* will be prepared for DMA and a suitable end_io handler set up.
427-
*/
428-
bool bio_integrity_prep(struct bio *bio)
429-
{
430-
struct bio_integrity_payload *bip;
431-
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
432-
unsigned int len;
433-
void *buf;
434-
gfp_t gfp = GFP_NOIO;
435-
436-
if (!bi)
437-
return true;
438-
439-
if (!bio_sectors(bio))
440-
return true;
441-
442-
/* Already protected? */
443-
if (bio_integrity(bio))
444-
return true;
445-
446-
switch (bio_op(bio)) {
447-
case REQ_OP_READ:
448-
if (bi->flags & BLK_INTEGRITY_NOVERIFY)
449-
return true;
450-
break;
451-
case REQ_OP_WRITE:
452-
if (bi->flags & BLK_INTEGRITY_NOGENERATE)
453-
return true;
454-
455-
/*
456-
* Zero the memory allocated to not leak uninitialized kernel
457-
* memory to disk for non-integrity metadata where nothing else
458-
* initializes the memory.
459-
*/
460-
if (bi->csum_type == BLK_INTEGRITY_CSUM_NONE)
461-
gfp |= __GFP_ZERO;
462-
break;
463-
default:
464-
return true;
465-
}
466-
467-
/* Allocate kernel buffer for protection data */
468-
len = bio_integrity_bytes(bi, bio_sectors(bio));
469-
buf = kmalloc(len, gfp);
470-
if (unlikely(buf == NULL)) {
471-
goto err_end_io;
472-
}
473-
474-
bip = bio_integrity_alloc(bio, GFP_NOIO, 1);
475-
if (IS_ERR(bip)) {
476-
kfree(buf);
477-
goto err_end_io;
478-
}
479-
480-
bip->bip_flags |= BIP_BLOCK_INTEGRITY;
481-
bip_set_seed(bip, bio->bi_iter.bi_sector);
482-
483-
if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
484-
bip->bip_flags |= BIP_IP_CHECKSUM;
485-
486-
/* describe what tags to check in payload */
487-
if (bi->csum_type)
488-
bip->bip_flags |= BIP_CHECK_GUARD;
489-
if (bi->flags & BLK_INTEGRITY_REF_TAG)
490-
bip->bip_flags |= BIP_CHECK_REFTAG;
491-
if (bio_integrity_add_page(bio, virt_to_page(buf), len,
492-
offset_in_page(buf)) < len) {
493-
printk(KERN_ERR "could not attach integrity payload\n");
494-
goto err_end_io;
495-
}
496-
497-
/* Auto-generate integrity metadata if this is a write */
498-
if (bio_data_dir(bio) == WRITE)
499-
blk_integrity_generate(bio);
500-
else
501-
bip->bio_iter = bio->bi_iter;
502-
return true;
503-
504-
err_end_io:
505-
bio->bi_status = BLK_STS_RESOURCE;
506-
bio_endio(bio);
507-
return false;
508-
}
509-
EXPORT_SYMBOL(bio_integrity_prep);
510-
511-
/**
512-
* bio_integrity_verify_fn - Integrity I/O completion worker
513-
* @work: Work struct stored in bio to be verified
514-
*
515-
* Description: This workqueue function is called to complete a READ
516-
* request. The function verifies the transferred integrity metadata
517-
* and then calls the original bio end_io function.
518-
*/
519-
static void bio_integrity_verify_fn(struct work_struct *work)
520-
{
521-
struct bio_integrity_payload *bip =
522-
container_of(work, struct bio_integrity_payload, bip_work);
523-
struct bio *bio = bip->bip_bio;
524-
525-
blk_integrity_verify(bio);
526-
527-
kfree(bvec_virt(bip->bip_vec));
528-
bio_integrity_free(bio);
529-
bio_endio(bio);
530-
}
531-
532-
/**
533-
* __bio_integrity_endio - Integrity I/O completion function
534-
* @bio: Protected bio
535-
*
536-
* Description: Completion for integrity I/O
537-
*
538-
* Normally I/O completion is done in interrupt context. However,
539-
* verifying I/O integrity is a time-consuming task which must be run
540-
* in process context. This function postpones completion
541-
* accordingly.
542-
*/
543-
bool __bio_integrity_endio(struct bio *bio)
544-
{
545-
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
546-
struct bio_integrity_payload *bip = bio_integrity(bio);
547-
548-
if (bio_op(bio) == REQ_OP_READ && !bio->bi_status && bi->csum_type) {
549-
INIT_WORK(&bip->bip_work, bio_integrity_verify_fn);
550-
queue_work(kintegrityd_wq, &bip->bip_work);
551-
return false;
552-
}
553-
554-
kfree(bvec_virt(bip->bip_vec));
555-
bio_integrity_free(bio);
556-
return true;
557-
}
558-
559409
/**
560410
* bio_integrity_advance - Advance integrity vector
561411
* @bio: bio whose integrity vector to update
@@ -644,15 +494,6 @@ void bioset_integrity_free(struct bio_set *bs)
644494

645495
void __init bio_integrity_init(void)
646496
{
647-
/*
648-
* kintegrityd won't block much but may burn a lot of CPU cycles.
649-
* Make it highpri CPU intensive wq with max concurrency of 1.
650-
*/
651-
kintegrityd_wq = alloc_workqueue("kintegrityd", WQ_MEM_RECLAIM |
652-
WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1);
653-
if (!kintegrityd_wq)
654-
panic("Failed to create kintegrityd\n");
655-
656497
bip_slab = kmem_cache_create("bio_integrity_payload",
657498
sizeof(struct bio_integrity_payload) +
658499
sizeof(struct bio_vec) * BIO_INLINE_VECS,

0 commit comments

Comments
 (0)