Blame view

block/blk-integrity.c 12.4 KB
7ba1ba12e   Martin K. Petersen   block: Block laye...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   * blk-integrity.c - Block layer data integrity extensions
   *
   * Copyright (C) 2007, 2008 Oracle Corporation
   * Written by: Martin K. Petersen <martin.petersen@oracle.com>
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License version
   * 2 as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; see the file COPYING.  If not, write to
   * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
   * USA.
   *
   */
  
  #include <linux/blkdev.h>
  #include <linux/mempool.h>
  #include <linux/bio.h>
  #include <linux/scatterlist.h>
d5decd3b9   Paul Gortmaker   block: add export...
27
  #include <linux/export.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
28
  #include <linux/slab.h>
7ba1ba12e   Martin K. Petersen   block: Block laye...
29
30
31
32
  
  #include "blk.h"
  
  static struct kmem_cache *integrity_cachep;
a63a5cf84   Mike Snitzer   dm: improve block...
33
  static const char *bi_unsupported_name = "unsupported";
7ba1ba12e   Martin K. Petersen   block: Block laye...
34
35
  /**
   * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
36
37
   * @q:		request queue
   * @bio:	bio with integrity metadata attached
7ba1ba12e   Martin K. Petersen   block: Block laye...
38
39
   *
   * Description: Returns the number of elements required in a
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
40
   * scatterlist corresponding to the integrity metadata in a bio.
7ba1ba12e   Martin K. Petersen   block: Block laye...
41
   */
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
42
  int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio)
7ba1ba12e   Martin K. Petersen   block: Block laye...
43
  {
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
44
  	struct bio_vec iv, ivprv = { NULL };
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
45
46
  	unsigned int segments = 0;
  	unsigned int seg_size = 0;
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
47
48
  	struct bvec_iter iter;
  	int prev = 0;
7ba1ba12e   Martin K. Petersen   block: Block laye...
49

d57a5f7c6   Kent Overstreet   bio-integrity: Co...
50
  	bio_for_each_integrity_vec(iv, bio, iter) {
7ba1ba12e   Martin K. Petersen   block: Block laye...
51

d57a5f7c6   Kent Overstreet   bio-integrity: Co...
52
53
  		if (prev) {
  			if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv))
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
54
  				goto new_segment;
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
55
  			if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv))
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
56
  				goto new_segment;
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
57
  			if (seg_size + iv.bv_len > queue_max_segment_size(q))
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
58
  				goto new_segment;
7ba1ba12e   Martin K. Petersen   block: Block laye...
59

d57a5f7c6   Kent Overstreet   bio-integrity: Co...
60
  			seg_size += iv.bv_len;
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
61
62
  		} else {
  new_segment:
7ba1ba12e   Martin K. Petersen   block: Block laye...
63
  			segments++;
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
64
  			seg_size = iv.bv_len;
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
65
  		}
7ba1ba12e   Martin K. Petersen   block: Block laye...
66

d57a5f7c6   Kent Overstreet   bio-integrity: Co...
67
  		prev = 1;
7ba1ba12e   Martin K. Petersen   block: Block laye...
68
69
70
71
72
73
74
75
76
  		ivprv = iv;
  	}
  
  	return segments;
  }
  EXPORT_SYMBOL(blk_rq_count_integrity_sg);
  
  /**
   * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
77
78
   * @q:		request queue
   * @bio:	bio with integrity metadata attached
7ba1ba12e   Martin K. Petersen   block: Block laye...
79
80
81
82
83
84
   * @sglist:	target scatterlist
   *
   * Description: Map the integrity vectors in request into a
   * scatterlist.  The scatterlist must be big enough to hold all
   * elements.  I.e. sized using blk_rq_count_integrity_sg().
   */
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
85
86
  int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio,
  			    struct scatterlist *sglist)
7ba1ba12e   Martin K. Petersen   block: Block laye...
87
  {
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
88
  	struct bio_vec iv, ivprv = { NULL };
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
89
90
  	struct scatterlist *sg = NULL;
  	unsigned int segments = 0;
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
91
92
  	struct bvec_iter iter;
  	int prev = 0;
7ba1ba12e   Martin K. Petersen   block: Block laye...
93

d57a5f7c6   Kent Overstreet   bio-integrity: Co...
94
  	bio_for_each_integrity_vec(iv, bio, iter) {
7ba1ba12e   Martin K. Petersen   block: Block laye...
95

d57a5f7c6   Kent Overstreet   bio-integrity: Co...
96
97
  		if (prev) {
  			if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv))
7ba1ba12e   Martin K. Petersen   block: Block laye...
98
  				goto new_segment;
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
99
  			if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv))
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
100
  				goto new_segment;
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
101
  			if (sg->length + iv.bv_len > queue_max_segment_size(q))
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
102
  				goto new_segment;
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
103
  			sg->length += iv.bv_len;
7ba1ba12e   Martin K. Petersen   block: Block laye...
104
105
106
107
108
  		} else {
  new_segment:
  			if (!sg)
  				sg = sglist;
  			else {
c8164d893   Paolo Bonzini   scatterlist: intr...
109
  				sg_unmark_end(sg);
7ba1ba12e   Martin K. Petersen   block: Block laye...
110
111
  				sg = sg_next(sg);
  			}
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
112
  			sg_set_page(sg, iv.bv_page, iv.bv_len, iv.bv_offset);
7ba1ba12e   Martin K. Petersen   block: Block laye...
113
114
  			segments++;
  		}
d57a5f7c6   Kent Overstreet   bio-integrity: Co...
115
  		prev = 1;
7ba1ba12e   Martin K. Petersen   block: Block laye...
116
117
118
119
120
121
122
123
124
125
126
  		ivprv = iv;
  	}
  
  	if (sg)
  		sg_mark_end(sg);
  
  	return segments;
  }
  EXPORT_SYMBOL(blk_rq_map_integrity_sg);
  
  /**
ad7fce931   Martin K. Petersen   block: Switch blk...
127
128
129
   * blk_integrity_compare - Compare integrity profile of two disks
   * @gd1:	Disk to compare
   * @gd2:	Disk to compare
7ba1ba12e   Martin K. Petersen   block: Block laye...
130
131
132
133
   *
   * Description: Meta-devices like DM and MD need to verify that all
   * sub-devices use the same integrity format before advertising to
   * upper layers that they can send/receive integrity metadata.  This
ad7fce931   Martin K. Petersen   block: Switch blk...
134
   * function can be used to check whether two gendisk devices have
7ba1ba12e   Martin K. Petersen   block: Block laye...
135
136
   * compatible integrity formats.
   */
ad7fce931   Martin K. Petersen   block: Switch blk...
137
  int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
7ba1ba12e   Martin K. Petersen   block: Block laye...
138
  {
ad7fce931   Martin K. Petersen   block: Switch blk...
139
140
  	struct blk_integrity *b1 = gd1->integrity;
  	struct blk_integrity *b2 = gd2->integrity;
7ba1ba12e   Martin K. Petersen   block: Block laye...
141

ad7fce931   Martin K. Petersen   block: Switch blk...
142
143
  	if (!b1 && !b2)
  		return 0;
7ba1ba12e   Martin K. Petersen   block: Block laye...
144
145
  
  	if (!b1 || !b2)
ad7fce931   Martin K. Petersen   block: Switch blk...
146
  		return -1;
7ba1ba12e   Martin K. Petersen   block: Block laye...
147

3be91c4a3   Martin K. Petersen   block: Deprecate ...
148
149
150
151
152
  	if (b1->interval != b2->interval) {
  		pr_err("%s: %s/%s protection interval %u != %u
  ",
  		       __func__, gd1->disk_name, gd2->disk_name,
  		       b1->interval, b2->interval);
7ba1ba12e   Martin K. Petersen   block: Block laye...
153
154
155
156
157
158
  		return -1;
  	}
  
  	if (b1->tuple_size != b2->tuple_size) {
  		printk(KERN_ERR "%s: %s/%s tuple sz %u != %u
  ", __func__,
ad7fce931   Martin K. Petersen   block: Switch blk...
159
  		       gd1->disk_name, gd2->disk_name,
7ba1ba12e   Martin K. Petersen   block: Block laye...
160
161
162
163
164
165
166
  		       b1->tuple_size, b2->tuple_size);
  		return -1;
  	}
  
  	if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) {
  		printk(KERN_ERR "%s: %s/%s tag sz %u != %u
  ", __func__,
ad7fce931   Martin K. Petersen   block: Switch blk...
167
  		       gd1->disk_name, gd2->disk_name,
7ba1ba12e   Martin K. Petersen   block: Block laye...
168
169
170
171
172
173
174
  		       b1->tag_size, b2->tag_size);
  		return -1;
  	}
  
  	if (strcmp(b1->name, b2->name)) {
  		printk(KERN_ERR "%s: %s/%s type %s != %s
  ", __func__,
ad7fce931   Martin K. Petersen   block: Switch blk...
175
  		       gd1->disk_name, gd2->disk_name,
7ba1ba12e   Martin K. Petersen   block: Block laye...
176
177
178
179
180
181
182
  		       b1->name, b2->name);
  		return -1;
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL(blk_integrity_compare);
4eaf99bea   Martin K. Petersen   block: Don't merg...
183
184
  bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
  			    struct request *next)
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
185
  {
4eaf99bea   Martin K. Petersen   block: Don't merg...
186
187
188
189
190
191
192
193
194
  	if (blk_integrity_rq(req) == 0 && blk_integrity_rq(next) == 0)
  		return true;
  
  	if (blk_integrity_rq(req) == 0 || blk_integrity_rq(next) == 0)
  		return false;
  
  	if (bio_integrity(req->bio)->bip_flags !=
  	    bio_integrity(next->bio)->bip_flags)
  		return false;
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
195
196
197
  
  	if (req->nr_integrity_segments + next->nr_integrity_segments >
  	    q->limits.max_integrity_segments)
4eaf99bea   Martin K. Petersen   block: Don't merg...
198
  		return false;
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
199

4eaf99bea   Martin K. Petersen   block: Don't merg...
200
  	return true;
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
201
202
  }
  EXPORT_SYMBOL(blk_integrity_merge_rq);
4eaf99bea   Martin K. Petersen   block: Don't merg...
203
204
  bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
  			     struct bio *bio)
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
205
206
207
  {
  	int nr_integrity_segs;
  	struct bio *next = bio->bi_next;
4eaf99bea   Martin K. Petersen   block: Don't merg...
208
209
210
211
212
213
214
215
  	if (blk_integrity_rq(req) == 0 && bio_integrity(bio) == NULL)
  		return true;
  
  	if (blk_integrity_rq(req) == 0 || bio_integrity(bio) == NULL)
  		return false;
  
  	if (bio_integrity(req->bio)->bip_flags != bio_integrity(bio)->bip_flags)
  		return false;
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
216
217
218
219
220
221
  	bio->bi_next = NULL;
  	nr_integrity_segs = blk_rq_count_integrity_sg(q, bio);
  	bio->bi_next = next;
  
  	if (req->nr_integrity_segments + nr_integrity_segs >
  	    q->limits.max_integrity_segments)
4eaf99bea   Martin K. Petersen   block: Don't merg...
222
  		return false;
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
223
224
  
  	req->nr_integrity_segments += nr_integrity_segs;
4eaf99bea   Martin K. Petersen   block: Don't merg...
225
  	return true;
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
226
227
  }
  EXPORT_SYMBOL(blk_integrity_merge_bio);
7ba1ba12e   Martin K. Petersen   block: Block laye...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  struct integrity_sysfs_entry {
  	struct attribute attr;
  	ssize_t (*show)(struct blk_integrity *, char *);
  	ssize_t (*store)(struct blk_integrity *, const char *, size_t);
  };
  
  static ssize_t integrity_attr_show(struct kobject *kobj, struct attribute *attr,
  				   char *page)
  {
  	struct blk_integrity *bi =
  		container_of(kobj, struct blk_integrity, kobj);
  	struct integrity_sysfs_entry *entry =
  		container_of(attr, struct integrity_sysfs_entry, attr);
  
  	return entry->show(bi, page);
  }
b984679ef   Jens Axboe   block: integrity ...
244
245
246
  static ssize_t integrity_attr_store(struct kobject *kobj,
  				    struct attribute *attr, const char *page,
  				    size_t count)
7ba1ba12e   Martin K. Petersen   block: Block laye...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  {
  	struct blk_integrity *bi =
  		container_of(kobj, struct blk_integrity, kobj);
  	struct integrity_sysfs_entry *entry =
  		container_of(attr, struct integrity_sysfs_entry, attr);
  	ssize_t ret = 0;
  
  	if (entry->store)
  		ret = entry->store(bi, page, count);
  
  	return ret;
  }
  
  static ssize_t integrity_format_show(struct blk_integrity *bi, char *page)
  {
  	if (bi != NULL && bi->name != NULL)
  		return sprintf(page, "%s
  ", bi->name);
  	else
  		return sprintf(page, "none
  ");
  }
  
  static ssize_t integrity_tag_size_show(struct blk_integrity *bi, char *page)
  {
  	if (bi != NULL)
  		return sprintf(page, "%u
  ", bi->tag_size);
  	else
  		return sprintf(page, "0
  ");
  }
8288f496e   Martin K. Petersen   block: Add prefix...
279
280
  static ssize_t integrity_verify_store(struct blk_integrity *bi,
  				      const char *page, size_t count)
7ba1ba12e   Martin K. Petersen   block: Block laye...
281
282
283
284
285
  {
  	char *p = (char *) page;
  	unsigned long val = simple_strtoul(p, &p, 10);
  
  	if (val)
8288f496e   Martin K. Petersen   block: Add prefix...
286
  		bi->flags |= BLK_INTEGRITY_VERIFY;
7ba1ba12e   Martin K. Petersen   block: Block laye...
287
  	else
8288f496e   Martin K. Petersen   block: Add prefix...
288
  		bi->flags &= ~BLK_INTEGRITY_VERIFY;
7ba1ba12e   Martin K. Petersen   block: Block laye...
289
290
291
  
  	return count;
  }
8288f496e   Martin K. Petersen   block: Add prefix...
292
  static ssize_t integrity_verify_show(struct blk_integrity *bi, char *page)
7ba1ba12e   Martin K. Petersen   block: Block laye...
293
  {
8288f496e   Martin K. Petersen   block: Add prefix...
294
295
  	return sprintf(page, "%d
  ", (bi->flags & BLK_INTEGRITY_VERIFY) != 0);
7ba1ba12e   Martin K. Petersen   block: Block laye...
296
  }
8288f496e   Martin K. Petersen   block: Add prefix...
297
298
  static ssize_t integrity_generate_store(struct blk_integrity *bi,
  					const char *page, size_t count)
7ba1ba12e   Martin K. Petersen   block: Block laye...
299
300
301
302
303
  {
  	char *p = (char *) page;
  	unsigned long val = simple_strtoul(p, &p, 10);
  
  	if (val)
8288f496e   Martin K. Petersen   block: Add prefix...
304
  		bi->flags |= BLK_INTEGRITY_GENERATE;
7ba1ba12e   Martin K. Petersen   block: Block laye...
305
  	else
8288f496e   Martin K. Petersen   block: Add prefix...
306
  		bi->flags &= ~BLK_INTEGRITY_GENERATE;
7ba1ba12e   Martin K. Petersen   block: Block laye...
307
308
309
  
  	return count;
  }
8288f496e   Martin K. Petersen   block: Add prefix...
310
  static ssize_t integrity_generate_show(struct blk_integrity *bi, char *page)
7ba1ba12e   Martin K. Petersen   block: Block laye...
311
  {
8288f496e   Martin K. Petersen   block: Add prefix...
312
313
  	return sprintf(page, "%d
  ", (bi->flags & BLK_INTEGRITY_GENERATE) != 0);
7ba1ba12e   Martin K. Petersen   block: Block laye...
314
  }
3aec2f41a   Martin K. Petersen   block: Add a disk...
315
316
317
318
319
320
  static ssize_t integrity_device_show(struct blk_integrity *bi, char *page)
  {
  	return sprintf(page, "%u
  ",
  		       (bi->flags & BLK_INTEGRITY_DEVICE_CAPABLE) != 0);
  }
7ba1ba12e   Martin K. Petersen   block: Block laye...
321
322
323
324
325
326
327
328
329
  static struct integrity_sysfs_entry integrity_format_entry = {
  	.attr = { .name = "format", .mode = S_IRUGO },
  	.show = integrity_format_show,
  };
  
  static struct integrity_sysfs_entry integrity_tag_size_entry = {
  	.attr = { .name = "tag_size", .mode = S_IRUGO },
  	.show = integrity_tag_size_show,
  };
8288f496e   Martin K. Petersen   block: Add prefix...
330
  static struct integrity_sysfs_entry integrity_verify_entry = {
7ba1ba12e   Martin K. Petersen   block: Block laye...
331
  	.attr = { .name = "read_verify", .mode = S_IRUGO | S_IWUSR },
8288f496e   Martin K. Petersen   block: Add prefix...
332
333
  	.show = integrity_verify_show,
  	.store = integrity_verify_store,
7ba1ba12e   Martin K. Petersen   block: Block laye...
334
  };
8288f496e   Martin K. Petersen   block: Add prefix...
335
  static struct integrity_sysfs_entry integrity_generate_entry = {
7ba1ba12e   Martin K. Petersen   block: Block laye...
336
  	.attr = { .name = "write_generate", .mode = S_IRUGO | S_IWUSR },
8288f496e   Martin K. Petersen   block: Add prefix...
337
338
  	.show = integrity_generate_show,
  	.store = integrity_generate_store,
7ba1ba12e   Martin K. Petersen   block: Block laye...
339
  };
3aec2f41a   Martin K. Petersen   block: Add a disk...
340
341
342
343
  static struct integrity_sysfs_entry integrity_device_entry = {
  	.attr = { .name = "device_is_integrity_capable", .mode = S_IRUGO },
  	.show = integrity_device_show,
  };
7ba1ba12e   Martin K. Petersen   block: Block laye...
344
345
346
  static struct attribute *integrity_attrs[] = {
  	&integrity_format_entry.attr,
  	&integrity_tag_size_entry.attr,
8288f496e   Martin K. Petersen   block: Add prefix...
347
348
  	&integrity_verify_entry.attr,
  	&integrity_generate_entry.attr,
3aec2f41a   Martin K. Petersen   block: Add a disk...
349
  	&integrity_device_entry.attr,
7ba1ba12e   Martin K. Petersen   block: Block laye...
350
351
  	NULL,
  };
52cf25d0a   Emese Revfy   Driver core: Cons...
352
  static const struct sysfs_ops integrity_ops = {
7ba1ba12e   Martin K. Petersen   block: Block laye...
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  	.show	= &integrity_attr_show,
  	.store	= &integrity_attr_store,
  };
  
  static int __init blk_dev_integrity_init(void)
  {
  	integrity_cachep = kmem_cache_create("blkdev_integrity",
  					     sizeof(struct blk_integrity),
  					     0, SLAB_PANIC, NULL);
  	return 0;
  }
  subsys_initcall(blk_dev_integrity_init);
  
  static void blk_integrity_release(struct kobject *kobj)
  {
  	struct blk_integrity *bi =
  		container_of(kobj, struct blk_integrity, kobj);
  
  	kmem_cache_free(integrity_cachep, bi);
  }
  
  static struct kobj_type integrity_ktype = {
  	.default_attrs	= integrity_attrs,
  	.sysfs_ops	= &integrity_ops,
  	.release	= blk_integrity_release,
  };
a63a5cf84   Mike Snitzer   dm: improve block...
379
380
381
382
383
384
385
  bool blk_integrity_is_initialized(struct gendisk *disk)
  {
  	struct blk_integrity *bi = blk_get_integrity(disk);
  
  	return (bi && bi->name && strcmp(bi->name, bi_unsupported_name) != 0);
  }
  EXPORT_SYMBOL(blk_integrity_is_initialized);
7ba1ba12e   Martin K. Petersen   block: Block laye...
386
387
388
  /**
   * blk_integrity_register - Register a gendisk as being integrity-capable
   * @disk:	struct gendisk pointer to make integrity-aware
322316385   Martin K. Petersen   block: Allow empt...
389
   * @template:	optional integrity profile to register
7ba1ba12e   Martin K. Petersen   block: Block laye...
390
391
392
393
394
   *
   * Description: When a device needs to advertise itself as being able
   * to send/receive integrity metadata it must use this function to
   * register the capability with the block layer.  The template is a
   * blk_integrity struct with values appropriate for the underlying
322316385   Martin K. Petersen   block: Allow empt...
395
396
   * hardware.  If template is NULL the new profile is allocated but
   * not filled out. See Documentation/block/data-integrity.txt.
7ba1ba12e   Martin K. Petersen   block: Block laye...
397
398
399
400
401
402
   */
  int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
  {
  	struct blk_integrity *bi;
  
  	BUG_ON(disk == NULL);
7ba1ba12e   Martin K. Petersen   block: Block laye...
403
404
  
  	if (disk->integrity == NULL) {
b984679ef   Jens Axboe   block: integrity ...
405
  		bi = kmem_cache_alloc(integrity_cachep,
322316385   Martin K. Petersen   block: Allow empt...
406
  				      GFP_KERNEL | __GFP_ZERO);
7ba1ba12e   Martin K. Petersen   block: Block laye...
407
408
409
410
  		if (!bi)
  			return -1;
  
  		if (kobject_init_and_add(&bi->kobj, &integrity_ktype,
ed9e19823   Tejun Heo   block: implement ...
411
412
  					 &disk_to_dev(disk)->kobj,
  					 "%s", "integrity")) {
7ba1ba12e   Martin K. Petersen   block: Block laye...
413
414
415
416
417
  			kmem_cache_free(integrity_cachep, bi);
  			return -1;
  		}
  
  		kobject_uevent(&bi->kobj, KOBJ_ADD);
8288f496e   Martin K. Petersen   block: Add prefix...
418
  		bi->flags |= BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE;
3be91c4a3   Martin K. Petersen   block: Deprecate ...
419
  		bi->interval = queue_logical_block_size(disk->queue);
7ba1ba12e   Martin K. Petersen   block: Block laye...
420
421
422
423
424
  		disk->integrity = bi;
  	} else
  		bi = disk->integrity;
  
  	/* Use the provided profile as template */
322316385   Martin K. Petersen   block: Allow empt...
425
426
427
428
429
  	if (template != NULL) {
  		bi->name = template->name;
  		bi->generate_fn = template->generate_fn;
  		bi->verify_fn = template->verify_fn;
  		bi->tuple_size = template->tuple_size;
322316385   Martin K. Petersen   block: Allow empt...
430
  		bi->tag_size = template->tag_size;
8288f496e   Martin K. Petersen   block: Add prefix...
431
  		bi->flags |= template->flags;
322316385   Martin K. Petersen   block: Allow empt...
432
  	} else
a63a5cf84   Mike Snitzer   dm: improve block...
433
  		bi->name = bi_unsupported_name;
7ba1ba12e   Martin K. Petersen   block: Block laye...
434

7d311cdab   Darrick J. Wong   bdi: allow block ...
435
  	disk->queue->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
7ba1ba12e   Martin K. Petersen   block: Block laye...
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  	return 0;
  }
  EXPORT_SYMBOL(blk_integrity_register);
  
  /**
   * blk_integrity_unregister - Remove block integrity profile
   * @disk:	disk whose integrity profile to deallocate
   *
   * Description: This function frees all memory used by the block
   * integrity profile.  To be called at device teardown.
   */
  void blk_integrity_unregister(struct gendisk *disk)
  {
  	struct blk_integrity *bi;
  
  	if (!disk || !disk->integrity)
  		return;
7d311cdab   Darrick J. Wong   bdi: allow block ...
453
  	disk->queue->backing_dev_info.capabilities &= ~BDI_CAP_STABLE_WRITES;
7ba1ba12e   Martin K. Petersen   block: Block laye...
454
455
456
457
  	bi = disk->integrity;
  
  	kobject_uevent(&bi->kobj, KOBJ_REMOVE);
  	kobject_del(&bi->kobj);
3839e4b29   Xiaotian Feng   block: fix improp...
458
  	kobject_put(&bi->kobj);
0c032ab88   Martin K. Petersen   block: Fix double...
459
  	disk->integrity = NULL;
7ba1ba12e   Martin K. Petersen   block: Block laye...
460
461
  }
  EXPORT_SYMBOL(blk_integrity_unregister);