aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2008-06-30 14:04:41 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-07-03 07:21:13 -0400
commit7ba1ba12eeef0aa7113beb16410ef8b7c748e18b (patch)
tree4629aabe88bf095d58eabd2f451207695bb35b08 /include/linux
parent51d654e1d885607a6edd02b337105fa5c28b6d33 (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.h94
-rw-r--r--include/linux/blkdev.h105
-rw-r--r--include/linux/genhd.h3
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
65struct bio_set; 65struct bio_set;
66struct bio; 66struct bio;
67struct bio_integrity_payload;
67typedef void (bio_end_io_t) (struct bio *, int); 68typedef void (bio_end_io_t) (struct bio *, int);
68typedef void (bio_destructor_t) (struct bio *); 69typedef 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 */
282struct 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 */
285struct bio_pair { 312struct 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};
291extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, 322extern 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 *,
334extern int bio_uncopy_user(struct bio *); 365extern int bio_uncopy_user(struct bio *);
335void zero_fill_bio(struct bio *bio); 366void zero_fill_bio(struct bio *bio);
336extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set *); 367extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set *);
368extern 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
347struct bio_set { 379struct 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
463extern struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *, gfp_t, unsigned int, struct bio_set *);
464extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int);
465extern void bio_integrity_free(struct bio *, struct bio_set *);
466extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int);
467extern int bio_integrity_enabled(struct bio *bio);
468extern int bio_integrity_set_tag(struct bio *, void *, unsigned int);
469extern int bio_integrity_get_tag(struct bio *, void *, unsigned int);
470extern int bio_integrity_prep(struct bio *);
471extern void bio_integrity_endio(struct bio *, int);
472extern void bio_integrity_advance(struct bio *, unsigned int);
473extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int);
474extern void bio_integrity_split(struct bio *, struct bio_pair *, int);
475extern int bio_integrity_clone(struct bio *, struct bio *, struct bio_set *);
476extern int bioset_integrity_create(struct bio_set *, int);
477extern void bioset_integrity_free(struct bio_set *);
478extern 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
875struct 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
884typedef void (integrity_gen_fn) (struct blk_integrity_exchg *);
885typedef int (integrity_vrfy_fn) (struct blk_integrity_exchg *);
886typedef void (integrity_set_tag_fn) (void *, void *, unsigned int);
887typedef void (integrity_get_tag_fn) (void *, void *, unsigned int);
888
889struct 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
905extern int blk_integrity_register(struct gendisk *, struct blk_integrity *);
906extern void blk_integrity_unregister(struct gendisk *);
907extern int blk_integrity_compare(struct block_device *, struct block_device *);
908extern int blk_rq_map_integrity_sg(struct request *, struct scatterlist *);
909extern int blk_rq_count_integrity_sg(struct request *);
910
911static 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
919static inline struct blk_integrity *bdev_get_integrity(struct block_device *bdev)
920{
921 return bdev->bd_disk->integrity;
922}
923
924static 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
934static 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
952static 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/*