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