at v4.12 12 kB view raw
1/* 2 * blk-integrity.c - Block layer data integrity extensions 3 * 4 * Copyright (C) 2007, 2008 Oracle Corporation 5 * Written by: Martin K. Petersen <martin.petersen@oracle.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License version 9 * 2 as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; see the file COPYING. If not, write to 18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, 19 * USA. 20 * 21 */ 22 23#include <linux/blkdev.h> 24#include <linux/backing-dev.h> 25#include <linux/mempool.h> 26#include <linux/bio.h> 27#include <linux/scatterlist.h> 28#include <linux/export.h> 29#include <linux/slab.h> 30 31#include "blk.h" 32 33/** 34 * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements 35 * @q: request queue 36 * @bio: bio with integrity metadata attached 37 * 38 * Description: Returns the number of elements required in a 39 * scatterlist corresponding to the integrity metadata in a bio. 40 */ 41int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio) 42{ 43 struct bio_vec iv, ivprv = { NULL }; 44 unsigned int segments = 0; 45 unsigned int seg_size = 0; 46 struct bvec_iter iter; 47 int prev = 0; 48 49 bio_for_each_integrity_vec(iv, bio, iter) { 50 51 if (prev) { 52 if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv)) 53 goto new_segment; 54 55 if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv)) 56 goto new_segment; 57 58 if (seg_size + iv.bv_len > queue_max_segment_size(q)) 59 goto new_segment; 60 61 seg_size += iv.bv_len; 62 } else { 63new_segment: 64 segments++; 65 seg_size = iv.bv_len; 66 } 67 68 prev = 1; 69 ivprv = iv; 70 } 71 72 return segments; 73} 74EXPORT_SYMBOL(blk_rq_count_integrity_sg); 75 76/** 77 * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist 78 * @q: request queue 79 * @bio: bio with integrity metadata attached 80 * @sglist: target scatterlist 81 * 82 * Description: Map the integrity vectors in request into a 83 * scatterlist. The scatterlist must be big enough to hold all 84 * elements. I.e. sized using blk_rq_count_integrity_sg(). 85 */ 86int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio, 87 struct scatterlist *sglist) 88{ 89 struct bio_vec iv, ivprv = { NULL }; 90 struct scatterlist *sg = NULL; 91 unsigned int segments = 0; 92 struct bvec_iter iter; 93 int prev = 0; 94 95 bio_for_each_integrity_vec(iv, bio, iter) { 96 97 if (prev) { 98 if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv)) 99 goto new_segment; 100 101 if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv)) 102 goto new_segment; 103 104 if (sg->length + iv.bv_len > queue_max_segment_size(q)) 105 goto new_segment; 106 107 sg->length += iv.bv_len; 108 } else { 109new_segment: 110 if (!sg) 111 sg = sglist; 112 else { 113 sg_unmark_end(sg); 114 sg = sg_next(sg); 115 } 116 117 sg_set_page(sg, iv.bv_page, iv.bv_len, iv.bv_offset); 118 segments++; 119 } 120 121 prev = 1; 122 ivprv = iv; 123 } 124 125 if (sg) 126 sg_mark_end(sg); 127 128 return segments; 129} 130EXPORT_SYMBOL(blk_rq_map_integrity_sg); 131 132/** 133 * blk_integrity_compare - Compare integrity profile of two disks 134 * @gd1: Disk to compare 135 * @gd2: Disk to compare 136 * 137 * Description: Meta-devices like DM and MD need to verify that all 138 * sub-devices use the same integrity format before advertising to 139 * upper layers that they can send/receive integrity metadata. This 140 * function can be used to check whether two gendisk devices have 141 * compatible integrity formats. 142 */ 143int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2) 144{ 145 struct blk_integrity *b1 = &gd1->queue->integrity; 146 struct blk_integrity *b2 = &gd2->queue->integrity; 147 148 if (!b1->profile && !b2->profile) 149 return 0; 150 151 if (!b1->profile || !b2->profile) 152 return -1; 153 154 if (b1->interval_exp != b2->interval_exp) { 155 pr_err("%s: %s/%s protection interval %u != %u\n", 156 __func__, gd1->disk_name, gd2->disk_name, 157 1 << b1->interval_exp, 1 << b2->interval_exp); 158 return -1; 159 } 160 161 if (b1->tuple_size != b2->tuple_size) { 162 pr_err("%s: %s/%s tuple sz %u != %u\n", __func__, 163 gd1->disk_name, gd2->disk_name, 164 b1->tuple_size, b2->tuple_size); 165 return -1; 166 } 167 168 if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) { 169 pr_err("%s: %s/%s tag sz %u != %u\n", __func__, 170 gd1->disk_name, gd2->disk_name, 171 b1->tag_size, b2->tag_size); 172 return -1; 173 } 174 175 if (b1->profile != b2->profile) { 176 pr_err("%s: %s/%s type %s != %s\n", __func__, 177 gd1->disk_name, gd2->disk_name, 178 b1->profile->name, b2->profile->name); 179 return -1; 180 } 181 182 return 0; 183} 184EXPORT_SYMBOL(blk_integrity_compare); 185 186bool blk_integrity_merge_rq(struct request_queue *q, struct request *req, 187 struct request *next) 188{ 189 if (blk_integrity_rq(req) == 0 && blk_integrity_rq(next) == 0) 190 return true; 191 192 if (blk_integrity_rq(req) == 0 || blk_integrity_rq(next) == 0) 193 return false; 194 195 if (bio_integrity(req->bio)->bip_flags != 196 bio_integrity(next->bio)->bip_flags) 197 return false; 198 199 if (req->nr_integrity_segments + next->nr_integrity_segments > 200 q->limits.max_integrity_segments) 201 return false; 202 203 if (integrity_req_gap_back_merge(req, next->bio)) 204 return false; 205 206 return true; 207} 208EXPORT_SYMBOL(blk_integrity_merge_rq); 209 210bool blk_integrity_merge_bio(struct request_queue *q, struct request *req, 211 struct bio *bio) 212{ 213 int nr_integrity_segs; 214 struct bio *next = bio->bi_next; 215 216 if (blk_integrity_rq(req) == 0 && bio_integrity(bio) == NULL) 217 return true; 218 219 if (blk_integrity_rq(req) == 0 || bio_integrity(bio) == NULL) 220 return false; 221 222 if (bio_integrity(req->bio)->bip_flags != bio_integrity(bio)->bip_flags) 223 return false; 224 225 bio->bi_next = NULL; 226 nr_integrity_segs = blk_rq_count_integrity_sg(q, bio); 227 bio->bi_next = next; 228 229 if (req->nr_integrity_segments + nr_integrity_segs > 230 q->limits.max_integrity_segments) 231 return false; 232 233 req->nr_integrity_segments += nr_integrity_segs; 234 235 return true; 236} 237EXPORT_SYMBOL(blk_integrity_merge_bio); 238 239struct integrity_sysfs_entry { 240 struct attribute attr; 241 ssize_t (*show)(struct blk_integrity *, char *); 242 ssize_t (*store)(struct blk_integrity *, const char *, size_t); 243}; 244 245static ssize_t integrity_attr_show(struct kobject *kobj, struct attribute *attr, 246 char *page) 247{ 248 struct gendisk *disk = container_of(kobj, struct gendisk, integrity_kobj); 249 struct blk_integrity *bi = &disk->queue->integrity; 250 struct integrity_sysfs_entry *entry = 251 container_of(attr, struct integrity_sysfs_entry, attr); 252 253 return entry->show(bi, page); 254} 255 256static ssize_t integrity_attr_store(struct kobject *kobj, 257 struct attribute *attr, const char *page, 258 size_t count) 259{ 260 struct gendisk *disk = container_of(kobj, struct gendisk, integrity_kobj); 261 struct blk_integrity *bi = &disk->queue->integrity; 262 struct integrity_sysfs_entry *entry = 263 container_of(attr, struct integrity_sysfs_entry, attr); 264 ssize_t ret = 0; 265 266 if (entry->store) 267 ret = entry->store(bi, page, count); 268 269 return ret; 270} 271 272static ssize_t integrity_format_show(struct blk_integrity *bi, char *page) 273{ 274 if (bi->profile && bi->profile->name) 275 return sprintf(page, "%s\n", bi->profile->name); 276 else 277 return sprintf(page, "none\n"); 278} 279 280static ssize_t integrity_tag_size_show(struct blk_integrity *bi, char *page) 281{ 282 return sprintf(page, "%u\n", bi->tag_size); 283} 284 285static ssize_t integrity_interval_show(struct blk_integrity *bi, char *page) 286{ 287 return sprintf(page, "%u\n", 288 bi->interval_exp ? 1 << bi->interval_exp : 0); 289} 290 291static ssize_t integrity_verify_store(struct blk_integrity *bi, 292 const char *page, size_t count) 293{ 294 char *p = (char *) page; 295 unsigned long val = simple_strtoul(p, &p, 10); 296 297 if (val) 298 bi->flags |= BLK_INTEGRITY_VERIFY; 299 else 300 bi->flags &= ~BLK_INTEGRITY_VERIFY; 301 302 return count; 303} 304 305static ssize_t integrity_verify_show(struct blk_integrity *bi, char *page) 306{ 307 return sprintf(page, "%d\n", (bi->flags & BLK_INTEGRITY_VERIFY) != 0); 308} 309 310static ssize_t integrity_generate_store(struct blk_integrity *bi, 311 const char *page, size_t count) 312{ 313 char *p = (char *) page; 314 unsigned long val = simple_strtoul(p, &p, 10); 315 316 if (val) 317 bi->flags |= BLK_INTEGRITY_GENERATE; 318 else 319 bi->flags &= ~BLK_INTEGRITY_GENERATE; 320 321 return count; 322} 323 324static ssize_t integrity_generate_show(struct blk_integrity *bi, char *page) 325{ 326 return sprintf(page, "%d\n", (bi->flags & BLK_INTEGRITY_GENERATE) != 0); 327} 328 329static ssize_t integrity_device_show(struct blk_integrity *bi, char *page) 330{ 331 return sprintf(page, "%u\n", 332 (bi->flags & BLK_INTEGRITY_DEVICE_CAPABLE) != 0); 333} 334 335static struct integrity_sysfs_entry integrity_format_entry = { 336 .attr = { .name = "format", .mode = S_IRUGO }, 337 .show = integrity_format_show, 338}; 339 340static struct integrity_sysfs_entry integrity_tag_size_entry = { 341 .attr = { .name = "tag_size", .mode = S_IRUGO }, 342 .show = integrity_tag_size_show, 343}; 344 345static struct integrity_sysfs_entry integrity_interval_entry = { 346 .attr = { .name = "protection_interval_bytes", .mode = S_IRUGO }, 347 .show = integrity_interval_show, 348}; 349 350static struct integrity_sysfs_entry integrity_verify_entry = { 351 .attr = { .name = "read_verify", .mode = S_IRUGO | S_IWUSR }, 352 .show = integrity_verify_show, 353 .store = integrity_verify_store, 354}; 355 356static struct integrity_sysfs_entry integrity_generate_entry = { 357 .attr = { .name = "write_generate", .mode = S_IRUGO | S_IWUSR }, 358 .show = integrity_generate_show, 359 .store = integrity_generate_store, 360}; 361 362static struct integrity_sysfs_entry integrity_device_entry = { 363 .attr = { .name = "device_is_integrity_capable", .mode = S_IRUGO }, 364 .show = integrity_device_show, 365}; 366 367static struct attribute *integrity_attrs[] = { 368 &integrity_format_entry.attr, 369 &integrity_tag_size_entry.attr, 370 &integrity_interval_entry.attr, 371 &integrity_verify_entry.attr, 372 &integrity_generate_entry.attr, 373 &integrity_device_entry.attr, 374 NULL, 375}; 376 377static const struct sysfs_ops integrity_ops = { 378 .show = &integrity_attr_show, 379 .store = &integrity_attr_store, 380}; 381 382static struct kobj_type integrity_ktype = { 383 .default_attrs = integrity_attrs, 384 .sysfs_ops = &integrity_ops, 385}; 386 387static int blk_integrity_nop_fn(struct blk_integrity_iter *iter) 388{ 389 return 0; 390} 391 392static const struct blk_integrity_profile nop_profile = { 393 .name = "nop", 394 .generate_fn = blk_integrity_nop_fn, 395 .verify_fn = blk_integrity_nop_fn, 396}; 397 398/** 399 * blk_integrity_register - Register a gendisk as being integrity-capable 400 * @disk: struct gendisk pointer to make integrity-aware 401 * @template: block integrity profile to register 402 * 403 * Description: When a device needs to advertise itself as being able to 404 * send/receive integrity metadata it must use this function to register 405 * the capability with the block layer. The template is a blk_integrity 406 * struct with values appropriate for the underlying hardware. See 407 * Documentation/block/data-integrity.txt. 408 */ 409void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template) 410{ 411 struct blk_integrity *bi = &disk->queue->integrity; 412 413 bi->flags = BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE | 414 template->flags; 415 bi->interval_exp = template->interval_exp ? : 416 ilog2(queue_logical_block_size(disk->queue)); 417 bi->profile = template->profile ? template->profile : &nop_profile; 418 bi->tuple_size = template->tuple_size; 419 bi->tag_size = template->tag_size; 420 421 disk->queue->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES; 422} 423EXPORT_SYMBOL(blk_integrity_register); 424 425/** 426 * blk_integrity_unregister - Unregister block integrity profile 427 * @disk: disk whose integrity profile to unregister 428 * 429 * Description: This function unregisters the integrity capability from 430 * a block device. 431 */ 432void blk_integrity_unregister(struct gendisk *disk) 433{ 434 disk->queue->backing_dev_info->capabilities &= ~BDI_CAP_STABLE_WRITES; 435 memset(&disk->queue->integrity, 0, sizeof(struct blk_integrity)); 436} 437EXPORT_SYMBOL(blk_integrity_unregister); 438 439void blk_integrity_add(struct gendisk *disk) 440{ 441 if (kobject_init_and_add(&disk->integrity_kobj, &integrity_ktype, 442 &disk_to_dev(disk)->kobj, "%s", "integrity")) 443 return; 444 445 kobject_uevent(&disk->integrity_kobj, KOBJ_ADD); 446} 447 448void blk_integrity_del(struct gendisk *disk) 449{ 450 kobject_uevent(&disk->integrity_kobj, KOBJ_REMOVE); 451 kobject_del(&disk->integrity_kobj); 452 kobject_put(&disk->integrity_kobj); 453}