}
#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);
+}
+
/*
* Parse a 128 bit uuid in 4 integers
* format is 32 hexx nibbles with options :.<space> separator
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++) {
if (!st)
return 0;
- st->ss->load_super(st, fd, name);
- /* Looks like a raid array .. */
- pr_err("%s appears to be part of a raid array:\n",
- name);
- st->ss->getinfo_super(st, &info, NULL);
- st->ss->free_super(st);
- crtime = info.array.ctime;
- level = map_num(pers, info.array.level);
- if (!level) level = "-unknown-";
- cont_err("level=%s devices=%d ctime=%s",
- level, info.array.raid_disks, ctime(&crtime));
+ if (st->ss->add_to_super != NULL) {
+ st->ss->load_super(st, fd, name);
+ /* Looks like a raid array .. */
+ pr_err("%s appears to be part of a raid array:\n", name);
+ st->ss->getinfo_super(st, &info, NULL);
+ st->ss->free_super(st);
+ crtime = info.array.ctime;
+ level = map_num(pers, info.array.level);
+ if (!level)
+ level = "-unknown-";
+ cont_err("level=%s devices=%d ctime=%s",
+ level, info.array.raid_disks, ctime(&crtime));
+ } else {
+ /* Looks like GPT or MBR */
+ pr_err("partition table exists on %s\n", name);
+ }
return 1;
}
#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)
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
*/
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 */
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.
return rv;
}
+void random_uuid(__u8 *buf)
+{
+ int fd, i, len;
+ __u32 r[4];
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0)
+ goto use_random;
+ len = read(fd, buf, 16);
+ close(fd);
+ if (len != 16)
+ goto use_random;
+
+ return;
+
+use_random:
+ for (i = 0; i < 4; i++)
+ r[i] = random();
+ memcpy(buf, r, 16);
+}
+
#ifndef MDASSEMBLE
int flush_metadata_updates(struct supertype *st)
{