imsm: validate arrays being created against firmware capabilities

These checks are only enabled when platform support for imsm is found,
i.e. ahci driver is loaded and talking to an Intel(R) controller, and
the option rom header is located.

They can be turned off by setting the environment variable
IMSM_NO_PLATFORM to 1.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
Dan Williams 2008-12-08 16:59:18 -07:00
parent 25921536da
commit 88c32bb1ec
3 changed files with 137 additions and 16 deletions

View File

@ -76,23 +76,28 @@ OBJS = mdadm.o config.o mdstat.o ReadMe.o util.o Manage.o Assemble.o Build.o \
Create.o Detail.o Examine.o Grow.o Monitor.o dlink.o Kill.o Query.o \
Incremental.o \
mdopen.o super0.o super1.o super-ddf.o super-intel.o bitmap.o \
restripe.o sysfs.o sha1.o mapfile.o crc32.o sg_io.o msg.o
restripe.o sysfs.o sha1.o mapfile.o crc32.o sg_io.o msg.o \
platform-intel.o probe_roms.o
SRCS = mdadm.c config.c mdstat.c ReadMe.c util.c Manage.c Assemble.c Build.c \
Create.c Detail.c Examine.c Grow.c Monitor.c dlink.c Kill.c Query.c \
Incremental.c \
mdopen.c super0.c super1.c super-ddf.c super-intel.c bitmap.c \
restripe.c sysfs.c sha1.c mapfile.c crc32.c sg_io.c msg.c
restripe.c sysfs.c sha1.c mapfile.c crc32.c sg_io.c msg.c \
platform-intel.c probe_roms.c
MON_OBJS = mdmon.o monitor.o managemon.o util.o mdstat.o sysfs.o config.o \
Kill.o sg_io.o dlink.o ReadMe.o super0.o super1.o super-intel.o \
super-ddf.o sha1.o crc32.o msg.o Monitor.o bitmap.o
super-ddf.o sha1.o crc32.o msg.o Monitor.o bitmap.o \
platform-intel.o probe_roms.o
STATICSRC = pwgr.c
STATICOBJS = pwgr.o
ASSEMBLE_SRCS := mdassemble.c Assemble.c Manage.c config.c dlink.c util.c \
super0.c super1.c super-ddf.c super-intel.c sha1.c crc32.c sg_io.c mdstat.c
super0.c super1.c super-ddf.c super-intel.c sha1.c crc32.c sg_io.c mdstat.c \
platform-intel.c probe_roms.c
ASSEMBLE_AUTO_SRCS := mdopen.c sysfs.c
ASSEMBLE_FLAGS:= $(CFLAGS) -DMDASSEMBLE
ifdef MDASSEMBLE_AUTO

View File

@ -17,6 +17,7 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <asm/types.h>
#include <strings.h>
/* The IMSM OROM Version Table definition */
struct imsm_orom {
@ -78,6 +79,42 @@ struct imsm_orom {
__u32 reserved2;
} __attribute__((packed));
static inline int imsm_orom_has_raid0(const struct imsm_orom *orom)
{
return !!(orom->rlc & IMSM_OROM_RLC_RAID0);
}
static inline int imsm_orom_has_raid1(const struct imsm_orom *orom)
{
return !!(orom->rlc & IMSM_OROM_RLC_RAID1);
}
static inline int imsm_orom_has_raid1e(const struct imsm_orom *orom)
{
return !!(orom->rlc & IMSM_OROM_RLC_RAID1E);
}
static inline int imsm_orom_has_raid10(const struct imsm_orom *orom)
{
return !!(orom->rlc & IMSM_OROM_RLC_RAID10);
}
static inline int imsm_orom_has_raid5(const struct imsm_orom *orom)
{
return !!(orom->rlc & IMSM_OROM_RLC_RAID5);
}
/**
* imsm_orom_has_chunk - check if the orom supports the given chunk size
* @orom: orom pointer from find_imsm_orom
* @chunk: chunk size in kibibytes
*/
static inline int imsm_orom_has_chunk(const struct imsm_orom *orom, int chunk)
{
int fs = ffs(chunk);
if (!fs)
return 0;
fs--; /* bit num to bit index */
return !!(orom->sss & (1 << (fs - 1)));
}
struct sys_dev {
char *path;
struct sys_dev *next;

View File

@ -21,6 +21,7 @@
#include "mdadm.h"
#include "mdmon.h"
#include "sha1.h"
#include "platform-intel.h"
#include <values.h>
#include <scsi/sg.h>
#include <ctype.h>
@ -230,6 +231,8 @@ struct intel_super {
struct dl *add; /* list of disks to add while mdmon active */
struct dl *missing; /* disks removed while we weren't looking */
struct bbm_log *bbm_log;
const char *hba; /* device path of the raid controller for this metadata */
const struct imsm_orom *orom; /* platform firmware support */
};
struct extent {
@ -1505,6 +1508,10 @@ static void __free_imsm(struct intel_super *super, int free_disks)
free(super->dev_tbl[i]);
super->dev_tbl[i] = NULL;
}
if (super->hba) {
free((void *) super->hba);
super->hba = NULL;
}
}
static void free_imsm(struct intel_super *super)
@ -1533,6 +1540,22 @@ static struct intel_super *alloc_super(int creating_imsm)
super->creating_imsm = creating_imsm;
super->current_vol = -1;
super->create_offset = ~((__u32 ) 0);
if (!check_env("IMSM_NO_PLATFORM"))
super->orom = find_imsm_orom();
if (super->orom) {
struct sys_dev *list, *ent;
/* find the first intel ahci controller */
list = find_driver_devices("pci", "ahci");
for (ent = list; ent; ent = ent->next)
if (devpath_to_vendor(ent->path) == 0x8086)
break;
if (ent) {
super->hba = ent->path;
ent->path = NULL;
}
free_sys_dev(&list);
}
}
return super;
@ -1817,9 +1840,9 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
unsigned long long array_blocks;
size_t size_old, size_new;
if (mpb->num_raid_devs >= 2) {
if (super->orom && mpb->num_raid_devs >= super->orom->vpa) {
fprintf(stderr, Name": This imsm-container already has the "
"maximum of 2 volumes\n");
"maximum of %d volumes\n", super->orom->vpa);
return 0;
}
@ -2014,6 +2037,16 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
int rv;
struct stat stb;
/* if we are on an RAID enabled platform check that the disk is
* attached to the raid controller
*/
if (super->hba && !disk_attached_to_hba(fd, super->hba)) {
fprintf(stderr,
Name ": %s is not attached to the raid controller: %s\n",
devname ? : "disk", super->hba);
return 1;
}
if (super->current_vol >= 0)
return add_to_super_imsm_volume(st, dk, fd, devname);
@ -2282,12 +2315,25 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
{
int fd;
unsigned long long ldsize;
const struct imsm_orom *orom;
if (level != LEVEL_CONTAINER)
return 0;
if (!dev)
return 1;
if (check_env("IMSM_NO_PLATFORM"))
orom = NULL;
else
orom = find_imsm_orom();
if (orom && raiddisks > orom->tds) {
if (verbose)
fprintf(stderr, Name ": %d exceeds maximum number of"
" platform supported disks: %d\n",
raiddisks, orom->tds);
return 0;
}
fd = open(dev, O_RDONLY|O_EXCL, 0);
if (fd < 0) {
if (verbose)
@ -2408,6 +2454,30 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten
return maxsize - reserve;
}
static int is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks)
{
if (level < 0 || level == 6 || level == 4)
return 0;
/* if we have an orom prevent invalid raid levels */
if (orom)
switch (level) {
case 0: return imsm_orom_has_raid0(orom);
case 1:
if (raiddisks > 2)
return imsm_orom_has_raid1e(orom);
else
return imsm_orom_has_raid1(orom);
case 10: return imsm_orom_has_raid10(orom);
case 5: return imsm_orom_has_raid5(orom);
}
else
return 1; /* not on an Intel RAID platform so anything goes */
return 0;
}
#define vprintf(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg))
/* validate_geometry_imsm_volume - lifted from validate_geometry_ddf_bvd
* FIX ME add ahci details
*/
@ -2425,20 +2495,29 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
struct extent *e;
int i;
if (level == LEVEL_CONTAINER)
return 0;
if (level == 1 && raiddisks > 2) {
if (verbose)
fprintf(stderr, Name ": imsm does not support more "
"than 2 in a raid1 configuration\n");
return 0;
}
/* We must have the container info already read in. */
if (!super)
return 0;
if (!is_raid_level_supported(super->orom, level, raiddisks)) {
vprintf(": platform does not support raid level: %d\n", level);
return 0;
}
if (super->orom && !imsm_orom_has_chunk(super->orom, chunk)) {
vprintf(": platform does not support a chunk size of: %d\n", chunk);
return 0;
}
if (layout != imsm_level_to_layout(level)) {
if (level == 5)
vprintf(": imsm raid 5 only supports the left-asymmetric layout\n");
else if (level == 10)
vprintf(": imsm raid 10 only supports the n2 layout\n");
else
vprintf(": imsm unknown layout %#x for this raid level %d\n",
layout, level);
return 0;
}
if (!dev) {
/* General test: make sure there is space for
* 'raiddisks' device extents of size 'size' at a given