blob: 5eba94787dce0194a3fd7a0010ebe095b3fb877a [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>
20#include <sys/types.h>
21#include <unistd.h>
22
23#include "topology.h"
24
25#ifndef MD_MAJOR
26#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#define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, struct md_array_info)
34
35struct 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
68static int is_md_device(dev_t devno)
69{
70 if (major(devno) == MD_MAJOR)
71 return 1;
72 return blkid_driver_has_major("md", major(devno));
73}
74
75static int probe_md_tp(blkid_probe pr,
76 const struct blkid_idmag *mag __attribute__((__unused__)))
77{
78 int fd = -1;
79 dev_t disk = 0;
80 dev_t devno = blkid_probe_get_devno(pr);
81 struct md_array_info md;
82
83 if (!devno)
84 goto nothing; /* probably not a block device */
85
86 if (!is_md_device(devno))
87 goto nothing;
88
89 if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk))
90 goto nothing;
91
92 if (disk == devno)
93 fd = pr->fd;
94 else {
95 char *diskpath = blkid_devno_to_devname(disk);
96
97 if (!diskpath)
98 goto nothing;
99
100 fd = open(diskpath, O_RDONLY|O_CLOEXEC);
101 free(diskpath);
102
103 if (fd == -1)
104 goto nothing;
105 }
106
107 memset(&md, 0, sizeof(md));
108
109 if (ioctl(fd, GET_ARRAY_INFO, &md))
110 goto nothing;
111
112 if (fd >= 0 && fd != pr->fd) {
113 close(fd);
114 fd = -1;
115 }
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 switch (md.level) {
122 case 6:
123 md.raid_disks--;
124 /* fallthrough */
125 case 5:
126 case 4:
127 md.raid_disks--;
128 /* fallthrough */
129 case 1:
130 case 0:
131 case 10:
132 break;
133 default:
134 goto nothing;
135 }
136
137 blkid_topology_set_minimum_io_size(pr, md.chunk_size);
138 blkid_topology_set_optimal_io_size(pr, md.chunk_size * md.raid_disks);
139
140 return 0;
141
142nothing:
143 if (fd >= 0 && fd != pr->fd)
144 close(fd);
145 return 1;
146}
147
148const struct blkid_idinfo md_tp_idinfo =
149{
150 .name = "md",
151 .probefunc = probe_md_tp,
152 .magics = BLKID_NONE_MAGIC
153};
154