blob: c23219742187b4db7bc29dda3251a6aec85b278d [file] [log] [blame]
bigbiff bigbiffe60683a2013-02-22 20:55:50 -05001/*
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>
Ethan Yonkerfefe5912017-09-30 22:22:13 -050020#include <sys/sysmacros.h>
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050021#include <sys/types.h>
22#include <unistd.h>
23
24#include "topology.h"
25
26#ifndef MD_MAJOR
27#define MD_MAJOR 9
28#endif
29
30#ifndef _IOT__IOTBASE_uint32_t
31#define _IOT__IOTBASE_uint32_t IOT_SIMPLE(uint32_t)
32#endif
33#define _IOT_md_array_info _IOT (_IOTS(uint32_t), 18, 0, 0, 0, 0)
34#define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, struct md_array_info)
35
36struct md_array_info {
37 /*
38 * Generic constant information
39 */
40 uint32_t major_version;
41 uint32_t minor_version;
42 uint32_t patch_version;
43 uint32_t ctime;
44 uint32_t level;
45 uint32_t size;
46 uint32_t nr_disks;
47 uint32_t raid_disks;
48 uint32_t md_minor;
49 uint32_t not_persistent;
50
51 /*
52 * Generic state information
53 */
54 uint32_t utime; /* 0 Superblock update time */
55 uint32_t state; /* 1 State bits (clean, ...) */
56 uint32_t active_disks; /* 2 Number of currently active disks */
57 uint32_t working_disks; /* 3 Number of working disks */
58 uint32_t failed_disks; /* 4 Number of failed disks */
59 uint32_t spare_disks; /* 5 Number of spare disks */
60
61 /*
62 * Personality information
63 */
64 uint32_t layout; /* 0 the array's physical layout */
65 uint32_t chunk_size; /* 1 chunk size in bytes */
66
67};
68
69static int is_md_device(dev_t devno)
70{
71 if (major(devno) == MD_MAJOR)
72 return 1;
73 return blkid_driver_has_major("md", major(devno));
74}
75
76static int probe_md_tp(blkid_probe pr,
77 const struct blkid_idmag *mag __attribute__((__unused__)))
78{
79 int fd = -1;
80 dev_t disk = 0;
81 dev_t devno = blkid_probe_get_devno(pr);
82 struct md_array_info md;
83
84 if (!devno)
85 goto nothing; /* probably not a block device */
86
87 if (!is_md_device(devno))
88 goto nothing;
89
90 if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk))
91 goto nothing;
92
93 if (disk == devno)
94 fd = pr->fd;
95 else {
96 char *diskpath = blkid_devno_to_devname(disk);
97
98 if (!diskpath)
99 goto nothing;
100
101 fd = open(diskpath, O_RDONLY|O_CLOEXEC);
102 free(diskpath);
103
104 if (fd == -1)
105 goto nothing;
106 }
107
108 memset(&md, 0, sizeof(md));
109
110 if (ioctl(fd, GET_ARRAY_INFO, &md))
111 goto nothing;
112
113 if (fd >= 0 && fd != pr->fd) {
114 close(fd);
115 fd = -1;
116 }
117
118 /*
119 * Ignore levels we don't want aligned (e.g. linear)
120 * and deduct disk(s) from stripe width on RAID4/5/6
121 */
122 switch (md.level) {
123 case 6:
124 md.raid_disks--;
125 /* fallthrough */
126 case 5:
127 case 4:
128 md.raid_disks--;
129 /* fallthrough */
130 case 1:
131 case 0:
132 case 10:
133 break;
134 default:
135 goto nothing;
136 }
137
138 blkid_topology_set_minimum_io_size(pr, md.chunk_size);
139 blkid_topology_set_optimal_io_size(pr, md.chunk_size * md.raid_disks);
140
141 return 0;
142
143nothing:
144 if (fd >= 0 && fd != pr->fd)
145 close(fd);
146 return 1;
147}
148
149const struct blkid_idinfo md_tp_idinfo =
150{
151 .name = "md",
152 .probefunc = probe_md_tp,
153 .magics = BLKID_NONE_MAGIC
154};
155