155 lines
3.1 KiB
C
155 lines
3.1 KiB
C
/*
|
|
* Linux Software RAID (md) topology
|
|
* -- this is fallback for old systems where the topology information is not
|
|
* exported by sysfs
|
|
*
|
|
* Copyright (C) 2009 Karel Zak <kzak@redhat.com>
|
|
*
|
|
* This file may be redistributed under the terms of the
|
|
* GNU Lesser General Public License.
|
|
*
|
|
*/
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include "topology.h"
|
|
|
|
#ifndef MD_MAJOR
|
|
#define MD_MAJOR 9
|
|
#endif
|
|
|
|
#ifndef _IOT__IOTBASE_uint32_t
|
|
#define _IOT__IOTBASE_uint32_t IOT_SIMPLE(uint32_t)
|
|
#endif
|
|
#define _IOT_md_array_info _IOT (_IOTS(uint32_t), 18, 0, 0, 0, 0)
|
|
#define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, struct md_array_info)
|
|
|
|
struct md_array_info {
|
|
/*
|
|
* Generic constant information
|
|
*/
|
|
uint32_t major_version;
|
|
uint32_t minor_version;
|
|
uint32_t patch_version;
|
|
uint32_t ctime;
|
|
uint32_t level;
|
|
uint32_t size;
|
|
uint32_t nr_disks;
|
|
uint32_t raid_disks;
|
|
uint32_t md_minor;
|
|
uint32_t not_persistent;
|
|
|
|
/*
|
|
* Generic state information
|
|
*/
|
|
uint32_t utime; /* 0 Superblock update time */
|
|
uint32_t state; /* 1 State bits (clean, ...) */
|
|
uint32_t active_disks; /* 2 Number of currently active disks */
|
|
uint32_t working_disks; /* 3 Number of working disks */
|
|
uint32_t failed_disks; /* 4 Number of failed disks */
|
|
uint32_t spare_disks; /* 5 Number of spare disks */
|
|
|
|
/*
|
|
* Personality information
|
|
*/
|
|
uint32_t layout; /* 0 the array's physical layout */
|
|
uint32_t chunk_size; /* 1 chunk size in bytes */
|
|
|
|
};
|
|
|
|
static int is_md_device(dev_t devno)
|
|
{
|
|
if (major(devno) == MD_MAJOR)
|
|
return 1;
|
|
return blkid_driver_has_major("md", major(devno));
|
|
}
|
|
|
|
static int probe_md_tp(blkid_probe pr,
|
|
const struct blkid_idmag *mag __attribute__((__unused__)))
|
|
{
|
|
int fd = -1;
|
|
dev_t disk = 0;
|
|
dev_t devno = blkid_probe_get_devno(pr);
|
|
struct md_array_info md;
|
|
|
|
if (!devno)
|
|
goto nothing; /* probably not a block device */
|
|
|
|
if (!is_md_device(devno))
|
|
goto nothing;
|
|
|
|
if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk))
|
|
goto nothing;
|
|
|
|
if (disk == devno)
|
|
fd = pr->fd;
|
|
else {
|
|
char *diskpath = blkid_devno_to_devname(disk);
|
|
|
|
if (!diskpath)
|
|
goto nothing;
|
|
|
|
fd = open(diskpath, O_RDONLY|O_CLOEXEC);
|
|
free(diskpath);
|
|
|
|
if (fd == -1)
|
|
goto nothing;
|
|
}
|
|
|
|
memset(&md, 0, sizeof(md));
|
|
|
|
if (ioctl(fd, GET_ARRAY_INFO, &md))
|
|
goto nothing;
|
|
|
|
if (fd >= 0 && fd != pr->fd) {
|
|
close(fd);
|
|
fd = -1;
|
|
}
|
|
|
|
/*
|
|
* Ignore levels we don't want aligned (e.g. linear)
|
|
* and deduct disk(s) from stripe width on RAID4/5/6
|
|
*/
|
|
switch (md.level) {
|
|
case 6:
|
|
md.raid_disks--;
|
|
/* fallthrough */
|
|
case 5:
|
|
case 4:
|
|
md.raid_disks--;
|
|
/* fallthrough */
|
|
case 1:
|
|
case 0:
|
|
case 10:
|
|
break;
|
|
default:
|
|
goto nothing;
|
|
}
|
|
|
|
blkid_topology_set_minimum_io_size(pr, md.chunk_size);
|
|
blkid_topology_set_optimal_io_size(pr, md.chunk_size * md.raid_disks);
|
|
|
|
return 0;
|
|
|
|
nothing:
|
|
if (fd >= 0 && fd != pr->fd)
|
|
close(fd);
|
|
return 1;
|
|
}
|
|
|
|
const struct blkid_idinfo md_tp_idinfo =
|
|
{
|
|
.name = "md",
|
|
.probefunc = probe_md_tp,
|
|
.magics = BLKID_NONE_MAGIC
|
|
};
|
|
|