4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License version 2 for more details. A copy is
14 * included in the COPYING file that accompanied this code.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * Copyright (c) 2017, Intel Corporation.
25 * lustre/utils/lsnapshot.c
27 * Author: Fan, Yong <fan.yong@intel.com>
37 #include <sys/types.h>
45 #include <libcfs/util/list.h>
46 #include <libcfs/util/ioctl.h>
47 #include <libcfs/util/string.h>
48 #include <linux/lustre/lustre_ioctl.h>
49 #include <linux/lustre/lustre_barrier_user.h>
53 #define SNAPSHOT_CONF_DIR "/etc/lsnapshot"
54 #define LDEV_CONF "/etc/ldev.conf"
55 #define SNAPSHOT_LOG "/var/log/lsnapshot.log"
56 #define SNAPSHOT_MAGIC "0x14F711B9"
57 #define MAX_BUF_SIZE 4096
65 struct snapshot_target {
66 struct list_head st_list;
67 /* Target node name. */
69 /* Where the pool is */
71 /* The target pool name on the target node. */
73 /* The backend filesystem name against the target pool. */
76 unsigned int st_index;
84 struct snapshot_instance {
85 struct list_head si_mdts_list;
86 struct list_head si_osts_list;
87 struct snapshot_target *si_mgs;
88 struct snapshot_target *si_mdt0;
102 static const char snapshot_rsh_default[] = "ssh";
103 static char snapshot_path[MAX_BUF_SIZE];
105 static char *snapshot_role2name(char *name, enum snapshot_role role,
109 snprintf(name, 8, "MDT%04x", index);
110 else if (role & SR_MGS)
111 snprintf(name, 4, "MGS");
113 snprintf(name, 8, "OST%04x", index);
118 #define SNAPSHOT_ADD_LOG(si, format, ...) \
120 char buf[MAX_BUF_SIZE]; \
124 memset(buf, 0, sizeof(buf)); \
126 snprintf(buf, sizeof(buf) - 1, "%s", ctime(&tt)); \
127 ptr = strrchr(buf, '\n'); \
131 fprintf(si->si_log_fp, "%s (%d:%s:%d:%s:%s): "format, buf, \
132 getpid(), __func__, __LINE__, si->si_fsname, \
133 si->si_rsh, ## __VA_ARGS__); \
137 #define DFSNAME "%s/%s"
138 #define DSSNAME "%s/%s@%s"
139 #define DZFS "%s zfs"
140 #define DIMPORT "%s zpool import -d %s %s > /dev/null 2>&1"
142 #define PRSH(si, st) (si)->si_rsh, (st)->st_host
143 #define PFSNAME(st) (st)->st_pool, (st)->st_filesystem
144 #define PSSNAME(si, st) PFSNAME(st), (si)->si_ssname
145 #define PSS_NEW(si, st) PFSNAME(st), (si)->si_new_ssname
146 #define PZFS(st) snapshot_path
147 #define PIMPORT(st) snapshot_path, \
148 (st)->st_dir ? (st)->st_dir : "/dev -d /tmp", (st)->st_pool
150 char *snapshot_fgets(FILE *fp, char *buf, int buflen)
154 memset(buf, 0, buflen);
155 if (fgets(buf, buflen, fp) == NULL)
158 ptr = strchr(buf, '\n');
165 static int snapshot_exec(const char *cmd)
171 /* system() return value depends on both the system() general framework,
172 * such as whether fork()/exec() success or fail, and the real @cmd exec
173 * result. Especially, if the @cmd is remote command, we may cannot know
174 * the real failure. */
176 /* fork()/exec() error */
178 return errno != 0 ? -errno : -1;
181 rc = WEXITSTATUS(rc);
184 } else if (WIFSIGNALED(rc)) {
187 /* all other known or unknown cases. */
194 static int snapshot_load_conf_ldev(struct snapshot_instance *si, char *buf,
195 struct snapshot_target *st, char **role)
205 rc = sscanf(buf, "%ms %ms %ms %ms",
206 &st->st_host, &ignore, &label, &device);
215 * [md|zfs:][pool_dir/]<pool>/<filesystem> */
216 ptr = strchr(device, ':');
219 if (strncmp(device, "zfs:", strlen("zfs:")) != 0) {
227 ptr1 = strrchr(ptr, '/');
228 /* "ptr1 - ptr + 1 == strlen(ptr)" means '/' is at the tail. */
229 if (!ptr1 || ptr1 == ptr || ptr1 - ptr + 1 == strlen(ptr)) {
235 st->st_filesystem = malloc(len);
236 if (!st->st_filesystem) {
242 strncpy(st->st_filesystem, ptr1 + 1, len - 1);
243 st->st_filesystem[len - 1] = '\0';
246 ptr1 = strrchr(ptr, '/');
248 st->st_dir = strdup(ptr);
256 st->st_pool = strdup(ptr);
263 * fsname-<role><index> or <role><index> */
264 ptr = strrchr(label, '-');
266 if (strncmp(si->si_fsname, label, ptr - label) != 0) {
267 /* This line is NOT for current filesystem .*/
277 if (strlen(ptr) < 3 || strlen(ptr) > 7) {
288 strncpy(*role, ptr, 3);
292 while (isxdigit(ptr[len])) {
293 if (isdigit(ptr[len]))
295 st->st_index * 16 + ptr[len] - '0';
296 else if (isupper(ptr[len]))
298 st->st_index * 16 + ptr[len] - 'A' + 10;
301 st->st_index * 16 + ptr[len] - 'a' + 10;
306 if (strncasecmp(*role, "MGS", 3) != 0)
314 if (!isxdigit(ptr[len]) && ptr[len] != '\0') {
329 * For old snasphot tools, the configration is in /etc/lsnapshot/${fsname}.conf,
331 * <host> <pool_dir> <pool> <local_fsname> <role(,s)> <index>
335 * host-mdt1 /tmp myfs-mdt1 mdt1 MGS,MDT 0
336 * host-mdt2 /tmp myfs-mdt2 mdt2 MDT 1
337 * host-ost1 /tmp myfs-ost1 ost1 OST 0
338 * host-ost2 /tmp myfs-ost2 ost2 OST 1
341 * For new snasphot tools, the configration is in /etc/ldev.conf, which is not
342 * only for snapshot, but also for other purpose. The format is:
343 * <host> foreign/- <label> <device> [journal-path]/- [raidtab]
345 * The format of <label> is:
346 * fsname-<role><index> or <role><index>
348 * The format of <device> is:
349 * [md|zfs:][pool_dir/]<pool>/<filesystem>
351 * Snapshot only uses the fields <host>, <label> and <device>.
355 * host-mdt1 - myfs-MDT0000 zfs:/tmp/myfs-mdt1/mdt1
358 * \retval 0 for success
359 * \retval +ve the line# with which the current line is conflict
360 * \retval -EAGAIN skip current line
361 * \retval -ve other failures
363 static int snapshot_load_conf_one(struct snapshot_instance *si,
364 char *buf, int line_num, bool is_ldev)
366 struct snapshot_target *st;
371 path = getenv("PATH");
375 memset(snapshot_path, 0, sizeof(snapshot_path));
376 snprintf(snapshot_path, sizeof(snapshot_path) - 1, "PATH='%s'", path);
378 /* filter out space */
379 while (isspace(*buf))
382 /* skip empty line */
386 /* skip comment line */
390 st = malloc(sizeof(*st));
394 memset(st, 0, sizeof(*st));
395 INIT_LIST_HEAD(&st->st_list);
398 rc = snapshot_load_conf_ldev(si, buf, st, &role);
400 rc = sscanf(buf, "%ms %ms %ms %ms %ms %d",
401 &st->st_host, &st->st_dir, &st->st_pool,
402 &st->st_filesystem, &role, &st->st_index);
411 if (strncasecmp(role, "MGS", 3) == 0) {
412 st->st_role = SR_MGS;
413 if (role[3] == ',') {
415 if (strncasecmp(&role[4], "MDT", 3) != 0) {
420 st->st_role |= SR_MDT;
422 } else if (strncasecmp(role, "MDT", 3) == 0) {
423 st->st_role = SR_MDT;
424 if (role[3] == ',') {
426 if (strncasecmp(&role[4], "MGS", 3) != 0) {
431 st->st_role |= SR_MGS;
433 } else if (strncasecmp(role, "OST", 3) == 0) {
434 st->st_role = SR_OST;
440 st->st_line = line_num;
441 if (st->st_role & SR_MDT) {
442 /* MGS is the first, MDT0 is just after the MGS
443 * if they are not combined together. */
444 if (st->st_role & SR_MGS) {
446 rc = si->si_mgs->st_line;
451 list_add(&st->st_list, &si->si_mdts_list);
454 if (st->st_index == 0) {
456 rc = si->si_mdt0->st_line;
461 if (list_empty(&st->st_list)) {
462 if (list_empty(&si->si_mdts_list) ||
464 list_add(&st->st_list,
467 list_add(&st->st_list,
468 &si->si_mgs->st_list);
470 } else if (list_empty(&st->st_list)) {
471 list_add_tail(&st->st_list, &si->si_mdts_list);
473 } else if (st->st_role & SR_MGS) {
475 rc = si->si_mgs->st_line;
480 list_add(&st->st_list, &si->si_mdts_list);
482 list_add_tail(&st->st_list, &si->si_osts_list);
496 if (st->st_filesystem)
497 free(st->st_filesystem);
504 static int snapshot_load_conf(struct snapshot_instance *si, int lock_mode)
507 char buf[MAX_BUF_SIZE];
514 memset(conf_name, 0, sizeof(conf_name));
515 strncpy(conf_name, LDEV_CONF, sizeof(conf_name) - 1);
516 fd = open(conf_name, O_RDONLY);
518 if (errno != ENOENT) {
520 "Can't open the snapshot config file %s: %s\n",
521 conf_name, strerror(errno));
526 snprintf(conf_name, sizeof(conf_name) - 1, "%s/%s.conf",
527 SNAPSHOT_CONF_DIR, si->si_fsname);
528 fd = open(conf_name, O_RDONLY);
531 "Can't open the snapshot config file %s: %s\n",
532 conf_name, strerror(errno));
540 rc = flock(fd, lock_mode | LOCK_NB);
543 "Can't lock the snapshot config file %s (%d): %s\n",
544 conf_name, lock_mode, strerror(errno));
549 fp = fdopen(fd, "r");
552 "Can't fdopen the snapshot config file %s: %s\n",
553 conf_name, strerror(errno));
558 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
559 rc = snapshot_load_conf_one(si, buf, line_num, is_ldev);
562 "Invalid snapshot config file %s at the line "
563 "%d '%s'\n", conf_name, line_num, buf);
564 } else if (rc == -EAGAIN) {
568 "The config role has been specified repeatedly "
569 "at the lines %d/%d in %s\n",
570 rc, line_num, conf_name);
582 "Miss MDT0 in the config file %s\n",
588 /* By default, the MGS is on the MDT0 if it is not specified. */
590 si->si_mgs = si->si_mdt0;
591 si->si_mgs->st_role |= SR_MGS;
594 if (list_empty(&si->si_osts_list)) {
596 "Miss OST(s) in the config file %s\n",
615 static void snapshot_unload_conf(struct snapshot_instance *si)
617 struct snapshot_target *st;
619 while (!list_empty(&si->si_mdts_list)) {
620 st = list_entry(si->si_mdts_list.next,
621 struct snapshot_target, st_list);
622 list_del(&st->st_list);
626 free(st->st_filesystem);
630 while (!list_empty(&si->si_osts_list)) {
631 st = list_entry(si->si_osts_list.next,
632 struct snapshot_target, st_list);
633 list_del(&st->st_list);
637 free(st->st_filesystem);
644 if (si->si_conf_fd >= 0) {
645 flock(si->si_conf_fd, LOCK_UN);
646 close(si->si_conf_fd);
651 static int snapshot_handle_string_option(char **dst, const char *option,
652 const char *opt_name)
654 if (*dst && *dst != snapshot_rsh_default) {
656 "%s option has been specified repeatedly.\n", opt_name);
660 *dst = strdup(option);
666 static void snapshot_fini(struct snapshot_instance *si)
668 snapshot_unload_conf(si);
671 fclose(si->si_log_fp);
673 if (si->si_rsh && si->si_rsh != snapshot_rsh_default)
679 if (si->si_new_ssname)
680 free(si->si_new_ssname);
682 free(si->si_comment);
687 static struct snapshot_instance *
688 snapshot_init(int argc, char * const argv[], const struct option *longopts,
689 const char *optstring, void (*usage)(void),
690 int lock_mode, int *err)
692 struct snapshot_instance *si;
697 si = malloc(sizeof(*si));
700 "No enough memory to initialize snapshot instance.\n");
705 memset(si, 0, sizeof(*si));
706 INIT_LIST_HEAD(&si->si_mdts_list);
707 INIT_LIST_HEAD(&si->si_osts_list);
708 si->si_rsh = (char *)snapshot_rsh_default;
710 si->si_timeout = BARRIER_TIMEOUT_DEFAULT;
711 si->si_barrier = true;
712 si->si_detail = false;
713 si->si_force = false;
715 while ((opt = getopt_long(argc, argv, optstring,
716 longopts, &idx)) != EOF) {
719 if (!optarg || strcmp(optarg, "on") == 0) {
720 si->si_barrier = true;
721 } else if (strcmp(optarg, "off") == 0) {
722 si->si_barrier = false;
730 *err = snapshot_handle_string_option(&si->si_comment,
736 si->si_detail = true;
742 *err = snapshot_handle_string_option(&si->si_fsname,
748 *err = snapshot_handle_string_option(&si->si_ssname,
754 *err = snapshot_handle_string_option(&si->si_new_ssname,
761 *err = snapshot_handle_string_option(&si->si_rsh,
768 si->si_timeout = atoi(optarg);
782 if (!si->si_fsname) {
783 fprintf(stderr, "The fsname must be specified\n");
789 if (strlen(si->si_fsname) > 8) {
790 fprintf(stderr, "Invalid fsname %s\n", si->si_fsname);
795 si->si_log_fp = fopen(SNAPSHOT_LOG, "a");
796 if (!si->si_log_fp) {
799 "Can't open the snapshot log file %s: %s\n",
800 SNAPSHOT_LOG, strerror(errno));
804 *err = snapshot_load_conf(si, lock_mode);
807 if (*err != 0 && si) {
815 static int __snapshot_wait(struct snapshot_instance *si,
816 struct list_head *head, int *err)
818 struct snapshot_target *st;
822 list_for_each_entry(st, head, st_list) {
826 rc = waitpid(st->st_pid, &st->st_status, 0);
828 SNAPSHOT_ADD_LOG(si, "Can't wait child (%d) operation "
829 "on the target <%s:%x:%d>: %s\n",
830 st->st_pid, st->st_host, st->st_role,
831 st->st_index, strerror(errno));
837 /* continue to wait for next */
841 if (WIFEXITED(st->st_status)) {
842 rc = WEXITSTATUS(st->st_status);
847 st->st_ignored = true;
853 } else if (WIFSIGNALED(st->st_status)) {
854 SNAPSHOT_ADD_LOG(si, "The child (%d) operation on the "
855 "target <%s:%x:%d> was killed by "
857 st->st_pid, st->st_host, st->st_role,
858 st->st_index, WTERMSIG(st->st_status));
863 SNAPSHOT_ADD_LOG(si, "The child (%d) operation on the "
864 "target <%s:%x:%d> failed for "
866 st->st_pid, st->st_host, st->st_role,
879 static int snapshot_wait(struct snapshot_instance *si, int *err)
883 count = __snapshot_wait(si, &si->si_mdts_list, err);
884 count += __snapshot_wait(si, &si->si_osts_list, err);
889 static char *snapshot_first_skip_blank(char *buf)
893 ptr = strchr(buf, ' ');
895 ptr = strchr(buf, '\t');
900 while (*ptr == ' ' || *ptr == '\t')
909 static int mdt0_is_lustre_snapshot(struct snapshot_instance *si)
911 struct snapshot_target *st = si->si_mdt0;
912 char buf[MAX_BUF_SIZE * 3];
916 memset(buf, 0, sizeof(buf));
917 snprintf(buf, sizeof(buf) - 1,
918 DRSH" '"DIMPORT"; "DZFS
919 " get -H -o value lustre:magic "DSSNAME"'",
920 PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
921 fp = popen(buf, "r");
923 SNAPSHOT_ADD_LOG(si, "Popen fail to check snapshot "
924 "on mdt0: %s\n", strerror(errno));
928 if (snapshot_fgets(fp, buf, strlen(SNAPSHOT_MAGIC) + 1) == NULL) {
930 } else if (strcmp(buf, SNAPSHOT_MAGIC) == 0) {
934 "The target %s is not Lustre snapshot "
935 "or it does not exists\n", si->si_ssname);
943 static int target_is_mounted(struct snapshot_instance *si,
944 struct snapshot_target *st, const char *ssname)
946 char buf[MAX_BUF_SIZE];
947 char fullname[MAX_BUF_SIZE];
952 memset(buf, 0, sizeof(buf));
953 snprintf(buf, sizeof(buf) - 1,
956 fp = popen(buf, "r");
958 SNAPSHOT_ADD_LOG(si, "Popen fail to check target mount: %s\n",
963 memset(fullname, 0, sizeof(fullname));
965 snprintf(fullname, sizeof(fullname) - 1,
967 PFSNAME(st), ssname);
969 snprintf(fullname, sizeof(fullname) - 1,
973 while (snapshot_fgets(fp, buf, sizeof(buf)) != NULL) {
974 ptr = strstr(buf, fullname);
978 ptr += strlen(fullname) + 1; /* mount point */
979 if (ptr >= buf + strlen(buf))
982 ptr = strstr(ptr, "type lustre");
993 static int snapshot_get_fsname(struct snapshot_instance *si,
994 char *fsname, int fslen)
996 struct snapshot_target *st = si->si_mdt0;
997 char buf[MAX_BUF_SIZE * 3];
1001 memset(buf, 0, sizeof(buf));
1002 snprintf(buf, sizeof(buf) - 1,
1003 DRSH" '"DIMPORT"; "DZFS
1004 " get -H -o value lustre:fsname "DSSNAME"'",
1005 PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
1006 fp = popen(buf, "r");
1008 SNAPSHOT_ADD_LOG(si, "Popen fail to get fsname: %s\n",
1013 if (snapshot_fgets(fp, fsname, fslen) == NULL)
1020 static int snapshot_get_mgsnode(struct snapshot_instance *si,
1021 char *node, int size)
1023 char buf[MAX_BUF_SIZE * 2];
1024 struct snapshot_target *st;
1028 st = list_entry(si->si_osts_list.next, struct snapshot_target,
1030 memset(buf, 0, sizeof(buf));
1031 snprintf(buf, sizeof(buf) - 1,
1032 DRSH" '"DZFS" get -H -o value lustre:mgsnode "DFSNAME"'",
1033 PRSH(si, st), PZFS(st), PFSNAME(st));
1034 fp = popen(buf, "r");
1036 SNAPSHOT_ADD_LOG(si, "Popen fail to get mgsnode: %s\n",
1041 if (snapshot_fgets(fp, node, size) == NULL)
1048 static int snapshot_exists_check(struct snapshot_instance *si,
1049 struct snapshot_target *st)
1051 char buf[MAX_BUF_SIZE * 2];
1055 memset(buf, 0, sizeof(buf));
1056 snprintf(buf, sizeof(buf) - 1,
1057 DRSH" '"DZFS" list "DSSNAME" 2>/dev/null'",
1058 PRSH(si, st), PZFS(st), PSSNAME(si, st));
1059 fp = popen(buf, "r");
1061 SNAPSHOT_ADD_LOG(si, "Popen fail to create check: %s\n",
1066 if (snapshot_fgets(fp, buf, sizeof(buf)) != NULL)
1073 static int snapshot_general_check(struct snapshot_instance *si)
1075 return mdt0_is_lustre_snapshot(si);
1078 static void snapshot_create_usage(void)
1081 "Create snapshot for the given filesystem.\n"
1083 "snapshot_create [-b | --barrier [on | off]] "
1084 "[-c | --comment comment] "
1085 "<-F | --fsname fsname> "
1086 "[-h | --help] <-n | --name ssname> "
1087 "[-r | --rsh remote_shell]"
1088 "[-t | --timeout timeout]\n"
1090 "-b: set write barrier before creating snapshot, "
1091 "the default value is 'on'.\n"
1092 "-c: describe what the snapshot is for, and so on.\n"
1093 "-F: the filesystem name.\n"
1094 "-h: for help information.\n"
1095 "-n: the snapshot's name.\n"
1096 "-r: the remote shell used for communication with remote "
1097 "target, the default value is 'ssh'.\n"
1098 "-t: the life cycle (seconds) for write barrier, "
1099 "the default value is %d seconds.\n",
1100 BARRIER_TIMEOUT_DEFAULT);
1103 static int snapshot_create_check(struct snapshot_instance *si)
1107 rc = snapshot_exists_check(si, si->si_mdt0);
1109 fprintf(stderr, "The snapshot %s exists\n", si->si_ssname);
1114 static int snapshot_inherit_prop(struct snapshot_instance *si,
1115 struct snapshot_target *st,
1116 char *cmd, int size)
1118 char buf[MAX_BUF_SIZE * 3];
1123 memset(buf, 0, sizeof(buf));
1124 snprintf(buf, sizeof(buf) - 1,
1125 DRSH" \""DIMPORT"; "DZFS
1126 " get all "DFSNAME" | grep lustre: | grep local$ | "
1127 "awk '{ \\$1=\\\"\\\"; \\$NF=\\\"\\\"; print \\$0 }' | "
1128 "sed -e 's/^ //'\"",
1129 PRSH(si, st), PIMPORT(st), PZFS(st), PFSNAME(st));
1130 fp = popen(buf, "r");
1132 SNAPSHOT_ADD_LOG(si, "Popen fail to list one: %s\n",
1137 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
1141 if (strncmp(buf, "lustre:fsname",
1142 strlen("lustre:fsname")) == 0)
1145 if (strncmp(buf, "lustre:magic",
1146 strlen("lustre:magic")) == 0)
1149 if (strncmp(buf, "lustre:ctime",
1150 strlen("lustre:ctime")) == 0)
1153 if (strncmp(buf, "lustre:mtime",
1154 strlen("lustre:mtime")) == 0)
1157 if (strncmp(buf, "lustre:comment",
1158 strlen("lustre:comment")) == 0)
1161 if (strncmp(buf, "lustre:svname",
1162 strlen("lustre:svname")) == 0)
1165 if (strncmp(buf, "lustre:mgsnode",
1166 strlen("lustre:mgsnode")) == 0)
1169 ptr = strchr(buf, ' ');
1171 ptr = strchr(buf, '\t');
1178 while (*ptr == ' ' || *ptr == '\t')
1184 end = strchr(ptr, ' ');
1186 end = strchr(buf, '\t');
1190 rc = scnprintf(cmd + len, size - len - 1,
1191 "-o %s=\"%s\" ", buf, ptr);
1202 static int __snapshot_create(struct snapshot_instance *si,
1203 struct list_head *head, const char *fsname,
1204 const char *mgsnode, __u64 xtime)
1206 struct snapshot_target *st;
1210 list_for_each_entry(st, head, st_list) {
1217 SNAPSHOT_ADD_LOG(si, "Can't fork for create snapshot "
1218 "(%s@%s <%s>) on the target "
1220 fsname, si->si_ssname,
1221 si->si_comment, st->st_host,
1222 st->st_role, st->st_index,
1229 char cmd[MAX_BUF_SIZE];
1232 memset(cmd, 0, sizeof(cmd));
1233 len = scnprintf(cmd, sizeof(cmd) - 1,
1234 DRSH" '"DZFS" snapshot "
1235 "-o lustre:fsname=%s "
1236 "-o lustre:magic=%s "
1237 "-o lustre:ctime=%llu "
1238 "-o lustre:mtime=%llu ",
1239 PRSH(si, st), PZFS(st), fsname,
1241 (unsigned long long)xtime,
1242 (unsigned long long)xtime);
1246 if (si->si_comment) {
1247 rc = scnprintf(cmd + len, sizeof(cmd) - len - 1,
1248 "-o lustre:comment=\"%s\" ",
1256 /* Make the inherited properties as local ones,
1257 * then even if others changed (or removed) the
1258 * property of the parent dataset, the snapshot
1259 * will not be affected. */
1260 rc = snapshot_inherit_prop(si, st, cmd + len,
1261 MAX_BUF_SIZE - len - 1);
1263 SNAPSHOT_ADD_LOG(si, "Can't filter property on "
1264 "target (%s:%x:%d): rc = %d\n",
1265 st->st_host, st->st_role,
1272 if (st->st_role & SR_OST)
1273 rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
1274 "-o lustre:svname=%s-OST%04x "
1275 "-o lustre:mgsnode=%s "DSSNAME"'",
1276 fsname, st->st_index, mgsnode,
1278 else if (!(st->st_role & SR_MGS) ||
1279 /* MGS is on MDT0 */
1280 si->si_mdt0 == si->si_mgs)
1281 rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
1282 "-o lustre:svname=%s-MDT%04x "
1283 "-o lustre:mgsnode=%s "DSSNAME"'",
1284 fsname, st->st_index, mgsnode,
1288 rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
1289 DSSNAME"'", PSSNAME(si, st));
1293 rc = snapshot_exec(cmd);
1295 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
1296 "target (%s:%x:%d): rc = %d\n",
1297 cmd, st->st_host, st->st_role,
1301 } /* end of child */
1303 /* parent continue to run more snapshot commands in parallel. */
1310 static int __snapshot_destroy(struct snapshot_instance *si,
1311 struct list_head *head);
1313 static int snapshot_create(struct snapshot_instance *si)
1316 char buf[MAX_BUF_SIZE];
1323 rc = snapshot_create_check(si);
1327 rc = gettimeofday(&tv, NULL);
1331 srandom(tv.tv_usec);
1332 snprintf(new_fsname, sizeof(new_fsname), "%08x", (__u32)random());
1334 rc = snapshot_get_mgsnode(si, buf, sizeof(buf));
1338 __argv[1] = si->si_fsname;
1339 /* 1. Get barrier */
1340 if (si->si_barrier) {
1343 memset(tbuf, 0, sizeof(tbuf));
1344 snprintf(tbuf, 7, "%u", si->si_timeout);
1345 __argv[0] = "barrier_freeze";
1347 rc = jt_barrier_freeze(3, __argv);
1349 SNAPSHOT_ADD_LOG(si, "Can't set barrier within %u "
1350 "seconds on %s: rc = %d\n",
1351 si->si_timeout, si->si_fsname, rc);
1357 /* 2. Fork config llog on MGS */
1358 __argv[0] = "fork_lcfg";
1359 __argv[2] = new_fsname;
1360 rc = jt_lcfg_fork(3, __argv);
1362 SNAPSHOT_ADD_LOG(si, "Can't fork config log for create "
1363 "snapshot %s from %s to %s: rc = %d\n",
1364 si->si_ssname, si->si_fsname, new_fsname, rc);
1368 /* 3.1 Create snapshot on every MDT */
1369 rc = __snapshot_create(si, &si->si_mdts_list, new_fsname, buf,
1372 /* 3.2 Create snapshot on every OST */
1373 rc = __snapshot_create(si, &si->si_osts_list, new_fsname, buf,
1376 /* 4. Wait for all children, even though part of them maybe failed */
1377 snapshot_wait(si, &rc1);
1380 /* 5. Put barrier */
1381 if (si->si_barrier) {
1383 struct barrier_ctl bc;
1385 rc = __jt_barrier_stat(__argv[1], &bc);
1387 SNAPSHOT_ADD_LOG(si, "Can't get barrier status "
1390 } else if (bc.bc_status != BS_FROZEN ||
1391 bc.bc_timeout <= 0) {
1392 SNAPSHOT_ADD_LOG(si, "The barrier expired "
1393 "on %s\n", si->si_fsname);
1398 __argv[0] = "barrier_thaw";
1399 rc2 = jt_barrier_thaw(2, __argv);
1401 SNAPSHOT_ADD_LOG(si, "Can't release barrier on %s: "
1402 "rc = %d\n", si->si_fsname, rc2);
1407 si->si_force = true;
1408 __snapshot_destroy(si, &si->si_osts_list);
1409 __snapshot_destroy(si, &si->si_mdts_list);
1410 snapshot_wait(si, &rc2);
1412 __argv[0] = "erase_lcfg";
1413 __argv[1] = new_fsname;
1415 jt_lcfg_erase(3, __argv);
1418 return rc ? rc : (rc1 ? rc1 : rc2);
1421 int jt_snapshot_create(int argc, char **argv)
1423 struct snapshot_instance *si;
1424 struct option long_opts[] = {
1425 { .val = 'b', .name = "barrier", .has_arg = optional_argument },
1426 { .val = 'c', .name = "comment", .has_arg = required_argument },
1427 { .val = 'F', .name = "fsname", .has_arg = required_argument },
1428 { .val = 'h', .name = "help", .has_arg = no_argument },
1429 { .val = 'n', .name = "name", .has_arg = required_argument },
1430 { .val = 'r', .name = "rsh", .has_arg = required_argument },
1431 { .val = 't', .name = "timeout", .has_arg = required_argument },
1435 si = snapshot_init(argc, argv, long_opts, "b::c:F:hn:r:t:",
1436 snapshot_create_usage, LOCK_EX, &rc);
1440 if (!si->si_ssname) {
1442 "Miss the snapshot name to be created\n");
1443 snapshot_create_usage();
1448 rc = snapshot_create(si);
1451 "Can't create the snapshot %s\n", si->si_ssname);
1452 SNAPSHOT_ADD_LOG(si, "Can't create snapshot %s with "
1453 "comment <%s> barrier <%s>, timeout "
1455 si->si_ssname, si->si_comment,
1456 si->si_barrier ? "enable" : "disable",
1457 si->si_barrier ? si->si_timeout : -1, rc);
1459 SNAPSHOT_ADD_LOG(si, "Create snapshot %s successfully "
1460 "with comment <%s>, barrier <%s>, "
1462 si->si_ssname, si->si_comment,
1463 si->si_barrier ? "enable" : "disable",
1464 si->si_barrier ? si->si_timeout : -1);
1471 static void snapshot_destroy_usage(void)
1474 "Destroy the specified snapshot.\n"
1476 "snapshot_destroy [-f | --force] "
1477 "<-F | --fsname fsname> [-h | --help] "
1478 "<-n | --name ssname> "
1479 "[-r | --rsh remote_shell]\n"
1481 "-f: destroy the snapshot by force.\n"
1482 "-F: the filesystem name.\n"
1483 "-h: for help information.\n"
1484 "-n: the snapshot's name.\n"
1485 "-r: the remote shell used for communication with remote "
1486 "target, the default value is 'ssh'.\n");
1489 static int snapshot_destroy_check(struct snapshot_instance *si)
1491 struct list_head *head = &si->si_osts_list;
1492 struct snapshot_target *st;
1497 list_for_each_entry(st, head, st_list) {
1504 SNAPSHOT_ADD_LOG(si, "Can't fork for check snapshot "
1505 "%s on the target (%s:%x:%d): %s\n",
1506 si->si_ssname, st->st_host,
1507 st->st_role, st->st_index,
1514 rc = snapshot_exists_check(si, st);
1516 /* The snapshot piece does not exist */
1519 exit(rc == -EEXIST ? 0: rc);
1520 } /* end of child */
1522 /* parent continue to run more snapshot commands in parallel. */
1526 if (head == &si->si_osts_list) {
1527 head = &si->si_mdts_list;
1531 snapshot_wait(si, &rc);
1535 head = &si->si_osts_list;
1538 list_for_each_entry(st, head, st_list) {
1539 if (st->st_ignored && !si->si_force) {
1542 snapshot_role2name(name, st->st_role, st->st_index);
1544 "Miss snapshot piece on the %s. Use '-f' "
1545 "option if want to destroy it by force.\n",
1552 if (head == &si->si_osts_list) {
1553 head = &si->si_mdts_list;
1558 rc = snapshot_general_check(si);
1563 static int __snapshot_destroy(struct snapshot_instance *si,
1564 struct list_head *head)
1566 struct snapshot_target *st;
1570 list_for_each_entry(st, head, st_list) {
1579 SNAPSHOT_ADD_LOG(si, "Can't fork for destroy snapshot "
1580 "%s on the target (%s:%x:%d): %s\n",
1581 si->si_ssname, st->st_host,
1582 st->st_role, st->st_index,
1589 char cmd[MAX_BUF_SIZE * 2];
1591 memset(cmd, 0, sizeof(cmd));
1593 snprintf(cmd, sizeof(cmd) - 1,
1594 DRSH" 'umount -f "DSSNAME
1595 " > /dev/null 2>&1; "DZFS
1596 " destroy -f "DSSNAME"'",
1597 PRSH(si, st), PSSNAME(si, st),
1598 PZFS(st), PSSNAME(si, st));
1600 snprintf(cmd, sizeof(cmd) - 1,
1601 DRSH" '"DZFS" destroy "DSSNAME"'",
1602 PRSH(si, st), PZFS(st),
1604 rc = snapshot_exec(cmd);
1606 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
1607 "target (%s:%x:%d): rc = %d\n",
1608 cmd, st->st_host, st->st_role,
1612 } /* end of child */
1614 /* parent continue to run more snapshot commands in parallel. */
1621 static int snapshot_destroy(struct snapshot_instance *si)
1629 rc = snapshot_destroy_check(si);
1633 rc = snapshot_get_fsname(si, fsname, sizeof(fsname));
1637 /* 1.1 Destroy snapshot on every OST */
1638 rc = __snapshot_destroy(si, &si->si_osts_list);
1639 if (!si->si_force) {
1643 __snapshot_wait(si, &si->si_osts_list, &rc);
1648 /* 1.2 Destroy snapshot on every MDT */
1649 rc1 = __snapshot_destroy(si, &si->si_mdts_list);
1651 /* 2 Wait for all children, even though part of them maybe failed */
1652 snapshot_wait(si, &rc2);
1653 if (rc2 == -ENOENT && si->si_force)
1656 /* 3. Erase config llog from MGS */
1657 if ((!rc && !rc1 && !rc2) || si->si_force) {
1660 __argv[0] = "erase_lcfg";
1663 rc3 = jt_lcfg_erase(3, __argv);
1664 if (rc3 && errno == ENOENT)
1667 SNAPSHOT_ADD_LOG(si, "Can't erase config for destroy "
1668 "snapshot %s, fsname %s: rc = %d\n",
1669 si->si_ssname, fsname, rc3);
1672 return rc ? rc : (rc1 ? rc1 : (rc2 ? rc2 : rc3));
1675 int jt_snapshot_destroy(int argc, char **argv)
1677 struct snapshot_instance *si;
1678 struct option long_opts[] = {
1679 { .val = 'f', .name = "force", .has_arg = no_argument },
1680 { .val = 'F', .name = "fsname", .has_arg = required_argument },
1681 { .val = 'h', .name = "help", .has_arg = no_argument },
1682 { .val = 'n', .name = "name", .has_arg = required_argument },
1683 { .val = 'r', .name = "rsh", .has_arg = required_argument },
1687 si = snapshot_init(argc, argv, long_opts, "fF:hn:r:",
1688 snapshot_destroy_usage, LOCK_EX, &rc);
1692 if (!si->si_ssname) {
1694 "Miss the snapshot name to be destroyed\n");
1695 snapshot_destroy_usage();
1700 rc = snapshot_destroy(si);
1703 "Can't destroy the snapshot %s\n", si->si_ssname);
1704 SNAPSHOT_ADD_LOG(si, "Can't destroy snapshot %s with "
1705 "force <%s>: %d\n", si->si_ssname,
1706 si->si_force ? "enable" : "disable", rc);
1708 SNAPSHOT_ADD_LOG(si, "Destroy snapshot %s successfully "
1709 "with force <%s>\n", si->si_ssname,
1710 si->si_force ? "enable" : "disable");
1717 static void snapshot_modify_usage(void)
1720 "Change the specified snapshot's name and/or comment.\n"
1722 "snapshot_modify [-c | --comment comment] "
1723 "<-F | --fsname fsname> [-h | --help] "
1724 "<-n | --name ssname> [-N | --new new_ssname] "
1725 "[-r | --rsh remote_shell]\n"
1727 "-c: update the snapshot's comment.\n"
1728 "-F: the filesystem name.\n"
1729 "-h: for help information.\n"
1730 "-n: the snapshot's name.\n"
1731 "-N: rename the snapshot's name as the new_ssname.\n"
1732 "-r: the remote shell used for communication with remote "
1733 "target, the default value is 'ssh'.\n");
1736 static int snapshot_modify_check(struct snapshot_instance *si)
1740 if (si->si_new_ssname &&
1741 strcmp(si->si_ssname, si->si_new_ssname) == 0) {
1742 fprintf(stderr, "The new snapshot's name is the same as "
1743 "the old one %s %s.\n",
1744 si->si_ssname, si->si_new_ssname);
1748 if (!si->si_new_ssname && !si->si_comment) {
1749 fprintf(stderr, "Miss options, nothing to be changed.\n");
1753 rc = mdt0_is_lustre_snapshot(si);
1754 if (!rc && si->si_new_ssname) {
1755 rc = target_is_mounted(si, si->si_mdt0, si->si_ssname);
1758 "snapshot %s is mounted, can't be renamed.\n",
1767 static int __snapshot_modify(struct snapshot_instance *si,
1768 struct list_head *head, __u64 xtime)
1770 struct snapshot_target *st;
1774 list_for_each_entry(st, head, st_list) {
1781 SNAPSHOT_ADD_LOG(si, "Can't fork for modify snapshot "
1782 "(%s|%s, <%s>) on the target "
1784 si->si_ssname, si->si_new_ssname,
1785 si->si_comment, st->st_host,
1786 st->st_role, st->st_index,
1793 char cmd[MAX_BUF_SIZE * 5];
1795 memset(cmd, 0, sizeof(cmd));
1796 if (si->si_new_ssname && si->si_comment)
1797 snprintf(cmd, sizeof(cmd) - 1,
1798 DRSH" '"DIMPORT"; "DZFS" rename "
1799 DSSNAME" "DSSNAME" && "DZFS
1800 " set lustre:comment=\"%s\" "DSSNAME
1802 " set lustre:mtime=%llu "DSSNAME"'",
1803 PRSH(si, st), PIMPORT(st), PZFS(st),
1804 PSSNAME(si, st), PSS_NEW(si, st),
1805 PZFS(st), si->si_comment,
1806 PSS_NEW(si, st), PZFS(st),
1807 (unsigned long long)xtime,
1809 else if (si->si_new_ssname)
1810 snprintf(cmd, sizeof(cmd) - 1,
1811 DRSH" '"DIMPORT"; "DZFS
1812 " rename "DSSNAME" "DSSNAME" && "DZFS
1813 " set lustre:mtime=%llu "DSSNAME"'",
1814 PRSH(si, st), PIMPORT(st), PZFS(st),
1815 PSSNAME(si, st), PSS_NEW(si, st),
1816 PZFS(st), (unsigned long long)xtime,
1818 else if (si->si_comment)
1819 snprintf(cmd, sizeof(cmd) - 1,
1820 DRSH" '"DIMPORT"; "DZFS
1821 " set lustre:comment=\"%s\" "DSSNAME
1823 " set lustre:mtime=%llu "DSSNAME"'",
1824 PRSH(si, st), PIMPORT(st), PZFS(st),
1825 si->si_comment, PSSNAME(si, st),
1826 PZFS(st), (unsigned long long)xtime,
1831 rc = snapshot_exec(cmd);
1833 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
1834 "target (%s:%x:%d): rc = %d\n",
1835 cmd, st->st_host, st->st_role,
1839 } /* end of child */
1841 /* parent continue to run more snapshot commands in parallel. */
1848 static int snapshot_modify(struct snapshot_instance *si)
1854 rc = snapshot_modify_check(si);
1860 /* Modify snapshot on every MDT */
1861 rc = __snapshot_modify(si, &si->si_mdts_list, (__u64)tt);
1863 /* Modify snapshot on every OST */
1864 rc = __snapshot_modify(si, &si->si_osts_list, (__u64)tt);
1866 /* Wait for all children, even though part of them maybe failed */
1867 snapshot_wait(si, &rc1);
1869 return rc ? rc : rc1;
1872 int jt_snapshot_modify(int argc, char **argv)
1874 struct snapshot_instance *si;
1875 struct option long_opts[] = {
1876 { .val = 'c', .name = "comment", .has_arg = required_argument },
1877 { .val = 'F', .name = "fsname", .has_arg = required_argument },
1878 { .val = 'h', .name = "help", .has_arg = no_argument },
1879 { .val = 'n', .name = "name", .has_arg = required_argument },
1880 { .val = 'N', .name = "new", .has_arg = required_argument },
1881 { .val = 'r', .name = "rsh", .has_arg = required_argument },
1885 si = snapshot_init(argc, argv, long_opts, "c:F:hn:N:r:",
1886 snapshot_modify_usage, LOCK_EX, &rc);
1890 if (!si->si_ssname) {
1892 "Miss the snapshot name to be modified\n");
1893 snapshot_modify_usage();
1898 rc = snapshot_modify(si);
1901 "Can't modify the snapshot %s\n", si->si_ssname);
1902 SNAPSHOT_ADD_LOG(si, "Can't modify snapshot %s with "
1903 "name <%s>, comment <%s>: %d\n",
1904 si->si_ssname, si->si_new_ssname,
1905 si->si_comment, rc);
1907 SNAPSHOT_ADD_LOG(si, "Modify snapshot %s successfully "
1908 "with name <%s>, comment <%s>\n",
1909 si->si_ssname, si->si_new_ssname,
1917 static void snapshot_list_usage(void)
1920 "List the specified snapshot or all snapshots.\n"
1922 "snapshot_list [-d | --detail] "
1923 "<-F | --fsname fsname> [-h | --help] "
1924 "[-n | --name ssname] [-r | --rsh remote_shell]\n"
1926 "-d: list every piece for the specified snapshot.\n"
1927 "-F: the filesystem name.\n"
1928 "-h: for help information.\n"
1929 "-n: the snapshot's name.\n"
1930 "-r: the remote shell used for communication with remote "
1931 "target, the default value is 'ssh'.\n");
1934 static int snapshot_list_one(struct snapshot_instance *si,
1935 struct snapshot_target *st)
1937 char buf[MAX_BUF_SIZE * 3];
1941 memset(buf, 0, sizeof(buf));
1942 snprintf(buf, sizeof(buf) - 1,
1943 DRSH" \""DIMPORT"; "DZFS
1944 " get all "DSSNAME" | grep lustre: | grep local$ | "
1945 "awk '{ \\$1=\\\"\\\"; \\$NF=\\\"\\\"; print \\$0 }' | "
1946 "sed -e 's/^ //'\"",
1947 PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
1948 fp = popen(buf, "r");
1950 SNAPSHOT_ADD_LOG(si, "Popen fail to list one: %s\n",
1955 if (si->si_detail) {
1958 snapshot_role2name(name, st->st_role, st->st_index);
1959 printf("\nsnapshot_role: %s\n", name);
1962 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
1966 if (strncmp(buf, "lustre:fsname",
1967 strlen("lustre:fsname")) == 0) {
1968 ptr = snapshot_first_skip_blank(buf);
1970 printf("snapshot_fsname: %s\n", ptr);
1974 if (strncmp(buf, "lustre:comment",
1975 strlen("lustre:comment")) == 0) {
1976 ptr = snapshot_first_skip_blank(buf);
1978 printf("comment: %s\n", ptr);
1982 if (strncmp(buf, "lustre:ctime",
1983 strlen("lustre:ctime")) == 0) {
1984 ptr = snapshot_first_skip_blank(buf);
1986 xtime = (__u64)strtoull(ptr, NULL, 10);
1987 printf("create_time: %s",
1988 ctime((time_t *)&xtime));
1993 if (strncmp(buf, "lustre:mtime",
1994 strlen("lustre:mtime")) == 0) {
1995 ptr = snapshot_first_skip_blank(buf);
1997 xtime = (__u64)strtoull(ptr, NULL, 10);
1998 printf("modify_time: %s",
1999 ctime((time_t *)&xtime));
2006 rc = target_is_mounted(si, st, si->si_ssname);
2008 printf("status: unknown\n");
2010 printf("status: not mount\n");
2012 printf("status: mounted\n");
2017 static int __snapshot_list(struct snapshot_instance *si,
2018 struct list_head *head)
2020 struct snapshot_target *st;
2023 list_for_each_entry(st, head, st_list) {
2026 rc1 = snapshot_list_one(si, st);
2027 if (rc1 < 0 || rc >= 0)
2034 static int snapshot_list(struct snapshot_instance *si)
2038 rc = snapshot_general_check(si);
2042 printf("\nfilesystem_name: %s\nsnapshot_name: %s\n",
2043 si->si_fsname, si->si_ssname);
2045 if (!si->si_detail) {
2046 rc = snapshot_list_one(si, si->si_mdt0);
2050 rc = __snapshot_list(si, &si->si_mdts_list);
2051 rc1 = __snapshot_list(si, &si->si_osts_list);
2056 return rc < 0 ? rc : 0;
2059 static int snapshot_list_all(struct snapshot_instance *si)
2061 struct snapshot_target *st = si->si_mdt0;
2062 struct list_sub_item {
2063 struct list_head lsi_list;
2067 struct list_head list_sub_items;
2068 struct list_sub_item *lsi;
2069 char buf[MAX_BUF_SIZE * 2];
2073 INIT_LIST_HEAD(&list_sub_items);
2074 memset(buf, 0, sizeof(buf));
2075 snprintf(buf, sizeof(buf) - 1,
2076 DRSH" \""DZFS" get -H -r lustre:magic "DFSNAME
2077 " | grep %s | awk '{ print \\$1 }' | cut -d@ -f2\"",
2078 PRSH(si, st), PZFS(st), PFSNAME(st), SNAPSHOT_MAGIC);
2079 fp = popen(buf, "r");
2081 SNAPSHOT_ADD_LOG(si, "Popen fail to list ssnames: %s\n",
2086 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
2087 int len = strlen(buf);
2089 lsi = malloc(len + 1 + sizeof(struct list_sub_item));
2091 SNAPSHOT_ADD_LOG(si, "NOT enough memory\n");
2096 memcpy(lsi->lsi_ssname, buf, len + 1);
2097 list_add(&lsi->lsi_list, &list_sub_items);
2101 while (!list_empty(&list_sub_items)) {
2102 lsi = list_entry(list_sub_items.next,
2103 struct list_sub_item, lsi_list);
2104 list_del(&lsi->lsi_list);
2106 si->si_ssname = lsi->lsi_ssname;
2107 rc = snapshot_list(si);
2108 si->si_ssname = NULL;
2117 int jt_snapshot_list(int argc, char **argv)
2119 struct snapshot_instance *si;
2120 struct option long_opts[] = {
2121 { .val = 'd', .name = "detail", .has_arg = no_argument },
2122 { .val = 'F', .name = "fsname", .has_arg = required_argument },
2123 { .val = 'h', .name = "help", .has_arg = no_argument },
2124 { .val = 'n', .name = "name", .has_arg = required_argument },
2125 { .val = 'r', .name = "rsh", .has_arg = required_argument },
2129 si = snapshot_init(argc, argv, long_opts, "dF:hn:r:",
2130 snapshot_list_usage, LOCK_SH, &rc);
2135 rc = snapshot_list(si);
2137 rc = snapshot_list_all(si);
2141 "Can't list the snapshot %s\n", si->si_ssname);
2142 SNAPSHOT_ADD_LOG(si, "Can't list snapshot %s with detail "
2143 "<%s>: %d\n", si->si_ssname,
2144 si->si_detail ? "yes" : "no", rc);
2151 static void snapshot_mount_usage(void)
2154 "Mount the specified snapshot.\n"
2156 "snapshot_mount <-F | --fsname fsname> [-h | --help] "
2157 "<-n | --name ssname> "
2158 "[-r | --rsh remote_shell]\n"
2160 "-F: the filesystem name.\n"
2161 "-h: for help information.\n"
2162 "-n: the snapshot's name.\n"
2163 "-r: the remote shell used for communication with remote "
2164 "target, the default value is 'ssh'.\n");
2167 static int snapshot_mount_check(struct snapshot_instance *si, char *fsname,
2168 int fslen, bool *mgs_running)
2172 rc = mdt0_is_lustre_snapshot(si);
2176 rc = snapshot_get_fsname(si, fsname, fslen);
2180 rc = target_is_mounted(si, si->si_mgs, NULL);
2182 *mgs_running = true;
2189 static int snapshot_mount_target(struct snapshot_instance *si,
2190 struct snapshot_target *st, const char *optstr)
2192 char cmd[MAX_BUF_SIZE * 2];
2196 rc = target_is_mounted(si, st, si->si_ssname);
2203 memset(cmd, 0, sizeof(cmd));
2204 memset(name, 0, sizeof(name));
2205 snapshot_role2name(name, st->st_role, st->st_index);
2206 snprintf(cmd, sizeof(cmd) - 1,
2207 DRSH" '"DIMPORT"; mkdir -p /mnt/%s_%s && mount -t lustre "
2208 "-o rdonly_dev%s "DSSNAME" /mnt/%s_%s'",
2209 PRSH(si, st), PIMPORT(st), si->si_ssname, name,
2210 st != si->si_mdt0 ? "" : optstr, PSSNAME(si, st),
2211 si->si_ssname, name);
2212 rc = snapshot_exec(cmd);
2214 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on the target "
2215 "(%s:%x:%d): rc = %d\n", cmd, st->st_host,
2216 st->st_role, st->st_index, rc);
2221 static int __snapshot_mount(struct snapshot_instance *si,
2222 struct list_head *head)
2224 struct snapshot_target *st;
2228 list_for_each_entry(st, head, st_list) {
2229 if (st == si->si_mgs || st == si->si_mdt0)
2238 SNAPSHOT_ADD_LOG(si, "Can't fork for mount snapshot "
2239 "%s on target (%s:%x:%d): %s\n",
2240 si->si_ssname, st->st_host,
2241 st->st_role, st->st_index,
2248 rc = snapshot_mount_target(si, st, "");
2252 /* parent continue to run more snapshot commands in parallel. */
2259 static int __snapshot_umount(struct snapshot_instance *si,
2260 struct list_head *head);
2262 static int snapshot_mount(struct snapshot_instance *si)
2264 struct snapshot_target *st;
2270 bool mdt0_mounted = false;
2271 bool mgs_running = false;
2273 rc = snapshot_mount_check(si, fsname, sizeof(fsname), &mgs_running);
2276 "Can't mount the snapshot %s: %s\n",
2277 si->si_ssname, strerror(-rc));
2281 /* 1. MGS is not mounted yet, mount the MGS firstly */
2282 si->si_mgs->st_ignored = 0;
2283 si->si_mgs->st_pid = 0;
2285 rc = snapshot_mount_target(si, si->si_mgs, "");
2287 si->si_mgs->st_ignored = 1;
2293 "Can't mount the snapshot %s: %s\n",
2294 si->si_ssname, strerror(-rc));
2298 if (si->si_mgs == si->si_mdt0)
2299 mdt0_mounted = true;
2302 /* 2. Mount MDT0 if it is not combined with the MGS. */
2303 if (!mdt0_mounted) {
2304 si->si_mdt0->st_ignored = 0;
2305 si->si_mdt0->st_pid = 0;
2306 rc = snapshot_mount_target(si, si->si_mdt0, ",nomgs");
2311 /* 3.1 Mount other MDTs in parallel */
2312 rc = __snapshot_mount(si, &si->si_mdts_list);
2314 /* 3.2 Mount OSTs in parallel */
2315 rc = __snapshot_mount(si, &si->si_osts_list);
2317 /* Wait for all children, even though part of them maybe failed */
2318 failed = snapshot_wait(si, &rc1);
2320 list_for_each_entry(st, &si->si_mdts_list, st_list) {
2321 if (!st->st_ignored)
2325 list_for_each_entry(st, &si->si_osts_list, st_list) {
2326 if (!st->st_ignored)
2334 __snapshot_umount(si, &si->si_mdts_list);
2335 __snapshot_umount(si, &si->si_osts_list);
2336 snapshot_wait(si, &rc2);
2340 "Can't mount the snapshot %s: %s\n",
2341 si->si_ssname, strerror(-rc));
2344 "%d of %d pieces of the snapshot %s "
2345 "can't be mounted: %s\n",
2346 failed, needed, si->si_ssname, strerror(-rc1));
2348 return rc ? rc : rc1;
2353 "The snapshot %s has already been mounted by other\n",
2358 fprintf(stdout, "mounted the snapshot %s with fsname %s\n",
2359 si->si_ssname, fsname);
2364 int jt_snapshot_mount(int argc, char **argv)
2366 struct snapshot_instance *si;
2367 struct option long_opts[] = {
2368 { .val = 'F', .name = "fsname", .has_arg = required_argument },
2369 { .val = 'h', .name = "help", .has_arg = no_argument },
2370 { .val = 'n', .name = "name", .has_arg = required_argument },
2371 { .val = 'r', .name = "rsh", .has_arg = required_argument },
2375 si = snapshot_init(argc, argv, long_opts, "F:hn:r:",
2376 snapshot_mount_usage, LOCK_EX, &rc);
2380 if (!si->si_ssname) {
2382 "Miss the snapshot name to be mounted\n");
2383 snapshot_mount_usage();
2388 rc = snapshot_mount(si);
2390 SNAPSHOT_ADD_LOG(si, "Can't mount snapshot %s: %d\n",
2393 SNAPSHOT_ADD_LOG(si, "The snapshot %s is mounted\n",
2401 static void snapshot_umount_usage(void)
2404 "Umount the specified snapshot.\n"
2406 "snapshot_umount <-F | --fsname fsname> [-h | --help] "
2407 "<-n | --name ssname> "
2408 "[-r | --rsh remote_shell]\n"
2410 "-F: the filesystem name.\n"
2411 "-h: for help information.\n"
2412 "-n: the snapshot's name.\n"
2413 "-r: the remote shell used for communication with remote "
2414 "target, the default value is 'ssh'.\n");
2417 static int __snapshot_umount(struct snapshot_instance *si,
2418 struct list_head *head)
2420 struct snapshot_target *st;
2424 list_for_each_entry(st, head, st_list) {
2431 SNAPSHOT_ADD_LOG(si, "Can't fork for umount snapshot "
2432 "%s on target (%s:%x:%d): %s\n",
2433 si->si_ssname, st->st_host,
2434 st->st_role, st->st_index,
2441 char cmd[MAX_BUF_SIZE];
2443 rc = target_is_mounted(si, st, si->si_ssname);
2450 memset(cmd, 0, sizeof(cmd));
2451 snprintf(cmd, sizeof(cmd) - 1,
2452 DRSH" 'umount "DSSNAME"'",
2453 PRSH(si, st), PSSNAME(si, st));
2454 rc = snapshot_exec(cmd);
2459 /* parent continue to run more snapshot commands in parallel. */
2466 static int snapshot_umount(struct snapshot_instance *si)
2468 struct snapshot_target *st;
2475 rc = snapshot_general_check(si);
2478 "Can't umount the snapshot %s: %s\n",
2479 si->si_ssname, strerror(-rc));
2483 rc = __snapshot_umount(si, &si->si_mdts_list);
2484 rc1 = __snapshot_umount(si, &si->si_osts_list);
2485 failed = snapshot_wait(si, &rc2);
2487 list_for_each_entry(st, &si->si_mdts_list, st_list) {
2488 if (!st->st_ignored)
2492 list_for_each_entry(st, &si->si_osts_list, st_list) {
2493 if (!st->st_ignored)
2499 "The snapshot %s has not been mounted\n",
2506 "%d of %d pieces of the snapshot %s "
2507 "can't be umounted: %s\n",
2508 failed, needed, si->si_ssname, strerror(-rc2));
2510 return rc ? rc : (rc1 ? rc1 : rc2);
2513 int jt_snapshot_umount(int argc, char **argv)
2515 struct snapshot_instance *si;
2516 struct option long_opts[] = {
2517 { .val = 'F', .name = "fsname", .has_arg = required_argument },
2518 { .val = 'h', .name = "help", .has_arg = no_argument },
2519 { .val = 'n', .name = "name", .has_arg = required_argument },
2520 { .val = 'r', .name = "rsh", .has_arg = required_argument },
2524 si = snapshot_init(argc, argv, long_opts, "F:hn:r:",
2525 snapshot_umount_usage, LOCK_EX, &rc);
2529 if (!si->si_ssname) {
2531 "Miss the snapshot name to be umounted\n");
2532 snapshot_umount_usage();
2537 rc = snapshot_umount(si);
2539 SNAPSHOT_ADD_LOG(si, "Can't umount snapshot %s: %d\n",
2542 SNAPSHOT_ADD_LOG(si, "the snapshot %s have been umounted\n",