Coverage Report

Created: 2026-08-12 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/libblkid/src/superblocks/linux_raid.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
3
 *
4
 * Inspired by libvolume_id by
5
 *     Kay Sievers <kay.sievers@vrfy.org>
6
 *
7
 * This file may be redistributed under the terms of the
8
 * GNU Lesser General Public License.
9
 */
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <unistd.h>
13
#include <string.h>
14
#include <stdint.h>
15
16
#include "superblocks.h"
17
18
struct mdp0_super_block {
19
  uint32_t  md_magic;
20
  uint32_t  major_version;
21
  uint32_t  minor_version;
22
  uint32_t  patch_version;
23
  uint32_t  gvalid_words;
24
  uint32_t  set_uuid0;
25
  uint32_t  ctime;
26
  uint32_t  level;
27
  uint32_t  size;
28
  uint32_t  nr_disks;
29
  uint32_t  raid_disks;
30
  uint32_t  md_minor;
31
  uint32_t  not_persistent;
32
  uint32_t  set_uuid1;
33
  uint32_t  set_uuid2;
34
  uint32_t  set_uuid3;
35
};
36
37
/*
38
 * Version-1, little-endian.
39
 */
40
struct mdp1_super_block {
41
  /* constant array information - 128 bytes */
42
  uint32_t  magic;    /* MD_SB_MAGIC: 0xa92b4efc - little endian */
43
  uint32_t  major_version;  /* 1 */
44
  uint32_t  feature_map;  /* 0 for now */
45
  uint32_t  pad0;   /* always set to 0 when writing */
46
47
  uint8_t   set_uuid[16]; /* user-space generated. */
48
  unsigned char set_name[32]; /* set and interpreted by user-space */
49
50
  uint64_t  ctime;    /* lo 40 bits are seconds, top 24 are microseconds or 0*/
51
  uint32_t  level;    /* -4 (multipath), -1 (linear), 0,1,4,5 */
52
  uint32_t  layout;   /* only for raid5 currently */
53
  uint64_t  size;   /* used size of component devices, in 512byte sectors */
54
55
  uint32_t  chunksize;  /* in 512byte sectors */
56
  uint32_t  raid_disks;
57
  uint32_t  bitmap_offset;  /* sectors after start of superblock that bitmap starts
58
           * NOTE: signed, so bitmap can be before superblock
59
           * only meaningful of feature_map[0] is set.
60
           */
61
62
  /* These are only valid with feature bit '4' */
63
  uint32_t  new_level;  /* new level we are reshaping to    */
64
  uint64_t  reshape_position; /* next address in array-space for reshape */
65
  uint32_t  delta_disks;  /* change in number of raid_disks   */
66
  uint32_t  new_layout; /* new layout         */
67
  uint32_t  new_chunk;  /* new chunk size (bytes)     */
68
  uint8_t   pad1[128-124];  /* set to 0 when written */
69
70
  /* constant this-device information - 64 bytes */
71
  uint64_t  data_offset;  /* sector start of data, often 0 */
72
  uint64_t  data_size;  /* sectors in this device that can be used for data */
73
  uint64_t  super_offset; /* sector start of this superblock */
74
  uint64_t  recovery_offset;/* sectors before this offset (from data_offset) have been recovered */
75
  uint32_t  dev_number; /* permanent identifier of this  device - not role in raid */
76
  uint32_t  cnt_corrected_read; /* number of read errors that were corrected by re-writing */
77
  uint8_t   device_uuid[16]; /* user-space setable, ignored by kernel */
78
        uint8_t   devflags;        /* per-device flags.  Only one defined...*/
79
  uint8_t   pad2[64-57];  /* set to 0 when writing */
80
81
  /* array state information - 64 bytes */
82
  uint64_t  utime;    /* 40 bits second, 24 bits microseconds */
83
  uint64_t  events;   /* incremented when superblock updated */
84
  uint64_t  resync_offset;  /* data before this offset (from data_offset) known to be in sync */
85
  uint32_t  sb_csum;  /* checksum up to dev_roles[max_dev] */
86
  uint32_t  max_dev;  /* size of dev_roles[] array to consider */
87
  uint8_t   pad3[64-32];  /* set to 0 when writing */
88
89
  /* device state information. Indexed by dev_number.
90
   * 2 bytes per device
91
   * Note there are no per-device state flags. State information is rolled
92
   * into the 'roles' value.  If a device is spare or faulty, then it doesn't
93
   * have a meaningful role.
94
   */
95
  uint16_t  dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */
96
};
97
98
99
20.5k
#define MD_RESERVED_BYTES   0x10000
100
25.6k
#define MD_SB_MAGIC     0xa92b4efc
101
102
static int probe_raid0(blkid_probe pr, uint64_t off)
103
5.13k
{
104
5.13k
  struct mdp0_super_block *mdp0;
105
5.13k
  union {
106
5.13k
    uint32_t ints[4];
107
5.13k
    uint8_t bytes[16];
108
5.13k
  } uuid;
109
5.13k
  uint32_t ma, mi, pa;
110
5.13k
  uint64_t size;
111
112
5.13k
  if (pr->size < MD_RESERVED_BYTES)
113
0
    return 1;
114
5.13k
  mdp0 = (struct mdp0_super_block *)
115
5.13k
      blkid_probe_get_buffer(pr,
116
5.13k
        off,
117
5.13k
        sizeof(struct mdp0_super_block));
118
5.13k
  if (!mdp0)
119
0
    return errno ? -errno : 1;
120
121
5.13k
  memset(uuid.ints, 0, sizeof(uuid.ints));
122
123
5.13k
  if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
124
0
    uuid.ints[0] = swab32(mdp0->set_uuid0);
125
0
    if (le32_to_cpu(mdp0->minor_version) >= 90) {
126
0
      uuid.ints[1] = swab32(mdp0->set_uuid1);
127
0
      uuid.ints[2] = swab32(mdp0->set_uuid2);
128
0
      uuid.ints[3] = swab32(mdp0->set_uuid3);
129
0
    }
130
0
    ma = le32_to_cpu(mdp0->major_version);
131
0
    mi = le32_to_cpu(mdp0->minor_version);
132
0
    pa = le32_to_cpu(mdp0->patch_version);
133
0
    size = le32_to_cpu(mdp0->size);
134
135
5.13k
  } else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
136
0
    uuid.ints[0] = mdp0->set_uuid0;
137
0
    if (be32_to_cpu(mdp0->minor_version) >= 90) {
138
0
      uuid.ints[1] = mdp0->set_uuid1;
139
0
      uuid.ints[2] = mdp0->set_uuid2;
140
0
      uuid.ints[3] = mdp0->set_uuid3;
141
0
    }
142
0
    ma = be32_to_cpu(mdp0->major_version);
143
0
    mi = be32_to_cpu(mdp0->minor_version);
144
0
    pa = be32_to_cpu(mdp0->patch_version);
145
0
    size = be32_to_cpu(mdp0->size);
146
0
  } else
147
5.13k
    return 1;
148
149
0
  size <<= 10;  /* convert KiB to bytes */
150
151
0
  if (pr->size < size + MD_RESERVED_BYTES)
152
    /* device is too small */
153
0
    return 1;
154
155
0
  if (off < size)
156
    /* no space before superblock */
157
0
    return 1;
158
159
  /*
160
   * Check for collisions between RAID and partition table
161
   *
162
   * For example the superblock is at the end of the last partition, it's
163
   * the same position as at the end of the disk...
164
   */
165
0
  if ((S_ISREG(pr->mode) || blkid_probe_is_wholedisk(pr)) &&
166
0
      blkid_probe_is_covered_by_pt(pr,
167
0
      off - size,       /* min. start  */
168
0
      size + MD_RESERVED_BYTES)) {   /* min. length */
169
170
    /* ignore this superblock, it's within any partition and
171
     * we are working with whole-disk now */
172
0
    return 1;
173
0
  }
174
175
0
  if (blkid_probe_sprintf_version(pr, "%u.%u.%u", ma, mi, pa) != 0)
176
0
    return 1;
177
0
  if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0)
178
0
    return 1;
179
0
  if (blkid_probe_set_magic(pr, off, sizeof(mdp0->md_magic),
180
0
        (unsigned char *) &mdp0->md_magic))
181
0
    return 1;
182
0
  return 0;
183
0
}
184
185
static int raid1_verify_csum(blkid_probe pr, off_t off,
186
    const struct mdp1_super_block *mdp1)
187
12
{
188
12
  uint64_t csummed_size = sizeof(struct mdp1_super_block)
189
12
    + (uint64_t) le32_to_cpu(mdp1->max_dev) * sizeof(mdp1->dev_roles[0]);
190
12
  const unsigned char *csummed = blkid_probe_get_buffer(pr, off, csummed_size);
191
12
  if (!csummed)
192
2
    return 1;
193
194
10
  uint64_t csum = 0;
195
196
10
  csum -= le32_to_cpu(*(uint32_t *) (csummed + offsetof(struct mdp1_super_block, sb_csum)));
197
198
12.5M
  while (csummed_size >= 4) {
199
12.5M
    csum += le32_to_cpu(*(uint32_t *) csummed);
200
12.5M
    csummed_size -= 4;
201
12.5M
    csummed += 4;
202
12.5M
  }
203
10
  if (csummed_size == 2)
204
3
    csum += le16_to_cpu(*(uint16_t *) csummed);
205
206
10
  csum = (csum >> 32) + (uint32_t) csum;
207
10
  return blkid_probe_verify_csum(pr, csum, le32_to_cpu(mdp1->sb_csum));
208
12
}
209
210
static int probe_raid1(blkid_probe pr, off_t off)
211
15.3k
{
212
15.3k
  struct mdp1_super_block *mdp1;
213
214
15.3k
  mdp1 = (struct mdp1_super_block *)
215
15.3k
      blkid_probe_get_buffer(pr,
216
15.3k
        off,
217
15.3k
        sizeof(struct mdp1_super_block));
218
15.3k
  if (!mdp1)
219
0
    return errno ? -errno : 1;
220
15.3k
  if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC)
221
15.2k
    return 1;
222
117
  if (le32_to_cpu(mdp1->major_version) != 1U)
223
26
    return 1;
224
91
  if (le64_to_cpu(mdp1->super_offset) != (uint64_t) off >> 9)
225
79
    return 1;
226
12
  if (!raid1_verify_csum(pr, off, mdp1))
227
10
    return 1;
228
2
  if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0)
229
0
    return 1;
230
2
  if (blkid_probe_set_uuid_as(pr,
231
2
      (unsigned char *) mdp1->device_uuid, "UUID_SUB") != 0)
232
0
    return 1;
233
2
  if (blkid_probe_set_label(pr, mdp1->set_name,
234
2
        sizeof(mdp1->set_name)) != 0)
235
0
    return 1;
236
2
  if (blkid_probe_set_magic(pr, off, sizeof(mdp1->magic),
237
2
        (unsigned char *) &mdp1->magic))
238
0
    return 1;
239
2
  return 0;
240
2
}
241
242
static int probe_raid(blkid_probe pr,
243
    const struct blkid_idmag *mag __attribute__((__unused__)))
244
5.13k
{
245
5.13k
  const char *ver = NULL;
246
5.13k
  int ret = BLKID_PROBE_NONE;
247
248
5.13k
  if (pr->size > MD_RESERVED_BYTES) {
249
    /* version 0 at the end of the device */
250
5.13k
    uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1))
251
5.13k
      - MD_RESERVED_BYTES;
252
5.13k
    ret = probe_raid0(pr, sboff);
253
5.13k
    if (ret < 1)
254
0
      return ret; /* error */
255
256
    /* version 1.0 at the end of the device */
257
5.13k
    sboff = (pr->size & ~(0x1000 - 1)) - 0x2000;
258
5.13k
    ret = probe_raid1(pr, sboff);
259
5.13k
    if (ret < 0)
260
0
      return ret; /* error */
261
5.13k
    if (ret == 0)
262
0
      ver = "1.0";
263
5.13k
  }
264
265
5.13k
  if (!ver) {
266
    /* version 1.1 at the start of the device */
267
5.13k
    ret = probe_raid1(pr, 0);
268
5.13k
    if (ret == 0)
269
2
      ver = "1.1";
270
271
    /* version 1.2 at 4k offset from the start */
272
5.13k
    else if (ret == BLKID_PROBE_NONE) {
273
5.13k
      ret = probe_raid1(pr, 0x1000);
274
5.13k
      if (ret == 0)
275
0
        ver = "1.2";
276
5.13k
    }
277
5.13k
  }
278
279
5.13k
  if (ver) {
280
2
    blkid_probe_set_version(pr, ver);
281
2
    return BLKID_PROBE_OK;
282
2
  }
283
5.13k
  return ret;
284
5.13k
}
285
286
287
const struct blkid_idinfo linuxraid_idinfo = {
288
  .name   = "linux_raid_member",
289
  .usage    = BLKID_USAGE_RAID,
290
  .probefunc  = probe_raid,
291
  .magics   = BLKID_NONE_MAGIC
292
};
293
294