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