Whamcloud - gitweb
LU-17000 misc: Fix Unused Value error(0)
[fs/lustre-release.git] / lustre / utils / lsnapshot.c
index 3d79674..00716e9 100644 (file)
@@ -44,6 +44,7 @@
 
 #include <libcfs/util/list.h>
 #include <libcfs/util/ioctl.h>
+#include <libcfs/util/string.h>
 #include <linux/lustre/lustre_ioctl.h>
 #include <linux/lustre/lustre_barrier_user.h>
 
@@ -65,6 +66,7 @@ struct snapshot_target {
        struct list_head         st_list;
        /* Target node name. */
        char                    *st_host;
+       char                    *st_fhost;
        /* Where the pool is */
        char                    *st_dir;
        /* The target pool name on the target node. */
@@ -138,7 +140,8 @@ do {                                                                        \
 #define DZFS "%s zfs"
 #define DIMPORT "%s zpool import -d %s %s > /dev/null 2>&1"
 
-#define PRSH(si, st) (si)->si_rsh, (st)->st_host
+#define PRSH(si, st, foreign) (si)->si_rsh, \
+               foreign ? (st)->st_fhost : (st)->st_host
 #define PFSNAME(st) (st)->st_pool, (st)->st_filesystem
 #define PSSNAME(si, st) PFSNAME(st), (si)->si_ssname
 #define PSS_NEW(si, st) PFSNAME(st), (si)->si_new_ssname
@@ -195,20 +198,19 @@ static int snapshot_load_conf_ldev(struct snapshot_instance *si, char *buf,
 {
        char *label = NULL;
        char *device = NULL;
-       char *ignore = NULL;
        char *ptr;
        char *ptr1;
        int len;
        int rc;
 
        rc = sscanf(buf, "%ms %ms %ms %ms",
-                   &st->st_host, &ignore, &label, &device);
+                   &st->st_host, &st->st_fhost, &label, &device);
        if (rc < 4) {
                rc = -EINVAL;
                goto out;
        }
-
-       free(ignore);
+       if (strcmp(st->st_fhost, "-") == 0)
+               st->st_fhost = NULL;
 
        /* Format of device:
         * [md|zfs:][pool_dir/]<pool>/<filesystem> */
@@ -244,28 +246,20 @@ static int snapshot_load_conf_ldev(struct snapshot_instance *si, char *buf,
        if (*ptr == '/') {
                ptr1 = strrchr(ptr, '/');
                *ptr1 = '\0';
-               len = strlen(ptr);
-               st->st_dir = malloc(len + 1);
+               st->st_dir = strdup(ptr);
                if (!st->st_dir) {
                        rc = -ENOMEM;
                        goto out;
                }
-
-               strncpy(st->st_dir, ptr, len);
-               st->st_dir[len] = '\0';
                ptr = ptr1 + 1;
        }
 
-       len = strlen(ptr);
-       st->st_pool = malloc(len + 1);
+       st->st_pool = strdup(ptr);
        if (!st->st_pool) {
                rc = -ENOMEM;
                goto out;
        }
 
-       strncpy(st->st_pool, ptr, len);
-       st->st_pool[len] = '\0';
-
        /* Format of label:
         * fsname-<role><index> or <role><index> */
        ptr = strrchr(label, '-');
@@ -404,11 +398,15 @@ static int snapshot_load_conf_one(struct snapshot_instance *si,
        if (is_ldev) {
                rc = snapshot_load_conf_ldev(si, buf, st, &role);
        } else {
-               rc = sscanf(buf, "%ms %ms %ms %ms %ms %d",
-                           &st->st_host, &st->st_dir, &st->st_pool,
-                           &st->st_filesystem, &role, &st->st_index);
-               if (rc < 6)
+               rc = sscanf(buf, "%ms %ms %ms %ms %ms %ms %d",
+                           &st->st_host, &st->st_fhost, &st->st_dir,
+                           &st->st_pool, &st->st_filesystem, &role,
+                           &st->st_index);
+               if (rc < 7)
                        rc = -EINVAL;
+
+               if (strcmp(st->st_fhost, "-") == 0)
+                       st->st_fhost = NULL;
        }
 
        if (rc < 0)
@@ -496,6 +494,8 @@ out:
        if (rc) {
                if (st->st_host)
                        free(st->st_host);
+               if (st->st_fhost)
+                       free(st->st_fhost);
                if (st->st_dir)
                        free(st->st_dir);
                if (st->st_pool)
@@ -559,7 +559,7 @@ static int snapshot_load_conf(struct snapshot_instance *si, int lock_mode)
                        "Can't fdopen the snapshot config file %s: %s\n",
                        conf_name, strerror(errno));
                rc = -1;
-               goto out;
+               goto out_fd;
        }
 
        while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
@@ -608,14 +608,18 @@ static int snapshot_load_conf(struct snapshot_instance *si, int lock_mode)
 
 out:
        if (fd >= 0) {
-               if (rc < 0) {
+               if (rc < 0)
                        flock(fd, LOCK_UN);
-                       close(fd);
-               } else {
+               else
                        si->si_conf_fd = fd;
-               }
        }
-
+       /* fclose() closes any associated underlying file descriptor.
+        * explicit close(fd) not required
+        */
+       fclose(fp);
+       return rc;
+out_fd:
+       close(fd);
        return rc;
 }
 
@@ -624,10 +628,11 @@ static void snapshot_unload_conf(struct snapshot_instance *si)
        struct snapshot_target *st;
 
        while (!list_empty(&si->si_mdts_list)) {
-               st = list_entry(si->si_mdts_list.next,
-                               struct snapshot_target, st_list);
+               st = list_first_entry(&si->si_mdts_list,
+                                     struct snapshot_target, st_list);
                list_del(&st->st_list);
                free(st->st_host);
+               free(st->st_fhost);
                free(st->st_dir);
                free(st->st_pool);
                free(st->st_filesystem);
@@ -635,10 +640,11 @@ static void snapshot_unload_conf(struct snapshot_instance *si)
        }
 
        while (!list_empty(&si->si_osts_list)) {
-               st = list_entry(si->si_osts_list.next,
-                               struct snapshot_target, st_list);
+               st = list_first_entry(&si->si_osts_list,
+                                     struct snapshot_target, st_list);
                list_del(&st->st_list);
                free(st->st_host);
+               free(st->st_fhost);
                free(st->st_dir);
                free(st->st_pool);
                free(st->st_filesystem);
@@ -658,21 +664,15 @@ static void snapshot_unload_conf(struct snapshot_instance *si)
 static int snapshot_handle_string_option(char **dst, const char *option,
                                         const char *opt_name)
 {
-       int len;
-
        if (*dst && *dst != snapshot_rsh_default) {
                fprintf(stderr,
                        "%s option has been specified repeatedly.\n", opt_name);
                return -EINVAL;
        }
 
-       len = strlen(option);
-       *dst = malloc(len + 1);
+       *dst = strdup(option);
        if (!*dst)
                return -ENOMEM;
-
-       strncpy(*dst, option, len);
-       (*dst)[len] = '\0';
        return 0;
 }
 
@@ -839,9 +839,11 @@ static int __snapshot_wait(struct snapshot_instance *si,
                rc = waitpid(st->st_pid, &st->st_status, 0);
                if (rc < 0) {
                        SNAPSHOT_ADD_LOG(si, "Can't wait child (%d) operation "
-                                        "on the target <%s:%x:%d>: %s\n",
-                                        st->st_pid, st->st_host, st->st_role,
-                                        st->st_index, strerror(errno));
+                                        "on the target <%s(%s):%x:%d>: %s\n",
+                                        st->st_pid, st->st_host,
+                                        st->st_fhost ? st->st_fhost : "none",
+                                        st->st_role, st->st_index,
+                                        strerror(errno));
                        count++;
                        if (*err == 0)
                                *err = rc;
@@ -865,19 +867,22 @@ static int __snapshot_wait(struct snapshot_instance *si,
                        }
                } else if (WIFSIGNALED(st->st_status)) {
                        SNAPSHOT_ADD_LOG(si, "The child (%d) operation on the "
-                                        "target <%s:%x:%d> was killed by "
+                                        "target <%s(%s):%x:%d> was killed by "
                                         "signal %d\n",
-                                        st->st_pid, st->st_host, st->st_role,
-                                        st->st_index, WTERMSIG(st->st_status));
+                                        st->st_pid, st->st_host,
+                                        st->st_fhost ? st->st_fhost : "none",
+                                        st->st_role, st->st_index,
+                                        WTERMSIG(st->st_status));
                        count++;
                        if (*err == 0)
                                *err = -EINTR;
                } else {
                        SNAPSHOT_ADD_LOG(si, "The child (%d) operation on the "
-                                        "target <%s:%x:%d> failed for "
+                                        "target <%s(%s):%x:%d> failed for "
                                         "unknown reason\n",
-                                        st->st_pid, st->st_host, st->st_role,
-                                        st->st_index);
+                                        st->st_pid, st->st_host,
+                                        st->st_fhost ? st->st_fhost : "none",
+                                        st->st_role, st->st_index);
                        count++;
                        if (*err == 0)
                                *err = -EFAULT;
@@ -922,15 +927,17 @@ static char *snapshot_first_skip_blank(char *buf)
 static int mdt0_is_lustre_snapshot(struct snapshot_instance *si)
 {
        struct snapshot_target *st = si->si_mdt0;
-       char buf[MAX_BUF_SIZE];
+       char buf[MAX_BUF_SIZE * 3];
        FILE *fp;
        int rc;
-
+       int foreign = 0;
+again:
        memset(buf, 0, sizeof(buf));
        snprintf(buf, sizeof(buf) - 1,
                 DRSH" '"DIMPORT"; "DZFS
-                " get -H -o value lustre:magic "DSSNAME"'",
-                PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
+                " get -H -o value lustre:magic "DSSNAME"' 2>/dev/null",
+                PRSH(si, st, foreign), PIMPORT(st), PZFS(st), PSSNAME(si, st));
+
        fp = popen(buf, "r");
        if (!fp) {
                SNAPSHOT_ADD_LOG(si, "Popen fail to check snapshot "
@@ -939,7 +946,13 @@ static int mdt0_is_lustre_snapshot(struct snapshot_instance *si)
        }
 
        if (snapshot_fgets(fp, buf, strlen(SNAPSHOT_MAGIC) + 1) == NULL) {
-               rc = -EINVAL;
+               if (foreign || !st->st_fhost) {
+                       rc = -EINVAL;
+               } else {
+                       foreign = 1;
+                       pclose(fp);
+                       goto again;
+               }
        } else if (strcmp(buf, SNAPSHOT_MAGIC) == 0) {
                rc = 0;
        } else {
@@ -961,11 +974,13 @@ static int target_is_mounted(struct snapshot_instance *si,
        FILE *fp;
        char *ptr;
        int rc = 0;
+       int foreign = 0;
 
+again:
        memset(buf, 0, sizeof(buf));
        snprintf(buf, sizeof(buf) - 1,
-                DRSH" 'mount'",
-                PRSH(si, st));
+                DRSH" 'mount' 2>/dev/null",
+                PRSH(si, st, foreign));
        fp = popen(buf, "r");
        if (!fp) {
                SNAPSHOT_ADD_LOG(si, "Popen fail to check target mount: %s\n",
@@ -1000,6 +1015,10 @@ static int target_is_mounted(struct snapshot_instance *si,
        }
 
        pclose(fp);
+       if (!rc && !foreign && st->st_fhost) {
+               foreign = 1;
+               goto again;
+       }
        return rc;
 }
 
@@ -1007,15 +1026,18 @@ static int snapshot_get_fsname(struct snapshot_instance *si,
                               char *fsname, int fslen)
 {
        struct snapshot_target *st = si->si_mdt0;
-       char buf[MAX_BUF_SIZE];
+       char buf[MAX_BUF_SIZE * 3];
        FILE *fp;
-       int rc = 0;
-
+       int rc;
+       int foreign = 0;
+again:
+       rc = 0;
        memset(buf, 0, sizeof(buf));
        snprintf(buf, sizeof(buf) - 1,
                 DRSH" '"DIMPORT"; "DZFS
-                " get -H -o value lustre:fsname "DSSNAME"'",
-                PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
+                " get -H -o value lustre:fsname "DSSNAME"' 2>/dev/null",
+                PRSH(si, st, foreign), PIMPORT(st), PZFS(st),
+                PSSNAME(si, st));
        fp = popen(buf, "r");
        if (!fp) {
                SNAPSHOT_ADD_LOG(si, "Popen fail to get fsname: %s\n",
@@ -1027,23 +1049,32 @@ static int snapshot_get_fsname(struct snapshot_instance *si,
                rc = -EINVAL;
 
        pclose(fp);
+
+       if (rc && !foreign && st->st_fhost) {
+               foreign = 1;
+               goto again;
+       }
        return rc;
 }
 
 static int snapshot_get_mgsnode(struct snapshot_instance *si,
                                char *node, int size)
 {
-       char buf[MAX_BUF_SIZE];
+       char buf[MAX_BUF_SIZE * 2];
        struct snapshot_target *st;
        FILE *fp;
-       int rc = 0;
+       int rc;
+       int foreign = 0;
 
-       st = list_entry(si->si_osts_list.next, struct snapshot_target,
-                       st_list);
+       st = list_first_entry(&si->si_osts_list, struct snapshot_target,
+                             st_list);
+again:
+       rc = 0;
        memset(buf, 0, sizeof(buf));
        snprintf(buf, sizeof(buf) - 1,
-                DRSH" '"DZFS" get -H -o value lustre:mgsnode "DFSNAME"'",
-                PRSH(si, st), PZFS(st), PFSNAME(st));
+                DRSH" '"DZFS" get -H -o value lustre:mgsnode "DFSNAME"'"
+                " 2>/dev/null", PRSH(si, st, foreign), PZFS(st),
+                PFSNAME(st));
        fp = popen(buf, "r");
        if (!fp) {
                SNAPSHOT_ADD_LOG(si, "Popen fail to get mgsnode: %s\n",
@@ -1055,20 +1086,27 @@ static int snapshot_get_mgsnode(struct snapshot_instance *si,
                rc = -EINVAL;
 
        pclose(fp);
+
+       if (rc && !foreign && st->st_fhost) {
+               foreign = 1;
+               goto again;
+       }
+
        return rc;
 }
 
 static int snapshot_exists_check(struct snapshot_instance *si,
                                 struct snapshot_target *st)
 {
-       char buf[MAX_BUF_SIZE];
+       char buf[MAX_BUF_SIZE * 2];
        FILE *fp;
        int rc = 0;
-
+       int foreign = 0;
+again:
        memset(buf, 0, sizeof(buf));
        snprintf(buf, sizeof(buf) - 1,
-                DRSH" '"DZFS" list "DSSNAME" 2>/dev/null'",
-                PRSH(si, st), PZFS(st), PSSNAME(si, st));
+                DRSH" '"DZFS" list "DSSNAME"' 2>/dev/null",
+                PRSH(si, st, foreign), PZFS(st), PSSNAME(si, st));
        fp = popen(buf, "r");
        if (!fp) {
                SNAPSHOT_ADD_LOG(si, "Popen fail to create check: %s\n",
@@ -1080,6 +1118,11 @@ static int snapshot_exists_check(struct snapshot_instance *si,
                rc = -EEXIST;
 
        pclose(fp);
+
+       if (rc != -EEXIST && !foreign && st->st_fhost) {
+               foreign = 1;
+               goto again;
+       }
        return rc;
 }
 
@@ -1128,18 +1171,19 @@ static int snapshot_inherit_prop(struct snapshot_instance *si,
                                 struct snapshot_target *st,
                                 char *cmd, int size)
 {
-       char buf[MAX_BUF_SIZE];
+       char buf[MAX_BUF_SIZE * 3];
        FILE *fp;
        int len = 0;
        int rc = 0;
-
+       int foreign = 0;
+again:
        memset(buf, 0, sizeof(buf));
        snprintf(buf, sizeof(buf) - 1,
                 DRSH" \""DIMPORT"; "DZFS
                 " get all "DFSNAME" | grep lustre: | grep local$ | "
                 "awk '{ \\$1=\\\"\\\"; \\$NF=\\\"\\\"; print \\$0 }' | "
-                "sed -e 's/^ //'\"",
-                PRSH(si, st), PIMPORT(st), PZFS(st), PFSNAME(st));
+                "sed -e 's/^ //'\" 2>/dev/null",
+                PRSH(si, st, foreign), PIMPORT(st), PZFS(st), PFSNAME(st));
        fp = popen(buf, "r");
        if (!fp) {
                SNAPSHOT_ADD_LOG(si, "Popen fail to list one: %s\n",
@@ -1150,7 +1194,7 @@ static int snapshot_inherit_prop(struct snapshot_instance *si,
        while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
                char *ptr;
                char *end;
-
+               foreign = 1;
                if (strncmp(buf, "lustre:fsname",
                            strlen("lustre:fsname")) == 0)
                        continue;
@@ -1200,15 +1244,21 @@ static int snapshot_inherit_prop(struct snapshot_instance *si,
                if (end)
                        *end = '\0';
 
-               rc = snprintf(cmd + len, size - len - 1,
-                             "-o %s=\"%s\" ", buf, ptr);
-               if (rc <= 0)
+               rc = scnprintf(cmd + len, size - len - 1,
+                              "-o %s=\"%s\" ", buf, ptr);
+               if (rc <= 0) {
+                       pclose(fp);
                        return -EOVERFLOW;
+               }
 
                len += rc;
        }
 
        pclose(fp);
+       if (!foreign && st->st_fhost) {
+               foreign = 1;
+               goto again;
+       }
        return len;
 }
 
@@ -1229,9 +1279,10 @@ static int __snapshot_create(struct snapshot_instance *si,
                if (pid < 0) {
                        SNAPSHOT_ADD_LOG(si, "Can't fork for create snapshot "
                                         "(%s@%s <%s>) on the target "
-                                        "(%s:%x:%d): %s\n",
+                                        "(%s(%s):%x:%d): %s\n",
                                         fsname, si->si_ssname,
                                         si->si_comment, st->st_host,
+                                        st->st_fhost ? st->st_fhost : "none",
                                         st->st_role, st->st_index,
                                         strerror(errno));
                        return pid;
@@ -1241,23 +1292,26 @@ static int __snapshot_create(struct snapshot_instance *si,
                if (pid == 0) {
                        char cmd[MAX_BUF_SIZE];
                        int len;
-
+                       int foreign = 0;
+again:
                        memset(cmd, 0, sizeof(cmd));
-                       len = snprintf(cmd, sizeof(cmd) - 1,
-                                      DRSH" '"DZFS" snapshot "
-                                      "-o lustre:fsname=%s "
-                                      "-o lustre:magic=%s "
-                                      "-o lustre:ctime=%llu "
-                                      "-o lustre:mtime=%llu ",
-                                      PRSH(si, st), PZFS(st), fsname,
-                                      SNAPSHOT_MAGIC, xtime, xtime);
+                       len = scnprintf(cmd, sizeof(cmd) - 1,
+                                       DRSH" '"DZFS" snapshot "
+                                       "-o lustre:fsname=%s "
+                                       "-o lustre:magic=%s "
+                                       "-o lustre:ctime=%llu "
+                                       "-o lustre:mtime=%llu ",
+                                       PRSH(si, st, foreign), PZFS(st),
+                                       fsname, SNAPSHOT_MAGIC,
+                                       (unsigned long long)xtime,
+                                       (unsigned long long)xtime);
                        if (len <= 0)
                                exit(-EOVERFLOW);
 
                        if (si->si_comment) {
-                               rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
-                                             "-o lustre:comment=\"%s\" ",
-                                             si->si_comment);
+                               rc = scnprintf(cmd + len, sizeof(cmd) - len - 1,
+                                              "-o lustre:comment=\"%s\" ",
+                                              si->si_comment);
                                if (rc <= 0)
                                        exit(-EOVERFLOW);
 
@@ -1273,9 +1327,9 @@ static int __snapshot_create(struct snapshot_instance *si,
                        if (rc < 0) {
                                SNAPSHOT_ADD_LOG(si, "Can't filter property on "
                                                 "target (%s:%x:%d): rc = %d\n",
+                                                foreign ? st->st_fhost :
                                                 st->st_host, st->st_role,
                                                 st->st_index, rc);
-
                                exit(rc);
                        }
 
@@ -1283,7 +1337,8 @@ static int __snapshot_create(struct snapshot_instance *si,
                        if (st->st_role & SR_OST)
                                rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
                                              "-o lustre:svname=%s-OST%04x "
-                                             "-o lustre:mgsnode=%s "DSSNAME"'",
+                                             "-o lustre:mgsnode=%s "DSSNAME"'"
+                                             " 2>/dev/null",
                                              fsname, st->st_index, mgsnode,
                                              PSSNAME(si, st));
                        else if (!(st->st_role & SR_MGS) ||
@@ -1291,22 +1346,30 @@ static int __snapshot_create(struct snapshot_instance *si,
                                 si->si_mdt0 == si->si_mgs)
                                rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
                                              "-o lustre:svname=%s-MDT%04x "
-                                             "-o lustre:mgsnode=%s "DSSNAME"'",
+                                             "-o lustre:mgsnode=%s "DSSNAME"'"
+                                             " 2>/dev/null",
                                              fsname, st->st_index, mgsnode,
                                              PSSNAME(si, st));
                        else
                                /* separated MGS */
                                rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
-                                             DSSNAME"'", PSSNAME(si, st));
+                                             DSSNAME"' 2>/dev/null",
+                                             PSSNAME(si, st));
                        if (rc <= 0)
                                exit(-EOVERFLOW);
 
                        rc = snapshot_exec(cmd);
-                       if (rc)
+                       if (rc) {
                                SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
                                                 "target (%s:%x:%d): rc = %d\n",
-                                                cmd, st->st_host, st->st_role,
+                                                cmd, foreign ? st->st_fhost :
+                                                st->st_host, st->st_role,
                                                 st->st_index, rc);
+                               if (!foreign && st->st_fhost) {
+                                       foreign = 1;
+                                       goto again;
+                               }
+                       }
 
                        exit(rc);
                } /* end of child */
@@ -1513,8 +1576,10 @@ again1:
                pid = fork();
                if (pid < 0) {
                        SNAPSHOT_ADD_LOG(si, "Can't fork for check snapshot "
-                                        "%s on the target (%s:%x:%d): %s\n",
+                                        "%s on the target (%s(%s):%x:%d): "
+                                        "%s\n",
                                         si->si_ssname, st->st_host,
+                                        st->st_fhost ? st->st_fhost : "none",
                                         st->st_role, st->st_index,
                                         strerror(errno));
                        return pid;
@@ -1588,8 +1653,10 @@ static int __snapshot_destroy(struct snapshot_instance *si,
                pid = fork();
                if (pid < 0) {
                        SNAPSHOT_ADD_LOG(si, "Can't fork for destroy snapshot "
-                                        "%s on the target (%s:%x:%d): %s\n",
+                                        "%s on the target (%s(%s):%x:%d): "
+                                        "%s\n",
                                         si->si_ssname, st->st_host,
+                                        st->st_fhost ? st->st_fhost : "none",
                                         st->st_role, st->st_index,
                                         strerror(errno));
                        return pid;
@@ -1597,27 +1664,37 @@ static int __snapshot_destroy(struct snapshot_instance *si,
 
                /* child */
                if (pid == 0) {
-                       char cmd[MAX_BUF_SIZE];
-
+                       char cmd[MAX_BUF_SIZE * 2];
+                       int foreign = 0;
+again:
                        memset(cmd, 0, sizeof(cmd));
                        if (si->si_force)
                                snprintf(cmd, sizeof(cmd) - 1,
                                         DRSH" 'umount -f "DSSNAME
                                         " > /dev/null 2>&1; "DZFS
-                                        " destroy -f "DSSNAME"'",
-                                        PRSH(si, st), PSSNAME(si, st),
-                                        PZFS(st), PSSNAME(si, st));
+                                        " destroy -f "DSSNAME"'"
+                                        " 2>/dev/null",
+                                        PRSH(si, st, foreign),
+                                        PSSNAME(si, st), PZFS(st),
+                                        PSSNAME(si, st));
                        else
                                snprintf(cmd, sizeof(cmd) - 1,
-                                        DRSH" '"DZFS" destroy "DSSNAME"'",
-                                        PRSH(si, st), PZFS(st),
+                                        DRSH" '"DZFS" destroy "DSSNAME"'"
+                                        " 2>/dev/null",
+                                        PRSH(si, st, foreign), PZFS(st),
                                         PSSNAME(si, st));
                        rc = snapshot_exec(cmd);
-                       if (rc)
+                       if (rc) {
                                SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
                                                 "target (%s:%x:%d): rc = %d\n",
-                                                cmd, st->st_host, st->st_role,
+                                                cmd, foreign ? st->st_fhost :
+                                                st->st_host, st->st_role,
                                                 st->st_index, rc);
+                               if (!foreign && st->st_fhost) {
+                                       foreign = 1;
+                                       goto again;
+                               }
+                       }
 
                        exit(rc);
                } /* end of child */
@@ -1791,9 +1868,10 @@ static int __snapshot_modify(struct snapshot_instance *si,
                if (pid < 0) {
                        SNAPSHOT_ADD_LOG(si, "Can't fork for modify snapshot "
                                         "(%s|%s, <%s>) on the target "
-                                        "(%s:%x:%d): %s\n",
+                                        "(%s(%s):%x:%d): %s\n",
                                         si->si_ssname, si->si_new_ssname,
                                         si->si_comment, st->st_host,
+                                        st->st_fhost ? st->st_fhost : "none",
                                         st->st_role, st->st_index,
                                         strerror(errno));
                        return pid;
@@ -1801,8 +1879,9 @@ static int __snapshot_modify(struct snapshot_instance *si,
 
                /* child */
                if (pid == 0) {
-                       char cmd[MAX_BUF_SIZE];
-
+                       char cmd[MAX_BUF_SIZE * 5];
+                       int foreign = 0;
+again:
                        memset(cmd, 0, sizeof(cmd));
                        if (si->si_new_ssname && si->si_comment)
                                snprintf(cmd, sizeof(cmd) - 1,
@@ -1810,38 +1889,51 @@ static int __snapshot_modify(struct snapshot_instance *si,
                                         DSSNAME" "DSSNAME" && "DZFS
                                         " set lustre:comment=\"%s\" "DSSNAME
                                         " && "DZFS
-                                        " set lustre:mtime=%llu "DSSNAME"'",
-                                        PRSH(si, st), PIMPORT(st), PZFS(st),
-                                        PSSNAME(si, st), PSS_NEW(si, st),
-                                        PZFS(st), si->si_comment,
-                                        PSS_NEW(si, st), PZFS(st), xtime,
+                                        " set lustre:mtime=%llu "DSSNAME"'"
+                                        " 2>/dev/null",
+                                        PRSH(si, st, foreign), PIMPORT(st),
+                                        PZFS(st), PSSNAME(si, st),
+                                        PSS_NEW(si, st), PZFS(st),
+                                        si->si_comment, PSS_NEW(si, st),
+                                        PZFS(st), (unsigned long long)xtime,
                                         PSS_NEW(si, st));
                        else if (si->si_new_ssname)
                                snprintf(cmd, sizeof(cmd) - 1,
                                         DRSH" '"DIMPORT"; "DZFS
                                         " rename "DSSNAME" "DSSNAME" && "DZFS
-                                        " set lustre:mtime=%llu "DSSNAME"'",
-                                        PRSH(si, st), PIMPORT(st), PZFS(st),
-                                        PSSNAME(si, st), PSS_NEW(si, st),
-                                        PZFS(st), xtime, PSS_NEW(si, st));
+                                        " set lustre:mtime=%llu "DSSNAME"'"
+                                        " 2>/dev/null",
+                                        PRSH(si, st, foreign), PIMPORT(st),
+                                        PZFS(st), PSSNAME(si, st),
+                                        PSS_NEW(si, st), PZFS(st),
+                                        (unsigned long long)xtime,
+                                        PSS_NEW(si, st));
                        else if (si->si_comment)
                                snprintf(cmd, sizeof(cmd) - 1,
                                         DRSH" '"DIMPORT"; "DZFS
                                         " set lustre:comment=\"%s\" "DSSNAME
-                                        " && "DZFS
-                                        " set lustre:mtime=%llu "DSSNAME"'",
-                                        PRSH(si, st), PIMPORT(st), PZFS(st),
-                                        si->si_comment, PSSNAME(si, st),
-                                        PZFS(st), xtime, PSSNAME(si, st));
+                                        " && "DZFS " set lustre:mtime=%llu "
+                                        DSSNAME"' 2>/dev/null",
+                                        PRSH(si, st, foreign), PIMPORT(st),
+                                        PZFS(st), si->si_comment,
+                                        PSSNAME(si, st), PZFS(st),
+                                        (unsigned long long)xtime,
+                                        PSSNAME(si, st));
                        else
                                exit(-EINVAL);
 
                        rc = snapshot_exec(cmd);
-                       if (rc)
+                       if (rc) {
                                SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
                                                 "target (%s:%x:%d): rc = %d\n",
-                                                cmd, st->st_host, st->st_role,
+                                                cmd, foreign ? st->st_fhost :
+                                                st->st_host, st->st_role,
                                                 st->st_index, rc);
+                               if (!foreign && st->st_fhost) {
+                                       foreign = 1;
+                                       goto again;
+                               }
+                       }
 
                        exit(rc);
                } /* end of child */
@@ -1942,17 +2034,20 @@ static void snapshot_list_usage(void)
 static int snapshot_list_one(struct snapshot_instance *si,
                             struct snapshot_target *st)
 {
-       char buf[MAX_BUF_SIZE];
+       char buf[MAX_BUF_SIZE * 3];
        FILE *fp;
        int rc;
+       int foreign = 0;
 
+again:
        memset(buf, 0, sizeof(buf));
        snprintf(buf, sizeof(buf) - 1,
                 DRSH" \""DIMPORT"; "DZFS
                 " get all "DSSNAME" | grep lustre: | grep local$ | "
                 "awk '{ \\$1=\\\"\\\"; \\$NF=\\\"\\\"; print \\$0 }' | "
-                "sed -e 's/^ //'\"",
-                PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
+                "sed -e 's/^ //'\" 2>/dev/null",
+                PRSH(si, st, foreign), PIMPORT(st), PZFS(st),
+                PSSNAME(si, st));
        fp = popen(buf, "r");
        if (!fp) {
                SNAPSHOT_ADD_LOG(si, "Popen fail to list one: %s\n",
@@ -1960,7 +2055,7 @@ static int snapshot_list_one(struct snapshot_instance *si,
                return -errno;
        }
 
-       if (si->si_detail) {
+       if (si->si_detail && !foreign) {
                char name[8];
 
                snapshot_role2name(name, st->st_role, st->st_index);
@@ -1970,6 +2065,7 @@ static int snapshot_list_one(struct snapshot_instance *si,
        while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
                __u64 xtime;
                char *ptr;
+               foreign = 1;
 
                if (strncmp(buf, "lustre:fsname",
                            strlen("lustre:fsname")) == 0) {
@@ -1991,7 +2087,7 @@ static int snapshot_list_one(struct snapshot_instance *si,
                            strlen("lustre:ctime")) == 0) {
                        ptr = snapshot_first_skip_blank(buf);
                        if (ptr) {
-                               sscanf(ptr, "%llu", &xtime);
+                               xtime = (__u64)strtoull(ptr, NULL, 10);
                                printf("create_time: %s",
                                       ctime((time_t *)&xtime));
                        }
@@ -2002,7 +2098,7 @@ static int snapshot_list_one(struct snapshot_instance *si,
                            strlen("lustre:mtime")) == 0) {
                        ptr = snapshot_first_skip_blank(buf);
                        if (ptr) {
-                               sscanf(ptr, "%llu", &xtime);
+                               xtime = (__u64)strtoull(ptr, NULL, 10);
                                printf("modify_time: %s",
                                       ctime((time_t *)&xtime));
                        }
@@ -2011,6 +2107,10 @@ static int snapshot_list_one(struct snapshot_instance *si,
        }
 
        pclose(fp);
+       if (!foreign && st->st_fhost) {
+               foreign = 1;
+               goto again;
+       }
        rc = target_is_mounted(si, st, si->si_ssname);
        if (rc < 0)
                printf("status: unknown\n");
@@ -2074,16 +2174,20 @@ static int snapshot_list_all(struct snapshot_instance *si)
 
        struct list_head list_sub_items;
        struct list_sub_item *lsi;
-       char buf[MAX_BUF_SIZE];
+       char buf[MAX_BUF_SIZE * 2];
        FILE *fp;
        int rc = 0;
+       int foreign = 0;
 
        INIT_LIST_HEAD(&list_sub_items);
+again:
        memset(buf, 0, sizeof(buf));
        snprintf(buf, sizeof(buf) - 1,
                 DRSH" \""DZFS" get -H -r lustre:magic "DFSNAME
-                " | grep %s | awk '{ print \\$1 }' | cut -d@ -f2\"",
-                PRSH(si, st), PZFS(st), PFSNAME(st), SNAPSHOT_MAGIC);
+                " | grep %s | awk '{ print \\$1 }' | cut -d@ -f2\" "
+                " 2>/dev/null",
+                PRSH(si, st, foreign), PZFS(st), PFSNAME(st),
+                SNAPSHOT_MAGIC);
        fp = popen(buf, "r");
        if (!fp) {
                SNAPSHOT_ADD_LOG(si, "Popen fail to list ssnames: %s\n",
@@ -2093,6 +2197,7 @@ static int snapshot_list_all(struct snapshot_instance *si)
 
        while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
                int len = strlen(buf);
+               foreign = 1;
 
                lsi = malloc(len + 1 + sizeof(struct list_sub_item));
                if (!lsi) {
@@ -2101,15 +2206,18 @@ static int snapshot_list_all(struct snapshot_instance *si)
                        break;
                }
 
-               strncpy(lsi->lsi_ssname, buf, len);
-               lsi->lsi_ssname[len] = '\0';
+               memcpy(lsi->lsi_ssname, buf, len + 1);
                list_add(&lsi->lsi_list, &list_sub_items);
        }
 
        pclose(fp);
+       if (!foreign && st->st_fhost) {
+               foreign = 1;
+               goto again;
+       }
        while (!list_empty(&list_sub_items)) {
-               lsi = list_entry(list_sub_items.next,
-                                struct list_sub_item, lsi_list);
+               lsi = list_first_entry(&list_sub_items,
+                                      struct list_sub_item, lsi_list);
                list_del(&lsi->lsi_list);
                if (!rc) {
                        si->si_ssname = lsi->lsi_ssname;
@@ -2198,9 +2306,10 @@ static int snapshot_mount_check(struct snapshot_instance *si, char *fsname,
 static int snapshot_mount_target(struct snapshot_instance *si,
                                 struct snapshot_target *st, const char *optstr)
 {
-       char cmd[MAX_BUF_SIZE];
+       char cmd[MAX_BUF_SIZE * 2];
        char name[8];
        int rc;
+       int foreign = 0;
 
        rc = target_is_mounted(si, st, si->si_ssname);
        if (rc < 0)
@@ -2209,20 +2318,27 @@ static int snapshot_mount_target(struct snapshot_instance *si,
        if (rc > 0)
                return -ESRCH;
 
-       memset(cmd, 0, sizeof(cmd));
        memset(name, 0, sizeof(name));
        snapshot_role2name(name, st->st_role, st->st_index);
+again:
+       memset(cmd, 0, sizeof(cmd));
        snprintf(cmd, sizeof(cmd) - 1,
                 DRSH" '"DIMPORT"; mkdir -p /mnt/%s_%s && mount -t lustre "
-                "-o rdonly_dev%s "DSSNAME" /mnt/%s_%s'",
-                PRSH(si, st), PIMPORT(st), si->si_ssname, name,
+                "-o rdonly_dev%s "DSSNAME" /mnt/%s_%s' 2>/dev/null",
+                PRSH(si, st, foreign), PIMPORT(st), si->si_ssname, name,
                 st != si->si_mdt0 ? "" : optstr, PSSNAME(si, st),
                 si->si_ssname, name);
        rc = snapshot_exec(cmd);
-       if (rc)
+       if (rc) {
                SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on the target "
-                                "(%s:%x:%d): rc = %d\n", cmd, st->st_host,
+                                "(%s:%x:%d): rc = %d\n",
+                                cmd, foreign ? st->st_fhost : st->st_host,
                                 st->st_role, st->st_index, rc);
+               if (!foreign && st->st_fhost) {
+                       foreign = 1;
+                       goto again;
+               }
+       }
 
        return rc;
 }
@@ -2245,8 +2361,9 @@ static int __snapshot_mount(struct snapshot_instance *si,
                pid = fork();
                if (pid < 0) {
                        SNAPSHOT_ADD_LOG(si, "Can't fork for mount snapshot "
-                                        "%s on target (%s:%x:%d): %s\n",
+                                        "%s on target (%s(%s):%x:%d): %s\n",
                                         si->si_ssname, st->st_host,
+                                        st->st_fhost ? st->st_fhost : "none",
                                         st->st_role, st->st_index,
                                         strerror(errno));
                        return pid;
@@ -2306,6 +2423,8 @@ static int snapshot_mount(struct snapshot_instance *si)
 
                if (si->si_mgs == si->si_mdt0)
                        mdt0_mounted = true;
+       } else {
+               si->si_mgs->st_ignored = 1;
        }
 
        /* 2. Mount MDT0 if it is not combined with the MGS. */
@@ -2313,6 +2432,10 @@ static int snapshot_mount(struct snapshot_instance *si)
                si->si_mdt0->st_ignored = 0;
                si->si_mdt0->st_pid = 0;
                rc = snapshot_mount_target(si, si->si_mdt0, ",nomgs");
+               if (rc == -ESRCH) {
+                       si->si_mdt0->st_ignored = 1;
+                       rc = 0;
+               }
                if (rc)
                        goto cleanup;
        }
@@ -2438,8 +2561,9 @@ static int __snapshot_umount(struct snapshot_instance *si,
                pid = fork();
                if (pid < 0) {
                        SNAPSHOT_ADD_LOG(si, "Can't fork for umount snapshot "
-                                        "%s on target (%s:%x:%d): %s\n",
+                                        "%s on target (%s(%s):%x:%d): %s\n",
                                         si->si_ssname, st->st_host,
+                                        st->st_fhost ? st->st_fhost : "none",
                                         st->st_role, st->st_index,
                                         strerror(errno));
                        return pid;
@@ -2448,6 +2572,7 @@ static int __snapshot_umount(struct snapshot_instance *si,
                /* child */
                if (pid == 0) {
                        char cmd[MAX_BUF_SIZE];
+                       int foreign = 0;
 
                        rc = target_is_mounted(si, st, si->si_ssname);
                        if (rc < 0)
@@ -2455,12 +2580,16 @@ static int __snapshot_umount(struct snapshot_instance *si,
 
                        if (!rc)
                                exit(-ESRCH);
-
+again:
                        memset(cmd, 0, sizeof(cmd));
                        snprintf(cmd, sizeof(cmd) - 1,
-                                DRSH" 'umount "DSSNAME"'",
-                                PRSH(si, st), PSSNAME(si, st));
+                                DRSH" 'umount "DSSNAME"' 2>/dev/null",
+                                PRSH(si, st, foreign), PSSNAME(si, st));
                        rc = snapshot_exec(cmd);
+                       if (rc && !foreign && st->st_fhost) {
+                               foreign = 1;
+                               goto again;
+                       }
 
                        exit(rc);
                }