Coverage Report

Created: 2026-08-31 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/libblkid/src/superblocks/bcache.c
Line
Count
Source
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>
13
#include <inttypes.h>
14
15
#include "buffer.h"
16
#include "superblocks.h"
17
#include "crc32c.h"
18
#include "crc64.h"
19
#include "xxhash.h"
20
21
#define SB_LABEL_SIZE      32
22
#define SB_JOURNAL_BUCKETS 256U
23
24
/*
25
 * The bcache_super_block is adapted from struct cache_sb in kernel.
26
 * https://github.com/torvalds/linux/blob/master/drivers/md/bcache/bcache_ondisk.h
27
 */
28
struct bcache_super_block {
29
  uint64_t    csum;
30
  uint64_t    offset;   /* where this super block was written */
31
  uint64_t    version;
32
  uint8_t     magic[16];  /* bcache file system identifier */
33
  uint8_t     uuid[16]; /* device identifier */
34
  uint8_t     set_info[16]; /* magic or uuid */
35
  uint8_t     label[SB_LABEL_SIZE];
36
  uint64_t    flags;
37
  uint64_t    seq;
38
39
  uint64_t    feature_compat;
40
  uint64_t    feature_incompat;
41
  uint64_t    feature_ro_compat;
42
43
  uint64_t    pad[5];
44
45
  union {
46
  struct {
47
    /* Cache devices */
48
    uint64_t  nbuckets; /* device size */
49
50
    uint16_t  block_size; /* sectors */
51
    uint16_t  bucket_size;  /* sectors */
52
53
    uint16_t  nr_in_set;
54
    uint16_t  nr_this_dev;
55
  };
56
  struct {
57
    /* Backing devices */
58
    uint64_t  data_offset;
59
  };
60
  };
61
62
  uint32_t    last_mount;
63
64
  uint16_t    first_bucket;
65
  union {
66
    uint16_t  njournal_buckets;
67
    uint16_t  keys;
68
  };
69
  uint64_t    d[SB_JOURNAL_BUCKETS];  /* journal buckets */
70
  uint16_t    obso_bucket_size_hi;  /* obsoleted */
71
} __attribute__((packed));
72
73
struct bcachefs_sb_field {
74
  uint32_t  u64s;
75
  uint32_t  type;
76
}  __attribute__((packed));
77
78
struct bcachefs_sb_member {
79
  uint8_t   uuid[16];
80
  uint64_t  nbuckets;
81
  uint16_t  first_bucket;
82
  uint16_t  bucket_size;
83
  uint8_t   btree_bitmap_shift;
84
  uint8_t   pad[3];
85
  uint64_t  last_mount;
86
  uint64_t  flags;
87
  /* fields below were added after members_v1 */
88
  uint32_t  iops[4];
89
  uint64_t  errors[3];
90
  uint64_t  errors_at_reset[3];
91
  uint64_t  errors_reset_time;
92
  uint64_t  seq;
93
  uint64_t  btree_allocated_bitmap;
94
  uint32_t  last_journal_bucket;
95
  uint32_t  last_journal_bucket_offset;
96
97
  /* device name/model info from the last FS mount */
98
  uint8_t   device_name[16];
99
  uint8_t   device_model[64];
100
} __attribute__((packed));
101
102
struct bcachefs_sb_field_members_v1 {
103
  struct bcachefs_sb_field  field;
104
  struct bcachefs_sb_member members[];
105
}  __attribute__((packed));
106
107
struct bcachefs_sb_field_members_v2 {
108
  struct bcachefs_sb_field  field;
109
  uint16_t      member_bytes;
110
  uint8_t       pad[6];
111
  struct bcachefs_sb_member members[];
112
}  __attribute__((packed));
113
114
struct bcachefs_sb_disk_group {
115
  uint8_t   label[SB_LABEL_SIZE];
116
  uint64_t  flags[2];
117
} __attribute__((packed));
118
119
struct bcachefs_sb_field_disk_groups {
120
  struct bcachefs_sb_field  field;
121
  struct bcachefs_sb_disk_group   disk_groups[];
122
}  __attribute__((packed));
123
124
enum bcachefs_sb_csum_type {
125
  BCACHEFS_SB_CSUM_TYPE_NONE = 0,
126
  BCACHEFS_SB_CSUM_TYPE_CRC32C = 1,
127
  BCACHEFS_SB_CSUM_TYPE_CRC64 = 2,
128
  BCACHEFS_SB_CSUM_TYPE_XXHASH = 7,
129
};
130
131
union bcachefs_sb_csum {
132
  uint32_t crc32c;
133
  uint64_t crc64;
134
  XXH64_hash_t xxh64;
135
  uint8_t raw[16];
136
} __attribute__((packed));
137
138
struct bcachefs_sb_layout {
139
  uint8_t   magic[16];
140
  uint8_t   layout_type;
141
  uint8_t   sb_max_size_bits;
142
  uint8_t   nr_superblocks;
143
  uint8_t   pad[5];
144
  uint64_t  sb_offset[61];
145
} __attribute__((packed));
146
147
struct bcachefs_super_block {
148
  union bcachefs_sb_csum  csum;
149
  uint16_t  version;
150
  uint16_t  version_min;
151
  uint16_t  pad[2];
152
  uint8_t   magic[16];
153
  uint8_t   uuid[16];
154
  uint8_t   user_uuid[16];
155
  uint8_t   label[SB_LABEL_SIZE];
156
  uint64_t  offset;
157
  uint64_t  seq;
158
  uint16_t  block_size;
159
  uint8_t   dev_idx;
160
  uint8_t   nr_devices;
161
  uint32_t  u64s;
162
  uint64_t  time_base_lo;
163
  uint32_t  time_base_hi;
164
  uint32_t  time_precision;
165
  uint64_t  flags[8];
166
  uint64_t  features[2];
167
  uint64_t  compat[2];
168
  struct bcachefs_sb_layout layout;
169
  struct bcachefs_sb_field _start[];
170
}  __attribute__((packed));
171
172
/* magic string */
173
#define BCACHE_SB_MAGIC     "\xc6\x85\x73\xf6\x4e\x1a\x45\xca\x82\x65\xf5\x7f\x48\xba\x6d\x81"
174
#define BCACHEFS_SB_MAGIC   "\xc6\x85\x73\xf6\x66\xce\x90\xa9\xd9\x6a\x60\xcf\x80\x3d\xf7\xef"
175
/* magic string len */
176
#define BCACHE_SB_MAGIC_LEN (sizeof(BCACHE_SB_MAGIC) - 1)
177
/* super block offset */
178
721
#define BCACHE_SB_OFF       0x1000U
179
/* supper block offset in kB */
180
#define BCACHE_SB_KBOFF     (BCACHE_SB_OFF >> 10)
181
/* magic string offset within super block */
182
#define BCACHE_SB_MAGIC_OFF offsetof(struct bcache_super_block, magic)
183
/* start of checksummed data within superblock */
184
924
#define BCACHE_SB_CSUMMED_START 8U
185
/* granularity of offset and length fields within superblock */
186
3.53k
#define BCACHEFS_SECTOR_SIZE   512U
187
/* maximum superblock size shift */
188
278
#define BCACHEFS_SB_MAX_SIZE_SHIFT   0x10U
189
/* fields offset within super block */
190
532
#define BCACHEFS_SB_FIELDS_OFF offsetof(struct bcachefs_super_block, _start)
191
/* tag value for v1 members field */
192
25.3k
#define BCACHEFS_SB_FIELD_TYPE_MEMBERS_V1 1
193
/* v1 members field size in bytes */
194
5.75k
#define BCACHEFS_SB_FIELD_MEMBERS_V1_BYTES 56
195
/* tag value for v2 members field */
196
25.3k
#define BCACHEFS_SB_FIELD_TYPE_MEMBERS_V2 11
197
/* tag value for disk_groups field */
198
25.3k
#define BCACHEFS_SB_FIELD_TYPE_DISK_GROUPS 5
199
/* version splitting helpers */
200
254
#define BCH_VERSION_MAJOR(_v)           ((uint16_t) ((_v) >> 10))
201
254
#define BCH_VERSION_MINOR(_v)           ((uint16_t) ((_v) & ~(~0U << 10)))
202
203
57.3k
#define BYTES(f) ((((uint64_t) le32_to_cpu((f)->u64s)) * 8))
204
205
static int bcache_verify_checksum(blkid_probe pr, const struct blkid_idmag *mag,
206
    const struct bcache_super_block *bcs)
207
657
{
208
657
  const unsigned char *csummed;
209
657
  size_t csummed_size;
210
657
  uint64_t csum;
211
212
657
  if (le16_to_cpu(bcs->keys) > ARRAY_SIZE(bcs->d))
213
195
    return 0;
214
215
  /* up to the end of bcs->d[] */
216
462
  csummed_size = offsetof(__typeof__(*bcs), d) +
217
462
    sizeof(bcs->d[0]) * le16_to_cpu(bcs->keys);
218
462
  csummed = blkid_probe_get_sb_buffer(pr, mag, csummed_size);
219
462
  if (!csummed)
220
0
    return 0;
221
462
  csum = ul_crc64_we(csummed + BCACHE_SB_CSUMMED_START,
222
462
         csummed_size - BCACHE_SB_CSUMMED_START);
223
462
  return blkid_probe_verify_csum(pr, csum, le64_to_cpu(bcs->csum));
224
462
}
225
226
static int probe_bcache (blkid_probe pr, const struct blkid_idmag *mag)
227
657
{
228
657
  const struct bcache_super_block *bcs;
229
230
657
  bcs = blkid_probe_get_sb(pr, mag, struct bcache_super_block);
231
657
  if (!bcs)
232
0
    return errno ? -errno : BLKID_PROBE_NONE;
233
234
657
  if (!bcache_verify_checksum(pr, mag, bcs))
235
195
    return BLKID_PROBE_NONE;
236
237
462
  if (le64_to_cpu(bcs->offset) != BCACHE_SB_OFF / 512)
238
457
    return BLKID_PROBE_NONE;
239
240
5
  if (blkid_probe_sprintf_version(pr, "%"PRIu64, le64_to_cpu(bcs->version)) < 0)
241
0
    return BLKID_PROBE_NONE;
242
243
5
  if (blkid_probe_set_uuid(pr, bcs->uuid) < 0)
244
0
    return BLKID_PROBE_NONE;
245
246
5
  if (blkid_probe_set_label(pr, bcs->label, sizeof(bcs->label)) < 0)
247
0
    return BLKID_PROBE_NONE;
248
249
5
  if (blkid_probe_set_block_size(pr, le16_to_cpu(bcs->block_size) * 512))
250
0
    return BLKID_PROBE_NONE;
251
252
5
  blkid_probe_set_wiper(pr, 0, BCACHE_SB_OFF);
253
254
5
  return BLKID_PROBE_OK;
255
5
}
256
257
8.83k
#define FIELD_END(s, field) offsetof(s, field) + sizeof_member(s, field)
258
259
/* Fields must be dynamically checked for existence before accessing (using FIELD_END) */
260
static const struct bcachefs_sb_member *bcachefs_sb_member_get_unsafe(
261
  const struct bcachefs_sb_member *members,
262
  uint16_t member_bytes, size_t i)
263
7.71k
{
264
7.71k
  return (const void*)((const char *) members + i * member_bytes);
265
7.71k
}
266
267
static void probe_bcachefs_sb_members(blkid_probe pr,
268
             const struct bcachefs_super_block *bcs,
269
             const struct bcachefs_sb_field *field,
270
             const struct bcachefs_sb_member *members,
271
             uint16_t member_bytes, size_t member_array_offset,
272
             uint8_t *current_member_group)
273
6.12k
{
274
6.12k
  uint64_t sectors = 0;
275
6.12k
  uint8_t i;
276
6.12k
  const struct bcachefs_sb_member *current;
277
278
6.12k
  if (BYTES(field) != member_array_offset + bcs->nr_devices * member_bytes)
279
3.79k
    return;
280
281
2.32k
  current = bcachefs_sb_member_get_unsafe(members, member_bytes, bcs->dev_idx);
282
283
2.32k
  if (member_bytes < FIELD_END(struct bcachefs_sb_member, uuid))
284
158
    return;
285
286
2.16k
  blkid_probe_set_uuid_as(pr, current->uuid, "UUID_SUB");
287
288
2.16k
  if (member_bytes < FIELD_END(struct bcachefs_sb_member, nbuckets) ||
289
2.16k
      member_bytes < FIELD_END(struct bcachefs_sb_member, bucket_size))
290
0
    return;
291
292
7.55k
  for (i = 0; i < bcs->nr_devices; i++) {
293
5.38k
    const struct bcachefs_sb_member *member = bcachefs_sb_member_get_unsafe(members, member_bytes, i);
294
5.38k
    sectors += le64_to_cpu(member->nbuckets) * le16_to_cpu(member->bucket_size);
295
5.38k
  }
296
2.16k
  blkid_probe_set_fssize(pr, sectors * BCACHEFS_SECTOR_SIZE);
297
298
2.16k
  if (member_bytes < FIELD_END(struct bcachefs_sb_member, flags))
299
0
    return;
300
301
2.16k
  *current_member_group = le64_to_cpu(current->flags) >> 20 & 0xFF;
302
2.16k
}
303
304
static void probe_bcachefs_device_label(blkid_probe pr,
305
          const struct bcachefs_sb_field *field,
306
          unsigned group_idx)
307
52
{
308
52
  const struct bcachefs_sb_field_disk_groups *disk_groups =
309
52
      (const struct bcachefs_sb_field_disk_groups *) field;
310
52
  const struct bcachefs_sb_disk_group *group;
311
52
  size_t groups_nr = (BYTES(field) - offsetof(__typeof__(*disk_groups), disk_groups)) / sizeof(*group);
312
52
  size_t nr = 0;
313
52
  size_t total_sublabel_length = 0;
314
52
  uint16_t path[32];
315
52
  struct ul_buffer buf = UL_INIT_BUFFER;
316
317
140
  while (1) {
318
140
    if (nr == ARRAY_SIZE(path) || group_idx >= groups_nr)
319
38
      return;
320
321
102
    group = disk_groups->disk_groups + group_idx;
322
323
102
    uint64_t group_flags_0 = le64_to_cpu(group->flags[0]);
324
102
    bool deleted = group_flags_0 & 0x1;
325
102
    uint32_t parent = group_flags_0 >> 6 & ((1 << 18) - 1);
326
327
102
    if (deleted)
328
3
      return;
329
330
99
    path[nr++] = group_idx;
331
99
    total_sublabel_length += strnlen((const char*)group->label, sizeof(group->label));
332
333
99
    if (!parent)
334
11
      break;
335
88
    group_idx = parent - 1;
336
88
  }
337
338
11
  if (ul_buffer_alloc_data(&buf, total_sublabel_length + nr + 1))
339
0
    return;
340
341
34
  while (nr--) {
342
23
    group_idx = path[nr];
343
23
    group = disk_groups->disk_groups + group_idx;
344
345
23
    ul_buffer_append_data(&buf, (const char*)group->label,
346
23
      strnlen((const char*)group->label, sizeof(group->label)));
347
23
    ul_buffer_append_data(&buf, nr ? "." : "", 1);
348
23
  }
349
350
11
  if (!ul_buffer_is_empty(&buf)) {
351
11
    blkid_probe_set_id_label(pr, "LABEL_SUB",
352
11
                             (const unsigned char*)ul_buffer_get_data(&buf, NULL, NULL),
353
11
                             ul_buffer_get_datasiz(&buf));
354
11
  }
355
356
11
  ul_buffer_free_data(&buf);
357
11
}
358
359
static int is_within_range(const void *start, uint64_t size, const void *end)
360
51.1k
{
361
51.1k
  ptrdiff_t diff;
362
363
51.1k
  if (start >= end)
364
6
    return 0; // should not happen
365
366
51.0k
  diff = (unsigned char *) end - (unsigned char *) start;
367
51.0k
  return size <= (uint64_t) diff;
368
51.1k
}
369
370
static void probe_bcachefs_sb_fields(blkid_probe pr, const struct bcachefs_super_block *bcs,
371
             const unsigned char *sb_start, const unsigned char *sb_end)
372
254
{
373
254
  const unsigned char *field_addr = sb_start + BCACHEFS_SB_FIELDS_OFF;
374
254
  const struct bcachefs_sb_field_disk_groups *disk_groups = NULL;
375
254
  uint8_t current_member_group = 0; /* 0 means unset */
376
377
25.5k
  while (1) {
378
25.5k
    struct bcachefs_sb_field *field = (struct bcachefs_sb_field *) field_addr;
379
25.5k
    uint64_t field_size;
380
25.5k
    uint32_t type;
381
382
25.5k
    if (!is_within_range(field, sizeof(*field), sb_end))
383
6
      break;
384
385
25.5k
    field_size = BYTES(field);
386
387
25.5k
    if (field_size < sizeof(*field))
388
56
      break;
389
390
25.5k
    if (!is_within_range(field, field_size, sb_end))
391
185
      break;
392
393
25.3k
    type = le32_to_cpu(field->type);
394
25.3k
    if (!type)
395
7
      break;
396
397
25.3k
    if (type == BCACHEFS_SB_FIELD_TYPE_MEMBERS_V1) {
398
5.75k
      struct bcachefs_sb_field_members_v1 *members = (struct bcachefs_sb_field_members_v1 *) field;
399
5.75k
      probe_bcachefs_sb_members(pr, bcs, field, members->members,
400
5.75k
        BCACHEFS_SB_FIELD_MEMBERS_V1_BYTES, offsetof(__typeof__(*members), members),
401
5.75k
        &current_member_group);
402
5.75k
    }
403
404
25.3k
    if (type == BCACHEFS_SB_FIELD_TYPE_MEMBERS_V2) {
405
375
      struct bcachefs_sb_field_members_v2 *members = (struct bcachefs_sb_field_members_v2 *) field;
406
375
      probe_bcachefs_sb_members(pr, bcs, field, members->members,
407
375
        le16_to_cpu(members->member_bytes), offsetof(__typeof__(*members), members),
408
375
        &current_member_group);
409
375
    }
410
411
25.3k
    if (type == BCACHEFS_SB_FIELD_TYPE_DISK_GROUPS)
412
904
      disk_groups = (const struct bcachefs_sb_field_disk_groups *) field;
413
414
25.3k
    field_addr += BYTES(field);
415
25.3k
  }
416
417
254
  if (disk_groups && current_member_group)
418
52
    probe_bcachefs_device_label(pr, &disk_groups->field, current_member_group - 1);
419
254
}
420
421
static int bcachefs_validate_checksum(blkid_probe pr, const struct bcachefs_super_block *bcs,
422
              const unsigned char *sb, const unsigned char *sb_end)
423
254
{
424
254
  uint8_t checksum_type = be64_to_cpu(bcs->flags[0]) >> 58;
425
254
  const unsigned char *checksummed_data_start = sb + sizeof(bcs->csum);
426
254
  size_t checksummed_data_size = sb_end - checksummed_data_start;
427
428
254
  switch (checksum_type) {
429
8
    case BCACHEFS_SB_CSUM_TYPE_NONE:
430
8
      return 1;
431
12
    case BCACHEFS_SB_CSUM_TYPE_CRC32C: {
432
12
      uint32_t crc = crc32c(~0LL, checksummed_data_start, checksummed_data_size) ^ ~0LL;
433
12
      return blkid_probe_verify_csum(pr, crc, le32_to_cpu(bcs->csum.crc32c));
434
0
    }
435
21
    case BCACHEFS_SB_CSUM_TYPE_CRC64: {
436
21
      uint64_t crc = ul_crc64_we(checksummed_data_start, checksummed_data_size);
437
21
      return blkid_probe_verify_csum(pr, crc, le64_to_cpu(bcs->csum.crc64));
438
0
    }
439
108
    case BCACHEFS_SB_CSUM_TYPE_XXHASH: {
440
108
      XXH64_hash_t xxh64 = XXH64(checksummed_data_start, checksummed_data_size, 0);
441
108
      return blkid_probe_verify_csum(pr, xxh64, le64_to_cpu(bcs->csum.xxh64));
442
0
    }
443
105
    default:
444
105
      DBG(LOWPROBE, ul_debug("bcachefs: unknown checksum type %d, ignoring.", checksum_type));
445
105
      return 1;
446
254
  }
447
254
}
448
449
static int probe_bcachefs(blkid_probe pr, const struct blkid_idmag *mag)
450
585
{
451
585
  const struct bcachefs_super_block *bcs;
452
585
  const unsigned char *sb, *sb_end;
453
585
  uint64_t sb_size, blocksize, offset_sectors;
454
585
  uint16_t version;
455
456
585
  bcs = blkid_probe_get_sb(pr, mag, struct bcachefs_super_block);
457
585
  if (!bcs)
458
2
    return errno ? -errno : BLKID_PROBE_NONE;
459
460
583
  offset_sectors = blkid_probe_get_idmag_off(pr, mag) / BCACHEFS_SECTOR_SIZE;
461
583
  if (le64_to_cpu(bcs->offset) != offset_sectors)
462
284
    return BLKID_PROBE_NONE;
463
464
299
  if (bcs->nr_devices == 0 || bcs->dev_idx >= bcs->nr_devices)
465
21
    return BLKID_PROBE_NONE;
466
467
278
  sb_size = BCACHEFS_SB_FIELDS_OFF + BYTES(bcs);
468
469
278
  if (bcs->layout.sb_max_size_bits > BCACHEFS_SB_MAX_SIZE_SHIFT)
470
2
    return BLKID_PROBE_NONE;
471
472
276
  if (sb_size > (BCACHEFS_SECTOR_SIZE << bcs->layout.sb_max_size_bits))
473
20
    return BLKID_PROBE_NONE;
474
475
256
  sb = blkid_probe_get_sb_buffer(pr, mag, sb_size);
476
256
  if (!sb)
477
2
    return BLKID_PROBE_NONE;
478
254
  sb_end = sb + sb_size;
479
480
254
  if (!bcachefs_validate_checksum(pr, bcs, sb, sb_end))
481
0
    return BLKID_PROBE_NONE;
482
483
254
  blkid_probe_set_uuid(pr, bcs->user_uuid);
484
254
  blkid_probe_set_label(pr, bcs->label, sizeof(bcs->label));
485
254
  version = le16_to_cpu(bcs->version);
486
254
  blkid_probe_sprintf_version(pr, "%"PRIu16".%"PRIu16,
487
254
            BCH_VERSION_MAJOR(version),
488
254
            BCH_VERSION_MINOR(version));
489
254
  blocksize = le16_to_cpu(bcs->block_size);
490
254
  blkid_probe_set_block_size(pr, blocksize * BCACHEFS_SECTOR_SIZE);
491
254
  blkid_probe_set_fsblocksize(pr, blocksize * BCACHEFS_SECTOR_SIZE);
492
254
  blkid_probe_set_wiper(pr, 0, BCACHE_SB_OFF);
493
494
254
  probe_bcachefs_sb_fields(pr, bcs, sb, sb_end);
495
496
254
  return BLKID_PROBE_OK;
497
254
}
498
499
const struct blkid_idinfo bcache_idinfo =
500
{
501
  .name   = "bcache",
502
  .usage    = BLKID_USAGE_OTHER,
503
  .probefunc  = probe_bcache,
504
  .minsz    = 8192,
505
  .magics   =
506
  {
507
    {
508
      .magic = BCACHE_SB_MAGIC,
509
      .len   = BCACHE_SB_MAGIC_LEN,
510
      .kboff = BCACHE_SB_KBOFF,
511
      .sboff = BCACHE_SB_MAGIC_OFF
512
    },
513
    { NULL }
514
  }
515
};
516
517
const struct blkid_idinfo bcachefs_idinfo =
518
{
519
  .name   = "bcachefs",
520
  .usage    = BLKID_USAGE_FILESYSTEM,
521
  .probefunc  = probe_bcachefs,
522
  .minsz    = 256 * BCACHEFS_SECTOR_SIZE,
523
  .magics   = {
524
    {
525
      .magic = BCACHE_SB_MAGIC,
526
      .len   = BCACHE_SB_MAGIC_LEN,
527
      .kboff = BCACHE_SB_KBOFF,
528
      .sboff = BCACHE_SB_MAGIC_OFF,
529
    },
530
    {
531
      .magic = BCACHEFS_SB_MAGIC,
532
      .len   = BCACHE_SB_MAGIC_LEN,
533
      .kboff = BCACHE_SB_KBOFF,
534
      .sboff = BCACHE_SB_MAGIC_OFF,
535
    },
536
    {
537
      .magic = BCACHEFS_SB_MAGIC,
538
      .len   = BCACHE_SB_MAGIC_LEN,
539
      .kboff = 1 << 11,
540
      .sboff = BCACHE_SB_MAGIC_OFF,
541
    },
542
    {
543
      .magic = BCACHEFS_SB_MAGIC,
544
      .len   = BCACHE_SB_MAGIC_LEN,
545
      .kboff = -(1 << 10),
546
      .sboff = BCACHE_SB_MAGIC_OFF,
547
    },
548
    { NULL }
549
  }
550
};