diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2008-06-30 14:04:41 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2008-07-03 07:21:13 -0400 |
commit | 7ba1ba12eeef0aa7113beb16410ef8b7c748e18b (patch) | |
tree | 4629aabe88bf095d58eabd2f451207695bb35b08 /include/linux | |
parent | 51d654e1d885607a6edd02b337105fa5c28b6d33 (diff) |
block: Block layer data integrity support
Some block devices support verifying the integrity of requests by way
of checksums or other protection information that is submitted along
with the I/O.
This patch implements support for generating and verifying integrity
metadata, as well as correctly merging, splitting and cloning bios and
requests that have this extra information attached.
See Documentation/block/data-integrity.txt for more information.
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/bio.h | 94 | ||||
-rw-r--r-- | include/linux/blkdev.h | 105 | ||||
-rw-r--r-- | include/linux/genhd.h | 3 |
3 files changed, 198 insertions, 4 deletions
diff --git a/include/linux/bio.h b/include/linux/bio.h index 49dfb3cb7460..6bfc3e8d9d89 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h | |||
@@ -64,6 +64,7 @@ struct bio_vec { | |||
64 | 64 | ||
65 | struct bio_set; | 65 | struct bio_set; |
66 | struct bio; | 66 | struct bio; |
67 | struct bio_integrity_payload; | ||
67 | typedef void (bio_end_io_t) (struct bio *, int); | 68 | typedef void (bio_end_io_t) (struct bio *, int); |
68 | typedef void (bio_destructor_t) (struct bio *); | 69 | typedef void (bio_destructor_t) (struct bio *); |
69 | 70 | ||
@@ -112,6 +113,9 @@ struct bio { | |||
112 | atomic_t bi_cnt; /* pin count */ | 113 | atomic_t bi_cnt; /* pin count */ |
113 | 114 | ||
114 | void *bi_private; | 115 | void *bi_private; |
116 | #if defined(CONFIG_BLK_DEV_INTEGRITY) | ||
117 | struct bio_integrity_payload *bi_integrity; /* data integrity */ | ||
118 | #endif | ||
115 | 119 | ||
116 | bio_destructor_t *bi_destructor; /* destructor */ | 120 | bio_destructor_t *bi_destructor; /* destructor */ |
117 | }; | 121 | }; |
@@ -271,6 +275,29 @@ static inline void *bio_data(struct bio *bio) | |||
271 | */ | 275 | */ |
272 | #define bio_get(bio) atomic_inc(&(bio)->bi_cnt) | 276 | #define bio_get(bio) atomic_inc(&(bio)->bi_cnt) |
273 | 277 | ||
278 | #if defined(CONFIG_BLK_DEV_INTEGRITY) | ||
279 | /* | ||
280 | * bio integrity payload | ||
281 | */ | ||
282 | struct bio_integrity_payload { | ||
283 | struct bio *bip_bio; /* parent bio */ | ||
284 | struct bio_vec *bip_vec; /* integrity data vector */ | ||
285 | |||
286 | sector_t bip_sector; /* virtual start sector */ | ||
287 | |||
288 | void *bip_buf; /* generated integrity data */ | ||
289 | bio_end_io_t *bip_end_io; /* saved I/O completion fn */ | ||
290 | |||
291 | int bip_error; /* saved I/O error */ | ||
292 | unsigned int bip_size; | ||
293 | |||
294 | unsigned short bip_pool; /* pool the ivec came from */ | ||
295 | unsigned short bip_vcnt; /* # of integrity bio_vecs */ | ||
296 | unsigned short bip_idx; /* current bip_vec index */ | ||
297 | |||
298 | struct work_struct bip_work; /* I/O completion */ | ||
299 | }; | ||
300 | #endif /* CONFIG_BLK_DEV_INTEGRITY */ | ||
274 | 301 | ||
275 | /* | 302 | /* |
276 | * A bio_pair is used when we need to split a bio. | 303 | * A bio_pair is used when we need to split a bio. |
@@ -283,10 +310,14 @@ static inline void *bio_data(struct bio *bio) | |||
283 | * in bio2.bi_private | 310 | * in bio2.bi_private |
284 | */ | 311 | */ |
285 | struct bio_pair { | 312 | struct bio_pair { |
286 | struct bio bio1, bio2; | 313 | struct bio bio1, bio2; |
287 | struct bio_vec bv1, bv2; | 314 | struct bio_vec bv1, bv2; |
288 | atomic_t cnt; | 315 | #if defined(CONFIG_BLK_DEV_INTEGRITY) |
289 | int error; | 316 | struct bio_integrity_payload bip1, bip2; |
317 | struct bio_vec iv1, iv2; | ||
318 | #endif | ||
319 | atomic_t cnt; | ||
320 | int error; | ||
290 | }; | 321 | }; |
291 | extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, | 322 | extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, |
292 | int first_sectors); | 323 | int first_sectors); |
@@ -334,6 +365,7 @@ extern struct bio *bio_copy_user_iov(struct request_queue *, struct sg_iovec *, | |||
334 | extern int bio_uncopy_user(struct bio *); | 365 | extern int bio_uncopy_user(struct bio *); |
335 | void zero_fill_bio(struct bio *bio); | 366 | void zero_fill_bio(struct bio *bio); |
336 | extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set *); | 367 | extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set *); |
368 | extern unsigned int bvec_nr_vecs(unsigned short idx); | ||
337 | 369 | ||
338 | /* | 370 | /* |
339 | * bio_set is used to allow other portions of the IO system to | 371 | * bio_set is used to allow other portions of the IO system to |
@@ -346,6 +378,9 @@ extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set | |||
346 | 378 | ||
347 | struct bio_set { | 379 | struct bio_set { |
348 | mempool_t *bio_pool; | 380 | mempool_t *bio_pool; |
381 | #if defined(CONFIG_BLK_DEV_INTEGRITY) | ||
382 | mempool_t *bio_integrity_pool; | ||
383 | #endif | ||
349 | mempool_t *bvec_pools[BIOVEC_NR_POOLS]; | 384 | mempool_t *bvec_pools[BIOVEC_NR_POOLS]; |
350 | }; | 385 | }; |
351 | 386 | ||
@@ -410,5 +445,56 @@ static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx, | |||
410 | __bio_kmap_irq((bio), (bio)->bi_idx, (flags)) | 445 | __bio_kmap_irq((bio), (bio)->bi_idx, (flags)) |
411 | #define bio_kunmap_irq(buf,flags) __bio_kunmap_irq(buf, flags) | 446 | #define bio_kunmap_irq(buf,flags) __bio_kunmap_irq(buf, flags) |
412 | 447 | ||
448 | #if defined(CONFIG_BLK_DEV_INTEGRITY) | ||
449 | |||
450 | #define bip_vec_idx(bip, idx) (&(bip->bip_vec[(idx)])) | ||
451 | #define bip_vec(bip) bip_vec_idx(bip, 0) | ||
452 | |||
453 | #define __bip_for_each_vec(bvl, bip, i, start_idx) \ | ||
454 | for (bvl = bip_vec_idx((bip), (start_idx)), i = (start_idx); \ | ||
455 | i < (bip)->bip_vcnt; \ | ||
456 | bvl++, i++) | ||
457 | |||
458 | #define bip_for_each_vec(bvl, bip, i) \ | ||
459 | __bip_for_each_vec(bvl, bip, i, (bip)->bip_idx) | ||
460 | |||
461 | #define bio_integrity(bio) ((bio)->bi_integrity ? 1 : 0) | ||
462 | |||
463 | extern struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *, gfp_t, unsigned int, struct bio_set *); | ||
464 | extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int); | ||
465 | extern void bio_integrity_free(struct bio *, struct bio_set *); | ||
466 | extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int); | ||
467 | extern int bio_integrity_enabled(struct bio *bio); | ||
468 | extern int bio_integrity_set_tag(struct bio *, void *, unsigned int); | ||
469 | extern int bio_integrity_get_tag(struct bio *, void *, unsigned int); | ||
470 | extern int bio_integrity_prep(struct bio *); | ||
471 | extern void bio_integrity_endio(struct bio *, int); | ||
472 | extern void bio_integrity_advance(struct bio *, unsigned int); | ||
473 | extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int); | ||
474 | extern void bio_integrity_split(struct bio *, struct bio_pair *, int); | ||
475 | extern int bio_integrity_clone(struct bio *, struct bio *, struct bio_set *); | ||
476 | extern int bioset_integrity_create(struct bio_set *, int); | ||
477 | extern void bioset_integrity_free(struct bio_set *); | ||
478 | extern void bio_integrity_init_slab(void); | ||
479 | |||
480 | #else /* CONFIG_BLK_DEV_INTEGRITY */ | ||
481 | |||
482 | #define bio_integrity(a) (0) | ||
483 | #define bioset_integrity_create(a, b) (0) | ||
484 | #define bio_integrity_prep(a) (0) | ||
485 | #define bio_integrity_enabled(a) (0) | ||
486 | #define bio_integrity_clone(a, b, c) (0) | ||
487 | #define bioset_integrity_free(a) do { } while (0) | ||
488 | #define bio_integrity_free(a, b) do { } while (0) | ||
489 | #define bio_integrity_endio(a, b) do { } while (0) | ||
490 | #define bio_integrity_advance(a, b) do { } while (0) | ||
491 | #define bio_integrity_trim(a, b, c) do { } while (0) | ||
492 | #define bio_integrity_split(a, b, c) do { } while (0) | ||
493 | #define bio_integrity_set_tag(a, b, c) do { } while (0) | ||
494 | #define bio_integrity_get_tag(a, b, c) do { } while (0) | ||
495 | #define bio_integrity_init_slab(a) do { } while (0) | ||
496 | |||
497 | #endif /* CONFIG_BLK_DEV_INTEGRITY */ | ||
498 | |||
413 | #endif /* CONFIG_BLOCK */ | 499 | #endif /* CONFIG_BLOCK */ |
414 | #endif /* __LINUX_BIO_H */ | 500 | #endif /* __LINUX_BIO_H */ |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 6a3da6717135..4a9ed45270ff 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -112,6 +112,7 @@ enum rq_flag_bits { | |||
112 | __REQ_ALLOCED, /* request came from our alloc pool */ | 112 | __REQ_ALLOCED, /* request came from our alloc pool */ |
113 | __REQ_RW_META, /* metadata io request */ | 113 | __REQ_RW_META, /* metadata io request */ |
114 | __REQ_COPY_USER, /* contains copies of user pages */ | 114 | __REQ_COPY_USER, /* contains copies of user pages */ |
115 | __REQ_INTEGRITY, /* integrity metadata has been remapped */ | ||
115 | __REQ_NR_BITS, /* stops here */ | 116 | __REQ_NR_BITS, /* stops here */ |
116 | }; | 117 | }; |
117 | 118 | ||
@@ -134,6 +135,7 @@ enum rq_flag_bits { | |||
134 | #define REQ_ALLOCED (1 << __REQ_ALLOCED) | 135 | #define REQ_ALLOCED (1 << __REQ_ALLOCED) |
135 | #define REQ_RW_META (1 << __REQ_RW_META) | 136 | #define REQ_RW_META (1 << __REQ_RW_META) |
136 | #define REQ_COPY_USER (1 << __REQ_COPY_USER) | 137 | #define REQ_COPY_USER (1 << __REQ_COPY_USER) |
138 | #define REQ_INTEGRITY (1 << __REQ_INTEGRITY) | ||
137 | 139 | ||
138 | #define BLK_MAX_CDB 16 | 140 | #define BLK_MAX_CDB 16 |
139 | 141 | ||
@@ -865,6 +867,109 @@ void kblockd_flush_work(struct work_struct *work); | |||
865 | MODULE_ALIAS("block-major-" __stringify(major) "-*") | 867 | MODULE_ALIAS("block-major-" __stringify(major) "-*") |
866 | 868 | ||
867 | 869 | ||
870 | #if defined(CONFIG_BLK_DEV_INTEGRITY) | ||
871 | |||
872 | #define INTEGRITY_FLAG_READ 1 /* verify data integrity on read */ | ||
873 | #define INTEGRITY_FLAG_WRITE 2 /* generate data integrity on write */ | ||
874 | |||
875 | struct blk_integrity_exchg { | ||
876 | void *prot_buf; | ||
877 | void *data_buf; | ||
878 | sector_t sector; | ||
879 | unsigned int data_size; | ||
880 | unsigned short sector_size; | ||
881 | const char *disk_name; | ||
882 | }; | ||
883 | |||
884 | typedef void (integrity_gen_fn) (struct blk_integrity_exchg *); | ||
885 | typedef int (integrity_vrfy_fn) (struct blk_integrity_exchg *); | ||
886 | typedef void (integrity_set_tag_fn) (void *, void *, unsigned int); | ||
887 | typedef void (integrity_get_tag_fn) (void *, void *, unsigned int); | ||
888 | |||
889 | struct blk_integrity { | ||
890 | integrity_gen_fn *generate_fn; | ||
891 | integrity_vrfy_fn *verify_fn; | ||
892 | integrity_set_tag_fn *set_tag_fn; | ||
893 | integrity_get_tag_fn *get_tag_fn; | ||
894 | |||
895 | unsigned short flags; | ||
896 | unsigned short tuple_size; | ||
897 | unsigned short sector_size; | ||
898 | unsigned short tag_size; | ||
899 | |||
900 | const char *name; | ||
901 | |||
902 | struct kobject kobj; | ||
903 | }; | ||
904 | |||
905 | extern int blk_integrity_register(struct gendisk *, struct blk_integrity *); | ||
906 | extern void blk_integrity_unregister(struct gendisk *); | ||
907 | extern int blk_integrity_compare(struct block_device *, struct block_device *); | ||
908 | extern int blk_rq_map_integrity_sg(struct request *, struct scatterlist *); | ||
909 | extern int blk_rq_count_integrity_sg(struct request *); | ||
910 | |||
911 | static inline unsigned short blk_integrity_tuple_size(struct blk_integrity *bi) | ||
912 | { | ||
913 | if (bi) | ||
914 | return bi->tuple_size; | ||
915 | |||
916 | return 0; | ||
917 | } | ||
918 | |||
919 | static inline struct blk_integrity *bdev_get_integrity(struct block_device *bdev) | ||
920 | { | ||
921 | return bdev->bd_disk->integrity; | ||
922 | } | ||
923 | |||
924 | static inline unsigned int bdev_get_tag_size(struct block_device *bdev) | ||
925 | { | ||
926 | struct blk_integrity *bi = bdev_get_integrity(bdev); | ||
927 | |||
928 | if (bi) | ||
929 | return bi->tag_size; | ||
930 | |||
931 | return 0; | ||
932 | } | ||
933 | |||
934 | static inline int bdev_integrity_enabled(struct block_device *bdev, int rw) | ||
935 | { | ||
936 | struct blk_integrity *bi = bdev_get_integrity(bdev); | ||
937 | |||
938 | if (bi == NULL) | ||
939 | return 0; | ||
940 | |||
941 | if (rw == READ && bi->verify_fn != NULL && | ||
942 | test_bit(INTEGRITY_FLAG_READ, &bi->flags)) | ||
943 | return 1; | ||
944 | |||
945 | if (rw == WRITE && bi->generate_fn != NULL && | ||
946 | test_bit(INTEGRITY_FLAG_WRITE, &bi->flags)) | ||
947 | return 1; | ||
948 | |||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | static inline int blk_integrity_rq(struct request *rq) | ||
953 | { | ||
954 | BUG_ON(rq->bio == NULL); | ||
955 | |||
956 | return bio_integrity(rq->bio); | ||
957 | } | ||
958 | |||
959 | #else /* CONFIG_BLK_DEV_INTEGRITY */ | ||
960 | |||
961 | #define blk_integrity_rq(rq) (0) | ||
962 | #define blk_rq_count_integrity_sg(a) (0) | ||
963 | #define blk_rq_map_integrity_sg(a, b) (0) | ||
964 | #define bdev_get_integrity(a) (0) | ||
965 | #define bdev_get_tag_size(a) (0) | ||
966 | #define blk_integrity_compare(a, b) (0) | ||
967 | #define blk_integrity_register(a, b) (0) | ||
968 | #define blk_integrity_unregister(a) do { } while (0); | ||
969 | |||
970 | #endif /* CONFIG_BLK_DEV_INTEGRITY */ | ||
971 | |||
972 | |||
868 | #else /* CONFIG_BLOCK */ | 973 | #else /* CONFIG_BLOCK */ |
869 | /* | 974 | /* |
870 | * stubs for when the block layer is configured out | 975 | * stubs for when the block layer is configured out |
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index ae7aec3cabee..524ec96f5a23 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -141,6 +141,9 @@ struct gendisk { | |||
141 | struct disk_stats dkstats; | 141 | struct disk_stats dkstats; |
142 | #endif | 142 | #endif |
143 | struct work_struct async_notify; | 143 | struct work_struct async_notify; |
144 | #ifdef CONFIG_BLK_DEV_INTEGRITY | ||
145 | struct blk_integrity *integrity; | ||
146 | #endif | ||
144 | }; | 147 | }; |
145 | 148 | ||
146 | /* | 149 | /* |