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, '/');
247 st->st_dir = strdup(ptr);
255 st->st_pool = strdup(ptr);
262 * fsname-<role><index> or <role><index> */
263 ptr = strrchr(label, '-');
265 if (strncmp(si->si_fsname, label, ptr - label) != 0) {
266 /* This line is NOT for current filesystem .*/
276 if (strlen(ptr) < 3 || strlen(ptr) > 7) {
287 strncpy(*role, ptr, 3);
291 while (isxdigit(ptr[len])) {
292 if (isdigit(ptr[len]))
294 st->st_index * 16 + ptr[len] - '0';
295 else if (isupper(ptr[len]))
297 st->st_index * 16 + ptr[len] - 'A' + 10;
300 st->st_index * 16 + ptr[len] - 'a' + 10;
305 if (strncasecmp(*role, "MGS", 3) != 0)
313 if (!isxdigit(ptr[len]) && ptr[len] != '\0') {
328 * For old snasphot tools, the configration is in /etc/lsnapshot/${fsname}.conf,
330 * <host> <pool_dir> <pool> <local_fsname> <role(,s)> <index>
334 * host-mdt1 /tmp myfs-mdt1 mdt1 MGS,MDT 0
335 * host-mdt2 /tmp myfs-mdt2 mdt2 MDT 1
336 * host-ost1 /tmp myfs-ost1 ost1 OST 0
337 * host-ost2 /tmp myfs-ost2 ost2 OST 1
340 * For new snasphot tools, the configration is in /etc/ldev.conf, which is not
341 * only for snapshot, but also for other purpose. The format is:
342 * <host> foreign/- <label> <device> [journal-path]/- [raidtab]
344 * The format of <label> is:
345 * fsname-<role><index> or <role><index>
347 * The format of <device> is:
348 * [md|zfs:][pool_dir/]<pool>/<filesystem>
350 * Snapshot only uses the fields <host>, <label> and <device>.
354 * host-mdt1 - myfs-MDT0000 zfs:/tmp/myfs-mdt1/mdt1
357 * \retval 0 for success
358 * \retval +ve the line# with which the current line is conflict
359 * \retval -EAGAIN skip current line
360 * \retval -ve other failures
362 static int snapshot_load_conf_one(struct snapshot_instance *si,
363 char *buf, int line_num, bool is_ldev)
365 struct snapshot_target *st;
370 path = getenv("PATH");
374 memset(snapshot_path, 0, sizeof(snapshot_path));
375 snprintf(snapshot_path, sizeof(snapshot_path) - 1, "PATH='%s'", path);
377 /* filter out space */
378 while (isspace(*buf))
381 /* skip empty line */
385 /* skip comment line */
389 st = malloc(sizeof(*st));
393 memset(st, 0, sizeof(*st));
394 INIT_LIST_HEAD(&st->st_list);
397 rc = snapshot_load_conf_ldev(si, buf, st, &role);
399 rc = sscanf(buf, "%ms %ms %ms %ms %ms %d",
400 &st->st_host, &st->st_dir, &st->st_pool,
401 &st->st_filesystem, &role, &st->st_index);
410 if (strncasecmp(role, "MGS", 3) == 0) {
411 st->st_role = SR_MGS;
412 if (role[3] == ',') {
414 if (strncasecmp(&role[4], "MDT", 3) != 0) {
419 st->st_role |= SR_MDT;
421 } else if (strncasecmp(role, "MDT", 3) == 0) {
422 st->st_role = SR_MDT;
423 if (role[3] == ',') {
425 if (strncasecmp(&role[4], "MGS", 3) != 0) {
430 st->st_role |= SR_MGS;
432 } else if (strncasecmp(role, "OST", 3) == 0) {
433 st->st_role = SR_OST;
439 st->st_line = line_num;
440 if (st->st_role & SR_MDT) {
441 /* MGS is the first, MDT0 is just after the MGS
442 * if they are not combined together. */
443 if (st->st_role & SR_MGS) {
445 rc = si->si_mgs->st_line;
450 list_add(&st->st_list, &si->si_mdts_list);
453 if (st->st_index == 0) {
455 rc = si->si_mdt0->st_line;
460 if (list_empty(&st->st_list)) {
461 if (list_empty(&si->si_mdts_list) ||
463 list_add(&st->st_list,
466 list_add(&st->st_list,
467 &si->si_mgs->st_list);
469 } else if (list_empty(&st->st_list)) {
470 list_add_tail(&st->st_list, &si->si_mdts_list);
472 } else if (st->st_role & SR_MGS) {
474 rc = si->si_mgs->st_line;
479 list_add(&st->st_list, &si->si_mdts_list);
481 list_add_tail(&st->st_list, &si->si_osts_list);
495 if (st->st_filesystem)
496 free(st->st_filesystem);
503 static int snapshot_load_conf(struct snapshot_instance *si, int lock_mode)
506 char buf[MAX_BUF_SIZE];
513 memset(conf_name, 0, sizeof(conf_name));
514 strncpy(conf_name, LDEV_CONF, sizeof(conf_name) - 1);
515 fd = open(conf_name, O_RDONLY);
517 if (errno != ENOENT) {
519 "Can't open the snapshot config file %s: %s\n",
520 conf_name, strerror(errno));
525 snprintf(conf_name, sizeof(conf_name) - 1, "%s/%s.conf",
526 SNAPSHOT_CONF_DIR, si->si_fsname);
527 fd = open(conf_name, O_RDONLY);
530 "Can't open the snapshot config file %s: %s\n",
531 conf_name, strerror(errno));
539 rc = flock(fd, lock_mode | LOCK_NB);
542 "Can't lock the snapshot config file %s (%d): %s\n",
543 conf_name, lock_mode, strerror(errno));
548 fp = fdopen(fd, "r");
551 "Can't fdopen the snapshot config file %s: %s\n",
552 conf_name, strerror(errno));
557 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
558 rc = snapshot_load_conf_one(si, buf, line_num, is_ldev);
561 "Invalid snapshot config file %s at the line "
562 "%d '%s'\n", conf_name, line_num, buf);
563 } else if (rc == -EAGAIN) {
567 "The config role has been specified repeatedly "
568 "at the lines %d/%d in %s\n",
569 rc, line_num, conf_name);
581 "Miss MDT0 in the config file %s\n",
587 /* By default, the MGS is on the MDT0 if it is not specified. */
589 si->si_mgs = si->si_mdt0;
590 si->si_mgs->st_role |= SR_MGS;
593 if (list_empty(&si->si_osts_list)) {
595 "Miss OST(s) in the config file %s\n",
614 static void snapshot_unload_conf(struct snapshot_instance *si)
616 struct snapshot_target *st;
618 while (!list_empty(&si->si_mdts_list)) {
619 st = list_entry(si->si_mdts_list.next,
620 struct snapshot_target, st_list);
621 list_del(&st->st_list);
625 free(st->st_filesystem);
629 while (!list_empty(&si->si_osts_list)) {
630 st = list_entry(si->si_osts_list.next,
631 struct snapshot_target, st_list);
632 list_del(&st->st_list);
636 free(st->st_filesystem);
643 if (si->si_conf_fd >= 0) {
644 flock(si->si_conf_fd, LOCK_UN);
645 close(si->si_conf_fd);
650 static int snapshot_handle_string_option(char **dst, const char *option,
651 const char *opt_name)
653 if (*dst && *dst != snapshot_rsh_default) {
655 "%s option has been specified repeatedly.\n", opt_name);
659 *dst = strdup(option);
665 static void snapshot_fini(struct snapshot_instance *si)
667 snapshot_unload_conf(si);
670 fclose(si->si_log_fp);
672 if (si->si_rsh && si->si_rsh != snapshot_rsh_default)
678 if (si->si_new_ssname)
679 free(si->si_new_ssname);
681 free(si->si_comment);
686 static struct snapshot_instance *
687 snapshot_init(int argc, char * const argv[], const struct option *longopts,
688 const char *optstring, void (*usage)(void),
689 int lock_mode, int *err)
691 struct snapshot_instance *si;
696 si = malloc(sizeof(*si));
699 "No enough memory to initialize snapshot instance.\n");
704 memset(si, 0, sizeof(*si));
705 INIT_LIST_HEAD(&si->si_mdts_list);
706 INIT_LIST_HEAD(&si->si_osts_list);
707 si->si_rsh = (char *)snapshot_rsh_default;
709 si->si_timeout = BARRIER_TIMEOUT_DEFAULT;
710 si->si_barrier = true;
711 si->si_detail = false;
712 si->si_force = false;
714 while ((opt = getopt_long(argc, argv, optstring,
715 longopts, &idx)) != EOF) {
718 if (!optarg || strcmp(optarg, "on") == 0) {
719 si->si_barrier = true;
720 } else if (strcmp(optarg, "off") == 0) {
721 si->si_barrier = false;
729 *err = snapshot_handle_string_option(&si->si_comment,
735 si->si_detail = true;
741 *err = snapshot_handle_string_option(&si->si_fsname,
747 *err = snapshot_handle_string_option(&si->si_ssname,
753 *err = snapshot_handle_string_option(&si->si_new_ssname,
760 *err = snapshot_handle_string_option(&si->si_rsh,
767 si->si_timeout = atoi(optarg);
781 if (!si->si_fsname) {
782 fprintf(stderr, "The fsname must be specified\n");
788 if (strlen(si->si_fsname) > 8) {
789 fprintf(stderr, "Invalid fsname %s\n", si->si_fsname);
794 si->si_log_fp = fopen(SNAPSHOT_LOG, "a");
795 if (!si->si_log_fp) {
798 "Can't open the snapshot log file %s: %s\n",
799 SNAPSHOT_LOG, strerror(errno));
803 *err = snapshot_load_conf(si, lock_mode);
806 if (*err != 0 && si) {
814 static int __snapshot_wait(struct snapshot_instance *si,
815 struct list_head *head, int *err)
817 struct snapshot_target *st;
821 list_for_each_entry(st, head, st_list) {
825 rc = waitpid(st->st_pid, &st->st_status, 0);
827 SNAPSHOT_ADD_LOG(si, "Can't wait child (%d) operation "
828 "on the target <%s:%x:%d>: %s\n",
829 st->st_pid, st->st_host, st->st_role,
830 st->st_index, strerror(errno));
836 /* continue to wait for next */
840 if (WIFEXITED(st->st_status)) {
841 rc = WEXITSTATUS(st->st_status);
846 st->st_ignored = true;
852 } else if (WIFSIGNALED(st->st_status)) {
853 SNAPSHOT_ADD_LOG(si, "The child (%d) operation on the "
854 "target <%s:%x:%d> was killed by "
856 st->st_pid, st->st_host, st->st_role,
857 st->st_index, WTERMSIG(st->st_status));
862 SNAPSHOT_ADD_LOG(si, "The child (%d) operation on the "
863 "target <%s:%x:%d> failed for "
865 st->st_pid, st->st_host, st->st_role,
878 static int snapshot_wait(struct snapshot_instance *si, int *err)
882 count = __snapshot_wait(si, &si->si_mdts_list, err);
883 count += __snapshot_wait(si, &si->si_osts_list, err);
888 static char *snapshot_first_skip_blank(char *buf)
892 ptr = strchr(buf, ' ');
894 ptr = strchr(buf, '\t');
899 while (*ptr == ' ' || *ptr == '\t')
908 static int mdt0_is_lustre_snapshot(struct snapshot_instance *si)
910 struct snapshot_target *st = si->si_mdt0;
911 char buf[MAX_BUF_SIZE * 3];
915 memset(buf, 0, sizeof(buf));
916 snprintf(buf, sizeof(buf) - 1,
917 DRSH" '"DIMPORT"; "DZFS
918 " get -H -o value lustre:magic "DSSNAME"'",
919 PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
920 fp = popen(buf, "r");
922 SNAPSHOT_ADD_LOG(si, "Popen fail to check snapshot "
923 "on mdt0: %s\n", strerror(errno));
927 if (snapshot_fgets(fp, buf, strlen(SNAPSHOT_MAGIC) + 1) == NULL) {
929 } else if (strcmp(buf, SNAPSHOT_MAGIC) == 0) {
933 "The target %s is not Lustre snapshot "
934 "or it does not exists\n", si->si_ssname);
942 static int target_is_mounted(struct snapshot_instance *si,
943 struct snapshot_target *st, const char *ssname)
945 char buf[MAX_BUF_SIZE];
946 char fullname[MAX_BUF_SIZE];
951 memset(buf, 0, sizeof(buf));
952 snprintf(buf, sizeof(buf) - 1,
955 fp = popen(buf, "r");
957 SNAPSHOT_ADD_LOG(si, "Popen fail to check target mount: %s\n",
962 memset(fullname, 0, sizeof(fullname));
964 snprintf(fullname, sizeof(fullname) - 1,
966 PFSNAME(st), ssname);
968 snprintf(fullname, sizeof(fullname) - 1,
972 while (snapshot_fgets(fp, buf, sizeof(buf)) != NULL) {
973 ptr = strstr(buf, fullname);
977 ptr += strlen(fullname) + 1; /* mount point */
978 if (ptr >= buf + strlen(buf))
981 ptr = strstr(ptr, "type lustre");
992 static int snapshot_get_fsname(struct snapshot_instance *si,
993 char *fsname, int fslen)
995 struct snapshot_target *st = si->si_mdt0;
996 char buf[MAX_BUF_SIZE * 3];
1000 memset(buf, 0, sizeof(buf));
1001 snprintf(buf, sizeof(buf) - 1,
1002 DRSH" '"DIMPORT"; "DZFS
1003 " get -H -o value lustre:fsname "DSSNAME"'",
1004 PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
1005 fp = popen(buf, "r");
1007 SNAPSHOT_ADD_LOG(si, "Popen fail to get fsname: %s\n",
1012 if (snapshot_fgets(fp, fsname, fslen) == NULL)
1019 static int snapshot_get_mgsnode(struct snapshot_instance *si,
1020 char *node, int size)
1022 char buf[MAX_BUF_SIZE * 2];
1023 struct snapshot_target *st;
1027 st = list_entry(si->si_osts_list.next, struct snapshot_target,
1029 memset(buf, 0, sizeof(buf));
1030 snprintf(buf, sizeof(buf) - 1,
1031 DRSH" '"DZFS" get -H -o value lustre:mgsnode "DFSNAME"'",
1032 PRSH(si, st), PZFS(st), PFSNAME(st));
1033 fp = popen(buf, "r");
1035 SNAPSHOT_ADD_LOG(si, "Popen fail to get mgsnode: %s\n",
1040 if (snapshot_fgets(fp, node, size) == NULL)
1047 static int snapshot_exists_check(struct snapshot_instance *si,
1048 struct snapshot_target *st)
1050 char buf[MAX_BUF_SIZE * 2];
1054 memset(buf, 0, sizeof(buf));
1055 snprintf(buf, sizeof(buf) - 1,
1056 DRSH" '"DZFS" list "DSSNAME" 2>/dev/null'",
1057 PRSH(si, st), PZFS(st), PSSNAME(si, st));
1058 fp = popen(buf, "r");
1060 SNAPSHOT_ADD_LOG(si, "Popen fail to create check: %s\n",
1065 if (snapshot_fgets(fp, buf, sizeof(buf)) != NULL)
1072 static int snapshot_general_check(struct snapshot_instance *si)
1074 return mdt0_is_lustre_snapshot(si);
1077 static void snapshot_create_usage(void)
1080 "Create snapshot for the given filesystem.\n"
1082 "snapshot_create [-b | --barrier [on | off]] "
1083 "[-c | --comment comment] "
1084 "<-F | --fsname fsname> "
1085 "[-h | --help] <-n | --name ssname> "
1086 "[-r | --rsh remote_shell]"
1087 "[-t | --timeout timeout]\n"
1089 "-b: set write barrier before creating snapshot, "
1090 "the default value is 'on'.\n"
1091 "-c: describe what the snapshot is for, and so on.\n"
1092 "-F: the filesystem name.\n"
1093 "-h: for help information.\n"
1094 "-n: the snapshot's name.\n"
1095 "-r: the remote shell used for communication with remote "
1096 "target, the default value is 'ssh'.\n"
1097 "-t: the life cycle (seconds) for write barrier, "
1098 "the default value is %d seconds.\n",
1099 BARRIER_TIMEOUT_DEFAULT);
1102 static int snapshot_create_check(struct snapshot_instance *si)
1106 rc = snapshot_exists_check(si, si->si_mdt0);
1108 fprintf(stderr, "The snapshot %s exists\n", si->si_ssname);
1113 static int snapshot_inherit_prop(struct snapshot_instance *si,
1114 struct snapshot_target *st,
1115 char *cmd, int size)
1117 char buf[MAX_BUF_SIZE * 3];
1122 memset(buf, 0, sizeof(buf));
1123 snprintf(buf, sizeof(buf) - 1,
1124 DRSH" \""DIMPORT"; "DZFS
1125 " get all "DFSNAME" | grep lustre: | grep local$ | "
1126 "awk '{ \\$1=\\\"\\\"; \\$NF=\\\"\\\"; print \\$0 }' | "
1127 "sed -e 's/^ //'\"",
1128 PRSH(si, st), PIMPORT(st), PZFS(st), PFSNAME(st));
1129 fp = popen(buf, "r");
1131 SNAPSHOT_ADD_LOG(si, "Popen fail to list one: %s\n",
1136 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
1140 if (strncmp(buf, "lustre:fsname",
1141 strlen("lustre:fsname")) == 0)
1144 if (strncmp(buf, "lustre:magic",
1145 strlen("lustre:magic")) == 0)
1148 if (strncmp(buf, "lustre:ctime",
1149 strlen("lustre:ctime")) == 0)
1152 if (strncmp(buf, "lustre:mtime",
1153 strlen("lustre:mtime")) == 0)
1156 if (strncmp(buf, "lustre:comment",
1157 strlen("lustre:comment")) == 0)
1160 if (strncmp(buf, "lustre:svname",
1161 strlen("lustre:svname")) == 0)
1164 if (strncmp(buf, "lustre:mgsnode",
1165 strlen("lustre:mgsnode")) == 0)
1168 ptr = strchr(buf, ' ');
1170 ptr = strchr(buf, '\t');
1177 while (*ptr == ' ' || *ptr == '\t')
1183 end = strchr(ptr, ' ');
1185 end = strchr(buf, '\t');
1189 rc = snprintf(cmd + len, size - len - 1,
1190 "-o %s=\"%s\" ", buf, ptr);
1201 static int __snapshot_create(struct snapshot_instance *si,
1202 struct list_head *head, const char *fsname,
1203 const char *mgsnode, __u64 xtime)
1205 struct snapshot_target *st;
1209 list_for_each_entry(st, head, st_list) {
1216 SNAPSHOT_ADD_LOG(si, "Can't fork for create snapshot "
1217 "(%s@%s <%s>) on the target "
1219 fsname, si->si_ssname,
1220 si->si_comment, st->st_host,
1221 st->st_role, st->st_index,
1228 char cmd[MAX_BUF_SIZE];
1231 memset(cmd, 0, sizeof(cmd));
1232 len = snprintf(cmd, sizeof(cmd) - 1,
1233 DRSH" '"DZFS" snapshot "
1234 "-o lustre:fsname=%s "
1235 "-o lustre:magic=%s "
1236 "-o lustre:ctime=%llu "
1237 "-o lustre:mtime=%llu ",
1238 PRSH(si, st), PZFS(st), fsname,
1240 (unsigned long long)xtime,
1241 (unsigned long long)xtime);
1245 if (si->si_comment) {
1246 rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
1247 "-o lustre:comment=\"%s\" ",
1255 /* Make the inherited properties as local ones,
1256 * then even if others changed (or removed) the
1257 * property of the parent dataset, the snapshot
1258 * will not be affected. */
1259 rc = snapshot_inherit_prop(si, st, cmd + len,
1260 MAX_BUF_SIZE - len - 1);
1262 SNAPSHOT_ADD_LOG(si, "Can't filter property on "
1263 "target (%s:%x:%d): rc = %d\n",
1264 st->st_host, st->st_role,
1271 if (st->st_role & SR_OST)
1272 rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
1273 "-o lustre:svname=%s-OST%04x "
1274 "-o lustre:mgsnode=%s "DSSNAME"'",
1275 fsname, st->st_index, mgsnode,
1277 else if (!(st->st_role & SR_MGS) ||
1278 /* MGS is on MDT0 */
1279 si->si_mdt0 == si->si_mgs)
1280 rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
1281 "-o lustre:svname=%s-MDT%04x "
1282 "-o lustre:mgsnode=%s "DSSNAME"'",
1283 fsname, st->st_index, mgsnode,
1287 rc = snprintf(cmd + len, sizeof(cmd) - len - 1,
1288 DSSNAME"'", PSSNAME(si, st));
1292 rc = snapshot_exec(cmd);
1294 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
1295 "target (%s:%x:%d): rc = %d\n",
1296 cmd, st->st_host, st->st_role,
1300 } /* end of child */
1302 /* parent continue to run more snapshot commands in parallel. */
1309 static int __snapshot_destroy(struct snapshot_instance *si,
1310 struct list_head *head);
1312 static int snapshot_create(struct snapshot_instance *si)
1315 char buf[MAX_BUF_SIZE];
1322 rc = snapshot_create_check(si);
1326 rc = gettimeofday(&tv, NULL);
1330 srandom(tv.tv_usec);
1331 snprintf(new_fsname, sizeof(new_fsname), "%08x", (__u32)random());
1333 rc = snapshot_get_mgsnode(si, buf, sizeof(buf));
1337 __argv[1] = si->si_fsname;
1338 /* 1. Get barrier */
1339 if (si->si_barrier) {
1342 memset(tbuf, 0, sizeof(tbuf));
1343 snprintf(tbuf, 7, "%u", si->si_timeout);
1344 __argv[0] = "barrier_freeze";
1346 rc = jt_barrier_freeze(3, __argv);
1348 SNAPSHOT_ADD_LOG(si, "Can't set barrier within %u "
1349 "seconds on %s: rc = %d\n",
1350 si->si_timeout, si->si_fsname, rc);
1356 /* 2. Fork config llog on MGS */
1357 __argv[0] = "fork_lcfg";
1358 __argv[2] = new_fsname;
1359 rc = jt_lcfg_fork(3, __argv);
1361 SNAPSHOT_ADD_LOG(si, "Can't fork config log for create "
1362 "snapshot %s from %s to %s: rc = %d\n",
1363 si->si_ssname, si->si_fsname, new_fsname, rc);
1367 /* 3.1 Create snapshot on every MDT */
1368 rc = __snapshot_create(si, &si->si_mdts_list, new_fsname, buf,
1371 /* 3.2 Create snapshot on every OST */
1372 rc = __snapshot_create(si, &si->si_osts_list, new_fsname, buf,
1375 /* 4. Wait for all children, even though part of them maybe failed */
1376 snapshot_wait(si, &rc1);
1379 /* 5. Put barrier */
1380 if (si->si_barrier) {
1382 struct barrier_ctl bc;
1384 rc = __jt_barrier_stat(__argv[1], &bc);
1386 SNAPSHOT_ADD_LOG(si, "Can't get barrier status "
1389 } else if (bc.bc_status != BS_FROZEN ||
1390 bc.bc_timeout <= 0) {
1391 SNAPSHOT_ADD_LOG(si, "The barrier expired "
1392 "on %s\n", si->si_fsname);
1397 __argv[0] = "barrier_thaw";
1398 rc2 = jt_barrier_thaw(2, __argv);
1400 SNAPSHOT_ADD_LOG(si, "Can't release barrier on %s: "
1401 "rc = %d\n", si->si_fsname, rc2);
1406 si->si_force = true;
1407 __snapshot_destroy(si, &si->si_osts_list);
1408 __snapshot_destroy(si, &si->si_mdts_list);
1409 snapshot_wait(si, &rc2);
1411 __argv[0] = "erase_lcfg";
1412 __argv[1] = new_fsname;
1414 jt_lcfg_erase(3, __argv);
1417 return rc ? rc : (rc1 ? rc1 : rc2);
1420 int jt_snapshot_create(int argc, char **argv)
1422 struct snapshot_instance *si;
1423 struct option long_opts[] = {
1424 { .val = 'b', .name = "barrier", .has_arg = optional_argument },
1425 { .val = 'c', .name = "comment", .has_arg = required_argument },
1426 { .val = 'F', .name = "fsname", .has_arg = required_argument },
1427 { .val = 'h', .name = "help", .has_arg = no_argument },
1428 { .val = 'n', .name = "name", .has_arg = required_argument },
1429 { .val = 'r', .name = "rsh", .has_arg = required_argument },
1430 { .val = 't', .name = "timeout", .has_arg = required_argument },
1434 si = snapshot_init(argc, argv, long_opts, "b::c:F:hn:r:t:",
1435 snapshot_create_usage, LOCK_EX, &rc);
1439 if (!si->si_ssname) {
1441 "Miss the snapshot name to be created\n");
1442 snapshot_create_usage();
1447 rc = snapshot_create(si);
1450 "Can't create the snapshot %s\n", si->si_ssname);
1451 SNAPSHOT_ADD_LOG(si, "Can't create snapshot %s with "
1452 "comment <%s> barrier <%s>, timeout "
1454 si->si_ssname, si->si_comment,
1455 si->si_barrier ? "enable" : "disable",
1456 si->si_barrier ? si->si_timeout : -1, rc);
1458 SNAPSHOT_ADD_LOG(si, "Create snapshot %s successfully "
1459 "with comment <%s>, barrier <%s>, "
1461 si->si_ssname, si->si_comment,
1462 si->si_barrier ? "enable" : "disable",
1463 si->si_barrier ? si->si_timeout : -1);
1470 static void snapshot_destroy_usage(void)
1473 "Destroy the specified snapshot.\n"
1475 "snapshot_destroy [-f | --force] "
1476 "<-F | --fsname fsname> [-h | --help] "
1477 "<-n | --name ssname> "
1478 "[-r | --rsh remote_shell]\n"
1480 "-f: destroy the snapshot by force.\n"
1481 "-F: the filesystem name.\n"
1482 "-h: for help information.\n"
1483 "-n: the snapshot's name.\n"
1484 "-r: the remote shell used for communication with remote "
1485 "target, the default value is 'ssh'.\n");
1488 static int snapshot_destroy_check(struct snapshot_instance *si)
1490 struct list_head *head = &si->si_osts_list;
1491 struct snapshot_target *st;
1496 list_for_each_entry(st, head, st_list) {
1503 SNAPSHOT_ADD_LOG(si, "Can't fork for check snapshot "
1504 "%s on the target (%s:%x:%d): %s\n",
1505 si->si_ssname, st->st_host,
1506 st->st_role, st->st_index,
1513 rc = snapshot_exists_check(si, st);
1515 /* The snapshot piece does not exist */
1518 exit(rc == -EEXIST ? 0: rc);
1519 } /* end of child */
1521 /* parent continue to run more snapshot commands in parallel. */
1525 if (head == &si->si_osts_list) {
1526 head = &si->si_mdts_list;
1530 snapshot_wait(si, &rc);
1534 head = &si->si_osts_list;
1537 list_for_each_entry(st, head, st_list) {
1538 if (st->st_ignored && !si->si_force) {
1541 snapshot_role2name(name, st->st_role, st->st_index);
1543 "Miss snapshot piece on the %s. Use '-f' "
1544 "option if want to destroy it by force.\n",
1551 if (head == &si->si_osts_list) {
1552 head = &si->si_mdts_list;
1557 rc = snapshot_general_check(si);
1562 static int __snapshot_destroy(struct snapshot_instance *si,
1563 struct list_head *head)
1565 struct snapshot_target *st;
1569 list_for_each_entry(st, head, st_list) {
1578 SNAPSHOT_ADD_LOG(si, "Can't fork for destroy snapshot "
1579 "%s on the target (%s:%x:%d): %s\n",
1580 si->si_ssname, st->st_host,
1581 st->st_role, st->st_index,
1588 char cmd[MAX_BUF_SIZE * 2];
1590 memset(cmd, 0, sizeof(cmd));
1592 snprintf(cmd, sizeof(cmd) - 1,
1593 DRSH" 'umount -f "DSSNAME
1594 " > /dev/null 2>&1; "DZFS
1595 " destroy -f "DSSNAME"'",
1596 PRSH(si, st), PSSNAME(si, st),
1597 PZFS(st), PSSNAME(si, st));
1599 snprintf(cmd, sizeof(cmd) - 1,
1600 DRSH" '"DZFS" destroy "DSSNAME"'",
1601 PRSH(si, st), PZFS(st),
1603 rc = snapshot_exec(cmd);
1605 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
1606 "target (%s:%x:%d): rc = %d\n",
1607 cmd, st->st_host, st->st_role,
1611 } /* end of child */
1613 /* parent continue to run more snapshot commands in parallel. */
1620 static int snapshot_destroy(struct snapshot_instance *si)
1628 rc = snapshot_destroy_check(si);
1632 rc = snapshot_get_fsname(si, fsname, sizeof(fsname));
1636 /* 1.1 Destroy snapshot on every OST */
1637 rc = __snapshot_destroy(si, &si->si_osts_list);
1638 if (!si->si_force) {
1642 __snapshot_wait(si, &si->si_osts_list, &rc);
1647 /* 1.2 Destroy snapshot on every MDT */
1648 rc1 = __snapshot_destroy(si, &si->si_mdts_list);
1650 /* 2 Wait for all children, even though part of them maybe failed */
1651 snapshot_wait(si, &rc2);
1652 if (rc2 == -ENOENT && si->si_force)
1655 /* 3. Erase config llog from MGS */
1656 if ((!rc && !rc1 && !rc2) || si->si_force) {
1659 __argv[0] = "erase_lcfg";
1662 rc3 = jt_lcfg_erase(3, __argv);
1663 if (rc3 && errno == ENOENT)
1666 SNAPSHOT_ADD_LOG(si, "Can't erase config for destroy "
1667 "snapshot %s, fsname %s: rc = %d\n",
1668 si->si_ssname, fsname, rc3);
1671 return rc ? rc : (rc1 ? rc1 : (rc2 ? rc2 : rc3));
1674 int jt_snapshot_destroy(int argc, char **argv)
1676 struct snapshot_instance *si;
1677 struct option long_opts[] = {
1678 { .val = 'f', .name = "force", .has_arg = no_argument },
1679 { .val = 'F', .name = "fsname", .has_arg = required_argument },
1680 { .val = 'h', .name = "help", .has_arg = no_argument },
1681 { .val = 'n', .name = "name", .has_arg = required_argument },
1682 { .val = 'r', .name = "rsh", .has_arg = required_argument },
1686 si = snapshot_init(argc, argv, long_opts, "fF:hn:r:",
1687 snapshot_destroy_usage, LOCK_EX, &rc);
1691 if (!si->si_ssname) {
1693 "Miss the snapshot name to be destroyed\n");
1694 snapshot_destroy_usage();
1699 rc = snapshot_destroy(si);
1702 "Can't destroy the snapshot %s\n", si->si_ssname);
1703 SNAPSHOT_ADD_LOG(si, "Can't destroy snapshot %s with "
1704 "force <%s>: %d\n", si->si_ssname,
1705 si->si_force ? "enable" : "disable", rc);
1707 SNAPSHOT_ADD_LOG(si, "Destroy snapshot %s successfully "
1708 "with force <%s>\n", si->si_ssname,
1709 si->si_force ? "enable" : "disable");
1716 static void snapshot_modify_usage(void)
1719 "Change the specified snapshot's name and/or comment.\n"
1721 "snapshot_modify [-c | --comment comment] "
1722 "<-F | --fsname fsname> [-h | --help] "
1723 "<-n | --name ssname> [-N | --new new_ssname] "
1724 "[-r | --rsh remote_shell]\n"
1726 "-c: update the snapshot's comment.\n"
1727 "-F: the filesystem name.\n"
1728 "-h: for help information.\n"
1729 "-n: the snapshot's name.\n"
1730 "-N: rename the snapshot's name as the new_ssname.\n"
1731 "-r: the remote shell used for communication with remote "
1732 "target, the default value is 'ssh'.\n");
1735 static int snapshot_modify_check(struct snapshot_instance *si)
1739 if (si->si_new_ssname &&
1740 strcmp(si->si_ssname, si->si_new_ssname) == 0) {
1741 fprintf(stderr, "The new snapshot's name is the same as "
1742 "the old one %s %s.\n",
1743 si->si_ssname, si->si_new_ssname);
1747 if (!si->si_new_ssname && !si->si_comment) {
1748 fprintf(stderr, "Miss options, nothing to be changed.\n");
1752 rc = mdt0_is_lustre_snapshot(si);
1753 if (!rc && si->si_new_ssname) {
1754 rc = target_is_mounted(si, si->si_mdt0, si->si_ssname);
1757 "snapshot %s is mounted, can't be renamed.\n",
1766 static int __snapshot_modify(struct snapshot_instance *si,
1767 struct list_head *head, __u64 xtime)
1769 struct snapshot_target *st;
1773 list_for_each_entry(st, head, st_list) {
1780 SNAPSHOT_ADD_LOG(si, "Can't fork for modify snapshot "
1781 "(%s|%s, <%s>) on the target "
1783 si->si_ssname, si->si_new_ssname,
1784 si->si_comment, st->st_host,
1785 st->st_role, st->st_index,
1792 char cmd[MAX_BUF_SIZE * 5];
1794 memset(cmd, 0, sizeof(cmd));
1795 if (si->si_new_ssname && si->si_comment)
1796 snprintf(cmd, sizeof(cmd) - 1,
1797 DRSH" '"DIMPORT"; "DZFS" rename "
1798 DSSNAME" "DSSNAME" && "DZFS
1799 " set lustre:comment=\"%s\" "DSSNAME
1801 " set lustre:mtime=%llu "DSSNAME"'",
1802 PRSH(si, st), PIMPORT(st), PZFS(st),
1803 PSSNAME(si, st), PSS_NEW(si, st),
1804 PZFS(st), si->si_comment,
1805 PSS_NEW(si, st), PZFS(st),
1806 (unsigned long long)xtime,
1808 else if (si->si_new_ssname)
1809 snprintf(cmd, sizeof(cmd) - 1,
1810 DRSH" '"DIMPORT"; "DZFS
1811 " rename "DSSNAME" "DSSNAME" && "DZFS
1812 " set lustre:mtime=%llu "DSSNAME"'",
1813 PRSH(si, st), PIMPORT(st), PZFS(st),
1814 PSSNAME(si, st), PSS_NEW(si, st),
1815 PZFS(st), (unsigned long long)xtime,
1817 else if (si->si_comment)
1818 snprintf(cmd, sizeof(cmd) - 1,
1819 DRSH" '"DIMPORT"; "DZFS
1820 " set lustre:comment=\"%s\" "DSSNAME
1822 " set lustre:mtime=%llu "DSSNAME"'",
1823 PRSH(si, st), PIMPORT(st), PZFS(st),
1824 si->si_comment, PSSNAME(si, st),
1825 PZFS(st), (unsigned long long)xtime,
1830 rc = snapshot_exec(cmd);
1832 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on "
1833 "target (%s:%x:%d): rc = %d\n",
1834 cmd, st->st_host, st->st_role,
1838 } /* end of child */
1840 /* parent continue to run more snapshot commands in parallel. */
1847 static int snapshot_modify(struct snapshot_instance *si)
1853 rc = snapshot_modify_check(si);
1859 /* Modify snapshot on every MDT */
1860 rc = __snapshot_modify(si, &si->si_mdts_list, (__u64)tt);
1862 /* Modify snapshot on every OST */
1863 rc = __snapshot_modify(si, &si->si_osts_list, (__u64)tt);
1865 /* Wait for all children, even though part of them maybe failed */
1866 snapshot_wait(si, &rc1);
1868 return rc ? rc : rc1;
1871 int jt_snapshot_modify(int argc, char **argv)
1873 struct snapshot_instance *si;
1874 struct option long_opts[] = {
1875 { .val = 'c', .name = "comment", .has_arg = required_argument },
1876 { .val = 'F', .name = "fsname", .has_arg = required_argument },
1877 { .val = 'h', .name = "help", .has_arg = no_argument },
1878 { .val = 'n', .name = "name", .has_arg = required_argument },
1879 { .val = 'N', .name = "new", .has_arg = required_argument },
1880 { .val = 'r', .name = "rsh", .has_arg = required_argument },
1884 si = snapshot_init(argc, argv, long_opts, "c:F:hn:N:r:",
1885 snapshot_modify_usage, LOCK_EX, &rc);
1889 if (!si->si_ssname) {
1891 "Miss the snapshot name to be modified\n");
1892 snapshot_modify_usage();
1897 rc = snapshot_modify(si);
1900 "Can't modify the snapshot %s\n", si->si_ssname);
1901 SNAPSHOT_ADD_LOG(si, "Can't modify snapshot %s with "
1902 "name <%s>, comment <%s>: %d\n",
1903 si->si_ssname, si->si_new_ssname,
1904 si->si_comment, rc);
1906 SNAPSHOT_ADD_LOG(si, "Modify snapshot %s successfully "
1907 "with name <%s>, comment <%s>\n",
1908 si->si_ssname, si->si_new_ssname,
1916 static void snapshot_list_usage(void)
1919 "List the specified snapshot or all snapshots.\n"
1921 "snapshot_list [-d | --detail] "
1922 "<-F | --fsname fsname> [-h | --help] "
1923 "[-n | --name ssname] [-r | --rsh remote_shell]\n"
1925 "-d: list every piece for the specified snapshot.\n"
1926 "-F: the filesystem name.\n"
1927 "-h: for help information.\n"
1928 "-n: the snapshot's name.\n"
1929 "-r: the remote shell used for communication with remote "
1930 "target, the default value is 'ssh'.\n");
1933 static int snapshot_list_one(struct snapshot_instance *si,
1934 struct snapshot_target *st)
1936 char buf[MAX_BUF_SIZE * 3];
1940 memset(buf, 0, sizeof(buf));
1941 snprintf(buf, sizeof(buf) - 1,
1942 DRSH" \""DIMPORT"; "DZFS
1943 " get all "DSSNAME" | grep lustre: | grep local$ | "
1944 "awk '{ \\$1=\\\"\\\"; \\$NF=\\\"\\\"; print \\$0 }' | "
1945 "sed -e 's/^ //'\"",
1946 PRSH(si, st), PIMPORT(st), PZFS(st), PSSNAME(si, st));
1947 fp = popen(buf, "r");
1949 SNAPSHOT_ADD_LOG(si, "Popen fail to list one: %s\n",
1954 if (si->si_detail) {
1957 snapshot_role2name(name, st->st_role, st->st_index);
1958 printf("\nsnapshot_role: %s\n", name);
1961 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
1965 if (strncmp(buf, "lustre:fsname",
1966 strlen("lustre:fsname")) == 0) {
1967 ptr = snapshot_first_skip_blank(buf);
1969 printf("snapshot_fsname: %s\n", ptr);
1973 if (strncmp(buf, "lustre:comment",
1974 strlen("lustre:comment")) == 0) {
1975 ptr = snapshot_first_skip_blank(buf);
1977 printf("comment: %s\n", ptr);
1981 if (strncmp(buf, "lustre:ctime",
1982 strlen("lustre:ctime")) == 0) {
1983 ptr = snapshot_first_skip_blank(buf);
1985 xtime = (__u64)strtoull(ptr, NULL, 10);
1986 printf("create_time: %s",
1987 ctime((time_t *)&xtime));
1992 if (strncmp(buf, "lustre:mtime",
1993 strlen("lustre:mtime")) == 0) {
1994 ptr = snapshot_first_skip_blank(buf);
1996 xtime = (__u64)strtoull(ptr, NULL, 10);
1997 printf("modify_time: %s",
1998 ctime((time_t *)&xtime));
2005 rc = target_is_mounted(si, st, si->si_ssname);
2007 printf("status: unknown\n");
2009 printf("status: not mount\n");
2011 printf("status: mounted\n");
2016 static int __snapshot_list(struct snapshot_instance *si,
2017 struct list_head *head)
2019 struct snapshot_target *st;
2022 list_for_each_entry(st, head, st_list) {
2025 rc1 = snapshot_list_one(si, st);
2026 if (rc1 < 0 || rc >= 0)
2033 static int snapshot_list(struct snapshot_instance *si)
2037 rc = snapshot_general_check(si);
2041 printf("\nfilesystem_name: %s\nsnapshot_name: %s\n",
2042 si->si_fsname, si->si_ssname);
2044 if (!si->si_detail) {
2045 rc = snapshot_list_one(si, si->si_mdt0);
2049 rc = __snapshot_list(si, &si->si_mdts_list);
2050 rc1 = __snapshot_list(si, &si->si_osts_list);
2055 return rc < 0 ? rc : 0;
2058 static int snapshot_list_all(struct snapshot_instance *si)
2060 struct snapshot_target *st = si->si_mdt0;
2061 struct list_sub_item {
2062 struct list_head lsi_list;
2066 struct list_head list_sub_items;
2067 struct list_sub_item *lsi;
2068 char buf[MAX_BUF_SIZE * 2];
2072 INIT_LIST_HEAD(&list_sub_items);
2073 memset(buf, 0, sizeof(buf));
2074 snprintf(buf, sizeof(buf) - 1,
2075 DRSH" \""DZFS" get -H -r lustre:magic "DFSNAME
2076 " | grep %s | awk '{ print \\$1 }' | cut -d@ -f2\"",
2077 PRSH(si, st), PZFS(st), PFSNAME(st), SNAPSHOT_MAGIC);
2078 fp = popen(buf, "r");
2080 SNAPSHOT_ADD_LOG(si, "Popen fail to list ssnames: %s\n",
2085 while (snapshot_fgets(fp, buf, MAX_BUF_SIZE) != NULL) {
2086 int len = strlen(buf);
2088 lsi = malloc(len + 1 + sizeof(struct list_sub_item));
2090 SNAPSHOT_ADD_LOG(si, "NOT enough memory\n");
2095 memcpy(lsi->lsi_ssname, buf, len + 1);
2096 list_add(&lsi->lsi_list, &list_sub_items);
2100 while (!list_empty(&list_sub_items)) {
2101 lsi = list_entry(list_sub_items.next,
2102 struct list_sub_item, lsi_list);
2103 list_del(&lsi->lsi_list);
2105 si->si_ssname = lsi->lsi_ssname;
2106 rc = snapshot_list(si);
2107 si->si_ssname = NULL;
2116 int jt_snapshot_list(int argc, char **argv)
2118 struct snapshot_instance *si;
2119 struct option long_opts[] = {
2120 { .val = 'd', .name = "detail", .has_arg = no_argument },
2121 { .val = 'F', .name = "fsname", .has_arg = required_argument },
2122 { .val = 'h', .name = "help", .has_arg = no_argument },
2123 { .val = 'n', .name = "name", .has_arg = required_argument },
2124 { .val = 'r', .name = "rsh", .has_arg = required_argument },
2128 si = snapshot_init(argc, argv, long_opts, "dF:hn:r:",
2129 snapshot_list_usage, LOCK_SH, &rc);
2134 rc = snapshot_list(si);
2136 rc = snapshot_list_all(si);
2140 "Can't list the snapshot %s\n", si->si_ssname);
2141 SNAPSHOT_ADD_LOG(si, "Can't list snapshot %s with detail "
2142 "<%s>: %d\n", si->si_ssname,
2143 si->si_detail ? "yes" : "no", rc);
2150 static void snapshot_mount_usage(void)
2153 "Mount the specified snapshot.\n"
2155 "snapshot_mount <-F | --fsname fsname> [-h | --help] "
2156 "<-n | --name ssname> "
2157 "[-r | --rsh remote_shell]\n"
2159 "-F: the filesystem name.\n"
2160 "-h: for help information.\n"
2161 "-n: the snapshot's name.\n"
2162 "-r: the remote shell used for communication with remote "
2163 "target, the default value is 'ssh'.\n");
2166 static int snapshot_mount_check(struct snapshot_instance *si, char *fsname,
2167 int fslen, bool *mgs_running)
2171 rc = mdt0_is_lustre_snapshot(si);
2175 rc = snapshot_get_fsname(si, fsname, fslen);
2179 rc = target_is_mounted(si, si->si_mgs, NULL);
2181 *mgs_running = true;
2188 static int snapshot_mount_target(struct snapshot_instance *si,
2189 struct snapshot_target *st, const char *optstr)
2191 char cmd[MAX_BUF_SIZE * 2];
2195 rc = target_is_mounted(si, st, si->si_ssname);
2202 memset(cmd, 0, sizeof(cmd));
2203 memset(name, 0, sizeof(name));
2204 snapshot_role2name(name, st->st_role, st->st_index);
2205 snprintf(cmd, sizeof(cmd) - 1,
2206 DRSH" '"DIMPORT"; mkdir -p /mnt/%s_%s && mount -t lustre "
2207 "-o rdonly_dev%s "DSSNAME" /mnt/%s_%s'",
2208 PRSH(si, st), PIMPORT(st), si->si_ssname, name,
2209 st != si->si_mdt0 ? "" : optstr, PSSNAME(si, st),
2210 si->si_ssname, name);
2211 rc = snapshot_exec(cmd);
2213 SNAPSHOT_ADD_LOG(si, "Can't execute \"%s\" on the target "
2214 "(%s:%x:%d): rc = %d\n", cmd, st->st_host,
2215 st->st_role, st->st_index, rc);
2220 static int __snapshot_mount(struct snapshot_instance *si,
2221 struct list_head *head)
2223 struct snapshot_target *st;
2227 list_for_each_entry(st, head, st_list) {
2228 if (st == si->si_mgs || st == si->si_mdt0)
2237 SNAPSHOT_ADD_LOG(si, "Can't fork for mount snapshot "
2238 "%s on target (%s:%x:%d): %s\n",
2239 si->si_ssname, st->st_host,
2240 st->st_role, st->st_index,
2247 rc = snapshot_mount_target(si, st, "");
2251 /* parent continue to run more snapshot commands in parallel. */
2258 static int __snapshot_umount(struct snapshot_instance *si,
2259 struct list_head *head);
2261 static int snapshot_mount(struct snapshot_instance *si)
2263 struct snapshot_target *st;
2269 bool mdt0_mounted = false;
2270 bool mgs_running = false;
2272 rc = snapshot_mount_check(si, fsname, sizeof(fsname), &mgs_running);
2275 "Can't mount the snapshot %s: %s\n",
2276 si->si_ssname, strerror(-rc));
2280 /* 1. MGS is not mounted yet, mount the MGS firstly */
2281 si->si_mgs->st_ignored = 0;
2282 si->si_mgs->st_pid = 0;
2284 rc = snapshot_mount_target(si, si->si_mgs, "");
2286 si->si_mgs->st_ignored = 1;
2292 "Can't mount the snapshot %s: %s\n",
2293 si->si_ssname, strerror(-rc));
2297 if (si->si_mgs == si->si_mdt0)
2298 mdt0_mounted = true;
2301 /* 2. Mount MDT0 if it is not combined with the MGS. */
2302 if (!mdt0_mounted) {
2303 si->si_mdt0->st_ignored = 0;
2304 si->si_mdt0->st_pid = 0;
2305 rc = snapshot_mount_target(si, si->si_mdt0, ",nomgs");
2310 /* 3.1 Mount other MDTs in parallel */
2311 rc = __snapshot_mount(si, &si->si_mdts_list);
2313 /* 3.2 Mount OSTs in parallel */
2314 rc = __snapshot_mount(si, &si->si_osts_list);
2316 /* Wait for all children, even though part of them maybe failed */
2317 failed = snapshot_wait(si, &rc1);
2319 list_for_each_entry(st, &si->si_mdts_list, st_list) {
2320 if (!st->st_ignored)
2324 list_for_each_entry(st, &si->si_osts_list, st_list) {
2325 if (!st->st_ignored)
2333 __snapshot_umount(si, &si->si_mdts_list);
2334 __snapshot_umount(si, &si->si_osts_list);
2335 snapshot_wait(si, &rc2);
2339 "Can't mount the snapshot %s: %s\n",
2340 si->si_ssname, strerror(-rc));
2343 "%d of %d pieces of the snapshot %s "
2344 "can't be mounted: %s\n",
2345 failed, needed, si->si_ssname, strerror(-rc1));
2347 return rc ? rc : rc1;
2352 "The snapshot %s has already been mounted by other\n",
2357 fprintf(stdout, "mounted the snapshot %s with fsname %s\n",
2358 si->si_ssname, fsname);
2363 int jt_snapshot_mount(int argc, char **argv)
2365 struct snapshot_instance *si;
2366 struct option long_opts[] = {
2367 { .val = 'F', .name = "fsname", .has_arg = required_argument },
2368 { .val = 'h', .name = "help", .has_arg = no_argument },
2369 { .val = 'n', .name = "name", .has_arg = required_argument },
2370 { .val = 'r', .name = "rsh", .has_arg = required_argument },
2374 si = snapshot_init(argc, argv, long_opts, "F:hn:r:",
2375 snapshot_mount_usage, LOCK_EX, &rc);
2379 if (!si->si_ssname) {
2381 "Miss the snapshot name to be mounted\n");
2382 snapshot_mount_usage();
2387 rc = snapshot_mount(si);
2389 SNAPSHOT_ADD_LOG(si, "Can't mount snapshot %s: %d\n",
2392 SNAPSHOT_ADD_LOG(si, "The snapshot %s is mounted\n",
2400 static void snapshot_umount_usage(void)
2403 "Umount the specified snapshot.\n"
2405 "snapshot_umount <-F | --fsname fsname> [-h | --help] "
2406 "<-n | --name ssname> "
2407 "[-r | --rsh remote_shell]\n"
2409 "-F: the filesystem name.\n"
2410 "-h: for help information.\n"
2411 "-n: the snapshot's name.\n"
2412 "-r: the remote shell used for communication with remote "
2413 "target, the default value is 'ssh'.\n");
2416 static int __snapshot_umount(struct snapshot_instance *si,
2417 struct list_head *head)
2419 struct snapshot_target *st;
2423 list_for_each_entry(st, head, st_list) {
2430 SNAPSHOT_ADD_LOG(si, "Can't fork for umount snapshot "
2431 "%s on target (%s:%x:%d): %s\n",
2432 si->si_ssname, st->st_host,
2433 st->st_role, st->st_index,
2440 char cmd[MAX_BUF_SIZE];
2442 rc = target_is_mounted(si, st, si->si_ssname);
2449 memset(cmd, 0, sizeof(cmd));
2450 snprintf(cmd, sizeof(cmd) - 1,
2451 DRSH" 'umount "DSSNAME"'",
2452 PRSH(si, st), PSSNAME(si, st));
2453 rc = snapshot_exec(cmd);
2458 /* parent continue to run more snapshot commands in parallel. */
2465 static int snapshot_umount(struct snapshot_instance *si)
2467 struct snapshot_target *st;
2474 rc = snapshot_general_check(si);
2477 "Can't umount the snapshot %s: %s\n",
2478 si->si_ssname, strerror(-rc));
2482 rc = __snapshot_umount(si, &si->si_mdts_list);
2483 rc1 = __snapshot_umount(si, &si->si_osts_list);
2484 failed = snapshot_wait(si, &rc2);
2486 list_for_each_entry(st, &si->si_mdts_list, st_list) {
2487 if (!st->st_ignored)
2491 list_for_each_entry(st, &si->si_osts_list, st_list) {
2492 if (!st->st_ignored)
2498 "The snapshot %s has not been mounted\n",
2505 "%d of %d pieces of the snapshot %s "
2506 "can't be umounted: %s\n",
2507 failed, needed, si->si_ssname, strerror(-rc2));
2509 return rc ? rc : (rc1 ? rc1 : rc2);
2512 int jt_snapshot_umount(int argc, char **argv)
2514 struct snapshot_instance *si;
2515 struct option long_opts[] = {
2516 { .val = 'F', .name = "fsname", .has_arg = required_argument },
2517 { .val = 'h', .name = "help", .has_arg = no_argument },
2518 { .val = 'n', .name = "name", .has_arg = required_argument },
2519 { .val = 'r', .name = "rsh", .has_arg = required_argument },
2523 si = snapshot_init(argc, argv, long_opts, "F:hn:r:",
2524 snapshot_umount_usage, LOCK_EX, &rc);
2528 if (!si->si_ssname) {
2530 "Miss the snapshot name to be umounted\n");
2531 snapshot_umount_usage();
2536 rc = snapshot_umount(si);
2538 SNAPSHOT_ADD_LOG(si, "Can't umount snapshot %s: %d\n",
2541 SNAPSHOT_ADD_LOG(si, "the snapshot %s have been umounted\n",