return is_dlm_hooks_ready ? 1 : 0;
}
-#ifndef MDASSEMBLE
static struct dlm_hooks *dlm_hooks = NULL;
struct dlm_lock_resource *dlm_lock_res = NULL;
static int ast_called = 0;
out:
return ret;
}
-#else
-int cluster_get_dlmlock(int *lockid)
+
+int md_array_active(int fd)
{
- return -1;
+ struct mdinfo *sra;
+ struct mdu_array_info_s array;
+ int ret;
+
+ sra = sysfs_read(fd, NULL, GET_ARRAY_STATE);
+ if (sra) {
+ if (sra->array_state != ARRAY_CLEAR &&
+ sra->array_state != ARRAY_INACTIVE &&
+ sra->array_state != ARRAY_UNKNOWN_STATE)
+ ret = 0;
+ else
+ ret = -ENODEV;
+
+ free(sra);
+ } else {
+ /*
+ * GET_ARRAY_INFO doesn't provide access to the proper state
+ * information, so fallback to a basic check for raid_disks != 0
+ */
+ ret = ioctl(fd, GET_ARRAY_INFO, &array);
+ }
+
+ return !ret;
}
-int cluster_release_dlmlock(int lockid)
+
+/*
+ * Get array info from the kernel. Longer term we want to deprecate the
+ * ioctl and get it from sysfs.
+ */
+int md_get_array_info(int fd, struct mdu_array_info_s *array)
{
- return -1;
+ return ioctl(fd, GET_ARRAY_INFO, array);
+}
+
+/*
+ * Set array info
+ */
+int md_set_array_info(int fd, struct mdu_array_info_s *array)
+{
+ return ioctl(fd, SET_ARRAY_INFO, array);
+}
+
+/*
+ * Get disk info from the kernel.
+ */
+int md_get_disk_info(int fd, struct mdu_disk_info_s *disk)
+{
+ return ioctl(fd, GET_DISK_INFO, disk);
}
-#endif
/*
* Parse a 128 bit uuid in 4 integers
return 0;
}
-/*
- * Get the md version number.
- * We use the RAID_VERSION ioctl if it is supported
- * If not, but we have a block device with major '9', we assume
- * 0.36.0
- *
- * Return version number as 24 but number - assume version parts
- * always < 255
- */
-
-int md_get_version(int fd)
-{
- struct stat stb;
- mdu_version_t vers;
-
- if (fstat(fd, &stb)<0)
- return -1;
- if ((S_IFMT&stb.st_mode) != S_IFBLK)
- return -1;
-
- if (ioctl(fd, RAID_VERSION, &vers) == 0)
- return (vers.major*10000) + (vers.minor*100) + vers.patchlevel;
- if (errno == EACCES)
- return -1;
- if (major(stb.st_rdev) == MD_MAJOR)
- return (3600);
- return -1;
-}
-
int get_linux_version()
{
struct utsname name;
return (a*1000000)+(b*1000)+c;
}
-#ifndef MDASSEMBLE
int mdadm_version(char *version)
{
int a, b, c;
else
return rv;
}
-#endif
int parse_cluster_confirm_arg(char *input, char **devname, int *slot)
{
}
}
-int enough_fd(int fd)
-{
- struct mdu_array_info_s array;
- struct mdu_disk_info_s disk;
- int i, rv;
- char *avail;
-
- if (ioctl(fd, GET_ARRAY_INFO, &array) != 0 ||
- array.raid_disks <= 0)
- return 0;
- avail = xcalloc(array.raid_disks, 1);
- for (i = 0; i < MAX_DISKS && array.nr_disks > 0; i++) {
- disk.number = i;
- if (ioctl(fd, GET_DISK_INFO, &disk) != 0)
- continue;
- if (disk.major == 0 && disk.minor == 0)
- continue;
- array.nr_disks--;
-
- if (! (disk.state & (1<<MD_DISK_SYNC)))
- continue;
- if (disk.raid_disk < 0 || disk.raid_disk >= array.raid_disks)
- continue;
- avail[disk.raid_disk] = 1;
- }
- /* This is used on an active array, so assume it is clean */
- rv = enough(array.level, array.raid_disks, array.layout,
- 1, avail);
- free(avail);
- return rv;
-}
-
const int uuid_zero[4] = { 0, 0, 0, 0 };
int same_uuid(int a[4], int b[4], int swapuuid)
return __fname_from_uuid(info->uuid, (st->ss == &super1) ? 1 : st->ss->swapuuid, buf, sep);
}
-#ifndef MDASSEMBLE
int check_ext2(int fd, char *name)
{
/*
pr_err("assuming 'no'\n");
return 0;
}
-#endif /* MDASSEMBLE */
int is_standard(char *dev, int *nump)
{
return csum;
}
-#ifndef MDASSEMBLE
char *human_size(long long bytes)
{
- static char buf[30];
+ static char buf[47];
/* We convert bytes to either centi-M{ega,ibi}bytes or
* centi-G{igi,ibi}bytes, with appropriate rounding,
long cMiB = (bytes * 200LL / (1LL<<20) + 1) / 2;
long cMB = (bytes / ( 1000000LL / 200LL ) +1) /2;
snprintf(buf, sizeof(buf), " (%ld.%02ld MiB %ld.%02ld MB)",
- cMiB/100 , cMiB % 100,
- cMB/100, cMB % 100);
+ cMiB/100, cMiB % 100, cMB/100, cMB % 100);
} else {
long cGiB = (bytes * 200LL / (1LL<<30) +1) / 2;
long cGB = (bytes / (1000000000LL/200LL ) +1) /2;
snprintf(buf, sizeof(buf), " (%ld.%02ld GiB %ld.%02ld GB)",
- cGiB/100 , cGiB % 100,
- cGB/100, cGB % 100);
+ cGiB/100, cGiB % 100, cGB/100, cGB % 100);
}
return buf;
}
if (bytes < 2*1024LL*1024LL*1024LL) {
long cMiB = (bytes * 200LL / (1LL<<20) +1) /2;
snprintf(buf, sizeof(buf), "%ld.%02ldMiB",
- cMiB/100 , cMiB % 100);
+ cMiB/100, cMiB % 100);
} else {
long cGiB = (bytes * 200LL / (1LL<<30) +1) /2;
snprintf(buf, sizeof(buf), "%ld.%02ldGiB",
- cGiB/100 , cGiB % 100);
+ cGiB/100, cGiB % 100);
}
}
else if (prefix == JEDEC) {
if (bytes < 2*1024LL*1024LL*1024LL) {
long cMB = (bytes / ( 1000000LL / 200LL ) +1) /2;
snprintf(buf, sizeof(buf), "%ld.%02ldMB",
- cMB/100, cMB % 100);
+ cMB/100, cMB % 100);
} else {
long cGB = (bytes / (1000000000LL/200LL ) +1) /2;
snprintf(buf, sizeof(buf), "%ld.%02ldGB",
- cGB/100 , cGB % 100);
+ cGB/100, cGB % 100);
}
}
else
if (near*far == 1)
printf("NO REDUNDANCY");
}
-#endif
unsigned long long calc_array_size(int level, int raid_disks, int layout,
int chunksize, unsigned long long devsize)
return 0;
}
-#if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
char *get_md_name(char *devnm)
{
/* find /dev/md%d or /dev/md/%d or make a device /dev/.tmp.md%d */
if (strncmp(name, "/dev/.tmp.md", 12) == 0)
unlink(name);
}
-#endif /* !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO) */
int get_maj_min(char *dev, int *major, int *minor)
{
long delay = 1000;
sprintf(buf, "%d:%d", major(devid), minor(devid));
- for (i = 0 ; i < 25 ; i++) {
+ for (i = 0; i < 25; i++) {
int fd = dev_open(buf, flags|O_EXCL);
if (fd >= 0)
return fd;
(stb_want.st_mode & S_IFMT) != S_IFBLK)
return;
- for (i = 0 ; i < 25 ; i++) {
+ for (i = 0; i < 25; i++) {
struct stat stb;
if (stat(dev, &stb) == 0 &&
(stb.st_mode & S_IFMT) == S_IFBLK &&
&super0, &super1,
&super_ddf, &super_imsm,
&mbr, &gpt,
- NULL };
-
-#if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
+ NULL
+};
struct supertype *super_by_fd(int fd, char **subarrayp)
{
minor = sra->array.minor_version;
verstr = sra->text_version;
} else {
- if (ioctl(fd, GET_ARRAY_INFO, &array))
+ if (md_get_array_info(fd, &array))
array.major_version = array.minor_version = 0;
vers = array.major_version;
minor = array.minor_version;
verstr = "-no-metadata-";
}
- for (i = 0; st == NULL && superlist[i] ; i++)
+ for (i = 0; st == NULL && superlist[i]; i++)
st = superlist[i]->match_metadata_desc(verstr);
sysfs_free(sra);
return st;
}
-#endif /* !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO) */
int dev_size_from_id(dev_t id, unsigned long long *size)
{
st = xcalloc(1, sizeof(*st));
st->container_devnm[0] = 0;
- for (i = 0 ; superlist[i]; i++) {
+ for (i = 0; superlist[i]; i++) {
int rv;
ss = superlist[i];
if (guess_type == guess_array && ss->add_to_super == NULL)
ldsize <<= 9;
} else {
if (dname)
- pr_err("Cannot get size of %s: %s\b",
+ pr_err("Cannot get size of %s: %s\n",
dname, strerror(errno));
return 0;
}
return 1;
}
+/* Return sector size of device in bytes */
+int get_dev_sector_size(int fd, char *dname, unsigned int *sectsizep)
+{
+ unsigned int sectsize;
+
+ if (ioctl(fd, BLKSSZGET, §size) != 0) {
+ if (dname)
+ pr_err("Cannot get sector size of %s: %s\n",
+ dname, strerror(errno));
+ return 0;
+ }
+
+ *sectsizep = sectsize;
+ return 1;
+}
+
/* Return true if this can only be a container, not a member device.
* i.e. is and md device and size is zero
*/
int must_be_container(int fd)
{
+ struct mdinfo *mdi;
unsigned long long size;
- if (md_get_version(fd) < 0)
+
+ mdi = sysfs_read(fd, NULL, GET_VERSION);
+ if (!mdi)
return 0;
+ sysfs_free(mdi);
+
if (get_dev_size(fd, NULL, &size) == 0)
return 1;
if (size == 0)
unsigned long long curr_part_end;
unsigned all_partitions, entry_size;
unsigned part_nr;
+ unsigned int sector_size = 0;
*endofpart = 0;
BUILD_BUG_ON(sizeof(gpt) != 512);
/* skip protective MBR */
- lseek(fd, 512, SEEK_SET);
+ if (!get_dev_sector_size(fd, NULL, §or_size))
+ return 0;
+ lseek(fd, sector_size, SEEK_SET);
/* read GPT header */
if (read(fd, &gpt, 512) != 512)
return 0;
part = (struct GPT_part_entry *)buf;
+ /* set offset to third block (GPT entries) */
+ lseek(fd, sector_size*2, SEEK_SET);
for (part_nr = 0; part_nr < all_partitions; part_nr++) {
/* read partition entry */
if (read(fd, buf, entry_size) != (ssize_t)entry_size)
static int get_last_partition_end(int fd, unsigned long long *endofpart)
{
struct MBR boot_sect;
- struct MBR_part_record *part;
unsigned long long curr_part_end;
unsigned part_nr;
+ unsigned int sector_size;
int retval = 0;
*endofpart = 0;
if (boot_sect.magic == MBR_SIGNATURE_MAGIC) {
retval = 1;
/* found the correct signature */
- part = boot_sect.parts;
for (part_nr = 0; part_nr < MBR_PARTITIONS; part_nr++) {
+ /*
+ * Have to make every access through boot_sect rather
+ * than using a pointer to the partition table (or an
+ * entry), since the entries are not properly aligned.
+ */
+
/* check for GPT type */
- if (part->part_type == MBR_GPT_PARTITION_TYPE) {
+ if (boot_sect.parts[part_nr].part_type ==
+ MBR_GPT_PARTITION_TYPE) {
retval = get_gpt_last_partition_end(fd, endofpart);
break;
}
/* check the last used lba for the current partition */
- curr_part_end = __le32_to_cpu(part->first_sect_lba) +
- __le32_to_cpu(part->blocks_num);
+ curr_part_end =
+ __le32_to_cpu(boot_sect.parts[part_nr].first_sect_lba) +
+ __le32_to_cpu(boot_sect.parts[part_nr].blocks_num);
if (curr_part_end > *endofpart)
*endofpart = curr_part_end;
-
- part++;
}
} else {
/* Unknown partition table */
retval = -1;
}
+ /* calculate number of 512-byte blocks */
+ if (get_dev_sector_size(fd, NULL, §or_size))
+ *endofpart *= (sector_size / 512);
abort:
return retval;
}
* Check where the last partition ends
*/
unsigned long long endofpart;
- int ret;
- if ((ret = get_last_partition_end(fd, &endofpart)) > 0) {
+ if (get_last_partition_end(fd, &endofpart) > 0) {
/* There appears to be a partition table here */
if (freesize == 0) {
/* partitions will not be visible in new device */
{
/* Add a device to an array, in one of 2 ways. */
int rv;
-#ifndef MDASSEMBLE
+
if (st->ss->external) {
if (info->disk.state & (1<<MD_DISK_SYNC))
info->recovery_start = MaxSector;
}
}
} else
-#endif
rv = ioctl(mdfd, ADD_NEW_DISK, &info->disk);
return rv;
}
struct mdinfo *sra, struct mdinfo *info)
{
int rv;
+
/* Remove the disk given by 'info' from the array */
-#ifndef MDASSEMBLE
if (st->ss->external)
rv = sysfs_set_str(sra, info, "slot", "none");
else
-#endif
rv = ioctl(mdfd, HOT_REMOVE_DISK, makedev(info->disk.major,
info->disk.minor));
return rv;
}
+int hot_remove_disk(int mdfd, unsigned long dev, int force)
+{
+ int cnt = force ? 500 : 5;
+ int ret;
+
+ /* HOT_REMOVE_DISK can fail with EBUSY if there are
+ * outstanding IO requests to the device.
+ * In this case, it can be helpful to wait a little while,
+ * up to 5 seconds if 'force' is set, or 50 msec if not.
+ */
+ while ((ret = ioctl(mdfd, HOT_REMOVE_DISK, dev)) == -1 &&
+ errno == EBUSY &&
+ cnt-- > 0)
+ usleep(10000);
+
+ return ret;
+}
+
+int sys_hot_remove_disk(int statefd, int force)
+{
+ int cnt = force ? 500 : 5;
+ int ret;
+
+ while ((ret = write(statefd, "remove", 6)) == -1 &&
+ errno == EBUSY &&
+ cnt-- > 0)
+ usleep(10000);
+ return ret == 6 ? 0 : -1;
+}
+
int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info)
{
/* Initialise kernel's knowledge of array.
* This varies between externally managed arrays
* and older kernels
*/
- int vers = md_get_version(mdfd);
+ mdu_array_info_t inf;
int rv;
-#ifndef MDASSEMBLE
if (st->ss->external)
- rv = sysfs_set_array(info, vers);
- else
-#endif
- if ((vers % 100) >= 1) { /* can use different versions */
- mdu_array_info_t inf;
- memset(&inf, 0, sizeof(inf));
- inf.major_version = info->array.major_version;
- inf.minor_version = info->array.minor_version;
- rv = ioctl(mdfd, SET_ARRAY_INFO, &inf);
- } else
- rv = ioctl(mdfd, SET_ARRAY_INFO, NULL);
+ return sysfs_set_array(info, 9003);
+
+ memset(&inf, 0, sizeof(inf));
+ inf.major_version = info->array.major_version;
+ inf.minor_version = info->array.minor_version;
+ rv = md_set_array_info(mdfd, &inf);
+
return rv;
}
memcpy(buf, r, 16);
}
-#ifndef MDASSEMBLE
int flush_metadata_updates(struct supertype *st)
{
int sfd;
*st->update_tail = mu;
st->update_tail = &mu->next;
}
-#endif /* MDASSEMBLE */
#ifdef __TINYC__
/* tinyc doesn't optimize this check in ioctl.h out ... */
dup2(fd, mdfd);
}
-#ifndef MDASSEMBLE
static struct cmap_hooks *cmap_hooks = NULL;
static int is_cmap_hooks_ready = 0;
set_dlm_hooks();
set_cmap_hooks();
}
-#endif