Root/block/blk-integrity.c

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/mempool.h>
25#include <linux/bio.h>
26#include <linux/scatterlist.h>
27#include <linux/slab.h>
28
29#include "blk.h"
30
31static struct kmem_cache *integrity_cachep;
32
33/**
34 * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements
35 * @rq: request with integrity metadata attached
36 *
37 * Description: Returns the number of elements required in a
38 * scatterlist corresponding to the integrity metadata in a request.
39 */
40int blk_rq_count_integrity_sg(struct request *rq)
41{
42    struct bio_vec *iv, *ivprv;
43    struct req_iterator iter;
44    unsigned int segments;
45
46    ivprv = NULL;
47    segments = 0;
48
49    rq_for_each_integrity_segment(iv, rq, iter) {
50
51        if (!ivprv || !BIOVEC_PHYS_MERGEABLE(ivprv, iv))
52            segments++;
53
54        ivprv = iv;
55    }
56
57    return segments;
58}
59EXPORT_SYMBOL(blk_rq_count_integrity_sg);
60
61/**
62 * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist
63 * @rq: request with integrity metadata attached
64 * @sglist: target scatterlist
65 *
66 * Description: Map the integrity vectors in request into a
67 * scatterlist. The scatterlist must be big enough to hold all
68 * elements. I.e. sized using blk_rq_count_integrity_sg().
69 */
70int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist)
71{
72    struct bio_vec *iv, *ivprv;
73    struct req_iterator iter;
74    struct scatterlist *sg;
75    unsigned int segments;
76
77    ivprv = NULL;
78    sg = NULL;
79    segments = 0;
80
81    rq_for_each_integrity_segment(iv, rq, iter) {
82
83        if (ivprv) {
84            if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv))
85                goto new_segment;
86
87            sg->length += iv->bv_len;
88        } else {
89new_segment:
90            if (!sg)
91                sg = sglist;
92            else {
93                sg->page_link &= ~0x02;
94                sg = sg_next(sg);
95            }
96
97            sg_set_page(sg, iv->bv_page, iv->bv_len, iv->bv_offset);
98            segments++;
99        }
100
101        ivprv = iv;
102    }
103
104    if (sg)
105        sg_mark_end(sg);
106
107    return segments;
108}
109EXPORT_SYMBOL(blk_rq_map_integrity_sg);
110
111/**
112 * blk_integrity_compare - Compare integrity profile of two disks
113 * @gd1: Disk to compare
114 * @gd2: Disk to compare
115 *
116 * Description: Meta-devices like DM and MD need to verify that all
117 * sub-devices use the same integrity format before advertising to
118 * upper layers that they can send/receive integrity metadata. This
119 * function can be used to check whether two gendisk devices have
120 * compatible integrity formats.
121 */
122int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
123{
124    struct blk_integrity *b1 = gd1->integrity;
125    struct blk_integrity *b2 = gd2->integrity;
126
127    if (!b1 && !b2)
128        return 0;
129
130    if (!b1 || !b2)
131        return -1;
132
133    if (b1->sector_size != b2->sector_size) {
134        printk(KERN_ERR "%s: %s/%s sector sz %u != %u\n", __func__,
135               gd1->disk_name, gd2->disk_name,
136               b1->sector_size, b2->sector_size);
137        return -1;
138    }
139
140    if (b1->tuple_size != b2->tuple_size) {
141        printk(KERN_ERR "%s: %s/%s tuple sz %u != %u\n", __func__,
142               gd1->disk_name, gd2->disk_name,
143               b1->tuple_size, b2->tuple_size);
144        return -1;
145    }
146
147    if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) {
148        printk(KERN_ERR "%s: %s/%s tag sz %u != %u\n", __func__,
149               gd1->disk_name, gd2->disk_name,
150               b1->tag_size, b2->tag_size);
151        return -1;
152    }
153
154    if (strcmp(b1->name, b2->name)) {
155        printk(KERN_ERR "%s: %s/%s type %s != %s\n", __func__,
156               gd1->disk_name, gd2->disk_name,
157               b1->name, b2->name);
158        return -1;
159    }
160
161    return 0;
162}
163EXPORT_SYMBOL(blk_integrity_compare);
164
165struct integrity_sysfs_entry {
166    struct attribute attr;
167    ssize_t (*show)(struct blk_integrity *, char *);
168    ssize_t (*store)(struct blk_integrity *, const char *, size_t);
169};
170
171static ssize_t integrity_attr_show(struct kobject *kobj, struct attribute *attr,
172                   char *page)
173{
174    struct blk_integrity *bi =
175        container_of(kobj, struct blk_integrity, kobj);
176    struct integrity_sysfs_entry *entry =
177        container_of(attr, struct integrity_sysfs_entry, attr);
178
179    return entry->show(bi, page);
180}
181
182static ssize_t integrity_attr_store(struct kobject *kobj,
183                    struct attribute *attr, const char *page,
184                    size_t count)
185{
186    struct blk_integrity *bi =
187        container_of(kobj, struct blk_integrity, kobj);
188    struct integrity_sysfs_entry *entry =
189        container_of(attr, struct integrity_sysfs_entry, attr);
190    ssize_t ret = 0;
191
192    if (entry->store)
193        ret = entry->store(bi, page, count);
194
195    return ret;
196}
197
198static ssize_t integrity_format_show(struct blk_integrity *bi, char *page)
199{
200    if (bi != NULL && bi->name != NULL)
201        return sprintf(page, "%s\n", bi->name);
202    else
203        return sprintf(page, "none\n");
204}
205
206static ssize_t integrity_tag_size_show(struct blk_integrity *bi, char *page)
207{
208    if (bi != NULL)
209        return sprintf(page, "%u\n", bi->tag_size);
210    else
211        return sprintf(page, "0\n");
212}
213
214static ssize_t integrity_read_store(struct blk_integrity *bi,
215                    const char *page, size_t count)
216{
217    char *p = (char *) page;
218    unsigned long val = simple_strtoul(p, &p, 10);
219
220    if (val)
221        bi->flags |= INTEGRITY_FLAG_READ;
222    else
223        bi->flags &= ~INTEGRITY_FLAG_READ;
224
225    return count;
226}
227
228static ssize_t integrity_read_show(struct blk_integrity *bi, char *page)
229{
230    return sprintf(page, "%d\n", (bi->flags & INTEGRITY_FLAG_READ) != 0);
231}
232
233static ssize_t integrity_write_store(struct blk_integrity *bi,
234                     const char *page, size_t count)
235{
236    char *p = (char *) page;
237    unsigned long val = simple_strtoul(p, &p, 10);
238
239    if (val)
240        bi->flags |= INTEGRITY_FLAG_WRITE;
241    else
242        bi->flags &= ~INTEGRITY_FLAG_WRITE;
243
244    return count;
245}
246
247static ssize_t integrity_write_show(struct blk_integrity *bi, char *page)
248{
249    return sprintf(page, "%d\n", (bi->flags & INTEGRITY_FLAG_WRITE) != 0);
250}
251
252static struct integrity_sysfs_entry integrity_format_entry = {
253    .attr = { .name = "format", .mode = S_IRUGO },
254    .show = integrity_format_show,
255};
256
257static struct integrity_sysfs_entry integrity_tag_size_entry = {
258    .attr = { .name = "tag_size", .mode = S_IRUGO },
259    .show = integrity_tag_size_show,
260};
261
262static struct integrity_sysfs_entry integrity_read_entry = {
263    .attr = { .name = "read_verify", .mode = S_IRUGO | S_IWUSR },
264    .show = integrity_read_show,
265    .store = integrity_read_store,
266};
267
268static struct integrity_sysfs_entry integrity_write_entry = {
269    .attr = { .name = "write_generate", .mode = S_IRUGO | S_IWUSR },
270    .show = integrity_write_show,
271    .store = integrity_write_store,
272};
273
274static struct attribute *integrity_attrs[] = {
275    &integrity_format_entry.attr,
276    &integrity_tag_size_entry.attr,
277    &integrity_read_entry.attr,
278    &integrity_write_entry.attr,
279    NULL,
280};
281
282static const struct sysfs_ops integrity_ops = {
283    .show = &integrity_attr_show,
284    .store = &integrity_attr_store,
285};
286
287static int __init blk_dev_integrity_init(void)
288{
289    integrity_cachep = kmem_cache_create("blkdev_integrity",
290                         sizeof(struct blk_integrity),
291                         0, SLAB_PANIC, NULL);
292    return 0;
293}
294subsys_initcall(blk_dev_integrity_init);
295
296static void blk_integrity_release(struct kobject *kobj)
297{
298    struct blk_integrity *bi =
299        container_of(kobj, struct blk_integrity, kobj);
300
301    kmem_cache_free(integrity_cachep, bi);
302}
303
304static struct kobj_type integrity_ktype = {
305    .default_attrs = integrity_attrs,
306    .sysfs_ops = &integrity_ops,
307    .release = blk_integrity_release,
308};
309
310/**
311 * blk_integrity_register - Register a gendisk as being integrity-capable
312 * @disk: struct gendisk pointer to make integrity-aware
313 * @template: optional integrity profile to register
314 *
315 * Description: When a device needs to advertise itself as being able
316 * to send/receive integrity metadata it must use this function to
317 * register the capability with the block layer. The template is a
318 * blk_integrity struct with values appropriate for the underlying
319 * hardware. If template is NULL the new profile is allocated but
320 * not filled out. See Documentation/block/data-integrity.txt.
321 */
322int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
323{
324    struct blk_integrity *bi;
325
326    BUG_ON(disk == NULL);
327
328    if (disk->integrity == NULL) {
329        bi = kmem_cache_alloc(integrity_cachep,
330                      GFP_KERNEL | __GFP_ZERO);
331        if (!bi)
332            return -1;
333
334        if (kobject_init_and_add(&bi->kobj, &integrity_ktype,
335                     &disk_to_dev(disk)->kobj,
336                     "%s", "integrity")) {
337            kmem_cache_free(integrity_cachep, bi);
338            return -1;
339        }
340
341        kobject_uevent(&bi->kobj, KOBJ_ADD);
342
343        bi->flags |= INTEGRITY_FLAG_READ | INTEGRITY_FLAG_WRITE;
344        bi->sector_size = queue_logical_block_size(disk->queue);
345        disk->integrity = bi;
346    } else
347        bi = disk->integrity;
348
349    /* Use the provided profile as template */
350    if (template != NULL) {
351        bi->name = template->name;
352        bi->generate_fn = template->generate_fn;
353        bi->verify_fn = template->verify_fn;
354        bi->tuple_size = template->tuple_size;
355        bi->set_tag_fn = template->set_tag_fn;
356        bi->get_tag_fn = template->get_tag_fn;
357        bi->tag_size = template->tag_size;
358    } else
359        bi->name = "unsupported";
360
361    return 0;
362}
363EXPORT_SYMBOL(blk_integrity_register);
364
365/**
366 * blk_integrity_unregister - Remove block integrity profile
367 * @disk: disk whose integrity profile to deallocate
368 *
369 * Description: This function frees all memory used by the block
370 * integrity profile. To be called at device teardown.
371 */
372void blk_integrity_unregister(struct gendisk *disk)
373{
374    struct blk_integrity *bi;
375
376    if (!disk || !disk->integrity)
377        return;
378
379    bi = disk->integrity;
380
381    kobject_uevent(&bi->kobj, KOBJ_REMOVE);
382    kobject_del(&bi->kobj);
383    kobject_put(&bi->kobj);
384    kmem_cache_free(integrity_cachep, bi);
385    disk->integrity = NULL;
386}
387EXPORT_SYMBOL(blk_integrity_unregister);
388

Archive Download this file



interactive