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 <linux/lustre/lustre_ioctl.h>
48 #include <linux/lustre/lustre_barrier_user.h>
52 #define SNAPSHOT_CONF_DIR "/etc/lsnapshot"
53 #define LDEV_CONF "/etc/ldev.conf"
54 #define SNAPSHOT_LOG "/var/log/lsnapshot.log"
55 #define SNAPSHOT_MAGIC "0x14F711B9"
56 #define MAX_BUF_SIZE 4096
64 struct snapshot_target {
65 struct list_head st_list;
66 /* Target node name. */
68 /* Where the pool is */
70 /* The target pool name on the target node. */
72 /* The backend filesystem name against the target pool. */
75 unsigned int st_index;
83 struct snapshot_instance {
84 struct list_head si_mdts_list;
85 struct list_head si_osts_list;
86 struct snapshot_target *si_mgs;
87 struct snapshot_target *si_mdt0;
101 static const char snapshot_rsh_default[] = "ssh";
102 static char snapshot_path[MAX_BUF_SIZE];
104 static char *snapshot_role2name(char *name, enum snapshot_role role,
108 snprintf(name, 8, "MDT%04x", index);
109 else if (role & SR_MGS)
110 snprintf(name, 4, "MGS");
112 snprintf(name, 8, "OST%04x", index);
117 #define SNAPSHOT_ADD_LOG(si, format, ...) \
119 char buf[MAX_BUF_SIZE]; \
123 memset(buf, 0, sizeof(buf)); \
125 snprintf(buf, sizeof(buf) - 1, "%s", ctime(&tt)); \
126 ptr = strrchr(buf, '\n'); \
130 fprintf(si->si_log_fp, "%s (%d:%s:%d:%s:%s): "format, buf, \
131 getpid(), __func__, __LINE__, si->si_fsname, \
132 si->si_rsh, ## __VA_ARGS__); \
136 #define DFSNAME "%s/%s"
137 #define DSSNAME "%s/%s@%s"
138 #define DZFS "%s zfs"
139 #define DIMPORT "%s zpool import -d %s %s > /dev/null 2>&1"
141 #define PRSH(si, st) (si)->si_rsh, (st)->st_host
142 #define PFSNAME(st) (st)->st_pool, (st)->st_filesystem
143 #define PSSNAME(si, st) PFSNAME(st), (si)->si_ssname
144 #define PSS_NEW(si, st) PFSNAME(st), (si)->si_new_ssname
145 #define PZFS(st) snapshot_path
146 #define PIMPORT(st) snapshot_path, \
147 (st)->st_dir ? (st)->st_dir : "/dev -d /tmp", (st)->st_pool
149 char *snapshot_fgets(FILE *fp, char *buf, int buflen)
153 memset(buf, 0, buflen);
154 if (fgets(buf, buflen, fp) == NULL)
157 ptr = strchr(buf, '\n');
164 static int snapshot_exec(const char *cmd)
170 /* system() return value depends on both the system() general framework,
171 * such as whether fork()/exec() success or fail, and the real @cmd exec
172 * result. Especially, if the @cmd is remote command, we may cannot know
173 * the real failure. */
175 /* fork()/exec() error */
177 return errno != 0 ? -errno : -1;
180 rc = WEXITSTATUS(rc);
183 } else if (WIFSIGNALED(rc)) {
186 /* all other known or unknown cases. */
193 static int snapshot_load_conf_ldev(struct snapshot_instance *si, char *buf,
194 struct snapshot_target *st, char **role)
204 rc = sscanf(buf, "%ms %ms %ms %ms",
205 &st->st_host, &ignore, &label, &device);
214 * [md|zfs:][pool_dir/]<pool>/<filesystem> */
215 ptr = strchr(device, ':');
218 if (strncmp(device, "zfs:", strlen("zfs:")) != 0) {
226 ptr1 = strrchr(ptr, '/');
227 /* "ptr1 - ptr + 1 == strlen(ptr)" means '/' is at the tail. */
228 if (!ptr1 || ptr1 == ptr || ptr1 - ptr + 1 == strlen(ptr)) {
234 st->st_filesystem = malloc(len);
235 if (!st->st_filesystem) {
241 strncpy(st->st_filesystem, ptr1 + 1, len - 1);
242 st->st_filesystem[len - 1] = '\0';
245 ptr1 = strrchr(ptr, '/');
248 st->st_dir = malloc(len + 1);
254 strncpy(st->st_dir, ptr, len);
255 st->st_dir[len] = '\0';
260 st->st_pool = malloc(len + 1);
266 strncpy(st->st_pool, ptr, len);
267 st->st_pool[len] = '\0';
270 * fsname-<role><index> or <role><index> */
271 ptr = strchr(label, '-');
273 if (strncmp(si->si_fsname, label, ptr - label) != 0) {
274 /* This line is NOT for current filesystem .*/
284 if (strlen(ptr) < 3 || strlen(ptr) > 7) {
295 strncpy(*role, ptr, 3);
299 while (isxdigit(ptr[len])) {
300 if (isdigit(ptr[len]))
302 st->st_index * 16 + ptr[len] - '0';
303 else if (isupper(ptr[len]))
305 st->st_index * 16 + ptr[len] - 'A' + 10;
308 st->st_index * 16 + ptr[len] - 'a' + 10;
313 if (strncasecmp(*role, "MGS", 3) != 0)
321 if (!isxdigit(ptr[len]) && ptr[len] != '\0') {
336 * For old snasphot tools, the configration is in /etc/lsnapshot/${fsname}.conf,
338 * <host> <pool_dir> <pool> <local_fsname> <role(,s)> <index>
342 * host-mdt1 /tmp myfs-mdt1 mdt1 MGS,MDT 0
343 * host-mdt2 /tmp myfs-mdt2 mdt2 MDT 1
344 * host-ost1 /tmp myfs-ost1 ost1 OST 0
345 * host-ost2 /tmp myfs-ost2 ost2 OST 1
348 * For new snasphot tools, the configration is in /etc/ldev.conf, which is not
349 * only for snapshot, but also for other purpose. The format is:
350 * <host> foreign/- <label> <device> [journal-path]/- [raidtab]
352 * The format of <label> is:
353 * fsname-<role><index> or <role><index>
355 * The format of <device> is:
356 * [md|zfs:][pool_dir/]<pool>/<filesystem>
358 * Snapshot only uses the fields <host>, <label> and <device>.
362 * host-mdt1 - myfs-MDT0000 zfs:/tmp/myfs-mdt1/mdt1
365 * \retval 0 for success
366 * \retval +ve the line# with which the current line is conflict
367 * \retval -EAGAIN skip current line
368 * \retval -ve other failures
370 static int snapshot_load_conf_one(struct snapshot_instance *si,
371 char *buf, int line_num, bool is_ldev)
373 struct snapshot_target *st;
378 path = getenv("PATH");
382 memset(snapshot_path, 0, sizeof(snapshot_path));
383 snprintf(snapshot_path, sizeof(snapshot_path) - 1, "PATH='%s'", path);
385 /* filter out space */
386 while (isspace(*buf))
389 /* skip empty line */
393 /* skip comment line */
397 st = malloc(sizeof(*st));
401 memset(st, 0, sizeof(*st));
402 INIT_LIST_HEAD(&st->st_list);
405 rc = snapshot_load_conf_ldev(si, buf, st, &role);
407 rc = sscanf(buf, "%ms %ms %ms %ms %ms %d",
408 &st->st_host, &st->st_dir, &st->st_pool,
409 &st->st_filesystem, &role, &st->st_index);
418 if (strncasecmp(role, "MGS", 3) == 0) {
419 st->st_role = SR_MGS;
420 if (role[3] == ',') {
422 if (strncasecmp(&role[4], "MDT", 3) != 0) {
427 st->st_role |= SR_MDT;
429 } else if (strncasecmp(role, "MDT", 3) == 0) {
430 st->st_role = SR_MDT;
431 if (role[3] == ',') {
433 if (strncasecmp(&role[4], "MGS", 3) != 0) {
438 st->st_role |= SR_MGS;
440 } else if (strncasecmp(role, "OST", 3) == 0) {
441 st->st_role = SR_OST;
447 st->st_line = line_num;
448 if (st->st_role & SR_MDT) {
449 /* MGS is the first, MDT0 is just after the MGS
450 * if they are not combined together. */
451 if (st->st_role & SR_MGS) {
453 rc = si->si_mgs->st_line;
458 list_add(&st->st_list, &si->si_mdts_list);
461 if (st->st_index == 0) {
463 rc = si->si_mdt0->st_line;
468 if (list_empty(&st->st_list)) {
469 if (list_empty(&si->si_mdts_list) ||
471 list_add(&st->st_list,
474 list_add(&st->st_list,
475 &si->si_mgs->st_list);
477 } else if (list_empty(&st->st_list)) {
478 list_add_tail(&st->st_list, &si->si_mdts_list);
480 } else if (st->st_role & SR_MGS) {
482 rc = si->si_mgs->st_line;
487 list_add(&st->st_list, &si->si_mdts_list);
489 list_add_tail(&st->st_list, &si->si_osts_list);
503 if (st->st_filesystem)
504 free(st->st_filesystem);
511 static int snapshot_load_conf(struct snapshot_instance *si, int lock_mode)
514 char buf[MAX_BUF_SIZE];
521 memset(conf_name, 0, sizeof(conf_name));
522 strncpy(conf_name, LDEV_CONF, sizeof(conf_name) - 1);
523 fd = open(conf_name, O_RDONLY);
525 if (errno != ENOENT) {
527 "Can't open the snapshot config file %s: %s\n",
528 conf_name, strerror(errno));
533 snprintf(conf_name, sizeof(conf_name) - 1, "%s/%s.conf",
534 SNAPSHOT_CONF_DIR, si->si_fsname);
535 fd = open(conf_name, O_RDONLY);
538 "Can't open the snapshot config file %s: %s\n",
539 conf_name, strerror(errno));
547 rc = flock(fd, lock_mode | LOCK_NB);
550 "Can't lock the snapshot config file %s (%d): %s\n",
551 conf_name, lock_mode, strerror(errno));
556 fp = fdopen(fd, "r");
559 "Can't fdopen the snapshot config file %s: %s\n",
560 conf_name, strerror(errno));
565 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
566 rc = snapshot_load_conf_one(si, buf, line_num, is_ldev);
569 "Invalid snapshot config file %s at the line "
570 "%d '%s'\n", conf_name, line_num, buf);
571 } else if (rc == -EAGAIN) {
575 "The config role has been specified repeatedly "
576 "at the lines %d/%d in %s\n",
577 rc, line_num, conf_name);
589 "Miss MDT0 in the config file %s\n",
595 /* By default, the MGS is on the MDT0 if it is not specified. */
597 si->si_mgs = si->si_mdt0;
598 si->si_mgs->st_role |= SR_MGS;
601 if (list_empty(&si->si_osts_list)) {
603 "Miss OST(s) in the config file %s\n",
622 static void snapshot_unload_conf(struct snapshot_instance *si)
624 struct snapshot_target *st;
626 while (!list_empty(&si->si_mdts_list)) {
627 st = list_entry(si->si_mdts_list.next,
628 struct snapshot_target, st_list);
629 list_del(&st->st_list);
633 free(st->st_filesystem);
637 while (!list_empty(&si->si_osts_list)) {
638 st = list_entry(si->si_osts_list.next,
639 struct snapshot_target, st_list);
640 list_del(&st->st_list);
644 free(st->st_filesystem);
651 if (si->si_conf_fd >= 0) {
652 flock(si->si_conf_fd, LOCK_UN);
653 close(si->si_conf_fd);
658 static int snapshot_handle_string_option(char **dst, const char *option,
659 const char *opt_name)
663 if (*dst && *dst != snapshot_rsh_default) {
665 "%s option has been specified repeatedly.\n", opt_name);
669 len = strlen(option);
670 *dst = malloc(len + 1);
674 strncpy(*dst, option, len);
679 static void snapshot_fini(struct snapshot_instance *si)
681 snapshot_unload_conf(si);
684 fclose(si->si_log_fp);
686 if (si->si_rsh && si->si_rsh != snapshot_rsh_default)
692 if (si->si_new_ssname)
693 free(si->si_new_ssname);
695 free(si->si_comment);
700 static struct snapshot_instance *
701 snapshot_init(int argc, char * const argv[], const struct option *longopts,
702 const char *optstring, void (*usage)(void),
703 int lock_mode, int *err)
705 struct snapshot_instance *si;
710 si = malloc(sizeof(*si));
713 "No enough memory to initialize snapshot instance.\n");
718 memset(si, 0, sizeof(*si));
719 INIT_LIST_HEAD(&si->si_mdts_list);
720 INIT_LIST_HEAD(&si->si_osts_list);
721 si->si_rsh = (char *)snapshot_rsh_default;
723 si->si_timeout = BARRIER_TIMEOUT_DEFAULT;
724 si->si_barrier = true;
725 si->si_detail = false;
726 si->si_force = false;
728 while ((opt = getopt_long(argc, argv, optstring,
729 longopts, &idx)) != EOF) {
732 if (!optarg || strcmp(optarg, "on") == 0) {
733 si->si_barrier = true;
734 } else if (strcmp(optarg, "off") == 0) {
735 si->si_barrier = false;
743 *err = snapshot_handle_string_option(&si->si_comment,
749 si->si_detail = true;
755 *err = snapshot_handle_string_option(&si->si_fsname,
761 *err = snapshot_handle_string_option(&si->si_ssname,
767 *err = snapshot_handle_string_option(&si->si_new_ssname,
774 *err = snapshot_handle_string_option(&si->si_rsh,
781 si->si_timeout = atoi(optarg);
795 if (!si->si_fsname) {
796 fprintf(stderr, "The fsname must be specified\n");
802 if (strlen(si->si_fsname) > 8) {
803 fprintf(stderr, "Invalid fsname %s\n", si->si_fsname);
808 si->si_log_fp = fopen(SNAPSHOT_LOG, "a");
809 if (!si->si_log_fp) {
812 "Can't open the snapshot log file %s: %s\n",
813 SNAPSHOT_LOG, strerror(errno));
817 *err = snapshot_load_conf(si, lock_mode);
820 if (*err != 0 && si) {
828 static int __snapshot_wait(struct snapshot_instance *si,
829 struct list_head *head, int *err)
831 struct snapshot_target *st;
835 list_for_each_entry(st, head, st_list) {
839 rc = waitpid(st->st_pid, &st->st_status, 0);
841 SNAPSHOT_ADD_LOG(si, "Can't wait child (%d) operation "
842 "on the target <%s:%x:%d>: %s\n",
843 st->st_pid, st->st_host, st->st_role,
844 st->st_index, strerror(errno));
850 /* continue to wait for next */
854 if (WIFEXITED(st->st_status)) {
855 rc = WEXITSTATUS(st->st_status);
860 st->st_ignored = true;
866 } else if (WIFSIGNALED(st->st_status)) {
867 SNAPSHOT_ADD_LOG(si, "The child (%d) operation on the "
868 "target <%s:%x:%d> was killed by "
870 st->st_pid, st->st_host, st->st_role,
871 st->st_index, WTERMSIG(st->st_status));
876 SNAPSHOT_ADD_LOG(si, "The child (%d) operation on the "
877 "target <%s:%x:%d> failed for "
879 st->st_pid, st->st_host, st->st_role,
892 static int snapshot_wait(struct snapshot_instance *si, int *err)
896 count = __snapshot_wait(si, &si->si_mdts_list, err);
897 count += __snapshot_wait(si, &si->si_osts_list, err);
902 static char *snapshot_first_skip_blank(char *buf)
906 ptr = strchr(buf, ' ');
908 ptr = strchr(buf, '\t');
913 while (*ptr == ' ' || *ptr == '\t')
922 static int mdt0_is_lustre_snapshot(struct snapshot_instance *si)
924 struct snapshot_target *st = si->si_mdt0;
925 char buf[MAX_BUF_SIZE];
929 memset(buf, 0, sizeof(buf));
930 snprintf(buf, sizeof(buf) - 1,
931 DRSH" '"DIMPORT"; "DZFS
932 " get -H -o value lustre:magic "DSSNAME"'",
933 PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
934 fp = popen(buf, "r");
936 SNAPSHOT_ADD_LOG(si, "Popen fail to check snapshot "
937 "on mdt0: %s\n", strerror(errno));
941 if (snapshot_fgets(fp, buf, strlen(SNAPSHOT_MAGIC) + 1) == NULL) {
943 } else if (strcmp(buf, SNAPSHOT_MAGIC) == 0) {
947 "The target %s is not Lustre snapshot "
948 "or it does not exists\n", si->si_ssname);
956 static int target_is_mounted(struct snapshot_instance *si,
957 struct snapshot_target *st, const char *ssname)
959 char buf[MAX_BUF_SIZE];
960 char fullname[MAX_BUF_SIZE];
965 memset(buf, 0, sizeof(buf));
966 snprintf(buf, sizeof(buf) - 1,
969 fp = popen(buf, "r");
971 SNAPSHOT_ADD_LOG(si, "Popen fail to check target mount: %s\n",
976 memset(fullname, 0, sizeof(fullname));
978 snprintf(fullname, sizeof(fullname) - 1,
980 PFSNAME(st), ssname);
982 snprintf(fullname, sizeof(fullname) - 1,
986 while (snapshot_fgets(fp, buf, sizeof(buf)) != NULL) {
987 ptr = strstr(buf, fullname);
991 ptr += strlen(fullname) + 1; /* mount point */
992 if (ptr >= buf + strlen(buf))
995 ptr = strstr(ptr, "type lustre");
1006 static int snapshot_get_fsname(struct snapshot_instance *si,
1007 char *fsname, int fslen)
1009 struct snapshot_target *st = si->si_mdt0;
1010 char buf[MAX_BUF_SIZE];
1014 memset(buf, 0, sizeof(buf));
1015 snprintf(buf, sizeof(buf) - 1,
1016 DRSH" '"DIMPORT"; "DZFS
1017 " get -H -o value lustre:fsname "DSSNAME"'",
1018 PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
1019 fp = popen(buf, "r");
1021 SNAPSHOT_ADD_LOG(si, "Popen fail to get fsname: %s\n",
1026 if (snapshot_fgets(fp, fsname, fslen) == NULL)
1033 static int snapshot_get_mgsnode(struct snapshot_instance *si,
1034 char *node, int size)
1036 char buf[MAX_BUF_SIZE];
1037 struct snapshot_target *st;
1041 st = list_entry(si->si_osts_list.next, struct snapshot_target,
1043 memset(buf, 0, sizeof(buf));
1044 snprintf(buf, sizeof(buf) - 1,
1045 DRSH" '"DZFS" get -H -o value lustre:mgsnode "DFSNAME"'",
1046 PRSH(si, st), PZFS(st), PFSNAME(st));
1047 fp = popen(buf, "r");
1049 SNAPSHOT_ADD_LOG(si, "Popen fail to get mgsnode: %s\n",
1054 if (snapshot_fgets(fp, node, size) == NULL)
1061 static int snapshot_exists_check(struct snapshot_instance *si,
1062 struct snapshot_target *st)
1064 char buf[MAX_BUF_SIZE];
1068 memset(buf, 0, sizeof(buf));
1069 snprintf(buf, sizeof(buf) - 1,
1070 DRSH" '"DZFS" list "DSSNAME" 2>/dev/null'",
1071 PRSH(si, st), PZFS(st), PSSNAME(si, st));
1072 fp = popen(buf, "r");
1074 SNAPSHOT_ADD_LOG(si, "Popen fail to create check: %s\n",
1079 if (snapshot_fgets(fp, buf, sizeof(buf)) != NULL)
1086 static int snapshot_general_check(struct snapshot_instance *si)
1088 return mdt0_is_lustre_snapshot(si);
1091 static void snapshot_create_usage(void)
1094 "Create snapshot for the given filesystem.\n"
1096 "snapshot_create [-b | --barrier [on | off]] "
1097 "[-c | --comment comment] "
1098 "<-F | --fsname fsname> "
1099 "[-h | --help] <-n | --name ssname> "
1100 "[-r | --rsh remote_shell]"
1101 "[-t | --timeout timeout]\n"
1103 "-b: set write barrier before creating snapshot, "
1104 "the default value is 'on'.\n"
1105 "-c: describe what the snapshot is for, and so on.\n"
1106 "-F: the filesystem name.\n"
1107 "-h: for help information.\n"
1108 "-n: the snapshot's name.\n"
1109 "-r: the remote shell used for communication with remote "
1110 "target, the default value is 'ssh'.\n"
1111 "-t: the life cycle (seconds) for write barrier, "
1112 "the default value is %d seconds.\n",
1113 BARRIER_TIMEOUT_DEFAULT);
1116 static int snapshot_create_check(struct snapshot_instance *si)
1120 rc = snapshot_exists_check(si, si->si_mdt0);
1122 fprintf(stderr, "The snapshot %s exists\n", si->si_ssname);
1127 static int snapshot_inherit_prop(struct snapshot_instance *si,
1128 struct snapshot_target *st,
1129 char *cmd, int size)
1131 char buf[MAX_BUF_SIZE];
1136 memset(buf, 0, sizeof(buf));
1137 snprintf(buf, sizeof(buf) - 1,
1138 DRSH" \""DIMPORT"; "DZFS
1139 " get all "DFSNAME" | grep lustre: | grep local$ | "
1140 "awk '{ \\$1=\\\"\\\"; \\$NF=\\\"\\\"; print \\$0 }' | "
1141 "sed -e 's/^ //'\"",
1142 PRSH(si, st), PIMPORT(st), PZFS(st), PFSNAME(st));
1143 fp = popen(buf, "r");
1145 SNAPSHOT_ADD_LOG(si, "Popen fail to list one: %s\n",
1150 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
1154 if (strncmp(buf, "lustre:fsname",
1155 strlen("lustre:fsname")) == 0)
1158 if (strncmp(buf, "lustre:magic",
1159 strlen("lustre:magic")) == 0)
1162 if (strncmp(buf, "lustre:ctime",
1163 strlen("lustre:ctime")) == 0)
1166 if (strncmp(buf, "lustre:mtime",
1167 strlen("lustre:mtime")) == 0)
1170 if (strncmp(buf, "lustre:comment",
1171 strlen("lustre:comment")) == 0)
1174 if (strncmp(buf, "lustre:svname",
1175 strlen("lustre:svname")) == 0)
1178 if (strncmp(buf, "lustre:mgsnode",
1179 strlen("lustre:mgsnode")) == 0)
1182 ptr = strchr(buf, ' ');
1184 ptr = strchr(buf, '\t');
1191 while (*ptr == ' ' || *ptr == '\t')
1197 end = strchr(ptr, ' ');
1199 end = strchr(buf, '\t');
1203 rc = snprintf(cmd + len, size - len - 1,
1204 "-o %s=\"%s\" ", buf, ptr);
1215 static int __snapshot_create(struct snapshot_instance *si,
1216 struct list_head *head, const char *fsname,
1217 const char *mgsnode, __u64 xtime)
1219 struct snapshot_target *st;
1223 list_for_each_entry(st, head, st_list) {
1230 SNAPSHOT_ADD_LOG(si, "Can't fork for create snapshot "
1231 "(%s@%s <%s>) on the target "
1233 fsname, si->si_ssname,
1234 si->si_comment, st->st_host,
1235 st->st_role, st->st_index,
1242 char cmd[MAX_BUF_SIZE];
1245 memset(cmd, 0, sizeof(cmd));
1246 len = snprintf(cmd, sizeof(cmd) - 1,
1247 DRSH" '"DZFS" snapshot "
1248 "-o lustre:fsname=%s "
1249 "-o lustre:magic=%s "
1250 "-o lustre:ctime=%llu "
1251 "-o lustre:mtime=%llu ",
1252 PRSH(si, st), PZFS(st), fsname,
1253 SNAPSHOT_MAGIC, xtime, xtime);
1257 if (si->si_comment) {
1258 rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
1259 "-o lustre:comment=\"%s\" ",
1267 /* Make the inherited properties as local ones,
1268 * then even if others changed (or removed) the
1269 * property of the parent dataset, the snapshot
1270 * will not be affected. */
1271 rc = snapshot_inherit_prop(si, st, cmd + len,
1272 MAX_BUF_SIZE - len - 1);
1274 SNAPSHOT_ADD_LOG(si, "Can't filter property on "
1275 "target (%s:%x:%d): rc = %d\n",
1276 st->st_host, st->st_role,
1283 if (st->st_role & SR_OST)
1284 rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
1285 "-o lustre:svname=%s-OST%04x "
1286 "-o lustre:mgsnode=%s "DSSNAME"'",
1287 fsname, st->st_index, mgsnode,
1289 else if (!(st->st_role & SR_MGS) ||
1290 /* MGS is on MDT0 */
1291 si->si_mdt0 == si->si_mgs)
1292 rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
1293 "-o lustre:svname=%s-MDT%04x "
1294 "-o lustre:mgsnode=%s "DSSNAME"'",
1295 fsname, st->st_index, mgsnode,
1299 rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
1300 DSSNAME"'", PSSNAME(si, st));
1304 rc = snapshot_exec(cmd);
1306 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
1307 "target (%s:%x:%d): rc = %d\n",
1308 cmd, st->st_host, st->st_role,
1312 } /* end of child */
1314 /* parent continue to run more snapshot commands in parallel. */
1321 static int __snapshot_destroy(struct snapshot_instance *si,
1322 struct list_head *head);
1324 static int snapshot_create(struct snapshot_instance *si)
1327 char buf[MAX_BUF_SIZE];
1334 rc = snapshot_create_check(si);
1338 rc = gettimeofday(&tv, NULL);
1342 srandom(tv.tv_usec);
1343 snprintf(new_fsname, sizeof(new_fsname), "%08x", (__u32)random());
1345 rc = snapshot_get_mgsnode(si, buf, sizeof(buf));
1349 __argv[1] = si->si_fsname;
1350 /* 1. Get barrier */
1351 if (si->si_barrier) {
1354 memset(tbuf, 0, sizeof(tbuf));
1355 snprintf(tbuf, 7, "%u", si->si_timeout);
1356 __argv[0] = "barrier_freeze";
1358 rc = jt_barrier_freeze(3, __argv);
1360 SNAPSHOT_ADD_LOG(si, "Can't set barrier within %u "
1361 "seconds on %s: rc = %d\n",
1362 si->si_timeout, si->si_fsname, rc);
1368 /* 2. Fork config llog on MGS */
1369 __argv[0] = "fork_lcfg";
1370 __argv[2] = new_fsname;
1371 rc = jt_lcfg_fork(3, __argv);
1373 SNAPSHOT_ADD_LOG(si, "Can't fork config log for create "
1374 "snapshot %s from %s to %s: rc = %d\n",
1375 si->si_ssname, si->si_fsname, new_fsname, rc);
1379 /* 3.1 Create snapshot on every MDT */
1380 rc = __snapshot_create(si, &si->si_mdts_list, new_fsname, buf,
1383 /* 3.2 Create snapshot on every OST */
1384 rc = __snapshot_create(si, &si->si_osts_list, new_fsname, buf,
1387 /* 4. Wait for all children, even though part of them maybe failed */
1388 snapshot_wait(si, &rc1);
1391 /* 5. Put barrier */
1392 if (si->si_barrier) {
1394 struct barrier_ctl bc;
1396 rc = __jt_barrier_stat(__argv[1], &bc);
1398 SNAPSHOT_ADD_LOG(si, "Can't get barrier status "
1401 } else if (bc.bc_status != BS_FROZEN ||
1402 bc.bc_timeout <= 0) {
1403 SNAPSHOT_ADD_LOG(si, "The barrier expired "
1404 "on %s\n", si->si_fsname);
1409 __argv[0] = "barrier_thaw";
1410 rc2 = jt_barrier_thaw(2, __argv);
1412 SNAPSHOT_ADD_LOG(si, "Can't release barrier on %s: "
1413 "rc = %d\n", si->si_fsname, rc2);
1418 si->si_force = true;
1419 __snapshot_destroy(si, &si->si_osts_list);
1420 __snapshot_destroy(si, &si->si_mdts_list);
1421 snapshot_wait(si, &rc2);
1423 __argv[0] = "erase_lcfg";
1424 __argv[1] = new_fsname;
1426 jt_lcfg_erase(3, __argv);
1429 return rc ? rc : (rc1 ? rc1 : rc2);
1432 int jt_snapshot_create(int argc, char **argv)
1434 struct snapshot_instance *si;
1435 struct option long_opts[] = {
1436 { .val = 'b', .name = "barrier", .has_arg = optional_argument },
1437 { .val = 'c', .name = "comment", .has_arg = required_argument },
1438 { .val = 'F', .name = "fsname", .has_arg = required_argument },
1439 { .val = 'h', .name = "help", .has_arg = no_argument },
1440 { .val = 'n', .name = "name", .has_arg = required_argument },
1441 { .val = 'r', .name = "rsh", .has_arg = required_argument },
1442 { .val = 't', .name = "timeout", .has_arg = required_argument },
1446 si = snapshot_init(argc, argv, long_opts, "b::c:F:hn:r:t:",
1447 snapshot_create_usage, LOCK_EX, &rc);
1451 if (!si->si_ssname) {
1453 "Miss the snapshot name to be created\n");
1454 snapshot_create_usage();
1459 rc = snapshot_create(si);
1462 "Can't create the snapshot %s\n", si->si_ssname);
1463 SNAPSHOT_ADD_LOG(si, "Can't create snapshot %s with "
1464 "comment <%s> barrier <%s>, timeout "
1466 si->si_ssname, si->si_comment,
1467 si->si_barrier ? "enable" : "disable",
1468 si->si_barrier ? si->si_timeout : -1, rc);
1470 SNAPSHOT_ADD_LOG(si, "Create snapshot %s successfully "
1471 "with comment <%s>, barrier <%s>, "
1473 si->si_ssname, si->si_comment,
1474 si->si_barrier ? "enable" : "disable",
1475 si->si_barrier ? si->si_timeout : -1);
1482 static void snapshot_destroy_usage(void)
1485 "Destroy the specified snapshot.\n"
1487 "snapshot_destroy [-f | --force] "
1488 "<-F | --fsname fsname> [-h | --help] "
1489 "<-n | --name ssname> "
1490 "[-r | --rsh remote_shell]\n"
1492 "-f: destroy the snapshot by force.\n"
1493 "-F: the filesystem name.\n"
1494 "-h: for help information.\n"
1495 "-n: the snapshot's name.\n"
1496 "-r: the remote shell used for communication with remote "
1497 "target, the default value is 'ssh'.\n");
1500 static int snapshot_destroy_check(struct snapshot_instance *si)
1502 struct list_head *head = &si->si_osts_list;
1503 struct snapshot_target *st;
1508 list_for_each_entry(st, head, st_list) {
1515 SNAPSHOT_ADD_LOG(si, "Can't fork for check snapshot "
1516 "%s on the target (%s:%x:%d): %s\n",
1517 si->si_ssname, st->st_host,
1518 st->st_role, st->st_index,
1525 rc = snapshot_exists_check(si, st);
1527 /* The snapshot piece does not exist */
1530 exit(rc == -EEXIST ? 0: rc);
1531 } /* end of child */
1533 /* parent continue to run more snapshot commands in parallel. */
1537 if (head == &si->si_osts_list) {
1538 head = &si->si_mdts_list;
1542 snapshot_wait(si, &rc);
1546 head = &si->si_osts_list;
1549 list_for_each_entry(st, head, st_list) {
1550 if (st->st_ignored && !si->si_force) {
1553 snapshot_role2name(name, st->st_role, st->st_index);
1555 "Miss snapshot piece on the %s. Use '-f' "
1556 "option if want to destroy it by force.\n",
1563 if (head == &si->si_osts_list) {
1564 head = &si->si_mdts_list;
1569 rc = snapshot_general_check(si);
1574 static int __snapshot_destroy(struct snapshot_instance *si,
1575 struct list_head *head)
1577 struct snapshot_target *st;
1581 list_for_each_entry(st, head, st_list) {
1590 SNAPSHOT_ADD_LOG(si, "Can't fork for destroy snapshot "
1591 "%s on the target (%s:%x:%d): %s\n",
1592 si->si_ssname, st->st_host,
1593 st->st_role, st->st_index,
1600 char cmd[MAX_BUF_SIZE];
1602 memset(cmd, 0, sizeof(cmd));
1604 snprintf(cmd, sizeof(cmd) - 1,
1605 DRSH" 'umount -f "DSSNAME
1606 " > /dev/null 2>&1; "DZFS
1607 " destroy -f "DSSNAME"'",
1608 PRSH(si, st), PSSNAME(si, st),
1609 PZFS(st), PSSNAME(si, st));
1611 snprintf(cmd, sizeof(cmd) - 1,
1612 DRSH" '"DZFS" destroy "DSSNAME"'",
1613 PRSH(si, st), PZFS(st),
1615 rc = snapshot_exec(cmd);
1617 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
1618 "target (%s:%x:%d): rc = %d\n",
1619 cmd, st->st_host, st->st_role,
1623 } /* end of child */
1625 /* parent continue to run more snapshot commands in parallel. */
1632 static int snapshot_destroy(struct snapshot_instance *si)
1640 rc = snapshot_destroy_check(si);
1644 rc = snapshot_get_fsname(si, fsname, sizeof(fsname));
1648 /* 1.1 Destroy snapshot on every OST */
1649 rc = __snapshot_destroy(si, &si->si_osts_list);
1650 if (!si->si_force) {
1654 __snapshot_wait(si, &si->si_osts_list, &rc);
1659 /* 1.2 Destroy snapshot on every MDT */
1660 rc1 = __snapshot_destroy(si, &si->si_mdts_list);
1662 /* 2 Wait for all children, even though part of them maybe failed */
1663 snapshot_wait(si, &rc2);
1664 if (rc2 == -ENOENT && si->si_force)
1667 /* 3. Erase config llog from MGS */
1668 if ((!rc && !rc1 && !rc2) || si->si_force) {
1671 __argv[0] = "erase_lcfg";
1674 rc3 = jt_lcfg_erase(3, __argv);
1675 if (rc3 && errno == ENOENT)
1678 SNAPSHOT_ADD_LOG(si, "Can't erase config for destroy "
1679 "snapshot %s, fsname %s: rc = %d\n",
1680 si->si_ssname, fsname, rc3);
1683 return rc ? rc : (rc1 ? rc1 : (rc2 ? rc2 : rc3));
1686 int jt_snapshot_destroy(int argc, char **argv)
1688 struct snapshot_instance *si;
1689 struct option long_opts[] = {
1690 { .val = 'f', .name = "force", .has_arg = no_argument },
1691 { .val = 'F', .name = "fsname", .has_arg = required_argument },
1692 { .val = 'h', .name = "help", .has_arg = no_argument },
1693 { .val = 'n', .name = "name", .has_arg = required_argument },
1694 { .val = 'r', .name = "rsh", .has_arg = required_argument },
1698 si = snapshot_init(argc, argv, long_opts, "fF:hn:r:",
1699 snapshot_destroy_usage, LOCK_EX, &rc);
1703 if (!si->si_ssname) {
1705 "Miss the snapshot name to be destroyed\n");
1706 snapshot_destroy_usage();
1711 rc = snapshot_destroy(si);
1714 "Can't destroy the snapshot %s\n", si->si_ssname);
1715 SNAPSHOT_ADD_LOG(si, "Can't destroy snapshot %s with "
1716 "force <%s>: %d\n", si->si_ssname,
1717 si->si_force ? "enable" : "disable", rc);
1719 SNAPSHOT_ADD_LOG(si, "Destroy snapshot %s successfully "
1720 "with force <%s>\n", si->si_ssname,
1721 si->si_force ? "enable" : "disable");
1728 static void snapshot_modify_usage(void)
1731 "Change the specified snapshot's name and/or comment.\n"
1733 "snapshot_modify [-c | --comment comment] "
1734 "<-F | --fsname fsname> [-h | --help] "
1735 "<-n | --name ssname> [-N | --new new_ssname] "
1736 "[-r | --rsh remote_shell]\n"
1738 "-c: update the snapshot's comment.\n"
1739 "-F: the filesystem name.\n"
1740 "-h: for help information.\n"
1741 "-n: the snapshot's name.\n"
1742 "-N: rename the snapshot's name as the new_ssname.\n"
1743 "-r: the remote shell used for communication with remote "
1744 "target, the default value is 'ssh'.\n");
1747 static int snapshot_modify_check(struct snapshot_instance *si)
1751 if (si->si_new_ssname &&
1752 strcmp(si->si_ssname, si->si_new_ssname) == 0) {
1753 fprintf(stderr, "The new snapshot's name is the same as "
1754 "the old one %s %s.\n",
1755 si->si_ssname, si->si_new_ssname);
1759 if (!si->si_new_ssname && !si->si_comment) {
1760 fprintf(stderr, "Miss options, nothing to be changed.\n");
1764 rc = mdt0_is_lustre_snapshot(si);
1765 if (!rc && si->si_new_ssname) {
1766 rc = target_is_mounted(si, si->si_mdt0, si->si_ssname);
1769 "snapshot %s is mounted, can't be renamed.\n",
1778 static int __snapshot_modify(struct snapshot_instance *si,
1779 struct list_head *head, __u64 xtime)
1781 struct snapshot_target *st;
1785 list_for_each_entry(st, head, st_list) {
1792 SNAPSHOT_ADD_LOG(si, "Can't fork for modify snapshot "
1793 "(%s|%s, <%s>) on the target "
1795 si->si_ssname, si->si_new_ssname,
1796 si->si_comment, st->st_host,
1797 st->st_role, st->st_index,
1804 char cmd[MAX_BUF_SIZE];
1806 memset(cmd, 0, sizeof(cmd));
1807 if (si->si_new_ssname && si->si_comment)
1808 snprintf(cmd, sizeof(cmd) - 1,
1809 DRSH" '"DIMPORT"; "DZFS" rename "
1810 DSSNAME" "DSSNAME" && "DZFS
1811 " set lustre:comment=\"%s\" "DSSNAME
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), si->si_comment,
1817 PSS_NEW(si, st), PZFS(st), xtime,
1819 else if (si->si_new_ssname)
1820 snprintf(cmd, sizeof(cmd) - 1,
1821 DRSH" '"DIMPORT"; "DZFS
1822 " rename "DSSNAME" "DSSNAME" && "DZFS
1823 " set lustre:mtime=%llu "DSSNAME"'",
1824 PRSH(si, st), PIMPORT(st), PZFS(st),
1825 PSSNAME(si, st), PSS_NEW(si, st),
1826 PZFS(st), xtime, PSS_NEW(si, st));
1827 else if (si->si_comment)
1828 snprintf(cmd, sizeof(cmd) - 1,
1829 DRSH" '"DIMPORT"; "DZFS
1830 " set lustre:comment=\"%s\" "DSSNAME
1832 " set lustre:mtime=%llu "DSSNAME"'",
1833 PRSH(si, st), PIMPORT(st), PZFS(st),
1834 si->si_comment, PSSNAME(si, st),
1835 PZFS(st), xtime, PSSNAME(si, st));
1839 rc = snapshot_exec(cmd);
1841 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
1842 "target (%s:%x:%d): rc = %d\n",
1843 cmd, st->st_host, st->st_role,
1847 } /* end of child */
1849 /* parent continue to run more snapshot commands in parallel. */
1856 static int snapshot_modify(struct snapshot_instance *si)
1862 rc = snapshot_modify_check(si);
1868 /* Modify snapshot on every MDT */
1869 rc = __snapshot_modify(si, &si->si_mdts_list, (__u64)tt);
1871 /* Modify snapshot on every OST */
1872 rc = __snapshot_modify(si, &si->si_osts_list, (__u64)tt);
1874 /* Wait for all children, even though part of them maybe failed */
1875 snapshot_wait(si, &rc1);
1877 return rc ? rc : rc1;
1880 int jt_snapshot_modify(int argc, char **argv)
1882 struct snapshot_instance *si;
1883 struct option long_opts[] = {
1884 { .val = 'c', .name = "comment", .has_arg = required_argument },
1885 { .val = 'F', .name = "fsname", .has_arg = required_argument },
1886 { .val = 'h', .name = "help", .has_arg = no_argument },
1887 { .val = 'n', .name = "name", .has_arg = required_argument },
1888 { .val = 'N', .name = "new", .has_arg = required_argument },
1889 { .val = 'r', .name = "rsh", .has_arg = required_argument },
1893 si = snapshot_init(argc, argv, long_opts, "c:F:hn:N:r:",
1894 snapshot_modify_usage, LOCK_EX, &rc);
1898 if (!si->si_ssname) {
1900 "Miss the snapshot name to be modified\n");
1901 snapshot_modify_usage();
1906 rc = snapshot_modify(si);
1909 "Can't modify the snapshot %s\n", si->si_ssname);
1910 SNAPSHOT_ADD_LOG(si, "Can't modify snapshot %s with "
1911 "name <%s>, comment <%s>: %d\n",
1912 si->si_ssname, si->si_new_ssname,
1913 si->si_comment, rc);
1915 SNAPSHOT_ADD_LOG(si, "Modify snapshot %s successfully "
1916 "with name <%s>, comment <%s>\n",
1917 si->si_ssname, si->si_new_ssname,
1925 static void snapshot_list_usage(void)
1928 "List the specified snapshot or all snapshots.\n"
1930 "snapshot_list [-d | --detail] "
1931 "<-F | --fsname fsname> [-h | --help] "
1932 "[-n | --name ssname] [-r | --rsh remote_shell]\n"
1934 "-d: list every piece for the specified snapshot.\n"
1935 "-F: the filesystem name.\n"
1936 "-h: for help information.\n"
1937 "-n: the snapshot's name.\n"
1938 "-r: the remote shell used for communication with remote "
1939 "target, the default value is 'ssh'.\n");
1942 static int snapshot_list_one(struct snapshot_instance *si,
1943 struct snapshot_target *st)
1945 char buf[MAX_BUF_SIZE];
1949 memset(buf, 0, sizeof(buf));
1950 snprintf(buf, sizeof(buf) - 1,
1951 DRSH" \""DIMPORT"; "DZFS
1952 " get all "DSSNAME" | grep lustre: | grep local$ | "
1953 "awk '{ \\$1=\\\"\\\"; \\$NF=\\\"\\\"; print \\$0 }' | "
1954 "sed -e 's/^ //'\"",
1955 PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
1956 fp = popen(buf, "r");
1958 SNAPSHOT_ADD_LOG(si, "Popen fail to list one: %s\n",
1963 if (si->si_detail) {
1966 snapshot_role2name(name, st->st_role, st->st_index);
1967 printf("\nsnapshot_role: %s\n", name);
1970 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
1974 if (strncmp(buf, "lustre:fsname",
1975 strlen("lustre:fsname")) == 0) {
1976 ptr = snapshot_first_skip_blank(buf);
1978 printf("snapshot_fsname: %s\n", ptr);
1982 if (strncmp(buf, "lustre:comment",
1983 strlen("lustre:comment")) == 0) {
1984 ptr = snapshot_first_skip_blank(buf);
1986 printf("comment: %s\n", ptr);
1990 if (strncmp(buf, "lustre:ctime",
1991 strlen("lustre:ctime")) == 0) {
1992 ptr = snapshot_first_skip_blank(buf);
1994 sscanf(ptr, "%llu", &xtime);
1995 printf("create_time: %s",
1996 ctime((time_t *)&xtime));
2001 if (strncmp(buf, "lustre:mtime",
2002 strlen("lustre:mtime")) == 0) {
2003 ptr = snapshot_first_skip_blank(buf);
2005 sscanf(ptr, "%llu", &xtime);
2006 printf("modify_time: %s",
2007 ctime((time_t *)&xtime));
2014 rc = target_is_mounted(si, st, si->si_ssname);
2016 printf("status: unknown\n");
2018 printf("status: not mount\n");
2020 printf("status: mounted\n");
2025 static int __snapshot_list(struct snapshot_instance *si,
2026 struct list_head *head)
2028 struct snapshot_target *st;
2031 list_for_each_entry(st, head, st_list) {
2034 rc1 = snapshot_list_one(si, st);
2035 if (rc1 < 0 || rc >= 0)
2042 static int snapshot_list(struct snapshot_instance *si)
2046 rc = snapshot_general_check(si);
2050 printf("\nfilesystem_name: %s\nsnapshot_name: %s\n",
2051 si->si_fsname, si->si_ssname);
2053 if (!si->si_detail) {
2054 rc = snapshot_list_one(si, si->si_mdt0);
2058 rc = __snapshot_list(si, &si->si_mdts_list);
2059 rc1 = __snapshot_list(si, &si->si_osts_list);
2064 return rc < 0 ? rc : 0;
2067 static int snapshot_list_all(struct snapshot_instance *si)
2069 struct snapshot_target *st = si->si_mdt0;
2070 struct list_sub_item {
2071 struct list_head lsi_list;
2075 struct list_head list_sub_items;
2076 struct list_sub_item *lsi;
2077 char buf[MAX_BUF_SIZE];
2081 INIT_LIST_HEAD(&list_sub_items);
2082 memset(buf, 0, sizeof(buf));
2083 snprintf(buf, sizeof(buf) - 1,
2084 DRSH" \""DZFS" get -H -r lustre:magic "DFSNAME
2085 " | grep %s | awk '{ print \\$1 }' | cut -d@ -f2\"",
2086 PRSH(si, st), PZFS(st), PFSNAME(st), SNAPSHOT_MAGIC);
2087 fp = popen(buf, "r");
2089 SNAPSHOT_ADD_LOG(si, "Popen fail to list ssnames: %s\n",
2094 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
2095 int len = strlen(buf);
2097 lsi = malloc(len + 1 + sizeof(struct list_sub_item));
2099 SNAPSHOT_ADD_LOG(si, "NOT enough memory\n");
2104 strncpy(lsi->lsi_ssname, buf, len);
2105 lsi->lsi_ssname[len] = '\0';
2106 list_add(&lsi->lsi_list, &list_sub_items);
2110 while (!list_empty(&list_sub_items)) {
2111 lsi = list_entry(list_sub_items.next,
2112 struct list_sub_item, lsi_list);
2113 list_del(&lsi->lsi_list);
2115 si->si_ssname = lsi->lsi_ssname;
2116 rc = snapshot_list(si);
2117 si->si_ssname = NULL;
2126 int jt_snapshot_list(int argc, char **argv)
2128 struct snapshot_instance *si;
2129 struct option long_opts[] = {
2130 { .val = 'd', .name = "detail", .has_arg = no_argument },
2131 { .val = 'F', .name = "fsname", .has_arg = required_argument },
2132 { .val = 'h', .name = "help", .has_arg = no_argument },
2133 { .val = 'n', .name = "name", .has_arg = required_argument },
2134 { .val = 'r', .name = "rsh", .has_arg = required_argument },
2138 si = snapshot_init(argc, argv, long_opts, "dF:hn:r:",
2139 snapshot_list_usage, LOCK_SH, &rc);
2144 rc = snapshot_list(si);
2146 rc = snapshot_list_all(si);
2150 "Can't list the snapshot %s\n", si->si_ssname);
2151 SNAPSHOT_ADD_LOG(si, "Can't list snapshot %s with detail "
2152 "<%s>: %d\n", si->si_ssname,
2153 si->si_detail ? "yes" : "no", rc);
2160 static void snapshot_mount_usage(void)
2163 "Mount the specified snapshot.\n"
2165 "snapshot_mount <-F | --fsname fsname> [-h | --help] "
2166 "<-n | --name ssname> "
2167 "[-r | --rsh remote_shell]\n"
2169 "-F: the filesystem name.\n"
2170 "-h: for help information.\n"
2171 "-n: the snapshot's name.\n"
2172 "-r: the remote shell used for communication with remote "
2173 "target, the default value is 'ssh'.\n");
2176 static int snapshot_mount_check(struct snapshot_instance *si, char *fsname,
2177 int fslen, bool *mgs_running)
2181 rc = mdt0_is_lustre_snapshot(si);
2185 rc = snapshot_get_fsname(si, fsname, fslen);
2189 rc = target_is_mounted(si, si->si_mgs, NULL);
2191 *mgs_running = true;
2198 static int snapshot_mount_target(struct snapshot_instance *si,
2199 struct snapshot_target *st, const char *optstr)
2201 char cmd[MAX_BUF_SIZE];
2205 rc = target_is_mounted(si, st, si->si_ssname);
2212 memset(cmd, 0, sizeof(cmd));
2213 memset(name, 0, sizeof(name));
2214 snapshot_role2name(name, st->st_role, st->st_index);
2215 snprintf(cmd, sizeof(cmd) - 1,
2216 DRSH" '"DIMPORT"; mkdir -p /mnt/%s_%s && mount -t lustre "
2217 "-o rdonly_dev%s "DSSNAME" /mnt/%s_%s'",
2218 PRSH(si, st), PIMPORT(st), si->si_ssname, name,
2219 st != si->si_mdt0 ? "" : optstr, PSSNAME(si, st),
2220 si->si_ssname, name);
2221 rc = snapshot_exec(cmd);
2223 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on the target "
2224 "(%s:%x:%d): rc = %d\n", cmd, st->st_host,
2225 st->st_role, st->st_index, rc);
2230 static int __snapshot_mount(struct snapshot_instance *si,
2231 struct list_head *head)
2233 struct snapshot_target *st;
2237 list_for_each_entry(st, head, st_list) {
2238 if (st == si->si_mgs || st == si->si_mdt0)
2247 SNAPSHOT_ADD_LOG(si, "Can't fork for mount snapshot "
2248 "%s on target (%s:%x:%d): %s\n",
2249 si->si_ssname, st->st_host,
2250 st->st_role, st->st_index,
2257 rc = snapshot_mount_target(si, st, "");
2261 /* parent continue to run more snapshot commands in parallel. */
2268 static int __snapshot_umount(struct snapshot_instance *si,
2269 struct list_head *head);
2271 static int snapshot_mount(struct snapshot_instance *si)
2273 struct snapshot_target *st;
2279 bool mdt0_mounted = false;
2280 bool mgs_running = false;
2282 rc = snapshot_mount_check(si, fsname, sizeof(fsname), &mgs_running);
2285 "Can't mount the snapshot %s: %s\n",
2286 si->si_ssname, strerror(-rc));
2290 /* 1. MGS is not mounted yet, mount the MGS firstly */
2291 si->si_mgs->st_ignored = 0;
2292 si->si_mgs->st_pid = 0;
2294 rc = snapshot_mount_target(si, si->si_mgs, "");
2296 si->si_mgs->st_ignored = 1;
2302 "Can't mount the snapshot %s: %s\n",
2303 si->si_ssname, strerror(-rc));
2307 if (si->si_mgs == si->si_mdt0)
2308 mdt0_mounted = true;
2311 /* 2. Mount MDT0 if it is not combined with the MGS. */
2312 if (!mdt0_mounted) {
2313 si->si_mdt0->st_ignored = 0;
2314 si->si_mdt0->st_pid = 0;
2315 rc = snapshot_mount_target(si, si->si_mdt0, ",nomgs");
2320 /* 3.1 Mount other MDTs in parallel */
2321 rc = __snapshot_mount(si, &si->si_mdts_list);
2323 /* 3.2 Mount OSTs in parallel */
2324 rc = __snapshot_mount(si, &si->si_osts_list);
2326 /* Wait for all children, even though part of them maybe failed */
2327 failed = snapshot_wait(si, &rc1);
2329 list_for_each_entry(st, &si->si_mdts_list, st_list) {
2330 if (!st->st_ignored)
2334 list_for_each_entry(st, &si->si_osts_list, st_list) {
2335 if (!st->st_ignored)
2343 __snapshot_umount(si, &si->si_mdts_list);
2344 __snapshot_umount(si, &si->si_osts_list);
2345 snapshot_wait(si, &rc2);
2349 "Can't mount the snapshot %s: %s\n",
2350 si->si_ssname, strerror(-rc));
2353 "%d of %d pieces of the snapshot %s "
2354 "can't be mounted: %s\n",
2355 failed, needed, si->si_ssname, strerror(-rc1));
2357 return rc ? rc : rc1;
2362 "The snapshot %s has already been mounted by other\n",
2367 fprintf(stdout, "mounted the snapshot %s with fsname %s\n",
2368 si->si_ssname, fsname);
2373 int jt_snapshot_mount(int argc, char **argv)
2375 struct snapshot_instance *si;
2376 struct option long_opts[] = {
2377 { .val = 'F', .name = "fsname", .has_arg = required_argument },
2378 { .val = 'h', .name = "help", .has_arg = no_argument },
2379 { .val = 'n', .name = "name", .has_arg = required_argument },
2380 { .val = 'r', .name = "rsh", .has_arg = required_argument },
2384 si = snapshot_init(argc, argv, long_opts, "F:hn:r:",
2385 snapshot_mount_usage, LOCK_EX, &rc);
2389 if (!si->si_ssname) {
2391 "Miss the snapshot name to be mounted\n");
2392 snapshot_mount_usage();
2397 rc = snapshot_mount(si);
2399 SNAPSHOT_ADD_LOG(si, "Can't mount snapshot %s: %d\n",
2402 SNAPSHOT_ADD_LOG(si, "The snapshot %s is mounted\n",
2410 static void snapshot_umount_usage(void)
2413 "Umount the specified snapshot.\n"
2415 "snapshot_umount <-F | --fsname fsname> [-h | --help] "
2416 "<-n | --name ssname> "
2417 "[-r | --rsh remote_shell]\n"
2419 "-F: the filesystem name.\n"
2420 "-h: for help information.\n"
2421 "-n: the snapshot's name.\n"
2422 "-r: the remote shell used for communication with remote "
2423 "target, the default value is 'ssh'.\n");
2426 static int __snapshot_umount(struct snapshot_instance *si,
2427 struct list_head *head)
2429 struct snapshot_target *st;
2433 list_for_each_entry(st, head, st_list) {
2440 SNAPSHOT_ADD_LOG(si, "Can't fork for umount snapshot "
2441 "%s on target (%s:%x:%d): %s\n",
2442 si->si_ssname, st->st_host,
2443 st->st_role, st->st_index,
2450 char cmd[MAX_BUF_SIZE];
2452 rc = target_is_mounted(si, st, si->si_ssname);
2459 memset(cmd, 0, sizeof(cmd));
2460 snprintf(cmd, sizeof(cmd) - 1,
2461 DRSH" 'umount "DSSNAME"'",
2462 PRSH(si, st), PSSNAME(si, st));
2463 rc = snapshot_exec(cmd);
2468 /* parent continue to run more snapshot commands in parallel. */
2475 static int snapshot_umount(struct snapshot_instance *si)
2477 struct snapshot_target *st;
2484 rc = snapshot_general_check(si);
2487 "Can't umount the snapshot %s: %s\n",
2488 si->si_ssname, strerror(-rc));
2492 rc = __snapshot_umount(si, &si->si_mdts_list);
2493 rc1 = __snapshot_umount(si, &si->si_osts_list);
2494 failed = snapshot_wait(si, &rc2);
2496 list_for_each_entry(st, &si->si_mdts_list, st_list) {
2497 if (!st->st_ignored)
2501 list_for_each_entry(st, &si->si_osts_list, st_list) {
2502 if (!st->st_ignored)
2508 "The snapshot %s has not been mounted\n",
2515 "%d of %d pieces of the snapshot %s "
2516 "can't be umounted: %s\n",
2517 failed, needed, si->si_ssname, strerror(-rc2));
2519 return rc ? rc : (rc1 ? rc1 : rc2);
2522 int jt_snapshot_umount(int argc, char **argv)
2524 struct snapshot_instance *si;
2525 struct option long_opts[] = {
2526 { .val = 'F', .name = "fsname", .has_arg = required_argument },
2527 { .val = 'h', .name = "help", .has_arg = no_argument },
2528 { .val = 'n', .name = "name", .has_arg = required_argument },
2529 { .val = 'r', .name = "rsh", .has_arg = required_argument },
2533 si = snapshot_init(argc, argv, long_opts, "F:hn:r:",
2534 snapshot_umount_usage, LOCK_EX, &rc);
2538 if (!si->si_ssname) {
2540 "Miss the snapshot name to be umounted\n");
2541 snapshot_umount_usage();
2546 rc = snapshot_umount(si);
2548 SNAPSHOT_ADD_LOG(si, "Can't umount snapshot %s: %d\n",
2551 SNAPSHOT_ADD_LOG(si, "the snapshot %s have been umounted\n",