#include "mdadm.h"
#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>
+#include <signal.h>
/*
* following taken from linux/blkpg.h because they aren't
unlink(name);
}
-static int dev2major(int d)
-{
- if (d >= 0)
- return MD_MAJOR;
- else
- return get_mdp_major();
-}
-
-static int dev2minor(int d)
-{
- if (d >= 0)
- return d;
- return (-1-d) << MdpMinorShift;
-}
-
int find_free_devnum(int use_partitions)
{
int devnum;
if (e > dev && *e == ':' && e[1] &&
(minor = strtoul(e+1, &e, 0)) >= 0 &&
*e == 0) {
- snprintf(devname, sizeof(devname), "/dev/.tmp.md.%d:%d", major, minor);
+ 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_excl(int devnum)
+{
+ char buf[20];
+ int i;
+
+ sprintf(buf, "%d:%d", dev2major(devnum), dev2minor(devnum));
+ for (i=0 ; i<25 ; i++) {
+ int fd = dev_open(buf, O_RDWR|O_EXCL);
+ if (fd >= 0)
+ return fd;
+ if (errno != EBUSY)
+ return fd;
+ usleep(200000);
+ }
+ return -1;
+}
+
struct superswitch *superlist[] = { &super0, &super1, &super_ddf, &super_imsm, NULL };
#if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)
-struct supertype supertype_container_member;
-
struct supertype *super_by_fd(int fd)
{
mdu_array_info_t array;
char *verstr;
char version[20];
int i;
+ char *subarray = NULL;
sra = sysfs_read(fd, 0, GET_VERSION);
sprintf(version, "%d.%d", vers, minor);
verstr = version;
}
- if (minor == -2 && verstr[0] == '/')
- st = &supertype_container_member;
- else
- for (i = 0; st == NULL && superlist[i] ; i++)
- st = superlist[i]->match_metadata_desc(verstr);
+ if (minor == -2 && verstr[0] == '/') {
+ char *dev = verstr+1;
+ subarray = strchr(dev, '/');
+ int devnum;
+ if (subarray)
+ *subarray++ = '\0';
+ devnum = devname2devnum(dev);
+ subarray = strdup(subarray);
+ if (sra)
+ sysfs_free(sra);
+ sra = sysfs_read(-1, devnum, GET_VERSION);
+ verstr = sra->text_version ? : "-no-metadata-";
+ }
+
+ for (i = 0; st == NULL && superlist[i] ; i++)
+ st = superlist[i]->match_metadata_desc(verstr);
if (sra)
sysfs_free(sra);
- if (st)
+ if (st) {
st->sb = NULL;
+ if (subarray) {
+ strncpy(st->subarray, subarray, 32);
+ st->subarray[31] = 0;
+ free(subarray);
+ } else
+ st->subarray[0] = 0;
+ }
return st;
}
#endif /* !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO) */
-struct supertype *dup_super(struct supertype *st)
+struct supertype *dup_super(struct supertype *orig)
{
- struct supertype *stnew = NULL;
- char *verstr = NULL;
- char version[20];
- int i;
+ struct supertype *st;
+ if (!orig)
+ return orig;
+ st = malloc(sizeof(*st));
if (!st)
return st;
-
- if (st->ss->text_version)
- strcpy(version, st->ss->text_version);
- else if (st->minor_version == -1)
- sprintf(version, "%d", st->ss->major);
- else
- sprintf(version, "%d.%d", st->ss->major, st->minor_version);
- verstr = version;
-
- for (i = 0; stnew == NULL && superlist[i] ; i++)
- stnew = superlist[i]->match_metadata_desc(verstr);
-
- if (stnew)
- stnew->sb = NULL;
- return stnew;
+ memset(st, 0, sizeof(*st));
+ st->ss = orig->ss;
+ st->max_devs = orig->max_devs;
+ st->minor_version = orig->minor_version;
+ strcpy(st->subarray, orig->subarray);
+ st->sb = NULL;
+ st->info = NULL;
+ return st;
}
struct supertype *guess_super(int fd)
int i;
st = malloc(sizeof(*st));
- memset(st, 0, sizeof(*st));
for (i=0 ; superlist[i]; i++) {
int rv;
ss = superlist[i];
- st->ss = NULL;
+ memset(st, 0, sizeof(*st));
rv = ss->load_super(st, fd, NULL);
if (rv == 0) {
struct mdinfo info;
}
if (bestsuper != -1) {
int rv;
- st->ss = NULL;
+ memset(st, 0, sizeof(*st));
rv = superlist[bestsuper]->load_super(st, fd, NULL);
if (rv == 0) {
superlist[bestsuper]->free_super(st);
return dfd;
}
}
+ closedir(dir);
return -1;
}
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 fd2devnum(int fd)
{
struct stat stb;
return -1;
}
+int mdmon_running(int devnum)
+{
+ char path[100];
+ char pid[10];
+ int fd;
+ int n;
+ sprintf(path, "/var/run/mdadm/%s.pid", devnum2devname(devnum));
+ fd = open(path, O_RDONLY, 0);
+
+ if (fd < 0)
+ return 0;
+ n = read(fd, pid, 9);
+ close(fd);
+ if (n <= 0)
+ return 0;
+ if (kill(atoi(pid), 0) == 0)
+ return 1;
+ return 0;
+}
+
+int signal_mdmon(int devnum)
+{
+ char path[100];
+ char pid[10];
+ int fd;
+ int n;
+ sprintf(path, "/var/run/mdadm/%s.pid", devnum2devname(devnum));
+ fd = open(path, O_RDONLY, 0);
+
+ if (fd < 0)
+ return 0;
+ n = read(fd, pid, 9);
+ close(fd);
+ if (n <= 0)
+ return 0;
+ if (kill(atoi(pid), SIGUSR1) == 0)
+ return 1;
+ 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 (env_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",
+ map_dev(dev2major(devnum),
+ dev2minor(devnum),
+ 1), 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 env_no_mdmon(void)
+{
+ char *val = getenv("MDADM_NO_MDMON");
+
+ if (val && atoi(val) == 1)
+ return 1;
+
+ return 0;
+}
+
+
+int flush_metadata_updates(struct supertype *st)
+{
+ int sfd;
+ if (!st->updates) {
+ st->update_tail = NULL;
+ return -1;
+ }
+
+ sfd = connect_monitor(devnum2devname(st->container_dev));
+ if (sfd < 0)
+ return -1;
+
+ while (st->updates) {
+ struct metadata_update *mu = st->updates;
+ st->updates = mu->next;
+
+ send_message(sfd, mu, 0);
+ wait_reply(sfd, 0);
+ free(mu->buf);
+ free(mu);
+ }
+ ack(sfd, 0);
+ wait_reply(sfd, 0);
+ close(sfd);
+ st->update_tail = NULL;
+ return 0;
+}
+
+void append_metadata_update(struct supertype *st, void *buf, int len)
+{
+
+ struct metadata_update *mu = malloc(sizeof(*mu));
+
+ mu->buf = buf;
+ mu->len = len;
+ mu->space = NULL;
+ mu->next = NULL;
+ *st->update_tail = mu;
+ st->update_tail = &mu->next;
+}
+
+
#ifdef __TINYC__
/* tinyc doesn't optimize this check in ioctl.h out ... */
unsigned int __invalid_size_argument_for_IOC = 0;