Back to home page

LXR

 
 

    


0001 /*
0002  * blk-integrity.c - Block layer data integrity extensions
0003  *
0004  * Copyright (C) 2007, 2008 Oracle Corporation
0005  * Written by: Martin K. Petersen <martin.petersen@oracle.com>
0006  *
0007  * This program is free software; you can redistribute it and/or
0008  * modify it under the terms of the GNU General Public License version
0009  * 2 as published by the Free Software Foundation.
0010  *
0011  * This program is distributed in the hope that it will be useful, but
0012  * WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program; see the file COPYING.  If not, write to
0018  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
0019  * USA.
0020  *
0021  */
0022 
0023 #include <linux/blkdev.h>
0024 #include <linux/backing-dev.h>
0025 #include <linux/mempool.h>
0026 #include <linux/bio.h>
0027 #include <linux/scatterlist.h>
0028 #include <linux/export.h>
0029 #include <linux/slab.h>
0030 
0031 #include "blk.h"
0032 
0033 /**
0034  * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements
0035  * @q:      request queue
0036  * @bio:    bio with integrity metadata attached
0037  *
0038  * Description: Returns the number of elements required in a
0039  * scatterlist corresponding to the integrity metadata in a bio.
0040  */
0041 int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio)
0042 {
0043     struct bio_vec iv, ivprv = { NULL };
0044     unsigned int segments = 0;
0045     unsigned int seg_size = 0;
0046     struct bvec_iter iter;
0047     int prev = 0;
0048 
0049     bio_for_each_integrity_vec(iv, bio, iter) {
0050 
0051         if (prev) {
0052             if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv))
0053                 goto new_segment;
0054 
0055             if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv))
0056                 goto new_segment;
0057 
0058             if (seg_size + iv.bv_len > queue_max_segment_size(q))
0059                 goto new_segment;
0060 
0061             seg_size += iv.bv_len;
0062         } else {
0063 new_segment:
0064             segments++;
0065             seg_size = iv.bv_len;
0066         }
0067 
0068         prev = 1;
0069         ivprv = iv;
0070     }
0071 
0072     return segments;
0073 }
0074 EXPORT_SYMBOL(blk_rq_count_integrity_sg);
0075 
0076 /**
0077  * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist
0078  * @q:      request queue
0079  * @bio:    bio with integrity metadata attached
0080  * @sglist: target scatterlist
0081  *
0082  * Description: Map the integrity vectors in request into a
0083  * scatterlist.  The scatterlist must be big enough to hold all
0084  * elements.  I.e. sized using blk_rq_count_integrity_sg().
0085  */
0086 int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio,
0087                 struct scatterlist *sglist)
0088 {
0089     struct bio_vec iv, ivprv = { NULL };
0090     struct scatterlist *sg = NULL;
0091     unsigned int segments = 0;
0092     struct bvec_iter iter;
0093     int prev = 0;
0094 
0095     bio_for_each_integrity_vec(iv, bio, iter) {
0096 
0097         if (prev) {
0098             if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv))
0099                 goto new_segment;
0100 
0101             if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv))
0102                 goto new_segment;
0103 
0104             if (sg->length + iv.bv_len > queue_max_segment_size(q))
0105                 goto new_segment;
0106 
0107             sg->length += iv.bv_len;
0108         } else {
0109 new_segment:
0110             if (!sg)
0111                 sg = sglist;
0112             else {
0113                 sg_unmark_end(sg);
0114                 sg = sg_next(sg);
0115             }
0116 
0117             sg_set_page(sg, iv.bv_page, iv.bv_len, iv.bv_offset);
0118             segments++;
0119         }
0120 
0121         prev = 1;
0122         ivprv = iv;
0123     }
0124 
0125     if (sg)
0126         sg_mark_end(sg);
0127 
0128     return segments;
0129 }
0130 EXPORT_SYMBOL(blk_rq_map_integrity_sg);
0131 
0132 /**
0133  * blk_integrity_compare - Compare integrity profile of two disks
0134  * @gd1:    Disk to compare
0135  * @gd2:    Disk to compare
0136  *
0137  * Description: Meta-devices like DM and MD need to verify that all
0138  * sub-devices use the same integrity format before advertising to
0139  * upper layers that they can send/receive integrity metadata.  This
0140  * function can be used to check whether two gendisk devices have
0141  * compatible integrity formats.
0142  */
0143 int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
0144 {
0145     struct blk_integrity *b1 = &gd1->queue->integrity;
0146     struct blk_integrity *b2 = &gd2->queue->integrity;
0147 
0148     if (!b1->profile && !b2->profile)
0149         return 0;
0150 
0151     if (!b1->profile || !b2->profile)
0152         return -1;
0153 
0154     if (b1->interval_exp != b2->interval_exp) {
0155         pr_err("%s: %s/%s protection interval %u != %u\n",
0156                __func__, gd1->disk_name, gd2->disk_name,
0157                1 << b1->interval_exp, 1 << b2->interval_exp);
0158         return -1;
0159     }
0160 
0161     if (b1->tuple_size != b2->tuple_size) {
0162         pr_err("%s: %s/%s tuple sz %u != %u\n", __func__,
0163                gd1->disk_name, gd2->disk_name,
0164                b1->tuple_size, b2->tuple_size);
0165         return -1;
0166     }
0167 
0168     if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) {
0169         pr_err("%s: %s/%s tag sz %u != %u\n", __func__,
0170                gd1->disk_name, gd2->disk_name,
0171                b1->tag_size, b2->tag_size);
0172         return -1;
0173     }
0174 
0175     if (b1->profile != b2->profile) {
0176         pr_err("%s: %s/%s type %s != %s\n", __func__,
0177                gd1->disk_name, gd2->disk_name,
0178                b1->profile->name, b2->profile->name);
0179         return -1;
0180     }
0181 
0182     return 0;
0183 }
0184 EXPORT_SYMBOL(blk_integrity_compare);
0185 
0186 bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
0187                 struct request *next)
0188 {
0189     if (blk_integrity_rq(req) == 0 && blk_integrity_rq(next) == 0)
0190         return true;
0191 
0192     if (blk_integrity_rq(req) == 0 || blk_integrity_rq(next) == 0)
0193         return false;
0194 
0195     if (bio_integrity(req->bio)->bip_flags !=
0196         bio_integrity(next->bio)->bip_flags)
0197         return false;
0198 
0199     if (req->nr_integrity_segments + next->nr_integrity_segments >
0200         q->limits.max_integrity_segments)
0201         return false;
0202 
0203     if (integrity_req_gap_back_merge(req, next->bio))
0204         return false;
0205 
0206     return true;
0207 }
0208 EXPORT_SYMBOL(blk_integrity_merge_rq);
0209 
0210 bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
0211                  struct bio *bio)
0212 {
0213     int nr_integrity_segs;
0214     struct bio *next = bio->bi_next;
0215 
0216     if (blk_integrity_rq(req) == 0 && bio_integrity(bio) == NULL)
0217         return true;
0218 
0219     if (blk_integrity_rq(req) == 0 || bio_integrity(bio) == NULL)
0220         return false;
0221 
0222     if (bio_integrity(req->bio)->bip_flags != bio_integrity(bio)->bip_flags)
0223         return false;
0224 
0225     bio->bi_next = NULL;
0226     nr_integrity_segs = blk_rq_count_integrity_sg(q, bio);
0227     bio->bi_next = next;
0228 
0229     if (req->nr_integrity_segments + nr_integrity_segs >
0230         q->limits.max_integrity_segments)
0231         return false;
0232 
0233     req->nr_integrity_segments += nr_integrity_segs;
0234 
0235     return true;
0236 }
0237 EXPORT_SYMBOL(blk_integrity_merge_bio);
0238 
0239 struct integrity_sysfs_entry {
0240     struct attribute attr;
0241     ssize_t (*show)(struct blk_integrity *, char *);
0242     ssize_t (*store)(struct blk_integrity *, const char *, size_t);
0243 };
0244 
0245 static ssize_t integrity_attr_show(struct kobject *kobj, struct attribute *attr,
0246                    char *page)
0247 {
0248     struct gendisk *disk = container_of(kobj, struct gendisk, integrity_kobj);
0249     struct blk_integrity *bi = &disk->queue->integrity;
0250     struct integrity_sysfs_entry *entry =
0251         container_of(attr, struct integrity_sysfs_entry, attr);
0252 
0253     return entry->show(bi, page);
0254 }
0255 
0256 static ssize_t integrity_attr_store(struct kobject *kobj,
0257                     struct attribute *attr, const char *page,
0258                     size_t count)
0259 {
0260     struct gendisk *disk = container_of(kobj, struct gendisk, integrity_kobj);
0261     struct blk_integrity *bi = &disk->queue->integrity;
0262     struct integrity_sysfs_entry *entry =
0263         container_of(attr, struct integrity_sysfs_entry, attr);
0264     ssize_t ret = 0;
0265 
0266     if (entry->store)
0267         ret = entry->store(bi, page, count);
0268 
0269     return ret;
0270 }
0271 
0272 static ssize_t integrity_format_show(struct blk_integrity *bi, char *page)
0273 {
0274     if (bi->profile && bi->profile->name)
0275         return sprintf(page, "%s\n", bi->profile->name);
0276     else
0277         return sprintf(page, "none\n");
0278 }
0279 
0280 static ssize_t integrity_tag_size_show(struct blk_integrity *bi, char *page)
0281 {
0282     return sprintf(page, "%u\n", bi->tag_size);
0283 }
0284 
0285 static ssize_t integrity_interval_show(struct blk_integrity *bi, char *page)
0286 {
0287     return sprintf(page, "%u\n",
0288                bi->interval_exp ? 1 << bi->interval_exp : 0);
0289 }
0290 
0291 static ssize_t integrity_verify_store(struct blk_integrity *bi,
0292                       const char *page, size_t count)
0293 {
0294     char *p = (char *) page;
0295     unsigned long val = simple_strtoul(p, &p, 10);
0296 
0297     if (val)
0298         bi->flags |= BLK_INTEGRITY_VERIFY;
0299     else
0300         bi->flags &= ~BLK_INTEGRITY_VERIFY;
0301 
0302     return count;
0303 }
0304 
0305 static ssize_t integrity_verify_show(struct blk_integrity *bi, char *page)
0306 {
0307     return sprintf(page, "%d\n", (bi->flags & BLK_INTEGRITY_VERIFY) != 0);
0308 }
0309 
0310 static ssize_t integrity_generate_store(struct blk_integrity *bi,
0311                     const char *page, size_t count)
0312 {
0313     char *p = (char *) page;
0314     unsigned long val = simple_strtoul(p, &p, 10);
0315 
0316     if (val)
0317         bi->flags |= BLK_INTEGRITY_GENERATE;
0318     else
0319         bi->flags &= ~BLK_INTEGRITY_GENERATE;
0320 
0321     return count;
0322 }
0323 
0324 static ssize_t integrity_generate_show(struct blk_integrity *bi, char *page)
0325 {
0326     return sprintf(page, "%d\n", (bi->flags & BLK_INTEGRITY_GENERATE) != 0);
0327 }
0328 
0329 static ssize_t integrity_device_show(struct blk_integrity *bi, char *page)
0330 {
0331     return sprintf(page, "%u\n",
0332                (bi->flags & BLK_INTEGRITY_DEVICE_CAPABLE) != 0);
0333 }
0334 
0335 static struct integrity_sysfs_entry integrity_format_entry = {
0336     .attr = { .name = "format", .mode = S_IRUGO },
0337     .show = integrity_format_show,
0338 };
0339 
0340 static struct integrity_sysfs_entry integrity_tag_size_entry = {
0341     .attr = { .name = "tag_size", .mode = S_IRUGO },
0342     .show = integrity_tag_size_show,
0343 };
0344 
0345 static struct integrity_sysfs_entry integrity_interval_entry = {
0346     .attr = { .name = "protection_interval_bytes", .mode = S_IRUGO },
0347     .show = integrity_interval_show,
0348 };
0349 
0350 static struct integrity_sysfs_entry integrity_verify_entry = {
0351     .attr = { .name = "read_verify", .mode = S_IRUGO | S_IWUSR },
0352     .show = integrity_verify_show,
0353     .store = integrity_verify_store,
0354 };
0355 
0356 static struct integrity_sysfs_entry integrity_generate_entry = {
0357     .attr = { .name = "write_generate", .mode = S_IRUGO | S_IWUSR },
0358     .show = integrity_generate_show,
0359     .store = integrity_generate_store,
0360 };
0361 
0362 static struct integrity_sysfs_entry integrity_device_entry = {
0363     .attr = { .name = "device_is_integrity_capable", .mode = S_IRUGO },
0364     .show = integrity_device_show,
0365 };
0366 
0367 static struct attribute *integrity_attrs[] = {
0368     &integrity_format_entry.attr,
0369     &integrity_tag_size_entry.attr,
0370     &integrity_interval_entry.attr,
0371     &integrity_verify_entry.attr,
0372     &integrity_generate_entry.attr,
0373     &integrity_device_entry.attr,
0374     NULL,
0375 };
0376 
0377 static const struct sysfs_ops integrity_ops = {
0378     .show   = &integrity_attr_show,
0379     .store  = &integrity_attr_store,
0380 };
0381 
0382 static struct kobj_type integrity_ktype = {
0383     .default_attrs  = integrity_attrs,
0384     .sysfs_ops  = &integrity_ops,
0385 };
0386 
0387 static int blk_integrity_nop_fn(struct blk_integrity_iter *iter)
0388 {
0389     return 0;
0390 }
0391 
0392 static struct blk_integrity_profile nop_profile = {
0393     .name = "nop",
0394     .generate_fn = blk_integrity_nop_fn,
0395     .verify_fn = blk_integrity_nop_fn,
0396 };
0397 
0398 /**
0399  * blk_integrity_register - Register a gendisk as being integrity-capable
0400  * @disk:   struct gendisk pointer to make integrity-aware
0401  * @template:   block integrity profile to register
0402  *
0403  * Description: When a device needs to advertise itself as being able to
0404  * send/receive integrity metadata it must use this function to register
0405  * the capability with the block layer. The template is a blk_integrity
0406  * struct with values appropriate for the underlying hardware. See
0407  * Documentation/block/data-integrity.txt.
0408  */
0409 void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
0410 {
0411     struct blk_integrity *bi = &disk->queue->integrity;
0412 
0413     bi->flags = BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE |
0414         template->flags;
0415     bi->interval_exp = ilog2(queue_logical_block_size(disk->queue));
0416     bi->profile = template->profile ? template->profile : &nop_profile;
0417     bi->tuple_size = template->tuple_size;
0418     bi->tag_size = template->tag_size;
0419 
0420     blk_integrity_revalidate(disk);
0421 }
0422 EXPORT_SYMBOL(blk_integrity_register);
0423 
0424 /**
0425  * blk_integrity_unregister - Unregister block integrity profile
0426  * @disk:   disk whose integrity profile to unregister
0427  *
0428  * Description: This function unregisters the integrity capability from
0429  * a block device.
0430  */
0431 void blk_integrity_unregister(struct gendisk *disk)
0432 {
0433     blk_integrity_revalidate(disk);
0434     memset(&disk->queue->integrity, 0, sizeof(struct blk_integrity));
0435 }
0436 EXPORT_SYMBOL(blk_integrity_unregister);
0437 
0438 void blk_integrity_revalidate(struct gendisk *disk)
0439 {
0440     struct blk_integrity *bi = &disk->queue->integrity;
0441 
0442     if (!(disk->flags & GENHD_FL_UP))
0443         return;
0444 
0445     if (bi->profile)
0446         disk->queue->backing_dev_info.capabilities |=
0447             BDI_CAP_STABLE_WRITES;
0448     else
0449         disk->queue->backing_dev_info.capabilities &=
0450             ~BDI_CAP_STABLE_WRITES;
0451 }
0452 
0453 void blk_integrity_add(struct gendisk *disk)
0454 {
0455     if (kobject_init_and_add(&disk->integrity_kobj, &integrity_ktype,
0456                  &disk_to_dev(disk)->kobj, "%s", "integrity"))
0457         return;
0458 
0459     kobject_uevent(&disk->integrity_kobj, KOBJ_ADD);
0460 }
0461 
0462 void blk_integrity_del(struct gendisk *disk)
0463 {
0464     kobject_uevent(&disk->integrity_kobj, KOBJ_REMOVE);
0465     kobject_del(&disk->integrity_kobj);
0466     kobject_put(&disk->integrity_kobj);
0467 }