Coverage Report

Created: 2025-11-25 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/libblkid/src/topology/md.c
Line
Count
Source
1
/*
2
 * Linux Software RAID (md) topology
3
 * -- this is fallback for old systems where the topology information is not
4
 *    exported by sysfs
5
 *
6
 * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
7
 *
8
 * This file may be redistributed under the terms of the
9
 * GNU Lesser General Public License.
10
 *
11
 */
12
#include <errno.h>
13
#include <fcntl.h>
14
#include <stdint.h>
15
#include <stdio.h>
16
#include <stdlib.h>
17
#include <string.h>
18
#include <sys/ioctl.h>
19
#include <sys/stat.h>
20
#include <sys/types.h>
21
#include <unistd.h>
22
23
#include "topology.h"
24
25
#ifndef MD_MAJOR
26
0
#define MD_MAJOR  9
27
#endif
28
29
#ifndef _IOT__IOTBASE_uint32_t
30
#define _IOT__IOTBASE_uint32_t IOT_SIMPLE(uint32_t)
31
#endif
32
#define _IOT_md_array_info _IOT (_IOTS(uint32_t), 18, 0, 0, 0, 0)
33
0
#define GET_ARRAY_INFO          _IOR (MD_MAJOR, 0x11, struct md_array_info)
34
35
struct md_array_info {
36
  /*
37
   * Generic constant information
38
   */
39
  uint32_t major_version;
40
  uint32_t minor_version;
41
  uint32_t patch_version;
42
  uint32_t ctime;
43
  uint32_t level;
44
  uint32_t size;
45
  uint32_t nr_disks;
46
  uint32_t raid_disks;
47
  uint32_t md_minor;
48
  uint32_t not_persistent;
49
50
  /*
51
   * Generic state information
52
   */
53
  uint32_t utime;   /*  0 Superblock update time      */
54
  uint32_t state;   /*  1 State bits (clean, ...)     */
55
  uint32_t active_disks;  /*  2 Number of currently active disks  */
56
  uint32_t working_disks; /*  3 Number of working disks     */
57
  uint32_t failed_disks;  /*  4 Number of failed disks      */
58
  uint32_t spare_disks;   /*  5 Number of spare disks     */
59
60
  /*
61
   * Personality information
62
   */
63
  uint32_t layout;    /*  0 the array's physical layout   */
64
  uint32_t chunk_size;    /*  1 chunk size in bytes     */
65
66
};
67
68
static int is_md_device(dev_t devno)
69
0
{
70
0
  if (major(devno) == MD_MAJOR)
71
0
    return 1;
72
0
  return blkid_driver_has_major("md", major(devno));
73
0
}
74
75
static int probe_md_tp(blkid_probe pr,
76
    const struct blkid_idmag *mag __attribute__((__unused__)))
77
0
{
78
0
  int fd = -1;
79
0
  dev_t disk = 0;
80
0
  dev_t devno = blkid_probe_get_devno(pr);
81
0
  struct md_array_info md;
82
83
0
  if (!devno)
84
0
    goto nothing;   /* probably not a block device */
85
86
0
  if (!is_md_device(devno))
87
0
    goto nothing;
88
89
0
  if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk))
90
0
    goto nothing;
91
92
0
  if (disk == devno)
93
0
    fd = pr->fd;
94
0
  else {
95
0
    char *diskpath = blkid_devno_to_devname(disk);
96
97
0
    if (!diskpath)
98
0
      goto nothing;
99
100
0
    fd = open(diskpath, O_RDONLY|O_CLOEXEC);
101
0
    free(diskpath);
102
103
0
                if (fd == -1)
104
0
      goto nothing;
105
0
  }
106
107
0
  memset(&md, 0, sizeof(md));
108
109
0
  if (ioctl(fd, GET_ARRAY_INFO, &md))
110
0
    goto nothing;
111
112
0
  if (fd >= 0 && fd != pr->fd) {
113
0
    close(fd);
114
0
    fd = -1;
115
0
  }
116
117
  /*
118
   * Ignore levels we don't want aligned (e.g. linear)
119
   * and deduct disk(s) from stripe width on RAID4/5/6
120
   */
121
0
  switch (md.level) {
122
0
  case 6:
123
0
    md.raid_disks--;
124
0
    FALLTHROUGH;
125
0
  case 5:
126
0
  case 4:
127
0
    md.raid_disks--;
128
0
    FALLTHROUGH;
129
0
  case 1:
130
0
  case 0:
131
0
  case 10:
132
0
    break;
133
0
  default:
134
0
    goto nothing;
135
0
  }
136
137
0
  blkid_topology_set_minimum_io_size(pr, md.chunk_size);
138
0
  blkid_topology_set_optimal_io_size(pr, (unsigned long) md.chunk_size * md.raid_disks);
139
140
0
  return 0;
141
142
0
nothing:
143
0
  if (fd >= 0 && fd != pr->fd)
144
0
    close(fd);
145
0
  return 1;
146
0
}
147
148
const struct blkid_idinfo md_tp_idinfo =
149
{
150
  .name   = "md",
151
  .probefunc  = probe_md_tp,
152
  .magics   = BLKID_NONE_MAGIC
153
};
154