#include "md_p.h"
#include <sys/socket.h>
#include <sys/utsname.h>
+#include <sys/wait.h>
#include <sys/un.h>
#include <ctype.h>
#include <dirent.h>
}
}
+const int uuid_match_any[4] = { ~0, ~0, ~0, ~0 };
int same_uuid(int a[4], int b[4], int swapuuid)
{
+ if (memcmp(a, uuid_match_any, sizeof(int[4])) == 0 ||
+ memcmp(b, uuid_match_any, sizeof(int[4])) == 0)
+ return 1;
+
if (swapuuid) {
/* parse uuids are hostendian.
* uuid's from some superblocks are big-ending
memcpy(a, b, 16);
}
+char *fname_from_uuid(struct supertype *st, struct mdinfo *info, char *buf, char sep)
+{
+ int i, j;
+ int id;
+ char uuid[16];
+ char *c = buf;
+ strcpy(c, "UUID-");
+ c += strlen(c);
+ copy_uuid(uuid, info->uuid, st->ss->swapuuid);
+ for (i = 0; i < 4; i++) {
+ id = uuid[i];
+ if (i)
+ *c++ = sep;
+ for (j = 3; j >= 0; j--) {
+ sprintf(c,"%02x", (unsigned char) uuid[j+4*i]);
+ c+= 2;
+ }
+ }
+ return buf;
+}
+
#ifndef MDASSEMBLE
int check_ext2(int fd, char *name)
{
if (strncmp(d, "/d",2)==0)
d += 2, type=1; /* /dev/md/dN{pM} */
else if (strncmp(d, "/md_d", 5)==0)
- d += 5, type=1; /* /dev/md_dNpM */
+ d += 5, type=1; /* /dev/md_dN{pM} */
else if (strncmp(d, "/md", 3)==0)
d += 3, type=-1; /* /dev/mdN */
else if (d-dev > 3 && strncmp(d-2, "md/", 3)==0)
int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s)
{
struct stat st;
+
if (S_ISLNK(stb->st_mode)) {
- stat(name, &st);
+ if (stat(name, &st) != 0)
+ return 0;
stb = &st;
}
);
return buf;
}
+
+void print_r10_layout(int layout)
+{
+ int near = layout & 255;
+ int far = (layout >> 8) & 255;
+ int offset = (layout&0x10000);
+ char *sep = "";
+
+ if (near != 1) {
+ printf("%s near=%d", sep, near);
+ sep = ",";
+ }
+ if (far != 1)
+ printf("%s %s=%d", sep, offset?"offset":"far", far);
+ if (near*far == 1)
+ printf("NO REDUNDANCY");
+}
#endif
unsigned long long calc_array_size(int level, int raid_disks, int layout,
return data_disks * devsize;
}
-#if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
int get_mdp_major(void)
{
static int mdp_major = -1;
return mdp_major;
}
-
-
+#if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
char *get_md_name(int dev)
{
/* find /dev/md%d or /dev/md/%d or make a device /dev/.tmp.md%d */
snprintf(devname, sizeof(devname), "/dev/.tmp.md.%d:%d:%d",
(int)getpid(), major, minor);
if (mknod(devname, S_IFBLK|0600, makedev(major, minor))==0) {
- fd = open(devname, flags);
+ fd = open(devname, flags|O_DIRECT);
unlink(devname);
}
} else
- fd = open(dev, flags);
+ fd = open(dev, flags|O_DIRECT);
return fd;
}
+int open_dev(int devnum)
+{
+ char buf[20];
+
+ sprintf(buf, "%d:%d", dev2major(devnum), dev2minor(devnum));
+ return dev_open(buf, O_RDWR);
+}
+
int open_dev_excl(int devnum)
{
char buf[20];
return -1;
}
+int same_dev(char *one, char *two)
+{
+ struct stat st1, st2;
+ if (stat(one, &st1) != 0)
+ return 0;
+ if (stat(two, &st2) != 0)
+ return 0;
+ if ((st1.st_mode & S_IFMT) != S_IFBLK)
+ return 0;
+ if ((st2.st_mode & S_IFMT) != S_IFBLK)
+ return 0;
+ return st1.st_rdev == st2.st_rdev;
+}
+
+void wait_for(char *dev)
+{
+ int i;
+
+ for (i=0 ; i<25 ; i++) {
+ struct stat stb;
+ if (stat(dev, &stb) == 0)
+ return;
+ usleep(200000);
+ }
+}
+
struct superswitch *superlist[] = { &super0, &super1, &super_ddf, &super_imsm, NULL };
#if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
sprintf(version, "%d.%d", vers, minor);
verstr = version;
}
- if (minor == -2 && verstr[0] == '/') {
+ if (minor == -2 && is_subarray(verstr)) {
char *dev = verstr+1;
subarray = strchr(dev, '/');
int devnum;
if (subarray)
*subarray++ = '\0';
- if (strncmp(dev, "md_d", 4) == 0)
- devnum = -1-atoi(dev+4);
- else
- devnum = atoi(dev+2);
+ devnum = devname2devnum(dev);
subarray = strdup(subarray);
if (sra)
sysfs_free(sra);
return -1;
}
+int add_disk(int mdfd, struct supertype *st,
+ struct mdinfo *sra, struct mdinfo *info)
+{
+ /* Add a device to an array, in one of 2 ways. */
+ int rv;
+#ifndef MDASSEMBLE
+ if (st->ss->external) {
+ rv = sysfs_add_disk(sra, info);
+ if (! rv) {
+ struct mdinfo *sd2;
+ for (sd2 = sra->devs; sd2; sd2=sd2->next)
+ if (sd2 == info)
+ break;
+ if (sd2 == NULL) {
+ sd2 = malloc(sizeof(*sd2));
+ *sd2 = *info;
+ sd2->next = sra->devs;
+ sra->devs = sd2;
+ }
+ }
+ } else
+#endif
+ rv = ioctl(mdfd, ADD_NEW_DISK, &info->disk);
+ return rv;
+}
+
+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);
+ 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 rv;
+}
+
char *devnum2devname(int num)
{
char name[100];
return strdup(name);
}
+int devname2devnum(char *name)
+{
+ char *ep;
+ int num;
+ if (strncmp(name, "md_d", 4)==0)
+ num = -1-strtoul(name+4, &ep, 10);
+ else
+ num = strtoul(name+2, &ep, 10);
+ return num;
+}
+
+int stat2devnum(struct stat *st)
+{
+ char path[30];
+ char link[200];
+ char *cp;
+ int n;
+
+ if ((S_IFMT & st->st_mode) == S_IFBLK) {
+ if (major(st->st_rdev) == MD_MAJOR)
+ return minor(st->st_rdev);
+ else if (major(st->st_rdev) == get_mdp_major())
+ return -1- (minor(st->st_rdev)>>MdpMinorShift);
+
+ /* must be an extended-minor partition. Look at the
+ * /sys/dev/block/%d:%d link which must look like
+ * ../../block/mdXXX/mdXXXpYY
+ */
+ sprintf(path, "/sys/dev/block/%d:%d", major(st->st_rdev),
+ minor(st->st_rdev));
+ n = readlink(path, link, sizeof(link)-1);
+ if (n <= 0)
+ return NoMdDev;
+ link[n] = 0;
+ cp = strrchr(link, '/');
+ if (cp) *cp = 0;
+ cp = strchr(link, '/');
+ if (cp && strncmp(cp, "/md", 3) == 0)
+ return devname2devnum(cp+1);
+ }
+ return NoMdDev;
+
+}
+
int fd2devnum(int fd)
{
struct stat stb;
- if (fstat(fd, &stb) == 0 &&
- (S_IFMT&stb.st_mode)==S_IFBLK) {
- if (major(stb.st_rdev) == MD_MAJOR)
- return minor(stb.st_rdev);
- else
- return -1- (minor(stb.st_rdev)>>6);
- }
- return -1;
+ if (fstat(fd, &stb) == 0)
+ return stat2devnum(&stb);
+ return NoMdDev;
}
int mdmon_running(int devnum)
return 0;
}
+int start_mdmon(int devnum)
+{
+ int i;
+ int len;
+ pid_t pid;
+ int status;
+ char pathbuf[1024];
+ char *paths[4] = {
+ pathbuf,
+ "/sbin/mdmon",
+ "mdmon",
+ NULL
+ };
+
+ if (check_env("MDADM_NO_MDMON"))
+ return 0;
+
+ len = readlink("/proc/self/exe", pathbuf, sizeof(pathbuf));
+ if (len > 0) {
+ char *sl;
+ pathbuf[len] = 0;
+ sl = strrchr(pathbuf, '/');
+ if (sl)
+ sl++;
+ else
+ sl = pathbuf;
+ strcpy(sl, "mdmon");
+ } else
+ pathbuf[0] = '\0';
+
+ switch(fork()) {
+ case 0:
+ /* FIXME yuk. CLOSE_EXEC?? */
+ for (i=3; i < 100; i++)
+ close(i);
+ for (i=0; paths[i]; i++)
+ if (paths[i][0])
+ execl(paths[i], "mdmon",
+ devnum2devname(devnum),
+ NULL);
+ exit(1);
+ case -1: fprintf(stderr, Name ": cannot run mdmon. "
+ "Array remains readonly\n");
+ return -1;
+ default: /* parent - good */
+ pid = wait(&status);
+ if (pid < 0 || status != 0)
+ return -1;
+ }
+ return 0;
+}
+
+int check_env(char *name)
+{
+ char *val = getenv(name);
+
+ if (val && atoi(val) == 1)
+ return 1;
+
+ return 0;
+}
+#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 ... */