]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - msg.c
Create.c: fix uclibc build
[thirdparty/mdadm.git] / msg.c
diff --git a/msg.c b/msg.c
index bfeadb34f34d46f8d3d0ac037edeb345a26edcc9..ba0e25be906d5b80de7a9f55ffd504e23accc876 100644 (file)
--- a/msg.c
+++ b/msg.c
@@ -1,7 +1,7 @@
 /*
  * 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,
@@ -78,7 +78,6 @@ static int recv_buf(int fd, void* buf, int len, int tmo)
        return 0;
 }
 
-
 int send_message(int fd, struct metadata_update *msg, int tmo)
 {
        __s32 len = msg->len;
@@ -106,9 +105,7 @@ int receive_message(int fd, struct metadata_update *msg, int tmo)
        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);
@@ -173,7 +170,7 @@ int connect_monitor(char *devname)
 
        addr.sun_family = PF_LOCAL;
        strcpy(addr.sun_path, path);
-       if (connect(sfd, &addr, sizeof(addr)) < 0) {
+       if (connect(sfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
                close(sfd);
                return -1;
        }
@@ -207,9 +204,14 @@ int fping_monitor(int sfd)
 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;
 }
 
@@ -235,7 +237,7 @@ static char *ping_monitor_version(char *devname)
        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;
@@ -255,26 +257,27 @@ static int unblock_subarray(struct mdinfo *sra, const int unfreeze)
        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
@@ -289,17 +292,47 @@ int block_monitor(char *container, const int freeze)
                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[SYSFS_MAX_BUF_SIZE];
+       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;
        }
 
@@ -308,11 +341,10 @@ int block_monitor(char *container, const int freeze)
                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 */
@@ -325,9 +357,7 @@ int block_monitor(char *container, const int freeze)
                 * 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);
 
@@ -336,15 +366,26 @@ int block_monitor(char *container, const int freeze)
                     !sysfs_attribute_available(sra, NULL, "sync_action")) ||
                    (freeze &&
                     sysfs_attribute_available(sra, NULL, "sync_action") &&
-                    sysfs_get_str(sra, NULL, "sync_action", buf, 20) > 0 &&
+                    sysfs_get_str(sra, NULL, "sync_action", buf, sizeof(buf)) > 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 */
@@ -352,9 +393,9 @@ int block_monitor(char *container, const int freeze)
                        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->devnm);
                }
 
                ping_monitor(container); /* cleared frozen */
@@ -363,7 +404,6 @@ int block_monitor(char *container, const int freeze)
 
        sysfs_free(sra);
        free_mdstat(ent);
-       free(container);
 
        return rv;
 }
@@ -372,11 +412,11 @@ void unblock_monitor(char *container, const int unfreeze)
 {
        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;
        }
 
@@ -385,18 +425,21 @@ void unblock_monitor(char *container, const int unfreeze)
                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->devnm);
        }
-       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
@@ -420,3 +463,13 @@ int ping_manager(char *devname)
        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);
+}