Whamcloud - gitweb
LU-16847 ldiskfs: refactor code.
[fs/lustre-release.git] / lustre / osd-ldiskfs / osd_integrity.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2018, DataDirect Networks Storage.
24  * Author: Li Xi.
25  *
26  * Data integrity functions for OSD
27  * Codes copied from kernel 3.10.0-862.el7
28  * drivers/scsi/sd_dif.c and block/t10-pi.c
29  */
30 #ifdef HAVE_LINUX_BLK_INTEGRITY_HEADER
31  #include <linux/blk-integrity.h>
32 #else
33  #include <linux/blkdev.h>
34 #endif
35 #include <linux/blk_types.h>
36
37 #include <obd_cksum.h>
38 #include <lustre_compat.h>
39
40 #include "osd_internal.h"
41
42 #if IS_ENABLED(CONFIG_CRC_T10DIF)
43 #ifdef HAVE_BLK_INTEGRITY_ITER
44 # define blk_status_gen blk_status_t
45 # define RETURN_GEN(_gen_fn) return _gen_fn
46 #else
47 # define blk_status_gen void
48 # define RETURN_GEN(_gen_fn) _gen_fn
49 # define blk_integrity_iter blk_integrity_exchg
50 # define interval sector_size
51 # define seed sector
52 # define blk_status_t int
53 # define BLK_STS_PROTECTION -EIO
54 # define BLK_STS_OK 0
55 #endif
56 /*
57  * Data Integrity Field tuple.
58  */
59 struct t10_pi_tuple {
60        __be16 guard_tag;        /* Checksum */
61        __be16 app_tag;          /* Opaque storage */
62        __be32 ref_tag;          /* Target LBA or indirect LBA */
63 };
64
65 #define T10_PI_APP_ESCAPE cpu_to_be16(0xffff)
66 #define T10_PI_REF_ESCAPE cpu_to_be32(0xffffffff)
67
68 static struct niobuf_local *find_lnb(struct blk_integrity_iter *iter)
69 {
70         struct bio *bio = iter->bio;
71         struct bio_vec *bv = &bio->bi_io_vec[iter->bi_idx];
72         struct osd_bio_private *bio_private = bio->bi_private;
73         struct osd_iobuf *iobuf = bio_private->obp_iobuf;
74         int index = bio_private->obp_start_page_idx + iter->bi_idx;
75         int i;
76
77         /*
78          * blocks are contiguous in bio but pages added to bio
79          * could have a gap comparing to iobuf->dr_pages.
80          * e.g. a page mapped to a hole in the middle.
81          */
82         for (i = index; i < iobuf->dr_npages; i++) {
83                 if (iobuf->dr_pages[i] == bv->bv_page)
84                         return iobuf->dr_lnbs[i];
85         }
86
87         return NULL;
88 }
89
90 /*
91  * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
92  * 16 bit app tag, 32 bit reference tag (sector number).
93  *
94  * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque
95  * tag space.
96  */
97 static blk_status_gen osd_dif_generate(struct blk_integrity_iter *iter,
98                                 obd_dif_csum_fn *fn, enum osd_t10_type type)
99 {
100         struct niobuf_local *lnb = find_lnb(iter);
101         __be16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
102         unsigned int i;
103
104         ENTRY;
105         for (i = 0 ; i < iter->data_size ; i += iter->interval) {
106                 struct t10_pi_tuple *pi = iter->prot_buf;
107
108                 if (lnb && lnb->lnb_guard_rpc) {
109                         pi->guard_tag = *guard_buf;
110                         guard_buf++;
111                 } else {
112                         pi->guard_tag = fn(iter->data_buf, iter->interval);
113                 }
114                 pi->app_tag = 0;
115
116                 if (type == OSD_T10_TYPE1)
117                         pi->ref_tag = cpu_to_be32(lower_32_bits(iter->seed));
118                 else /* if (type == OSD_T10_TYPE3) */
119                         pi->ref_tag = 0;
120
121                 iter->data_buf += iter->interval;
122                 iter->prot_buf += sizeof(struct t10_pi_tuple);
123                 iter->seed++;
124         }
125
126 #ifdef HAVE_BLK_INTEGRITY_ITER
127         RETURN(BLK_STS_OK);
128 #else
129         RETURN_EXIT;
130 #endif
131 }
132
133 static blk_status_t osd_dif_verify(struct blk_integrity_iter *iter,
134                                    obd_dif_csum_fn *fn, enum osd_t10_type type)
135 {
136         struct niobuf_local *lnb = find_lnb(iter);
137         __be16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
138         unsigned int i;
139
140         ENTRY;
141         for (i = 0 ; i < iter->data_size ; i += iter->interval) {
142                 struct t10_pi_tuple *pi = iter->prot_buf;
143                 __be16 csum;
144
145                 if (type == OSD_T10_TYPE1 ||
146                     type == OSD_T10_TYPE2) {
147                         if (pi->app_tag == T10_PI_APP_ESCAPE) {
148                                 lnb = NULL;
149                                 goto next;
150                         }
151
152                         if (be32_to_cpu(pi->ref_tag) !=
153                             lower_32_bits(iter->seed)) {
154                                 CERROR("%s: ref tag error at location %llu (rcvd %u): rc = %d\n",
155                                        iter->disk_name,
156                                        (unsigned long long)iter->seed,
157                                        be32_to_cpu(pi->ref_tag),
158                                        BLK_STS_PROTECTION);
159                                 RETURN(BLK_STS_PROTECTION);
160                         }
161                 } else  if (type == OSD_T10_TYPE3) {
162                         if (pi->app_tag == T10_PI_APP_ESCAPE &&
163                             pi->ref_tag == T10_PI_REF_ESCAPE) {
164                                 lnb = NULL;
165                                 goto next;
166                         }
167                 }
168
169                 csum = fn(iter->data_buf, iter->interval);
170
171                 if (pi->guard_tag != csum) {
172                         CERROR("%s: guard tag error on sector %llu (rcvd %04x, want %04x): rc = %d\n",
173                                iter->disk_name, (unsigned long long)iter->seed,
174                                be16_to_cpu(pi->guard_tag), be16_to_cpu(csum),
175                                BLK_STS_PROTECTION);
176                         RETURN(BLK_STS_PROTECTION);
177                 }
178
179                 if (guard_buf) {
180                         *guard_buf = csum;
181                         guard_buf++;
182                 }
183
184 next:
185                 iter->data_buf += iter->interval;
186                 iter->prot_buf += sizeof(struct t10_pi_tuple);
187                 iter->seed++;
188         }
189
190         if (lnb)
191                 lnb->lnb_guard_disk = 1;
192
193         RETURN(BLK_STS_OK);
194 }
195
196 static blk_status_gen osd_dif_type1_generate_crc(struct blk_integrity_iter *iter)
197 {
198         RETURN_GEN(osd_dif_generate(iter, obd_dif_crc_fn, OSD_T10_TYPE1));
199 }
200
201 static blk_status_gen osd_dif_type1_generate_ip(struct blk_integrity_iter *iter)
202 {
203         RETURN_GEN(osd_dif_generate(iter, obd_dif_ip_fn, OSD_T10_TYPE1));
204 }
205
206 static blk_status_gen osd_dif_type3_generate_crc(struct blk_integrity_iter *iter)
207 {
208         RETURN_GEN(osd_dif_generate(iter, obd_dif_crc_fn, OSD_T10_TYPE3));
209 }
210
211 static blk_status_gen osd_dif_type3_generate_ip(struct blk_integrity_iter *iter)
212 {
213         RETURN_GEN(osd_dif_generate(iter, obd_dif_ip_fn, OSD_T10_TYPE3));
214 }
215 static blk_status_t osd_dif_type1_verify_crc(struct blk_integrity_iter *iter)
216 {
217         return osd_dif_verify(iter, obd_dif_crc_fn, OSD_T10_TYPE1);
218 }
219
220 static blk_status_t osd_dif_type1_verify_ip(struct blk_integrity_iter *iter)
221 {
222         return osd_dif_verify(iter, obd_dif_ip_fn, OSD_T10_TYPE1);
223 }
224
225 static blk_status_t osd_dif_type3_verify_crc(struct blk_integrity_iter *iter)
226 {
227         return osd_dif_verify(iter, obd_dif_crc_fn, OSD_T10_TYPE3);
228 }
229
230 static blk_status_t osd_dif_type3_verify_ip(struct blk_integrity_iter *iter)
231 {
232         return osd_dif_verify(iter, obd_dif_ip_fn, OSD_T10_TYPE3);
233 }
234
235 int osd_get_integrity_profile(struct osd_device *osd,
236                               integrity_gen_fn **generate_fn,
237                               integrity_vrfy_fn **verify_fn)
238 {
239         switch (osd->od_t10_type) {
240         case OSD_T10_TYPE1_CRC:
241                 *verify_fn = osd_dif_type1_verify_crc;
242                 *generate_fn = osd_dif_type1_generate_crc;
243                 break;
244         case OSD_T10_TYPE3_CRC:
245                 *verify_fn = osd_dif_type3_verify_crc;
246                 *generate_fn = osd_dif_type3_generate_crc;
247                 break;
248         case OSD_T10_TYPE1_IP:
249                 *verify_fn = osd_dif_type1_verify_ip;
250                 *generate_fn = osd_dif_type1_generate_ip;
251                 break;
252         case OSD_T10_TYPE3_IP:
253                 *verify_fn = osd_dif_type3_verify_ip;
254                 *generate_fn = osd_dif_type3_generate_ip;
255                 break;
256         default:
257                 return -ENOTSUPP;
258         }
259
260         return 0;
261 }
262 #endif /* CONFIG_CRC_T10DIF */
263
264 #if IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) && defined(HAVE_BIO_INTEGRITY_PREP_FN)
265 /*
266  * This function will change the data written, thus it should only be
267  * used when checking data integrity feature
268  */
269 static void bio_integrity_fault_inject(struct bio *bio)
270 {
271         struct bio_vec *bvec;
272         DECLARE_BVEC_ITER_ALL(iter_all);
273         void *kaddr;
274         char *addr;
275
276         bio_for_each_segment_all(bvec, bio, iter_all) {
277                 struct page *page = bvec->bv_page;
278
279                 kaddr = kmap(page);
280                 addr = kaddr;
281                 *addr = ~(*addr);
282                 kunmap(page);
283                 break;
284         }
285 }
286
287 static int bio_dif_compare(__u16 *expected_guard_buf, void *bio_prot_buf,
288                            unsigned int sectors, int tuple_size)
289 {
290         __be16 *expected_guard;
291         __be16 *bio_guard;
292         int i;
293
294         expected_guard = expected_guard_buf;
295         for (i = 0; i < sectors; i++) {
296                 bio_guard = (__u16 *)bio_prot_buf;
297                 if (*bio_guard != *expected_guard) {
298                         CERROR(
299                                "unexpected guard tags on sector %d expected guard %u, bio guard %u, sectors %u, tuple size %d\n",
300                                i, *expected_guard, *bio_guard, sectors,
301                                tuple_size);
302                         return -EIO;
303                 }
304                 expected_guard++;
305                 bio_prot_buf += tuple_size;
306         }
307         return 0;
308 }
309
310 static int osd_bio_integrity_compare(struct bio *bio, struct block_device *bdev,
311                                      struct osd_iobuf *iobuf, int index)
312 {
313         struct blk_integrity *bi = bdev_get_integrity(bdev);
314         struct bio_integrity_payload *bip = bio->bi_integrity;
315         struct niobuf_local *lnb = NULL;
316         unsigned short sector_size = blk_integrity_interval(bi);
317         void *bio_prot_buf = page_address(bip->bip_vec->bv_page) +
318                 bip->bip_vec->bv_offset;
319         struct bio_vec *bv;
320         sector_t sector = bio_start_sector(bio);
321         unsigned int i, sectors, total;
322         DECLARE_BVEC_ITER_ALL(iter_all);
323         __be16 *expected_guard;
324         int rc;
325
326         total = 0;
327         bio_for_each_segment_all(bv, bio, iter_all) {
328                 for (i = index; i < iobuf->dr_npages; i++) {
329                         if (iobuf->dr_pages[i] == bv->bv_page) {
330                                 lnb = iobuf->dr_lnbs[i];
331                                 break;
332                         }
333                 }
334                 if (!lnb)
335                         continue;
336                 expected_guard = lnb->lnb_guards;
337                 sectors = bv->bv_len / sector_size;
338                 if (lnb->lnb_guard_rpc) {
339                         rc = bio_dif_compare(expected_guard, bio_prot_buf,
340                                              sectors, bi->tuple_size);
341                         if (rc)
342                                 return rc;
343                 }
344
345                 sector += sectors;
346                 bio_prot_buf += sectors * bi->tuple_size;
347                 total += sectors * bi->tuple_size;
348                 LASSERT(total <= bip_size(bio->bi_integrity));
349                 index++;
350                 lnb = NULL;
351         }
352         return 0;
353 }
354
355 int osd_bio_integrity_handle(struct osd_device *osd, struct bio *bio,
356                              struct osd_iobuf *iobuf)
357 {
358         integrity_gen_fn *generate_fn = NULL;
359         integrity_vrfy_fn *verify_fn = NULL;
360         int rc;
361
362         ENTRY;
363
364         if (!iobuf->dr_integrity)
365                 RETURN(0);
366
367         rc = osd_get_integrity_profile(osd, &generate_fn, &verify_fn);
368         if (rc)
369                 RETURN(rc);
370
371 # ifdef HAVE_BIO_INTEGRITY_PREP_FN_RETURNS_BOOL
372         if (!bio_integrity_prep_fn(bio, generate_fn, verify_fn))
373                 RETURN(blk_status_to_errno(bio->bi_status));
374 # else
375         rc = bio_integrity_prep_fn(bio, generate_fn, verify_fn);
376         if (rc)
377                 RETURN(rc);
378 # endif
379
380         /* Verify and inject fault only when writing */
381         if (iobuf->dr_rw == 1) {
382                 if (unlikely(CFS_FAIL_CHECK(OBD_FAIL_OST_INTEGRITY_CMP))) {
383                         struct super_block *sb = osd_sb(osd);
384                         struct osd_bio_private *b_priv = bio->bi_private;
385                         int st_page_index = b_priv->obp_start_page_idx;
386
387                         rc = osd_bio_integrity_compare(bio, sb->s_bdev, iobuf,
388                                                        st_page_index);
389                         if (rc)
390                                 RETURN(rc);
391                 }
392
393                 if (unlikely(CFS_FAIL_CHECK(OBD_FAIL_OST_INTEGRITY_FAULT)))
394                         bio_integrity_fault_inject(bio);
395         }
396         RETURN(0);
397 }
398 #endif /* CONFIG_BLK_DEV_INTEGRITY */