]>
Commit | Line | Data |
---|---|---|
a083b725 RF |
1 | /* |
2 | * Copyright (C) 2013 Rolf Fokkens <rolf@fokkens.nl> | |
3 | * | |
4 | * This file may be redistributed under the terms of the | |
5 | * GNU Lesser General Public License. | |
6 | * | |
7 | * Based on code fragments from bcache-tools by Kent Overstreet: | |
8 | * http://evilpiepirate.org/git/bcache-tools.git | |
9 | */ | |
10 | ||
11 | #include <stddef.h> | |
12 | #include <stdio.h> | |
1b2efad2 | 13 | #include <inttypes.h> |
a083b725 RF |
14 | |
15 | #include "superblocks.h" | |
e9e51878 | 16 | #include "crc32c.h" |
93fc0656 | 17 | #include "crc64.h" |
f5c84384 | 18 | #include "xxhash.h" |
a083b725 RF |
19 | |
20 | #define SB_LABEL_SIZE 32 | |
d2f4b5c8 | 21 | #define SB_JOURNAL_BUCKETS 256U |
a083b725 | 22 | |
ebd13d3f | 23 | /* |
d2f4b5c8 TW |
24 | * The bcache_super_block is adapted from struct cache_sb in kernel. |
25 | * https://github.com/torvalds/linux/blob/master/drivers/md/bcache/bcache_ondisk.h | |
ebd13d3f | 26 | */ |
a083b725 RF |
27 | struct bcache_super_block { |
28 | uint64_t csum; | |
ebd13d3f | 29 | uint64_t offset; /* where this super block was written */ |
a083b725 | 30 | uint64_t version; |
ebd13d3f SK |
31 | uint8_t magic[16]; /* bcache file system identifier */ |
32 | uint8_t uuid[16]; /* device identifier */ | |
d2f4b5c8 TW |
33 | uint8_t set_info[16]; /* magic or uuid */ |
34 | uint8_t label[SB_LABEL_SIZE]; | |
35 | uint64_t flags; | |
36 | uint64_t seq; | |
37 | ||
38 | uint64_t feature_compat; | |
39 | uint64_t feature_incompat; | |
40 | uint64_t feature_ro_compat; | |
41 | ||
42 | uint64_t pad[5]; | |
43 | ||
44 | union { | |
45 | struct { | |
46 | /* Cache devices */ | |
47 | uint64_t nbuckets; /* device size */ | |
48 | ||
49 | uint16_t block_size; /* sectors */ | |
50 | uint16_t bucket_size; /* sectors */ | |
51 | ||
52 | uint16_t nr_in_set; | |
53 | uint16_t nr_this_dev; | |
54 | }; | |
55 | struct { | |
56 | /* Backing devices */ | |
57 | uint64_t data_offset; | |
58 | }; | |
59 | }; | |
60 | ||
61 | uint32_t last_mount; | |
62 | ||
63 | uint16_t first_bucket; | |
64 | union { | |
65 | uint16_t njournal_buckets; | |
66 | uint16_t keys; | |
67 | }; | |
68 | uint64_t d[SB_JOURNAL_BUCKETS]; /* journal buckets */ | |
69 | uint16_t obso_bucket_size_hi; /* obsoleted */ | |
b02fc968 | 70 | } __attribute__((packed)); |
a083b725 | 71 | |
4ad02a25 TW |
72 | struct bcachefs_sb_field { |
73 | uint32_t u64s; | |
74 | uint32_t type; | |
75 | } __attribute__((packed)); | |
76 | ||
77 | struct bcachefs_sb_member { | |
ba5c3e73 TW |
78 | uint8_t uuid[16]; |
79 | uint64_t nbuckets; | |
80 | uint16_t first_bucket; | |
81 | uint16_t bucket_size; | |
82 | uint32_t pad; | |
83 | uint64_t last_mount; | |
84 | uint64_t flags[2]; | |
85 | } __attribute__((packed)); | |
4ad02a25 TW |
86 | |
87 | struct bcachefs_sb_field_members { | |
88 | struct bcachefs_sb_field field; | |
89 | struct bcachefs_sb_member members[]; | |
90 | } __attribute__((packed)); | |
91 | ||
da91337a TW |
92 | struct bcachefs_sb_disk_group { |
93 | uint8_t label[SB_LABEL_SIZE]; | |
94 | uint64_t flags[2]; | |
95 | } __attribute__((packed)); | |
96 | ||
97 | struct bcachefs_sb_field_disk_groups { | |
98 | struct bcachefs_sb_field field; | |
99 | struct bcachefs_sb_disk_group disk_groups[]; | |
100 | } __attribute__((packed)); | |
101 | ||
e9e51878 TW |
102 | enum bcachefs_sb_csum_type { |
103 | BCACHEFS_SB_CSUM_TYPE_NONE = 0, | |
104 | BCACHEFS_SB_CSUM_TYPE_CRC32C = 1, | |
4a57b0b4 | 105 | BCACHEFS_SB_CSUM_TYPE_CRC64 = 2, |
f5c84384 | 106 | BCACHEFS_SB_CSUM_TYPE_XXHASH = 7, |
e9e51878 TW |
107 | }; |
108 | ||
109 | union bcachefs_sb_csum { | |
110 | uint32_t crc32c; | |
4a57b0b4 | 111 | uint64_t crc64; |
f5c84384 | 112 | XXH64_hash_t xxh64; |
e9e51878 TW |
113 | uint8_t raw[16]; |
114 | } __attribute__((packed)); | |
115 | ||
48d57379 CG |
116 | struct bcachefs_sb_layout { |
117 | uint8_t magic[16]; | |
118 | uint8_t layout_type; | |
119 | uint8_t sb_max_size_bits; | |
120 | uint8_t nr_superblocks; | |
121 | uint8_t pad[5]; | |
122 | uint64_t sb_offset[61]; | |
123 | } __attribute__((packed)); | |
124 | ||
64094168 | 125 | struct bcachefs_super_block { |
e9e51878 | 126 | union bcachefs_sb_csum csum; |
64094168 TW |
127 | uint16_t version; |
128 | uint16_t version_min; | |
129 | uint16_t pad[2]; | |
130 | uint8_t magic[16]; | |
131 | uint8_t uuid[16]; | |
132 | uint8_t user_uuid[16]; | |
133 | uint8_t label[SB_LABEL_SIZE]; | |
134 | uint64_t offset; | |
135 | uint64_t seq; | |
136 | uint16_t block_size; | |
4ad02a25 TW |
137 | uint8_t dev_idx; |
138 | uint8_t nr_devices; | |
139 | uint32_t u64s; | |
140 | uint64_t time_base_lo; | |
141 | uint32_t time_base_hi; | |
142 | uint32_t time_precision; | |
143 | uint64_t flags[8]; | |
144 | uint64_t features[2]; | |
145 | uint64_t compat[2]; | |
48d57379 | 146 | struct bcachefs_sb_layout layout; |
4ad02a25 | 147 | struct bcachefs_sb_field _start[]; |
64094168 TW |
148 | } __attribute__((packed)); |
149 | ||
a083b725 | 150 | /* magic string */ |
10211619 | 151 | #define BCACHE_SB_MAGIC "\xc6\x85\x73\xf6\x4e\x1a\x45\xca\x82\x65\xf5\x7f\x48\xba\x6d\x81" |
baf87230 | 152 | #define BCACHEFS_SB_MAGIC "\xc6\x85\x73\xf6\x66\xce\x90\xa9\xd9\x6a\x60\xcf\x80\x3d\xf7\xef" |
a083b725 | 153 | /* magic string len */ |
10211619 | 154 | #define BCACHE_SB_MAGIC_LEN (sizeof(BCACHE_SB_MAGIC) - 1) |
a083b725 | 155 | /* super block offset */ |
befe455f | 156 | #define BCACHE_SB_OFF 0x1000U |
a083b725 RF |
157 | /* supper block offset in kB */ |
158 | #define BCACHE_SB_KBOFF (BCACHE_SB_OFF >> 10) | |
159 | /* magic string offset within super block */ | |
77da12e7 | 160 | #define BCACHE_SB_MAGIC_OFF offsetof(struct bcache_super_block, magic) |
93fc0656 | 161 | /* start of checksummed data within superblock */ |
befe455f | 162 | #define BCACHE_SB_CSUMMED_START 8U |
64094168 | 163 | /* granularity of offset and length fields within superblock */ |
befe455f TW |
164 | #define BCACHEFS_SECTOR_SIZE 512U |
165 | /* maximum superblock size shift */ | |
166 | #define BCACHEFS_SB_MAX_SIZE_SHIFT 0x10U | |
eef4dbe0 | 167 | /* maximum superblock size */ |
befe455f | 168 | #define BCACHEFS_SB_MAX_SIZE (1U << BCACHEFS_SB_MAX_SIZE_SHIFT) |
4ad02a25 | 169 | /* fields offset within super block */ |
77da12e7 | 170 | #define BCACHEFS_SB_FIELDS_OFF offsetof(struct bcachefs_super_block, _start) |
4ad02a25 TW |
171 | /* tag value for members field */ |
172 | #define BCACHEFS_SB_FIELD_TYPE_MEMBERS 1 | |
da91337a TW |
173 | /* tag value for disk_groups field */ |
174 | #define BCACHEFS_SB_FIELD_TYPE_DISK_GROUPS 5 | |
8beea162 TW |
175 | /* version splitting helpers */ |
176 | #define BCH_VERSION_MAJOR(_v) ((uint16_t) ((_v) >> 10)) | |
177 | #define BCH_VERSION_MINOR(_v) ((uint16_t) ((_v) & ~(~0U << 10))) | |
4ad02a25 | 178 | |
df6e200f | 179 | #define BYTES(f) ((((uint64_t) le32_to_cpu((f)->u64s)) * 8)) |
93fc0656 TW |
180 | |
181 | static int bcache_verify_checksum(blkid_probe pr, const struct blkid_idmag *mag, | |
182 | const struct bcache_super_block *bcs) | |
183 | { | |
71406358 TW |
184 | const unsigned char *csummed; |
185 | size_t csummed_size; | |
186 | uint64_t csum; | |
187 | ||
188 | if (le16_to_cpu(bcs->keys) > ARRAY_SIZE(bcs->d)) | |
189 | return 0; | |
190 | ||
191 | /* up to the end of bcs->d[] */ | |
c81f7efc | 192 | csummed_size = offsetof(__typeof__(*bcs), d) + |
71406358 TW |
193 | sizeof(bcs->d[0]) * le16_to_cpu(bcs->keys); |
194 | csummed = blkid_probe_get_sb_buffer(pr, mag, csummed_size); | |
195 | csum = ul_crc64_we(csummed + BCACHE_SB_CSUMMED_START, | |
196 | csummed_size - BCACHE_SB_CSUMMED_START); | |
93fc0656 TW |
197 | return blkid_probe_verify_csum(pr, csum, le64_to_cpu(bcs->csum)); |
198 | } | |
a083b725 | 199 | |
a083b725 RF |
200 | static int probe_bcache (blkid_probe pr, const struct blkid_idmag *mag) |
201 | { | |
202 | struct bcache_super_block *bcs; | |
203 | ||
204 | bcs = blkid_probe_get_sb(pr, mag, struct bcache_super_block); | |
205 | if (!bcs) | |
37f40602 | 206 | return errno ? -errno : BLKID_PROBE_NONE; |
a083b725 | 207 | |
93fc0656 TW |
208 | if (!bcache_verify_checksum(pr, mag, bcs)) |
209 | return BLKID_PROBE_NONE; | |
210 | ||
a083b725 | 211 | if (le64_to_cpu(bcs->offset) != BCACHE_SB_OFF / 512) |
37f40602 | 212 | return BLKID_PROBE_NONE; |
a083b725 | 213 | |
1b2efad2 TW |
214 | if (blkid_probe_sprintf_version(pr, "%"PRIu64, le64_to_cpu(bcs->version)) < 0) |
215 | return BLKID_PROBE_NONE; | |
216 | ||
a083b725 | 217 | if (blkid_probe_set_uuid(pr, bcs->uuid) < 0) |
37f40602 | 218 | return BLKID_PROBE_NONE; |
a083b725 | 219 | |
11d0724f TW |
220 | if (blkid_probe_set_label(pr, bcs->label, sizeof(bcs->label)) < 0) |
221 | return BLKID_PROBE_NONE; | |
222 | ||
9bd80748 TW |
223 | if (blkid_probe_set_block_size(pr, le16_to_cpu(bcs->block_size) * 512)) |
224 | return BLKID_PROBE_NONE; | |
225 | ||
1db1994e TW |
226 | blkid_probe_set_wiper(pr, 0, BCACHE_SB_OFF); |
227 | ||
37f40602 | 228 | return BLKID_PROBE_OK; |
cf922860 | 229 | } |
a083b725 | 230 | |
ba5c3e73 TW |
231 | static void probe_bcachefs_sb_members(blkid_probe pr, |
232 | const struct bcachefs_super_block *bcs, | |
233 | const struct bcachefs_sb_field *field, | |
e601773d | 234 | uint8_t dev_idx) |
4ad02a25 | 235 | { |
77da12e7 KZ |
236 | struct bcachefs_sb_field_members *members = |
237 | (struct bcachefs_sb_field_members *) field; | |
238 | uint64_t sectors = 0; | |
239 | uint8_t i; | |
4ad02a25 | 240 | |
c81f7efc | 241 | if (BYTES(field) != offsetof(__typeof__(*members), members[bcs->nr_devices])) |
4ad02a25 TW |
242 | return; |
243 | ||
d9c72ffc TW |
244 | blkid_probe_set_uuid_as(pr, members->members[dev_idx].uuid, "UUID_SUB"); |
245 | ||
77da12e7 | 246 | for (i = 0; i < bcs->nr_devices; i++) { |
ba5c3e73 TW |
247 | struct bcachefs_sb_member *member = &members->members[i]; |
248 | sectors += le64_to_cpu(member->nbuckets) * le16_to_cpu(member->bucket_size); | |
249 | } | |
250 | blkid_probe_set_fssize(pr, sectors * BCACHEFS_SECTOR_SIZE); | |
4ad02a25 TW |
251 | } |
252 | ||
da91337a TW |
253 | static void probe_bcachefs_sb_disk_groups(blkid_probe pr, |
254 | const struct bcachefs_super_block *bcs, | |
255 | const struct bcachefs_sb_field *field, | |
256 | uint8_t dev_idx) | |
257 | { | |
258 | struct bcachefs_sb_field_disk_groups *disk_groups = | |
259 | (struct bcachefs_sb_field_disk_groups *) field; | |
260 | ||
c81f7efc | 261 | if (BYTES(field) != offsetof(__typeof__(*disk_groups), disk_groups[bcs->nr_devices])) |
da91337a TW |
262 | return; |
263 | ||
264 | blkid_probe_set_id_label(pr, "LABEL_SUB", | |
265 | disk_groups->disk_groups[dev_idx].label, | |
266 | sizeof(disk_groups->disk_groups[dev_idx].label)); | |
267 | } | |
268 | ||
7eba8f98 | 269 | static int is_within_range(const void *start, uint64_t size, const void *end) |
46ce48b6 TW |
270 | { |
271 | ptrdiff_t diff; | |
272 | ||
273 | if (start >= end) | |
274 | return 0; // should not happen | |
275 | ||
276 | diff = (unsigned char *) end - (unsigned char *) start; | |
277 | return size <= (uint64_t) diff; | |
278 | } | |
279 | ||
e9e51878 | 280 | static void probe_bcachefs_sb_fields(blkid_probe pr, const struct bcachefs_super_block *bcs, |
7eba8f98 | 281 | const unsigned char *sb_start, const unsigned char *sb_end) |
4ad02a25 | 282 | { |
7eba8f98 | 283 | const unsigned char *field_addr = sb_start + BCACHEFS_SB_FIELDS_OFF; |
4ad02a25 TW |
284 | |
285 | while (1) { | |
286 | struct bcachefs_sb_field *field = (struct bcachefs_sb_field *) field_addr; | |
64bfbdb4 | 287 | uint64_t field_size; |
dcf4b1b2 | 288 | uint32_t type; |
4ad02a25 | 289 | |
46ce48b6 | 290 | if (!is_within_range(field, sizeof(*field), sb_end)) |
64bfbdb4 TW |
291 | break; |
292 | ||
293 | field_size = BYTES(field); | |
294 | ||
295 | if (field_size < sizeof(*field)) | |
296 | break; | |
297 | ||
46ce48b6 | 298 | if (!is_within_range(field, field_size, sb_end)) |
64bfbdb4 | 299 | break; |
4ad02a25 | 300 | |
77da12e7 | 301 | type = le32_to_cpu(field->type); |
4ad02a25 TW |
302 | if (!type) |
303 | break; | |
304 | ||
305 | if (type == BCACHEFS_SB_FIELD_TYPE_MEMBERS) | |
e601773d | 306 | probe_bcachefs_sb_members(pr, bcs, field, bcs->dev_idx); |
4ad02a25 | 307 | |
da91337a TW |
308 | if (type == BCACHEFS_SB_FIELD_TYPE_DISK_GROUPS) |
309 | probe_bcachefs_sb_disk_groups(pr, bcs, field, bcs->dev_idx); | |
310 | ||
4ad02a25 TW |
311 | field_addr += BYTES(field); |
312 | } | |
313 | } | |
314 | ||
e9e51878 | 315 | static int bcachefs_validate_checksum(blkid_probe pr, const struct bcachefs_super_block *bcs, |
7eba8f98 | 316 | const unsigned char *sb, const unsigned char *sb_end) |
e9e51878 TW |
317 | { |
318 | uint8_t checksum_type = be64_to_cpu(bcs->flags[0]) >> 58; | |
7eba8f98 | 319 | const unsigned char *checksummed_data_start = sb + sizeof(bcs->csum); |
e9e51878 | 320 | size_t checksummed_data_size = sb_end - checksummed_data_start; |
77da12e7 | 321 | |
e9e51878 TW |
322 | switch (checksum_type) { |
323 | case BCACHEFS_SB_CSUM_TYPE_NONE: | |
324 | return 1; | |
325 | case BCACHEFS_SB_CSUM_TYPE_CRC32C: { | |
326 | uint32_t crc = crc32c(~0LL, checksummed_data_start, checksummed_data_size) ^ ~0LL; | |
327 | return blkid_probe_verify_csum(pr, crc, le32_to_cpu(bcs->csum.crc32c)); | |
328 | } | |
4a57b0b4 TW |
329 | case BCACHEFS_SB_CSUM_TYPE_CRC64: { |
330 | uint64_t crc = ul_crc64_we(checksummed_data_start, checksummed_data_size); | |
331 | return blkid_probe_verify_csum(pr, crc, le64_to_cpu(bcs->csum.crc64)); | |
332 | } | |
f5c84384 TW |
333 | case BCACHEFS_SB_CSUM_TYPE_XXHASH: { |
334 | XXH64_hash_t xxh64 = XXH64(checksummed_data_start, checksummed_data_size, 0); | |
335 | return blkid_probe_verify_csum(pr, xxh64, le64_to_cpu(bcs->csum.xxh64)); | |
336 | } | |
e9e51878 TW |
337 | default: |
338 | DBG(LOWPROBE, ul_debug("bcachefs: unknown checksum type %d, ignoring.", checksum_type)); | |
339 | return 1; | |
340 | } | |
341 | } | |
342 | ||
64094168 TW |
343 | static int probe_bcachefs(blkid_probe pr, const struct blkid_idmag *mag) |
344 | { | |
345 | struct bcachefs_super_block *bcs; | |
7eba8f98 | 346 | const unsigned char *sb, *sb_end; |
ca466a27 | 347 | uint64_t sb_size, blocksize, offset_sectors; |
8beea162 | 348 | uint16_t version; |
64094168 TW |
349 | |
350 | bcs = blkid_probe_get_sb(pr, mag, struct bcachefs_super_block); | |
351 | if (!bcs) | |
352 | return errno ? -errno : BLKID_PROBE_NONE; | |
353 | ||
ca466a27 TW |
354 | offset_sectors = blkid_probe_get_idmag_off(pr, mag) / BCACHEFS_SECTOR_SIZE; |
355 | if (le64_to_cpu(bcs->offset) != offset_sectors) | |
64094168 TW |
356 | return BLKID_PROBE_NONE; |
357 | ||
ba5c3e73 TW |
358 | if (bcs->nr_devices == 0 || bcs->dev_idx >= bcs->nr_devices) |
359 | return BLKID_PROBE_NONE; | |
360 | ||
77da12e7 | 361 | sb_size = BCACHEFS_SB_FIELDS_OFF + BYTES(bcs); |
48d57379 | 362 | |
eef4dbe0 TW |
363 | if (sb_size > BCACHEFS_SB_MAX_SIZE) |
364 | return BLKID_PROBE_NONE; | |
365 | ||
befe455f TW |
366 | if (bcs->layout.sb_max_size_bits > BCACHEFS_SB_MAX_SIZE_SHIFT) |
367 | return BLKID_PROBE_NONE; | |
368 | ||
369 | if (sb_size > (BCACHEFS_SECTOR_SIZE << bcs->layout.sb_max_size_bits)) | |
370 | return BLKID_PROBE_NONE; | |
371 | ||
77da12e7 KZ |
372 | sb = blkid_probe_get_sb_buffer(pr, mag, sb_size); |
373 | if (!sb) | |
374 | return BLKID_PROBE_NONE; | |
375 | sb_end = sb + sb_size; | |
376 | ||
377 | if (!bcachefs_validate_checksum(pr, bcs, sb, sb_end)) | |
378 | return BLKID_PROBE_NONE; | |
379 | ||
64094168 TW |
380 | blkid_probe_set_uuid(pr, bcs->user_uuid); |
381 | blkid_probe_set_label(pr, bcs->label, sizeof(bcs->label)); | |
8beea162 TW |
382 | version = le16_to_cpu(bcs->version); |
383 | blkid_probe_sprintf_version(pr, "%"PRIu16".%"PRIu16, | |
384 | BCH_VERSION_MAJOR(version), | |
385 | BCH_VERSION_MINOR(version)); | |
64094168 TW |
386 | blocksize = le16_to_cpu(bcs->block_size); |
387 | blkid_probe_set_block_size(pr, blocksize * BCACHEFS_SECTOR_SIZE); | |
ba5c3e73 | 388 | blkid_probe_set_fsblocksize(pr, blocksize * BCACHEFS_SECTOR_SIZE); |
64094168 | 389 | blkid_probe_set_wiper(pr, 0, BCACHE_SB_OFF); |
77da12e7 KZ |
390 | |
391 | probe_bcachefs_sb_fields(pr, bcs, sb, sb_end); | |
392 | ||
393 | return BLKID_PROBE_OK; | |
64094168 TW |
394 | } |
395 | ||
a083b725 RF |
396 | const struct blkid_idinfo bcache_idinfo = |
397 | { | |
398 | .name = "bcache", | |
399 | .usage = BLKID_USAGE_OTHER, | |
400 | .probefunc = probe_bcache, | |
401 | .minsz = 8192, | |
402 | .magics = | |
403 | { | |
10211619 KZ |
404 | { |
405 | .magic = BCACHE_SB_MAGIC, | |
406 | .len = BCACHE_SB_MAGIC_LEN, | |
407 | .kboff = BCACHE_SB_KBOFF, | |
408 | .sboff = BCACHE_SB_MAGIC_OFF | |
409 | }, | |
a083b725 RF |
410 | { NULL } |
411 | } | |
412 | }; | |
413 | ||
64094168 TW |
414 | const struct blkid_idinfo bcachefs_idinfo = |
415 | { | |
416 | .name = "bcachefs", | |
417 | .usage = BLKID_USAGE_FILESYSTEM, | |
418 | .probefunc = probe_bcachefs, | |
419 | .minsz = 256 * BCACHEFS_SECTOR_SIZE, | |
420 | .magics = { | |
421 | { | |
422 | .magic = BCACHE_SB_MAGIC, | |
423 | .len = BCACHE_SB_MAGIC_LEN, | |
424 | .kboff = BCACHE_SB_KBOFF, | |
425 | .sboff = BCACHE_SB_MAGIC_OFF, | |
426 | }, | |
427 | { | |
428 | .magic = BCACHEFS_SB_MAGIC, | |
429 | .len = BCACHE_SB_MAGIC_LEN, | |
430 | .kboff = BCACHE_SB_KBOFF, | |
431 | .sboff = BCACHE_SB_MAGIC_OFF, | |
432 | }, | |
8ca20ff6 TW |
433 | { |
434 | .magic = BCACHEFS_SB_MAGIC, | |
435 | .len = BCACHE_SB_MAGIC_LEN, | |
436 | .kboff = 1 << 11, | |
437 | .sboff = BCACHE_SB_MAGIC_OFF, | |
438 | }, | |
cd6812cb TW |
439 | { |
440 | .magic = BCACHEFS_SB_MAGIC, | |
441 | .len = BCACHE_SB_MAGIC_LEN, | |
442 | .kboff = -(1 << 10), | |
443 | .sboff = BCACHE_SB_MAGIC_OFF, | |
444 | }, | |
64094168 TW |
445 | { NULL } |
446 | } | |
447 | }; |