/*
* Copyright (C) 2008 Intel Corporation
*
- * mdmon socket / message handling
+ * mdmon socket / message handling
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
return 0;
}
-
int send_message(int fd, struct metadata_update *msg, int tmo)
{
__s32 len = msg->len;
if (rv < 0 || len > MSG_MAX_LEN)
return -1;
if (len > 0) {
- msg->buf = malloc(len);
- if (msg->buf == NULL)
- return -1;
+ msg->buf = xmalloc(len);
rv = recv_buf(fd, msg->buf, len, tmo);
if (rv < 0) {
free(msg->buf);
int ping_monitor(char *devname)
{
int sfd = connect_monitor(devname);
- int err = fping_monitor(sfd);
+ int err;
+
+ if (sfd >= 0) {
+ err = fping_monitor(sfd);
+ close(sfd);
+ } else
+ err = -1;
- close(sfd);
return err;
}
return msg.buf;
}
-static int unblock_subarray(struct mdinfo *sra, const int unfreeze)
+int unblock_subarray(struct mdinfo *sra, const int unfreeze)
{
char buf[64];
int rc = 0;
return rc;
}
-/**
- * block_monitor - prevent mdmon spare assignment
- * @container - container to block
- * @freeze - flag to additionally freeze sync_action
- *
- * This is used by the reshape code to freeze the container, and the
- * auto-rebuild implementation to atomically move spares. For reshape
- * we need to freeze sync_action in the auto-rebuild we only need to
- * block new spare assignment, existing rebuilds can continue
+int block_subarray(struct mdinfo *sra)
+{
+ char buf[64];
+ int rc = 0;
+
+ sprintf(buf, "external:%s\n", sra->text_version);
+ buf[9] = '-';
+ if (sysfs_set_str(sra, NULL, "metadata_version", buf))
+ rc = -1;
+
+ return rc;
+}
+
+/* check mdmon version if it supports
+ * array blocking mechanism
*/
-int block_monitor(char *container, const int freeze)
+int check_mdmon_version(char *container)
{
- int devnum = devname2devnum(container);
- struct mdstat_ent *ent, *e, *e2;
- struct mdinfo *sra = NULL;
char *version = NULL;
- char buf[64];
- int rv = 0;
- if (!mdmon_running(devnum)) {
+ if (!mdmon_running(container)) {
/* if mdmon is not active we assume that any instance that is
* later started will match the current mdadm version, if this
* assumption is violated we may inadvertantly rebuild an array
ver = version ? mdadm_version(version) : -1;
free(version);
if (ver < 3002000) {
- fprintf(stderr, Name
- ": mdmon instance for %s cannot be disabled\n",
- container);
+ pr_err("mdmon instance for %s cannot be disabled\n",
+ container);
return -1;
}
}
+ return 0;
+}
+
+/**
+ * block_monitor - prevent mdmon spare assignment
+ * @container - container to block
+ * @freeze - flag to additionally freeze sync_action
+ *
+ * This is used by the reshape code to freeze the container, and the
+ * auto-rebuild implementation to atomically move spares.
+ * In both cases we need to stop mdmon from assigning spares to replace
+ * failed devices as we might have other plans for the spare.
+ * For the reshape case we also need to 'freeze' sync_action so that
+ * no recovery happens until we have fully prepared for the reshape.
+ *
+ * We tell mdmon that the array is frozen by marking the 'metadata' name
+ * with a leading '-'. The previously told mdmon "Don't make this array
+ * read/write, leave it readonly". Now it means a more general "Don't
+ * reconfigure this array at all".
+ * As older versions of mdmon (which might run from initrd) don't understand
+ * this, we first check that the running mdmon is new enough.
+ */
+int block_monitor(char *container, const int freeze)
+{
+ struct mdstat_ent *ent, *e, *e2;
+ struct mdinfo *sra = NULL;
+ char buf[64];
+ int rv = 0;
+
+ if (check_mdmon_version(container))
+ return -1;
+
ent = mdstat_read(0, 0);
if (!ent) {
- fprintf(stderr, Name
- ": failed to read /proc/mdstat while disabling mdmon\n");
+ pr_err("failed to read /proc/mdstat while disabling mdmon\n");
return -1;
}
if (!is_container_member(e, container))
continue;
sysfs_free(sra);
- sra = sysfs_read(-1, e->devnum, GET_VERSION);
+ sra = sysfs_read(-1, e->devnm, GET_VERSION);
if (!sra) {
- fprintf(stderr, Name
- ": failed to read sysfs for subarray%s\n",
- to_subarray(e, container));
+ pr_err("failed to read sysfs for subarray%s\n",
+ to_subarray(e, container));
break;
}
/* can't reshape an array that we can't monitor */
* takeover in reshape case and spare reassignment in the
* auto-rebuild case)
*/
- sprintf(buf, "external:%s\n", sra->text_version);
- buf[9] = '-';
- if (sysfs_set_str(sra, NULL, "metadata_version", buf))
+ if (block_subarray(sra))
break;
ping_monitor(container);
sysfs_get_str(sra, NULL, "sync_action", buf, 20) > 0 &&
strcmp(buf, "frozen\n") == 0))
/* pass */;
- else
+ else {
+ unblock_subarray(sra, 0);
+ break;
+ }
+ /* Double check against races - there should be no spares
+ * or part-spares
+ */
+ sysfs_free(sra);
+ sra = sysfs_read(-1, e->devnm, GET_DEVS | GET_STATE);
+ if (sra && sra->array.spare_disks > 0) {
+ unblock_subarray(sra, freeze);
break;
+ }
}
if (e) {
- fprintf(stderr, Name ": failed to freeze subarray%s\n",
+ pr_err("failed to freeze subarray%s\n",
to_subarray(e, container));
/* thaw the partially frozen container */
if (!is_container_member(e2, container))
continue;
sysfs_free(sra);
- sra = sysfs_read(-1, e2->devnum, GET_VERSION);
+ sra = sysfs_read(-1, e2->devnm, GET_VERSION);
if (unblock_subarray(sra, freeze))
- fprintf(stderr, Name ": Failed to unfreeze %s\n", e2->dev);
+ pr_err("Failed to unfreeze %s\n", e2->dev);
}
ping_monitor(container); /* cleared frozen */
sysfs_free(sra);
free_mdstat(ent);
- free(container);
return rv;
}
{
struct mdstat_ent *ent, *e;
struct mdinfo *sra = NULL;
+ int to_ping = 0;
ent = mdstat_read(0, 0);
if (!ent) {
- fprintf(stderr, Name
- ": failed to read /proc/mdstat while unblocking container\n");
+ pr_err("failed to read /proc/mdstat while unblocking container\n");
return;
}
if (!is_container_member(e, container))
continue;
sysfs_free(sra);
- sra = sysfs_read(-1, e->devnum, GET_VERSION);
+ sra = sysfs_read(-1, e->devnm, GET_VERSION|GET_LEVEL);
+ if (!sra)
+ continue;
+ if (sra->array.level > 0)
+ to_ping++;
if (unblock_subarray(sra, unfreeze))
- fprintf(stderr, Name ": Failed to unfreeze %s\n", e->dev);
+ pr_err("Failed to unfreeze %s\n", e->dev);
}
- ping_monitor(container);
+ if (to_ping)
+ ping_monitor(container);
sysfs_free(sra);
free_mdstat(ent);
}
-
-
/* give the manager a chance to view the updated container state. This
* would naturally happen due to the manager noticing a change in
* /proc/mdstat; however, pinging encourages this detection to happen
close(sfd);
return err;
}
+
+/* using takeover operation for grow purposes, mdadm has to be sure
+ * that mdmon processes all updates, and if necessary it will be closed
+ * at takeover to raid0 operation
+ */
+void flush_mdmon(char *container)
+{
+ ping_manager(container);
+ ping_monitor(container);
+}