Whamcloud - gitweb
0c1412f50f4dc0e1e9c6e8957ef8ebe6a0319e78
[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 (sector number).
73  *
74  * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque
75  * tag space.
76  */
77 static void osd_dif_generate(struct blk_integrity_exchg *bix,
78                              obd_dif_csum_fn *fn, enum osd_t10_type type)
79 {
80         void *buf = bix->data_buf;
81         struct sd_dif_tuple *sdt = bix->prot_buf;
82         struct niobuf_local *lnb = find_lnb(bix);
83         __u16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
84         sector_t sector = bix->sector;
85         unsigned int i;
86
87         ENTRY;
88         for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
89                 if (lnb && lnb->lnb_guard_rpc) {
90                         sdt->guard_tag = *guard_buf;
91                         guard_buf++;
92                 } else {
93                         sdt->guard_tag = fn(buf, bix->sector_size);
94                 }
95                 sdt->app_tag = 0;
96                 if (type == OSD_T10_TYPE1)
97                         sdt->ref_tag = cpu_to_be32(sector & 0xffffffff);
98                 else /* if (type == OSD_T10_TYPE3) */
99                         sdt->ref_tag = 0;
100
101                 buf += bix->sector_size;
102                 sector++;
103         }
104         RETURN_EXIT;
105 }
106
107 static int osd_dif_verify(struct blk_integrity_exchg *bix,
108                           obd_dif_csum_fn *fn, enum osd_t10_type type)
109 {
110         void *buf = bix->data_buf;
111         struct sd_dif_tuple *sdt = bix->prot_buf;
112         struct niobuf_local *lnb = find_lnb(bix);
113         __u16 *guard_buf = lnb ? lnb->lnb_guards : NULL;
114         sector_t sector = bix->sector;
115         unsigned int i;
116         __u16 csum;
117
118         ENTRY;
119         for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
120                 if (type == OSD_T10_TYPE1) {
121                         /* Unwritten sectors */
122                         if (sdt->app_tag == 0xffff)
123                                 RETURN(0);
124
125                         if (be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
126                                 CERROR("%s: ref tag error on sector %lu (rcvd %u): rc = %d\n",
127                                        bix->disk_name, (unsigned long)sector,
128                                        be32_to_cpu(sdt->ref_tag), -EIO);
129                                 return -EIO;
130                         }
131                 } else /* if (type == OSD_T10_TYPE3) */ {
132                         /* Unwritten sectors */
133                         if (sdt->app_tag == 0xffff &&
134                             sdt->ref_tag == 0xffffffff)
135                                 RETURN(0);
136                 }
137
138                 csum = fn(buf, bix->sector_size);
139
140                 if (sdt->guard_tag != csum) {
141                         CERROR("%s: guard tag error on sector %lu (rcvd %04x, data %04x): rc = %d\n",
142                                bix->disk_name, (unsigned long)sector,
143                                be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum),
144                                -EIO);
145                         return -EIO;
146                 }
147
148                 if (guard_buf) {
149                         *guard_buf = csum;
150                         guard_buf++;
151                 }
152
153                 buf += bix->sector_size;
154                 sector++;
155         }
156
157         if (lnb)
158                 lnb->lnb_guard_disk = 1;
159
160         RETURN(0);
161 }
162
163 static void osd_dif_type1_generate_crc(struct blk_integrity_exchg *bix)
164 {
165         osd_dif_generate(bix, obd_dif_crc_fn, OSD_T10_TYPE1);
166 }
167
168 static void osd_dif_type1_generate_ip(struct blk_integrity_exchg *bix)
169 {
170         osd_dif_generate(bix, obd_dif_ip_fn, OSD_T10_TYPE1);
171 }
172
173 static void osd_dif_type3_generate_crc(struct blk_integrity_exchg *bix)
174 {
175         osd_dif_generate(bix, obd_dif_crc_fn, OSD_T10_TYPE3);
176 }
177
178 static void osd_dif_type3_generate_ip(struct blk_integrity_exchg *bix)
179 {
180         osd_dif_generate(bix, obd_dif_ip_fn, OSD_T10_TYPE3);
181 }
182
183 static int osd_dif_type1_verify_crc(struct blk_integrity_exchg *bix)
184 {
185         return osd_dif_verify(bix, obd_dif_crc_fn, OSD_T10_TYPE1);
186 }
187
188 static int osd_dif_type1_verify_ip(struct blk_integrity_exchg *bix)
189 {
190         return osd_dif_verify(bix, obd_dif_ip_fn, OSD_T10_TYPE1);
191 }
192
193 static int osd_dif_type3_verify_crc(struct blk_integrity_exchg *bix)
194 {
195         return osd_dif_verify(bix, obd_dif_crc_fn, OSD_T10_TYPE3);
196 }
197
198 static int osd_dif_type3_verify_ip(struct blk_integrity_exchg *bix)
199 {
200         return osd_dif_verify(bix, obd_dif_ip_fn, OSD_T10_TYPE3);
201 }
202
203 int osd_get_integrity_profile(struct osd_device *osd,
204                               integrity_gen_fn **generate_fn,
205                               integrity_vrfy_fn **verify_fn)
206 {
207         switch (osd->od_t10_type) {
208         case OSD_T10_TYPE1_CRC:
209                 *verify_fn = osd_dif_type1_verify_crc;
210                 *generate_fn = osd_dif_type1_generate_crc;
211                 break;
212         case OSD_T10_TYPE3_CRC:
213                 *verify_fn = osd_dif_type3_verify_crc;
214                 *generate_fn = osd_dif_type3_generate_crc;
215                 break;
216         case OSD_T10_TYPE1_IP:
217                 *verify_fn = osd_dif_type1_verify_ip;
218                 *generate_fn = osd_dif_type1_generate_ip;
219                 break;
220         case OSD_T10_TYPE3_IP:
221                 *verify_fn = osd_dif_type3_verify_ip;
222                 *generate_fn = osd_dif_type3_generate_ip;
223                 break;
224         default:
225                 return -ENOTSUPP;
226         }
227
228         return 0;
229 }
230 #endif /* CONFIG_CRC_T10DIF */