Whamcloud - gitweb
LU-14924 osd-ldiskfs: fix T10PI verify/generate_fn
[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 #include <linux/blkdev.h>
31 #include <linux/blk_types.h>
32
33 #include <obd_cksum.h>
34 #include <lustre_compat.h>
35
36 #include "osd_internal.h"
37
38 #if IS_ENABLED(CONFIG_CRC_T10DIF)
39 /*
40  * Data Integrity Field tuple.
41  */
42 struct sd_dif_tuple {
43        __be16 guard_tag;        /* Checksum */
44        __be16 app_tag;          /* Opaque storage */
45        __be32 ref_tag;          /* Target LBA or indirect LBA */
46 };
47
48 static struct niobuf_local *find_lnb(struct blk_integrity_exchg *bix)
49 {
50         struct bio *bio = bix->bio;
51         struct bio_vec *bv = bio_iovec_idx(bio, bix->bi_idx);
52         struct osd_bio_private *bio_private = bio->bi_private;
53         struct osd_iobuf *iobuf = bio_private->obp_iobuf;
54         int index = bio_private->obp_start_page_idx + bix->bi_idx;
55         int i;
56
57         /*
58          * blocks are contiguous in bio but pages added to bio
59          * could have a gap comparing to iobuf->dr_pages.
60          * e.g. a page mapped to a hole in the middle.
61          */
62         for (i = index; i < iobuf->dr_npages; i++) {
63                 if (iobuf->dr_pages[i] == bv->bv_page)
64                         return iobuf->dr_lnbs[i];
65         }
66
67         return NULL;
68 }
69
70 /*
71  * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
72  * 16 bit app tag, 32 bit reference tag.
73  */
74 static void osd_dif_type1_generate(struct blk_integrity_exchg *bix,
75                                    obd_dif_csum_fn *fn)
76 {
77         void *buf = bix->data_buf;
78         struct sd_dif_tuple *sdt = bix->prot_buf;
79         struct niobuf_local *lnb = find_lnb(bix);
80         __u16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
81         sector_t sector = bix->sector;
82         unsigned int i;
83
84         for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
85                 if (lnb && lnb->lnb_guard_rpc) {
86                         sdt->guard_tag = *guard_buf;
87                         guard_buf++;
88                 } else
89                         sdt->guard_tag = fn(buf, bix->sector_size);
90                 sdt->ref_tag = cpu_to_be32(sector & 0xffffffff);
91                 sdt->app_tag = 0;
92
93                 buf += bix->sector_size;
94                 sector++;
95         }
96 }
97
98 static void osd_dif_type1_generate_crc(struct blk_integrity_exchg *bix)
99 {
100         osd_dif_type1_generate(bix, obd_dif_crc_fn);
101 }
102
103 static void osd_dif_type1_generate_ip(struct blk_integrity_exchg *bix)
104 {
105         osd_dif_type1_generate(bix, obd_dif_ip_fn);
106 }
107
108 static int osd_dif_type1_verify(struct blk_integrity_exchg *bix,
109                                 obd_dif_csum_fn *fn)
110 {
111         void *buf = bix->data_buf;
112         struct sd_dif_tuple *sdt = bix->prot_buf;
113         struct niobuf_local *lnb = find_lnb(bix);
114         __u16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
115         sector_t sector = bix->sector;
116         unsigned int i;
117         __u16 csum;
118
119         for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
120                 /* Unwritten sectors */
121                 if (sdt->app_tag == 0xffff)
122                         return 0;
123
124                 if (be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
125                         CERROR("%s: ref tag error on sector %lu (rcvd %u)\n",
126                                bix->disk_name, (unsigned long)sector,
127                                be32_to_cpu(sdt->ref_tag));
128                         return -EIO;
129                 }
130
131                 csum = fn(buf, bix->sector_size);
132
133                 if (sdt->guard_tag != csum) {
134                         CERROR("%s: guard tag error on sector %lu " \
135                                "(rcvd %04x, data %04x)\n", bix->disk_name,
136                                (unsigned long)sector,
137                                be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
138                         return -EIO;
139                 }
140
141                 if (guard_buf) {
142                         *guard_buf = csum;
143                         guard_buf++;
144                 }
145
146                 buf += bix->sector_size;
147                 sector++;
148         }
149
150         if (lnb)
151                 lnb->lnb_guard_disk = 1;
152         return 0;
153 }
154
155 static int osd_dif_type1_verify_crc(struct blk_integrity_exchg *bix)
156 {
157         return osd_dif_type1_verify(bix, obd_dif_crc_fn);
158 }
159
160 static int osd_dif_type1_verify_ip(struct blk_integrity_exchg *bix)
161 {
162         return osd_dif_type1_verify(bix, obd_dif_ip_fn);
163 }
164
165 /*
166  * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque
167  * tag space.
168  */
169 static void osd_dif_type3_generate(struct blk_integrity_exchg *bix,
170                                    obd_dif_csum_fn *fn)
171 {
172         void *buf = bix->data_buf;
173         struct sd_dif_tuple *sdt = bix->prot_buf;
174         struct niobuf_local *lnb = find_lnb(bix);
175         __u16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
176         unsigned int i;
177
178         for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
179                 if (lnb && lnb->lnb_guard_rpc) {
180                         sdt->guard_tag = *guard_buf;
181                         guard_buf++;
182                 } else
183                         sdt->guard_tag = fn(buf, bix->sector_size);
184                 sdt->ref_tag = 0;
185                 sdt->app_tag = 0;
186
187                 buf += bix->sector_size;
188         }
189 }
190
191 static void osd_dif_type3_generate_crc(struct blk_integrity_exchg *bix)
192 {
193         osd_dif_type3_generate(bix, obd_dif_crc_fn);
194 }
195
196 static void osd_dif_type3_generate_ip(struct blk_integrity_exchg *bix)
197 {
198         osd_dif_type3_generate(bix, obd_dif_ip_fn);
199 }
200
201 static int osd_dif_type3_verify(struct blk_integrity_exchg *bix,
202                                 obd_dif_csum_fn *fn)
203 {
204         void *buf = bix->data_buf;
205         struct sd_dif_tuple *sdt = bix->prot_buf;
206         struct niobuf_local *lnb = find_lnb(bix);
207         __u16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
208         sector_t sector = bix->sector;
209         unsigned int i;
210         __u16 csum;
211
212         for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
213                 /* Unwritten sectors */
214                 if (sdt->app_tag == 0xffff && sdt->ref_tag == 0xffffffff)
215                         return 0;
216
217                 csum = fn(buf, bix->sector_size);
218
219                 if (sdt->guard_tag != csum) {
220                         CERROR("%s: guard tag error on sector %lu " \
221                                "(rcvd %04x, data %04x)\n", bix->disk_name,
222                                (unsigned long)sector,
223                                be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
224                         return -EIO;
225                 }
226
227                 if (guard_buf) {
228                         *guard_buf = csum;
229                         guard_buf++;
230                 }
231
232                 buf += bix->sector_size;
233                 sector++;
234         }
235
236         if (lnb)
237                 lnb->lnb_guard_disk = 1;
238         return 0;
239 }
240
241 static int osd_dif_type3_verify_crc(struct blk_integrity_exchg *bix)
242 {
243         return osd_dif_type3_verify(bix, obd_dif_crc_fn);
244 }
245
246 static int osd_dif_type3_verify_ip(struct blk_integrity_exchg *bix)
247 {
248         return osd_dif_type3_verify(bix, obd_dif_ip_fn);
249 }
250
251 int osd_get_integrity_profile(struct osd_device *osd,
252                               integrity_gen_fn **generate_fn,
253                               integrity_vrfy_fn **verify_fn)
254 {
255         switch (osd->od_t10_type) {
256         case OSD_T10_TYPE1_CRC:
257                 *verify_fn = osd_dif_type1_verify_crc;
258                 *generate_fn = osd_dif_type1_generate_crc;
259                 break;
260         case OSD_T10_TYPE3_CRC:
261                 *verify_fn = osd_dif_type3_verify_crc;
262                 *generate_fn = osd_dif_type3_generate_crc;
263                 break;
264         case OSD_T10_TYPE1_IP:
265                 *verify_fn = osd_dif_type1_verify_ip;
266                 *generate_fn = osd_dif_type1_generate_ip;
267                 break;
268         case OSD_T10_TYPE3_IP:
269                 *verify_fn = osd_dif_type3_verify_ip;
270                 *generate_fn = osd_dif_type3_generate_ip;
271                 break;
272         default:
273                 return -ENOTSUPP;
274         }
275
276         return 0;
277 }
278 #endif /* CONFIG_CRC_T10DIF */