}
#endif
+/*
+ * 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 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);
+}
+
/*
* Parse a 128 bit uuid in 4 integers
* format is 32 hexx nibbles with options :.<space> separator
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;
int i, rv;
char *avail;
- if (ioctl(fd, GET_ARRAY_INFO, &array) != 0 ||
- array.raid_disks <= 0)
+ if (md_get_array_info(fd, &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)
+ if (md_get_disk_info(fd, &disk) != 0)
continue;
if (disk.major == 0 && disk.minor == 0)
continue;
#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
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 &&
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);
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)
*/
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)
struct MBR boot_sect;
unsigned long long curr_part_end;
unsigned part_nr;
+ unsigned int sector_size;
int retval = 0;
*endofpart = 0;
/* 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 */
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
+ return sysfs_set_array(info, 9003);
#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);
+
+ 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;
}