17ba1ba12SMartin K. Petersen /* 27ba1ba12SMartin K. Petersen * blk-integrity.c - Block layer data integrity extensions 37ba1ba12SMartin K. Petersen * 47ba1ba12SMartin K. Petersen * Copyright (C) 2007, 2008 Oracle Corporation 57ba1ba12SMartin K. Petersen * Written by: Martin K. Petersen <martin.petersen@oracle.com> 67ba1ba12SMartin K. Petersen * 77ba1ba12SMartin K. Petersen * This program is free software; you can redistribute it and/or 87ba1ba12SMartin K. Petersen * modify it under the terms of the GNU General Public License version 97ba1ba12SMartin K. Petersen * 2 as published by the Free Software Foundation. 107ba1ba12SMartin K. Petersen * 117ba1ba12SMartin K. Petersen * This program is distributed in the hope that it will be useful, but 127ba1ba12SMartin K. Petersen * WITHOUT ANY WARRANTY; without even the implied warranty of 137ba1ba12SMartin K. Petersen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 147ba1ba12SMartin K. Petersen * General Public License for more details. 157ba1ba12SMartin K. Petersen * 167ba1ba12SMartin K. Petersen * You should have received a copy of the GNU General Public License 177ba1ba12SMartin K. Petersen * along with this program; see the file COPYING. If not, write to 187ba1ba12SMartin K. Petersen * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, 197ba1ba12SMartin K. Petersen * USA. 207ba1ba12SMartin K. Petersen * 217ba1ba12SMartin K. Petersen */ 227ba1ba12SMartin K. Petersen 237ba1ba12SMartin K. Petersen #include <linux/blkdev.h> 2466114cadSTejun Heo #include <linux/backing-dev.h> 257ba1ba12SMartin K. Petersen #include <linux/mempool.h> 267ba1ba12SMartin K. Petersen #include <linux/bio.h> 277ba1ba12SMartin K. Petersen #include <linux/scatterlist.h> 28d5decd3bSPaul Gortmaker #include <linux/export.h> 295a0e3ad6STejun Heo #include <linux/slab.h> 307ba1ba12SMartin K. Petersen 317ba1ba12SMartin K. Petersen #include "blk.h" 327ba1ba12SMartin K. Petersen 337ba1ba12SMartin K. Petersen /** 347ba1ba12SMartin K. Petersen * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements 3513f05c8dSMartin K. Petersen * @q: request queue 3613f05c8dSMartin K. Petersen * @bio: bio with integrity metadata attached 377ba1ba12SMartin K. Petersen * 387ba1ba12SMartin K. Petersen * Description: Returns the number of elements required in a 3913f05c8dSMartin K. Petersen * scatterlist corresponding to the integrity metadata in a bio. 407ba1ba12SMartin K. Petersen */ 4113f05c8dSMartin K. Petersen int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio) 427ba1ba12SMartin K. Petersen { 43d57a5f7cSKent Overstreet struct bio_vec iv, ivprv = { NULL }; 4413f05c8dSMartin K. Petersen unsigned int segments = 0; 4513f05c8dSMartin K. Petersen unsigned int seg_size = 0; 46d57a5f7cSKent Overstreet struct bvec_iter iter; 47d57a5f7cSKent Overstreet int prev = 0; 487ba1ba12SMartin K. Petersen 49d57a5f7cSKent Overstreet bio_for_each_integrity_vec(iv, bio, iter) { 507ba1ba12SMartin K. Petersen 51d57a5f7cSKent Overstreet if (prev) { 52d57a5f7cSKent Overstreet if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv)) 5313f05c8dSMartin K. Petersen goto new_segment; 547ba1ba12SMartin K. Petersen 55d57a5f7cSKent Overstreet if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv)) 5613f05c8dSMartin K. Petersen goto new_segment; 5713f05c8dSMartin K. Petersen 58d57a5f7cSKent Overstreet if (seg_size + iv.bv_len > queue_max_segment_size(q)) 5913f05c8dSMartin K. Petersen goto new_segment; 6013f05c8dSMartin K. Petersen 61d57a5f7cSKent Overstreet seg_size += iv.bv_len; 6213f05c8dSMartin K. Petersen } else { 6313f05c8dSMartin K. Petersen new_segment: 647ba1ba12SMartin K. Petersen segments++; 65d57a5f7cSKent Overstreet seg_size = iv.bv_len; 6613f05c8dSMartin K. Petersen } 677ba1ba12SMartin K. Petersen 68d57a5f7cSKent Overstreet prev = 1; 697ba1ba12SMartin K. Petersen ivprv = iv; 707ba1ba12SMartin K. Petersen } 717ba1ba12SMartin K. Petersen 727ba1ba12SMartin K. Petersen return segments; 737ba1ba12SMartin K. Petersen } 747ba1ba12SMartin K. Petersen EXPORT_SYMBOL(blk_rq_count_integrity_sg); 757ba1ba12SMartin K. Petersen 767ba1ba12SMartin K. Petersen /** 777ba1ba12SMartin K. Petersen * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist 7813f05c8dSMartin K. Petersen * @q: request queue 7913f05c8dSMartin K. Petersen * @bio: bio with integrity metadata attached 807ba1ba12SMartin K. Petersen * @sglist: target scatterlist 817ba1ba12SMartin K. Petersen * 827ba1ba12SMartin K. Petersen * Description: Map the integrity vectors in request into a 837ba1ba12SMartin K. Petersen * scatterlist. The scatterlist must be big enough to hold all 847ba1ba12SMartin K. Petersen * elements. I.e. sized using blk_rq_count_integrity_sg(). 857ba1ba12SMartin K. Petersen */ 8613f05c8dSMartin K. Petersen int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio, 8713f05c8dSMartin K. Petersen struct scatterlist *sglist) 887ba1ba12SMartin K. Petersen { 89d57a5f7cSKent Overstreet struct bio_vec iv, ivprv = { NULL }; 9013f05c8dSMartin K. Petersen struct scatterlist *sg = NULL; 9113f05c8dSMartin K. Petersen unsigned int segments = 0; 92d57a5f7cSKent Overstreet struct bvec_iter iter; 93d57a5f7cSKent Overstreet int prev = 0; 947ba1ba12SMartin K. Petersen 95d57a5f7cSKent Overstreet bio_for_each_integrity_vec(iv, bio, iter) { 967ba1ba12SMartin K. Petersen 97d57a5f7cSKent Overstreet if (prev) { 98d57a5f7cSKent Overstreet if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv)) 997ba1ba12SMartin K. Petersen goto new_segment; 1007ba1ba12SMartin K. Petersen 101d57a5f7cSKent Overstreet if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv)) 10213f05c8dSMartin K. Petersen goto new_segment; 10313f05c8dSMartin K. Petersen 104d57a5f7cSKent Overstreet if (sg->length + iv.bv_len > queue_max_segment_size(q)) 10513f05c8dSMartin K. Petersen goto new_segment; 10613f05c8dSMartin K. Petersen 107d57a5f7cSKent Overstreet sg->length += iv.bv_len; 1087ba1ba12SMartin K. Petersen } else { 1097ba1ba12SMartin K. Petersen new_segment: 1107ba1ba12SMartin K. Petersen if (!sg) 1117ba1ba12SMartin K. Petersen sg = sglist; 1127ba1ba12SMartin K. Petersen else { 113c8164d89SPaolo Bonzini sg_unmark_end(sg); 1147ba1ba12SMartin K. Petersen sg = sg_next(sg); 1157ba1ba12SMartin K. Petersen } 1167ba1ba12SMartin K. Petersen 117d57a5f7cSKent Overstreet sg_set_page(sg, iv.bv_page, iv.bv_len, iv.bv_offset); 1187ba1ba12SMartin K. Petersen segments++; 1197ba1ba12SMartin K. Petersen } 1207ba1ba12SMartin K. Petersen 121d57a5f7cSKent Overstreet prev = 1; 1227ba1ba12SMartin K. Petersen ivprv = iv; 1237ba1ba12SMartin K. Petersen } 1247ba1ba12SMartin K. Petersen 1257ba1ba12SMartin K. Petersen if (sg) 1267ba1ba12SMartin K. Petersen sg_mark_end(sg); 1277ba1ba12SMartin K. Petersen 1287ba1ba12SMartin K. Petersen return segments; 1297ba1ba12SMartin K. Petersen } 1307ba1ba12SMartin K. Petersen EXPORT_SYMBOL(blk_rq_map_integrity_sg); 1317ba1ba12SMartin K. Petersen 1327ba1ba12SMartin K. Petersen /** 133ad7fce93SMartin K. Petersen * blk_integrity_compare - Compare integrity profile of two disks 134ad7fce93SMartin K. Petersen * @gd1: Disk to compare 135ad7fce93SMartin K. Petersen * @gd2: Disk to compare 1367ba1ba12SMartin K. Petersen * 1377ba1ba12SMartin K. Petersen * Description: Meta-devices like DM and MD need to verify that all 1387ba1ba12SMartin K. Petersen * sub-devices use the same integrity format before advertising to 1397ba1ba12SMartin K. Petersen * upper layers that they can send/receive integrity metadata. This 140ad7fce93SMartin K. Petersen * function can be used to check whether two gendisk devices have 1417ba1ba12SMartin K. Petersen * compatible integrity formats. 1427ba1ba12SMartin K. Petersen */ 143ad7fce93SMartin K. Petersen int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2) 1447ba1ba12SMartin K. Petersen { 145ac6fc48cSDan Williams struct blk_integrity *b1 = &gd1->queue->integrity; 146ac6fc48cSDan Williams struct blk_integrity *b2 = &gd2->queue->integrity; 1477ba1ba12SMartin K. Petersen 14825520d55SMartin K. Petersen if (!b1->profile && !b2->profile) 149ad7fce93SMartin K. Petersen return 0; 1507ba1ba12SMartin K. Petersen 15125520d55SMartin K. Petersen if (!b1->profile || !b2->profile) 152ad7fce93SMartin K. Petersen return -1; 1537ba1ba12SMartin K. Petersen 154a48f041dSMartin K. Petersen if (b1->interval_exp != b2->interval_exp) { 1553be91c4aSMartin K. Petersen pr_err("%s: %s/%s protection interval %u != %u\n", 1563be91c4aSMartin K. Petersen __func__, gd1->disk_name, gd2->disk_name, 157a48f041dSMartin K. Petersen 1 << b1->interval_exp, 1 << b2->interval_exp); 1587ba1ba12SMartin K. Petersen return -1; 1597ba1ba12SMartin K. Petersen } 1607ba1ba12SMartin K. Petersen 1617ba1ba12SMartin K. Petersen if (b1->tuple_size != b2->tuple_size) { 16225520d55SMartin K. Petersen pr_err("%s: %s/%s tuple sz %u != %u\n", __func__, 163ad7fce93SMartin K. Petersen gd1->disk_name, gd2->disk_name, 1647ba1ba12SMartin K. Petersen b1->tuple_size, b2->tuple_size); 1657ba1ba12SMartin K. Petersen return -1; 1667ba1ba12SMartin K. Petersen } 1677ba1ba12SMartin K. Petersen 1687ba1ba12SMartin K. Petersen if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) { 16925520d55SMartin K. Petersen pr_err("%s: %s/%s tag sz %u != %u\n", __func__, 170ad7fce93SMartin K. Petersen gd1->disk_name, gd2->disk_name, 1717ba1ba12SMartin K. Petersen b1->tag_size, b2->tag_size); 1727ba1ba12SMartin K. Petersen return -1; 1737ba1ba12SMartin K. Petersen } 1747ba1ba12SMartin K. Petersen 1750f8087ecSMartin K. Petersen if (b1->profile != b2->profile) { 17625520d55SMartin K. Petersen pr_err("%s: %s/%s type %s != %s\n", __func__, 177ad7fce93SMartin K. Petersen gd1->disk_name, gd2->disk_name, 1780f8087ecSMartin K. Petersen b1->profile->name, b2->profile->name); 1797ba1ba12SMartin K. Petersen return -1; 1807ba1ba12SMartin K. Petersen } 1817ba1ba12SMartin K. Petersen 1827ba1ba12SMartin K. Petersen return 0; 1837ba1ba12SMartin K. Petersen } 1847ba1ba12SMartin K. Petersen EXPORT_SYMBOL(blk_integrity_compare); 1857ba1ba12SMartin K. Petersen 1864eaf99beSMartin K. Petersen bool blk_integrity_merge_rq(struct request_queue *q, struct request *req, 18713f05c8dSMartin K. Petersen struct request *next) 18813f05c8dSMartin K. Petersen { 1894eaf99beSMartin K. Petersen if (blk_integrity_rq(req) == 0 && blk_integrity_rq(next) == 0) 1904eaf99beSMartin K. Petersen return true; 1914eaf99beSMartin K. Petersen 1924eaf99beSMartin K. Petersen if (blk_integrity_rq(req) == 0 || blk_integrity_rq(next) == 0) 1934eaf99beSMartin K. Petersen return false; 1944eaf99beSMartin K. Petersen 1954eaf99beSMartin K. Petersen if (bio_integrity(req->bio)->bip_flags != 1964eaf99beSMartin K. Petersen bio_integrity(next->bio)->bip_flags) 1974eaf99beSMartin K. Petersen return false; 19813f05c8dSMartin K. Petersen 19913f05c8dSMartin K. Petersen if (req->nr_integrity_segments + next->nr_integrity_segments > 20013f05c8dSMartin K. Petersen q->limits.max_integrity_segments) 2014eaf99beSMartin K. Petersen return false; 20213f05c8dSMartin K. Petersen 2037f39add3SSagi Grimberg if (integrity_req_gap_back_merge(req, next->bio)) 2047f39add3SSagi Grimberg return false; 2057f39add3SSagi Grimberg 2064eaf99beSMartin K. Petersen return true; 20713f05c8dSMartin K. Petersen } 20813f05c8dSMartin K. Petersen EXPORT_SYMBOL(blk_integrity_merge_rq); 20913f05c8dSMartin K. Petersen 2104eaf99beSMartin K. Petersen bool blk_integrity_merge_bio(struct request_queue *q, struct request *req, 21113f05c8dSMartin K. Petersen struct bio *bio) 21213f05c8dSMartin K. Petersen { 21313f05c8dSMartin K. Petersen int nr_integrity_segs; 21413f05c8dSMartin K. Petersen struct bio *next = bio->bi_next; 21513f05c8dSMartin K. Petersen 2164eaf99beSMartin K. Petersen if (blk_integrity_rq(req) == 0 && bio_integrity(bio) == NULL) 2174eaf99beSMartin K. Petersen return true; 2184eaf99beSMartin K. Petersen 2194eaf99beSMartin K. Petersen if (blk_integrity_rq(req) == 0 || bio_integrity(bio) == NULL) 2204eaf99beSMartin K. Petersen return false; 2214eaf99beSMartin K. Petersen 2224eaf99beSMartin K. Petersen if (bio_integrity(req->bio)->bip_flags != bio_integrity(bio)->bip_flags) 2234eaf99beSMartin K. Petersen return false; 2244eaf99beSMartin K. Petersen 22513f05c8dSMartin K. Petersen bio->bi_next = NULL; 22613f05c8dSMartin K. Petersen nr_integrity_segs = blk_rq_count_integrity_sg(q, bio); 22713f05c8dSMartin K. Petersen bio->bi_next = next; 22813f05c8dSMartin K. Petersen 22913f05c8dSMartin K. Petersen if (req->nr_integrity_segments + nr_integrity_segs > 23013f05c8dSMartin K. Petersen q->limits.max_integrity_segments) 2314eaf99beSMartin K. Petersen return false; 23213f05c8dSMartin K. Petersen 23313f05c8dSMartin K. Petersen req->nr_integrity_segments += nr_integrity_segs; 23413f05c8dSMartin K. Petersen 2354eaf99beSMartin K. Petersen return true; 23613f05c8dSMartin K. Petersen } 23713f05c8dSMartin K. Petersen EXPORT_SYMBOL(blk_integrity_merge_bio); 23813f05c8dSMartin K. Petersen 2397ba1ba12SMartin K. Petersen struct integrity_sysfs_entry { 2407ba1ba12SMartin K. Petersen struct attribute attr; 2417ba1ba12SMartin K. Petersen ssize_t (*show)(struct blk_integrity *, char *); 2427ba1ba12SMartin K. Petersen ssize_t (*store)(struct blk_integrity *, const char *, size_t); 2437ba1ba12SMartin K. Petersen }; 2447ba1ba12SMartin K. Petersen 2457ba1ba12SMartin K. Petersen static ssize_t integrity_attr_show(struct kobject *kobj, struct attribute *attr, 2467ba1ba12SMartin K. Petersen char *page) 2477ba1ba12SMartin K. Petersen { 248aff34e19SMartin K. Petersen struct gendisk *disk = container_of(kobj, struct gendisk, integrity_kobj); 249ac6fc48cSDan Williams struct blk_integrity *bi = &disk->queue->integrity; 2507ba1ba12SMartin K. Petersen struct integrity_sysfs_entry *entry = 2517ba1ba12SMartin K. Petersen container_of(attr, struct integrity_sysfs_entry, attr); 2527ba1ba12SMartin K. Petersen 2537ba1ba12SMartin K. Petersen return entry->show(bi, page); 2547ba1ba12SMartin K. Petersen } 2557ba1ba12SMartin K. Petersen 256b984679eSJens Axboe static ssize_t integrity_attr_store(struct kobject *kobj, 257b984679eSJens Axboe struct attribute *attr, const char *page, 258b984679eSJens Axboe size_t count) 2597ba1ba12SMartin K. Petersen { 260aff34e19SMartin K. Petersen struct gendisk *disk = container_of(kobj, struct gendisk, integrity_kobj); 261ac6fc48cSDan Williams struct blk_integrity *bi = &disk->queue->integrity; 2627ba1ba12SMartin K. Petersen struct integrity_sysfs_entry *entry = 2637ba1ba12SMartin K. Petersen container_of(attr, struct integrity_sysfs_entry, attr); 2647ba1ba12SMartin K. Petersen ssize_t ret = 0; 2657ba1ba12SMartin K. Petersen 2667ba1ba12SMartin K. Petersen if (entry->store) 2677ba1ba12SMartin K. Petersen ret = entry->store(bi, page, count); 2687ba1ba12SMartin K. Petersen 2697ba1ba12SMartin K. Petersen return ret; 2707ba1ba12SMartin K. Petersen } 2717ba1ba12SMartin K. Petersen 2727ba1ba12SMartin K. Petersen static ssize_t integrity_format_show(struct blk_integrity *bi, char *page) 2737ba1ba12SMartin K. Petersen { 27425520d55SMartin K. Petersen if (bi->profile && bi->profile->name) 2750f8087ecSMartin K. Petersen return sprintf(page, "%s\n", bi->profile->name); 2767ba1ba12SMartin K. Petersen else 2777ba1ba12SMartin K. Petersen return sprintf(page, "none\n"); 2787ba1ba12SMartin K. Petersen } 2797ba1ba12SMartin K. Petersen 2807ba1ba12SMartin K. Petersen static ssize_t integrity_tag_size_show(struct blk_integrity *bi, char *page) 2817ba1ba12SMartin K. Petersen { 2827ba1ba12SMartin K. Petersen return sprintf(page, "%u\n", bi->tag_size); 2837ba1ba12SMartin K. Petersen } 2847ba1ba12SMartin K. Petersen 2854c241d08SMartin K. Petersen static ssize_t integrity_interval_show(struct blk_integrity *bi, char *page) 2864c241d08SMartin K. Petersen { 28725520d55SMartin K. Petersen return sprintf(page, "%u\n", 28825520d55SMartin K. Petersen bi->interval_exp ? 1 << bi->interval_exp : 0); 2894c241d08SMartin K. Petersen } 2904c241d08SMartin K. Petersen 2918288f496SMartin K. Petersen static ssize_t integrity_verify_store(struct blk_integrity *bi, 2927ba1ba12SMartin K. Petersen const char *page, size_t count) 2937ba1ba12SMartin K. Petersen { 2947ba1ba12SMartin K. Petersen char *p = (char *) page; 2957ba1ba12SMartin K. Petersen unsigned long val = simple_strtoul(p, &p, 10); 2967ba1ba12SMartin K. Petersen 2977ba1ba12SMartin K. Petersen if (val) 2988288f496SMartin K. Petersen bi->flags |= BLK_INTEGRITY_VERIFY; 2997ba1ba12SMartin K. Petersen else 3008288f496SMartin K. Petersen bi->flags &= ~BLK_INTEGRITY_VERIFY; 3017ba1ba12SMartin K. Petersen 3027ba1ba12SMartin K. Petersen return count; 3037ba1ba12SMartin K. Petersen } 3047ba1ba12SMartin K. Petersen 3058288f496SMartin K. Petersen static ssize_t integrity_verify_show(struct blk_integrity *bi, char *page) 3067ba1ba12SMartin K. Petersen { 3078288f496SMartin K. Petersen return sprintf(page, "%d\n", (bi->flags & BLK_INTEGRITY_VERIFY) != 0); 3087ba1ba12SMartin K. Petersen } 3097ba1ba12SMartin K. Petersen 3108288f496SMartin K. Petersen static ssize_t integrity_generate_store(struct blk_integrity *bi, 3117ba1ba12SMartin K. Petersen const char *page, size_t count) 3127ba1ba12SMartin K. Petersen { 3137ba1ba12SMartin K. Petersen char *p = (char *) page; 3147ba1ba12SMartin K. Petersen unsigned long val = simple_strtoul(p, &p, 10); 3157ba1ba12SMartin K. Petersen 3167ba1ba12SMartin K. Petersen if (val) 3178288f496SMartin K. Petersen bi->flags |= BLK_INTEGRITY_GENERATE; 3187ba1ba12SMartin K. Petersen else 3198288f496SMartin K. Petersen bi->flags &= ~BLK_INTEGRITY_GENERATE; 3207ba1ba12SMartin K. Petersen 3217ba1ba12SMartin K. Petersen return count; 3227ba1ba12SMartin K. Petersen } 3237ba1ba12SMartin K. Petersen 3248288f496SMartin K. Petersen static ssize_t integrity_generate_show(struct blk_integrity *bi, char *page) 3257ba1ba12SMartin K. Petersen { 3268288f496SMartin K. Petersen return sprintf(page, "%d\n", (bi->flags & BLK_INTEGRITY_GENERATE) != 0); 3277ba1ba12SMartin K. Petersen } 3287ba1ba12SMartin K. Petersen 3293aec2f41SMartin K. Petersen static ssize_t integrity_device_show(struct blk_integrity *bi, char *page) 3303aec2f41SMartin K. Petersen { 3313aec2f41SMartin K. Petersen return sprintf(page, "%u\n", 3323aec2f41SMartin K. Petersen (bi->flags & BLK_INTEGRITY_DEVICE_CAPABLE) != 0); 3333aec2f41SMartin K. Petersen } 3343aec2f41SMartin K. Petersen 3357ba1ba12SMartin K. Petersen static struct integrity_sysfs_entry integrity_format_entry = { 3367ba1ba12SMartin K. Petersen .attr = { .name = "format", .mode = S_IRUGO }, 3377ba1ba12SMartin K. Petersen .show = integrity_format_show, 3387ba1ba12SMartin K. Petersen }; 3397ba1ba12SMartin K. Petersen 3407ba1ba12SMartin K. Petersen static struct integrity_sysfs_entry integrity_tag_size_entry = { 3417ba1ba12SMartin K. Petersen .attr = { .name = "tag_size", .mode = S_IRUGO }, 3427ba1ba12SMartin K. Petersen .show = integrity_tag_size_show, 3437ba1ba12SMartin K. Petersen }; 3447ba1ba12SMartin K. Petersen 3454c241d08SMartin K. Petersen static struct integrity_sysfs_entry integrity_interval_entry = { 3464c241d08SMartin K. Petersen .attr = { .name = "protection_interval_bytes", .mode = S_IRUGO }, 3474c241d08SMartin K. Petersen .show = integrity_interval_show, 3484c241d08SMartin K. Petersen }; 3494c241d08SMartin K. Petersen 3508288f496SMartin K. Petersen static struct integrity_sysfs_entry integrity_verify_entry = { 3517ba1ba12SMartin K. Petersen .attr = { .name = "read_verify", .mode = S_IRUGO | S_IWUSR }, 3528288f496SMartin K. Petersen .show = integrity_verify_show, 3538288f496SMartin K. Petersen .store = integrity_verify_store, 3547ba1ba12SMartin K. Petersen }; 3557ba1ba12SMartin K. Petersen 3568288f496SMartin K. Petersen static struct integrity_sysfs_entry integrity_generate_entry = { 3577ba1ba12SMartin K. Petersen .attr = { .name = "write_generate", .mode = S_IRUGO | S_IWUSR }, 3588288f496SMartin K. Petersen .show = integrity_generate_show, 3598288f496SMartin K. Petersen .store = integrity_generate_store, 3607ba1ba12SMartin K. Petersen }; 3617ba1ba12SMartin K. Petersen 3623aec2f41SMartin K. Petersen static struct integrity_sysfs_entry integrity_device_entry = { 3633aec2f41SMartin K. Petersen .attr = { .name = "device_is_integrity_capable", .mode = S_IRUGO }, 3643aec2f41SMartin K. Petersen .show = integrity_device_show, 3653aec2f41SMartin K. Petersen }; 3663aec2f41SMartin K. Petersen 3677ba1ba12SMartin K. Petersen static struct attribute *integrity_attrs[] = { 3687ba1ba12SMartin K. Petersen &integrity_format_entry.attr, 3697ba1ba12SMartin K. Petersen &integrity_tag_size_entry.attr, 3704c241d08SMartin K. Petersen &integrity_interval_entry.attr, 3718288f496SMartin K. Petersen &integrity_verify_entry.attr, 3728288f496SMartin K. Petersen &integrity_generate_entry.attr, 3733aec2f41SMartin K. Petersen &integrity_device_entry.attr, 3747ba1ba12SMartin K. Petersen NULL, 3757ba1ba12SMartin K. Petersen }; 3767ba1ba12SMartin K. Petersen 37752cf25d0SEmese Revfy static const struct sysfs_ops integrity_ops = { 3787ba1ba12SMartin K. Petersen .show = &integrity_attr_show, 3797ba1ba12SMartin K. Petersen .store = &integrity_attr_store, 3807ba1ba12SMartin K. Petersen }; 3817ba1ba12SMartin K. Petersen 3827ba1ba12SMartin K. Petersen static struct kobj_type integrity_ktype = { 3837ba1ba12SMartin K. Petersen .default_attrs = integrity_attrs, 3847ba1ba12SMartin K. Petersen .sysfs_ops = &integrity_ops, 3857ba1ba12SMartin K. Petersen }; 3867ba1ba12SMartin K. Petersen 3874125a09bSDan Williams static int blk_integrity_nop_fn(struct blk_integrity_iter *iter) 3884125a09bSDan Williams { 3894125a09bSDan Williams return 0; 3904125a09bSDan Williams } 3914125a09bSDan Williams 3924125a09bSDan Williams static struct blk_integrity_profile nop_profile = { 3934125a09bSDan Williams .name = "nop", 3944125a09bSDan Williams .generate_fn = blk_integrity_nop_fn, 3954125a09bSDan Williams .verify_fn = blk_integrity_nop_fn, 3964125a09bSDan Williams }; 3974125a09bSDan Williams 3987ba1ba12SMartin K. Petersen /** 3997ba1ba12SMartin K. Petersen * blk_integrity_register - Register a gendisk as being integrity-capable 4007ba1ba12SMartin K. Petersen * @disk: struct gendisk pointer to make integrity-aware 40125520d55SMartin K. Petersen * @template: block integrity profile to register 4027ba1ba12SMartin K. Petersen * 40325520d55SMartin K. Petersen * Description: When a device needs to advertise itself as being able to 40425520d55SMartin K. Petersen * send/receive integrity metadata it must use this function to register 40525520d55SMartin K. Petersen * the capability with the block layer. The template is a blk_integrity 40625520d55SMartin K. Petersen * struct with values appropriate for the underlying hardware. See 40725520d55SMartin K. Petersen * Documentation/block/data-integrity.txt. 4087ba1ba12SMartin K. Petersen */ 40925520d55SMartin K. Petersen void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template) 4107ba1ba12SMartin K. Petersen { 411ac6fc48cSDan Williams struct blk_integrity *bi = &disk->queue->integrity; 4127ba1ba12SMartin K. Petersen 41325520d55SMartin K. Petersen bi->flags = BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE | 41425520d55SMartin K. Petersen template->flags; 415a48f041dSMartin K. Petersen bi->interval_exp = ilog2(queue_logical_block_size(disk->queue)); 4164125a09bSDan Williams bi->profile = template->profile ? template->profile : &nop_profile; 4177ba1ba12SMartin K. Petersen bi->tuple_size = template->tuple_size; 4187ba1ba12SMartin K. Petersen bi->tag_size = template->tag_size; 4197ba1ba12SMartin K. Petersen 42025520d55SMartin K. Petersen blk_integrity_revalidate(disk); 4217ba1ba12SMartin K. Petersen } 4227ba1ba12SMartin K. Petersen EXPORT_SYMBOL(blk_integrity_register); 4237ba1ba12SMartin K. Petersen 4247ba1ba12SMartin K. Petersen /** 42525520d55SMartin K. Petersen * blk_integrity_unregister - Unregister block integrity profile 42625520d55SMartin K. Petersen * @disk: disk whose integrity profile to unregister 4277ba1ba12SMartin K. Petersen * 42825520d55SMartin K. Petersen * Description: This function unregisters the integrity capability from 42925520d55SMartin K. Petersen * a block device. 4307ba1ba12SMartin K. Petersen */ 4317ba1ba12SMartin K. Petersen void blk_integrity_unregister(struct gendisk *disk) 4327ba1ba12SMartin K. Petersen { 43325520d55SMartin K. Petersen blk_integrity_revalidate(disk); 434ac6fc48cSDan Williams memset(&disk->queue->integrity, 0, sizeof(struct blk_integrity)); 43525520d55SMartin K. Petersen } 43625520d55SMartin K. Petersen EXPORT_SYMBOL(blk_integrity_unregister); 4377ba1ba12SMartin K. Petersen 43825520d55SMartin K. Petersen void blk_integrity_revalidate(struct gendisk *disk) 43925520d55SMartin K. Petersen { 440ac6fc48cSDan Williams struct blk_integrity *bi = &disk->queue->integrity; 44125520d55SMartin K. Petersen 44225520d55SMartin K. Petersen if (!(disk->flags & GENHD_FL_UP)) 4437ba1ba12SMartin K. Petersen return; 4447ba1ba12SMartin K. Petersen 44525520d55SMartin K. Petersen if (bi->profile) 44625520d55SMartin K. Petersen disk->queue->backing_dev_info.capabilities |= 44725520d55SMartin K. Petersen BDI_CAP_STABLE_WRITES; 44825520d55SMartin K. Petersen else 44925520d55SMartin K. Petersen disk->queue->backing_dev_info.capabilities &= 45025520d55SMartin K. Petersen ~BDI_CAP_STABLE_WRITES; 45125520d55SMartin K. Petersen } 4527d311cdaSDarrick J. Wong 45325520d55SMartin K. Petersen void blk_integrity_add(struct gendisk *disk) 45425520d55SMartin K. Petersen { 45525520d55SMartin K. Petersen if (kobject_init_and_add(&disk->integrity_kobj, &integrity_ktype, 45625520d55SMartin K. Petersen &disk_to_dev(disk)->kobj, "%s", "integrity")) 45725520d55SMartin K. Petersen return; 4587ba1ba12SMartin K. Petersen 45925520d55SMartin K. Petersen kobject_uevent(&disk->integrity_kobj, KOBJ_ADD); 46025520d55SMartin K. Petersen } 46125520d55SMartin K. Petersen 46225520d55SMartin K. Petersen void blk_integrity_del(struct gendisk *disk) 46325520d55SMartin K. Petersen { 464aff34e19SMartin K. Petersen kobject_uevent(&disk->integrity_kobj, KOBJ_REMOVE); 465aff34e19SMartin K. Petersen kobject_del(&disk->integrity_kobj); 466aff34e19SMartin K. Petersen kobject_put(&disk->integrity_kobj); 4677ba1ba12SMartin K. Petersen } 468