Whamcloud - gitweb
LU-16302 llite: Use alloc_inode_sb() to allocate inodes
[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 */