[Sheepdog] [PATCH] collie: split a collie.c into subcommand files
MORITA Kazutaka
morita.kazutaka at lab.ntt.co.jp
Tue Aug 9 18:44:53 CEST 2011
collie.c becomes large and we expect that collie will support more
commands in future, so let's split the code for readability.
Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
---
collie/Makefile.am | 4 +-
collie/cluster.c | 188 +++++++
collie/collie.c | 1573 +---------------------------------------------------
collie/collie.h | 77 +++
collie/common.c | 197 +++++++
collie/node.c | 132 +++++
collie/vdi.c | 1025 ++++++++++++++++++++++++++++++++++
7 files changed, 1648 insertions(+), 1548 deletions(-)
create mode 100644 collie/cluster.c
create mode 100644 collie/collie.h
create mode 100644 collie/common.c
create mode 100644 collie/node.c
create mode 100644 collie/vdi.c
diff --git a/collie/Makefile.am b/collie/Makefile.am
index 82fde03..477b150 100644
--- a/collie/Makefile.am
+++ b/collie/Makefile.am
@@ -23,11 +23,11 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
sbin_PROGRAMS = collie
-collie_SOURCES = collie.c treeview.c
+collie_SOURCES = collie.c common.c treeview.c vdi.c node.c cluster.c
collie_LDADD = ../lib/libsheepdog.a
collie_DEPENDENCIES = ../lib/libsheepdog.a
-noinst_HEADERS = treeview.h
+noinst_HEADERS = treeview.h collie.h
EXTRA_DIST =
diff --git a/collie/cluster.c b/collie/cluster.c
new file mode 100644
index 0000000..0d5dfbe
--- /dev/null
+++ b/collie/cluster.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <time.h>
+#include <sys/time.h>
+
+#include "collie.h"
+
+struct cluster_cmd_data {
+ int copies;
+} cluster_cmd_data;
+
+static int cluster_format(int argc, char **argv)
+{
+ int fd, ret;
+ struct sd_so_req hdr;
+ struct sd_so_rsp *rsp = (struct sd_so_rsp *)&hdr;
+ unsigned rlen, wlen;
+ struct timeval tv;
+
+ fd = connect_to(sdhost, sdport);
+ if (fd < 0)
+ return EXIT_SYSFAIL;
+
+ gettimeofday(&tv, NULL);
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ hdr.opcode = SD_OP_MAKE_FS;
+ hdr.copies = cluster_cmd_data.copies;
+ hdr.epoch = node_list_version;
+ hdr.ctime = (uint64_t) tv.tv_sec << 32 | tv.tv_usec * 1000;
+
+ rlen = 0;
+ wlen = 0;
+ ret = exec_req(fd, (struct sd_req *)&hdr, NULL, &wlen, &rlen);
+ close(fd);
+
+ if (ret) {
+ fprintf(stderr, "failed to connect\n");
+ return EXIT_SYSFAIL;
+ }
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ fprintf(stderr, "%s\n", sd_strerror(rsp->result));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int cluster_info(int argc, char **argv)
+{
+ int i, fd, ret;
+ struct sd_vdi_req hdr;
+ struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
+ unsigned rlen, wlen;
+ struct epoch_log logs[8];
+ int nr_logs;
+ time_t ti;
+ struct tm tm;
+ char time_str[128];
+
+ fd = connect_to(sdhost, sdport);
+ if (fd < 0)
+ return EXIT_SYSFAIL;
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ hdr.opcode = SD_OP_STAT_CLUSTER;
+ hdr.epoch = node_list_version;
+ hdr.data_length = sizeof(logs);
+
+ rlen = hdr.data_length;
+ wlen = 0;
+ ret = exec_req(fd, (struct sd_req *)&hdr, logs, &wlen, &rlen);
+ close(fd);
+
+ if (ret != 0)
+ return EXIT_SYSFAIL;
+
+ if (!raw_output)
+ printf("Cluster status: ");
+ if (rsp->result == SD_RES_SUCCESS)
+ printf("running\n");
+ else
+ printf("%s\n", sd_strerror(rsp->result));
+
+ if (!raw_output)
+ printf("\nCreation time Epoch Nodes\n");
+
+ nr_logs = rsp->data_length / sizeof(struct epoch_log);
+ for (i = 0; i < nr_logs; i++) {
+ int j;
+ char name[128];
+ struct sheepdog_node_list_entry *entry;
+
+ ti = logs[i].ctime >> 32;
+ if (raw_output) {
+ snprintf(time_str, sizeof(time_str), "%" PRIu64, (uint64_t) ti);
+ } else {
+ localtime_r(&ti, &tm);
+ strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm);
+ }
+
+ printf(raw_output ? "%s %d" : "%s %6d", time_str, logs[i].epoch);
+ printf(" [");
+ for (j = 0; j < logs[i].nr_nodes; j++) {
+ entry = logs[i].nodes + j;
+ printf("%s%s",
+ (j == 0) ? "" : ", ",
+ addr_to_str(name, sizeof(name),
+ entry->addr, entry->port));
+ }
+ printf("]\n");
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int cluster_shutdown(int argc, char **argv)
+{
+ int fd, ret;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ unsigned rlen, wlen;
+
+ fd = connect_to(sdhost, sdport);
+ if (fd < 0)
+ return EXIT_SYSFAIL;
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ hdr.opcode = SD_OP_SHUTDOWN;
+ hdr.epoch = node_list_version;
+
+ rlen = 0;
+ wlen = 0;
+ ret = exec_req(fd, &hdr, NULL, &wlen, &rlen);
+ close(fd);
+
+ if (ret) {
+ fprintf(stderr, "failed to connect\n");
+ return EXIT_SYSFAIL;
+ }
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ fprintf(stderr, "%s\n", sd_strerror(rsp->result));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static struct subcommand cluster_cmd[] = {
+ {"info", NULL, "aprh", "show cluster information",
+ 0, cluster_info},
+ {"format", NULL, "caph", "create a Sheepdog storage",
+ 0, cluster_format},
+ {"shutdown", NULL, "aph", "stop Sheepdog",
+ SUBCMD_FLAG_NEED_NODELIST, cluster_shutdown},
+ {NULL,},
+};
+
+static int cluster_parser(int ch, char *opt)
+{
+ switch (ch) {
+ case 'c':
+ cluster_cmd_data.copies = atoi(opt);
+ break;
+ }
+
+ return 0;
+}
+
+struct command cluster_command = {
+ "cluster",
+ cluster_cmd,
+ cluster_parser
+};
diff --git a/collie/collie.c b/collie/collie.c
index c5eae56..e064a0a 100644
--- a/collie/collie.c
+++ b/collie/collie.c
@@ -8,45 +8,20 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <ctype.h>
-#include <errno.h>
#include <getopt.h>
#include <inttypes.h>
-#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <sys/time.h>
#include "sheepdog_proto.h"
#include "sheep.h"
-#include "net.h"
-#include "treeview.h"
-#include "exits.h"
+#include "collie.h"
static char program_name[] = "collie";
-static const char *sdhost = "localhost";
-static int sdport = SD_LISTEN_PORT;
-static int highlight = 1;
-static int raw_output = 0;
-
-#define TEXT_NORMAL "\033[0m"
-#define TEXT_BOLD "\033[1m"
-
-struct sd_option {
- int val;
- const char *name;
- int has_arg;
- const char *desc;
-};
+const char *sdhost = "localhost";
+int sdport = SD_LISTEN_PORT;
+int highlight = 1;
+int raw_output = 0;
static const struct sd_option collie_options[] = {
@@ -70,75 +45,14 @@ static const struct sd_option collie_options[] = {
{ 0, NULL, 0, NULL },
};
-static void usage(int status);
-
-static uint64_t node_list_version;
-
-static struct sheepdog_node_list_entry node_list_entries[SD_MAX_NODES];
-static struct sheepdog_vnode_list_entry vnode_list_entries[SD_MAX_VNODES];
-static int nr_nodes, nr_vnodes;
-static unsigned master_idx;
-
-static int is_current(struct sheepdog_inode *i)
-{
- return !i->snap_ctime;
-}
-
-static char *size_to_str(uint64_t _size, char *str, int str_size)
-{
- const char *units[] = {"MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
- int i = 0;
- double size;
-
- if (raw_output) {
- snprintf(str, str_size, "%" PRIu64, _size);
- return str;
- }
-
- size = (double)_size;
- size /= 1024 * 1024;
- while (i < ARRAY_SIZE(units) && size >= 1024) {
- i++;
- size /= 1024;
- }
-
- if (size >= 10)
- snprintf(str, str_size, "%.0lf %s", size, units[i]);
- else
- snprintf(str, str_size, "%.1lf %s", size, units[i]);
-
- return str;
-}
-
-static int parse_option_size(const char *value, uint64_t *ret)
-{
- char *postfix;
- double sizef;
+static void usage(struct command *commands, int status);
- sizef = strtod(value, &postfix);
- switch (*postfix) {
- case 'T':
- sizef *= 1024;
- case 'G':
- sizef *= 1024;
- case 'M':
- sizef *= 1024;
- case 'K':
- case 'k':
- sizef *= 1024;
- case 'b':
- case '\0':
- *ret = (uint64_t) sizef;
- break;
- default:
- fprintf(stderr, "invalid parameter, %s\n", value);
- fprintf(stderr, "You may use k, M, G or T suffixes for "
- "kilobytes, megabytes, gigabytes and terabytes.\n");
- return -1;
- }
+uint64_t node_list_version;
- return 0;
-}
+struct sheepdog_node_list_entry node_list_entries[SD_MAX_NODES];
+struct sheepdog_vnode_list_entry vnode_list_entries[SD_MAX_VNODES];
+int nr_nodes, nr_vnodes;
+unsigned master_idx;
static int update_node_list(int max_nodes, int epoch)
{
@@ -201,1446 +115,6 @@ out:
return ret;
}
-static int sd_read_object(uint64_t oid, void *data, unsigned int datalen,
- uint64_t offset)
-{
- struct sd_obj_req hdr;
- struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
- char name[128];
- int n, fd, ret;
- unsigned wlen = 0, rlen = datalen;
-
- n = obj_to_sheep(vnode_list_entries, nr_vnodes, oid, 0);
-
- addr_to_str(name, sizeof(name), vnode_list_entries[n].addr, 0);
-
- fd = connect_to(name, vnode_list_entries[n].port);
- if (fd < 0) {
- fprintf(stderr, "failed to connect %s:%d\n", name,
- vnode_list_entries[n].port);
- return SD_RES_EIO;
- }
-
- memset(&hdr, 0, sizeof(hdr));
- hdr.epoch = node_list_version;
- hdr.opcode = SD_OP_READ_OBJ;
- hdr.oid = oid;
- /* use direct to avoid checking consistency */
- hdr.flags = SD_FLAG_CMD_DIRECT;
- hdr.data_length = rlen;
- hdr.offset = offset;
-
- ret = exec_req(fd, (struct sd_req *)&hdr, data, &wlen, &rlen);
- close(fd);
-
- if (ret) {
- fprintf(stderr, "failed to read object, %lx\n", oid);
- return SD_RES_EIO;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to read object, %lx %s\n", oid,
- sd_strerror(rsp->result));
- return rsp->result;
- }
-
- return SD_RES_SUCCESS;
-}
-
-static int sd_write_object(uint64_t oid, void *data, unsigned int datalen,
- uint64_t offset, uint32_t flags, int copies, int create)
-{
- struct sd_obj_req hdr;
- struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
- int fd, ret;
- unsigned wlen = datalen, rlen;
-
- fd = connect_to(sdhost, sdport);
- if (fd < 0) {
- fprintf(stderr, "failed to connect\n");
- return SD_RES_EIO;
- }
-
- memset(&hdr, 0, sizeof(hdr));
- hdr.epoch = node_list_version;
- if (create)
- hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
- else
- hdr.opcode = SD_OP_WRITE_OBJ;
- hdr.oid = oid;
- hdr.copies = copies;
- hdr.data_length = wlen;
- hdr.flags = (flags & ~SD_FLAG_CMD_DIRECT) | SD_FLAG_CMD_WRITE;
- hdr.offset = offset;
-
- ret = exec_req(fd, (struct sd_req *)&hdr, data, &wlen, &rlen);
- close(fd);
-
- if (ret) {
- fprintf(stderr, "failed to write object, %lx\n", oid);
- return SD_RES_EIO;
- }
- if (rsp->result != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to write object, %lx %s\n", oid,
- sd_strerror(rsp->result));
- return rsp->result;
- }
-
- return SD_RES_SUCCESS;
-}
-
-struct cluster_cmd_data {
- int copies;
-} cluster_cmd_data;
-
-struct vdi_cmd_data {
- unsigned int index;
- int snapshot_id;
- char snapshot_tag[SD_MAX_VDI_TAG_LEN];
- int exclusive;
- int delete;
- int prealloc;
-} vdi_cmd_data = { ~0, };
-
-static int cluster_format(int argc, char **argv)
-{
- int fd, ret;
- struct sd_so_req hdr;
- struct sd_so_rsp *rsp = (struct sd_so_rsp *)&hdr;
- unsigned rlen, wlen;
- struct timeval tv;
-
- fd = connect_to(sdhost, sdport);
- if (fd < 0)
- return EXIT_SYSFAIL;
-
- gettimeofday(&tv, NULL);
-
- memset(&hdr, 0, sizeof(hdr));
-
- hdr.opcode = SD_OP_MAKE_FS;
- hdr.copies = cluster_cmd_data.copies;
- hdr.epoch = node_list_version;
- hdr.ctime = (uint64_t) tv.tv_sec << 32 | tv.tv_usec * 1000;
-
- rlen = 0;
- wlen = 0;
- ret = exec_req(fd, (struct sd_req *)&hdr, NULL, &wlen, &rlen);
- close(fd);
-
- if (ret) {
- fprintf(stderr, "failed to connect\n");
- return EXIT_SYSFAIL;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- fprintf(stderr, "%s\n", sd_strerror(rsp->result));
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int shutdown_sheepdog(void)
-{
- int fd, ret;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- unsigned rlen, wlen;
-
- fd = connect_to(sdhost, sdport);
- if (fd < 0)
- return EXIT_SYSFAIL;
-
- memset(&hdr, 0, sizeof(hdr));
-
- hdr.opcode = SD_OP_SHUTDOWN;
- hdr.epoch = node_list_version;
-
- rlen = 0;
- wlen = 0;
- ret = exec_req(fd, &hdr, NULL, &wlen, &rlen);
- close(fd);
-
- if (ret) {
- fprintf(stderr, "failed to connect\n");
- return EXIT_SYSFAIL;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- fprintf(stderr, "%s\n", sd_strerror(rsp->result));
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-typedef void (*vdi_parser_func_t)(uint32_t vid, char *name, char *tag,
- uint32_t snapid, uint32_t flags,
- struct sheepdog_inode *i, void *data);
-
-static int parse_vdi(vdi_parser_func_t func, size_t size, void *data)
-{
- int ret, fd;
- unsigned long nr;
- static struct sheepdog_inode i;
- struct sd_req req;
- static DECLARE_BITMAP(vdi_inuse, SD_NR_VDIS);
- unsigned int rlen, wlen = 0;
-
- fd = connect_to(sdhost, sdport);
- if (fd < 0)
- return fd;
-
- memset(&req, 0, sizeof(req));
-
- req.opcode = SD_OP_READ_VDIS;
- req.data_length = sizeof(vdi_inuse);
- req.epoch = node_list_version;
-
- rlen = sizeof(vdi_inuse);
- ret = exec_req(fd, &req, vdi_inuse, &wlen, &rlen);
- if (ret < 0) {
- close(fd);
- return ret;
- }
- close(fd);
-
- for (nr = 0; nr < SD_NR_VDIS; nr++) {
- uint64_t oid;
-
- if (!test_bit(nr, vdi_inuse))
- continue;
-
- oid = vid_to_vdi_oid(nr);
-
- memset(&i, 0, sizeof(i));
- ret = sd_read_object(oid, &i, SD_INODE_HEADER_SIZE, 0);
- if (ret != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to read a inode header\n");
- continue;
- }
-
- if (i.name[0] == '\0') /* this vdi is deleted */
- continue;
-
- if (size > SD_INODE_HEADER_SIZE) {
- rlen = DIV_ROUND_UP(i.vdi_size, SD_DATA_OBJ_SIZE) *
- sizeof(i.data_vdi_id[0]);
- if (rlen > size - SD_INODE_HEADER_SIZE)
- rlen = size - SD_INODE_HEADER_SIZE;
-
- ret = sd_read_object(oid, ((char *)&i) + SD_INODE_HEADER_SIZE,
- rlen, SD_INODE_HEADER_SIZE);
-
- if (ret != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to read inode\n");
- continue;
- }
- }
-
- func(i.vdi_id, i.name, i.tag, i.snap_id, 0, &i, data);
- }
-
- return 0;
-}
-
-struct get_vdi_info {
- char *name;
- char *tag;
- uint32_t vid;
- uint32_t snapid;
-};
-
-static void print_vdi_list(uint32_t vid, char *name, char *tag, uint32_t snapid,
- uint32_t flags, struct sheepdog_inode *i, void *data)
-{
- int idx;
- uint64_t my_objs, cow_objs;
- char vdi_size_str[16], my_objs_str[16], cow_objs_str[16];
- time_t ti;
- struct tm tm;
- char dbuf[128];
- struct get_vdi_info *info = data;
-
- if (info && strcmp(name, info->name) != 0)
- return;
-
- ti = i->ctime >> 32;
- if (raw_output) {
- snprintf(dbuf, sizeof(dbuf), "%" PRIu64, (uint64_t) ti);
- } else {
- localtime_r(&ti, &tm);
- strftime(dbuf, sizeof(dbuf),
- "%Y-%m-%d %H:%M", &tm);
- }
-
- my_objs = 0;
- cow_objs = 0;
- for (idx = 0; idx < MAX_DATA_OBJS; idx++) {
- if (!i->data_vdi_id[idx])
- continue;
- if (is_data_obj_writeable(i, idx))
- my_objs++;
- else
- cow_objs++;
- }
-
- size_to_str(i->vdi_size, vdi_size_str, sizeof(vdi_size_str));
- size_to_str(my_objs * SD_DATA_OBJ_SIZE, my_objs_str, sizeof(my_objs_str));
- size_to_str(cow_objs * SD_DATA_OBJ_SIZE, cow_objs_str, sizeof(cow_objs_str));
-
- if (raw_output) {
- printf("%c ", is_current(i) ? '=' : 's');
- while (*name) {
- if (isspace(*name) || *name == '\\')
- putchar('\\');
- putchar(*name++);
- }
- printf(" %d %s %s %s %s %" PRIx32 "\n", snapid,
- vdi_size_str, my_objs_str, cow_objs_str, dbuf, vid);
- } else {
- printf("%c %-8s %5d %7s %7s %7s %s %7" PRIx32 "\n",
- is_current(i) ? ' ' : 's', name, snapid,
- vdi_size_str, my_objs_str, cow_objs_str, dbuf, vid);
- }
-}
-
-static void print_vdi_tree(uint32_t vid, char *name, char * tag, uint32_t snapid,
- uint32_t flags, struct sheepdog_inode *i, void *data)
-{
- time_t ti;
- struct tm tm;
- char buf[128];
-
- if (is_current(i))
- strcpy(buf, "(You Are Here)");
- else {
- ti = i->ctime >> 32;
- localtime_r(&ti, &tm);
-
- strftime(buf, sizeof(buf),
- "[%Y-%m-%d %H:%M]", &tm);
- }
-
- add_vdi_tree(name, buf, vid, i->parent_vdi_id, highlight && is_current(i));
-}
-
-static void print_vdi_graph(uint32_t vid, char *name, char * tag, uint32_t snapid,
- uint32_t flags, struct sheepdog_inode *i, void *data)
-{
- time_t ti;
- struct tm tm;
- char dbuf[128], tbuf[128], size_str[128];
-
- ti = i->ctime >> 32;
- localtime_r(&ti, &tm);
-
- strftime(dbuf, sizeof(dbuf), "%Y-%m-%d", &tm);
- strftime(tbuf, sizeof(tbuf), "%H:%M:%S", &tm);
- size_to_str(i->vdi_size, size_str, sizeof(size_str));
-
- printf(" \"%x\" -> \"%x\";\n", i->parent_vdi_id, vid);
- printf(" \"%x\" [\n"
- " group = \"%s\",\n"
- " label = \"",
- vid, name);
- printf("name: %10s\\n"
- "tag : %10x\\n"
- "size: %10s\\n"
- "date: %10s\\n"
- "time: %10s",
- name, snapid, size_str, dbuf, tbuf);
-
- if (is_current(i))
- printf("\",\n color=\"red\"\n ];\n\n");
- else
- printf("\"\n ];\n\n");
-
-}
-
-static void cal_total_vdi_size(uint32_t vid, char *name, char * tag,
- uint32_t snapid, uint32_t flags,
- struct sheepdog_inode *i, void *data)
-{
- uint64_t *size = data;
-
- if (is_current(i))
- *size += i->vdi_size;
-}
-
-static void get_oid(uint32_t vid, char *name, char *tag, uint32_t snapid,
- uint32_t flags, struct sheepdog_inode *i, void *data)
-{
- struct get_vdi_info *info = data;
-
- if (info->name) {
- if (info->tag) {
- if (!strcmp(name, info->name) && !strcmp(tag, info->tag))
- info->vid = vid;
- } else if (info->snapid) {
- if (!strcmp(name, info->name) && snapid == info->snapid)
- info->vid = vid;
- } else {
- if (!strcmp(name, info->name))
- info->vid = vid;
- }
- }
-}
-
-typedef void (*obj_parser_func_t)(char *sheep, uint64_t oid,
- struct sd_obj_rsp *rsp, char *buf, void *data);
-
-static void do_print_obj(char *sheep, uint64_t oid, struct sd_obj_rsp *rsp,
- char *buf, void *data)
-{
- switch (rsp->result) {
- case SD_RES_SUCCESS:
- printf("%s: has the object (should be %d copies)\n",
- sheep, rsp->copies);
- break;
- case SD_RES_NO_OBJ:
- printf("%s: doesn't have\n", sheep);
- break;
- case SD_RES_OLD_NODE_VER:
- case SD_RES_NEW_NODE_VER:
- printf("the node list has changed, try again\n");
- break;
- default:
- printf("%s: hit an expected error, %d\n",
- sheep, rsp->result);
- break;
- }
-}
-
-struct get_data_oid_info {
- int success;
- uint64_t data_oid;
- unsigned idx;
-};
-
-static void get_data_oid(char *sheep, uint64_t oid, struct sd_obj_rsp *rsp,
- char *buf, void *data)
-{
- struct get_data_oid_info *info = data;
- struct sheepdog_inode *inode = (struct sheepdog_inode *)buf;
-
- switch (rsp->result) {
- case SD_RES_SUCCESS:
- if (info->success)
- break;
- info->success = 1;
- if (inode->data_vdi_id[info->idx])
- info->data_oid = vid_to_data_oid(inode->data_vdi_id[info->idx], info->idx);
- break;
- case SD_RES_NO_OBJ:
- break;
- case SD_RES_OLD_NODE_VER:
- case SD_RES_NEW_NODE_VER:
- printf("the node list has changed, try again\n");
- break;
- default:
- printf("%s: hit an expected error, %d\n",
- sheep, rsp->result);
- break;
- }
-}
-
-static void parse_objs(uint64_t oid, obj_parser_func_t func, void *data)
-{
- char name[128];
- int i, fd, ret;
- char *buf;
-
- buf = zalloc(sizeof(struct sheepdog_inode));
- if (!buf) {
- fprintf(stderr, "out of memory\n");
- return;
- }
-
- for (i = 0; i < nr_nodes; i++) {
- unsigned wlen = 0, rlen = sizeof(struct sheepdog_inode);
- struct sd_obj_req hdr;
- struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
-
- addr_to_str(name, sizeof(name), node_list_entries[i].addr, 0);
-
- fd = connect_to(name, node_list_entries[i].port);
- if (fd < 0)
- break;
-
- memset(&hdr, 0, sizeof(hdr));
-
- hdr.opcode = SD_OP_READ_OBJ;
- hdr.data_length = rlen;
- hdr.flags = SD_FLAG_CMD_DIRECT;
- hdr.oid = oid;
- hdr.epoch = node_list_version;
-
- ret = exec_req(fd, (struct sd_req *)&hdr, buf, &wlen, &rlen);
- close(fd);
-
- sprintf(name + strlen(name), ":%d", node_list_entries[i].port);
-
- if (ret)
- printf("%s: can't connect\n", name);
- else
- func(name, oid, rsp, buf, data);
- }
-
- free(buf);
-}
-
-#define SUBCMD_FLAG_NEED_NODELIST (1 << 0)
-#define SUBCMD_FLAG_NEED_THIRD_ARG (1 << 1)
-
-struct subcommand {
- const char *name;
- const char *arg;
- const char *opts;
- const char *desc;
- unsigned long flags;
- int (*fn)(int, char **);
-};
-
-static int node_list(int argc, char **argv)
-{
- int i;
-
- if (!raw_output) {
- printf(" Idx - Host:Port Vnodes Zone\n");
- printf("---------------------------------------------\n");
- }
- for (i = 0; i < nr_nodes; i++) {
- char data[128];
-
- addr_to_str(data, sizeof(data), node_list_entries[i].addr,
- node_list_entries[i].port);
-
- if (i == master_idx) {
- if (highlight)
- printf(TEXT_BOLD);
- printf(raw_output ? "* %d %s %d %d\n" : "* %4d - %-20s\t%d%11d\n",
- i, data, node_list_entries[i].nr_vnodes,
- node_list_entries[i].zone);
- if (highlight)
- printf(TEXT_NORMAL);
- } else
- printf(raw_output ? "- %d %s %d %d\n" : " %4d - %-20s\t%d%11d\n",
- i, data, node_list_entries[i].nr_vnodes,
- node_list_entries[i].zone);
- }
-
- return EXIT_SUCCESS;
-}
-
-static int node_info(int argc, char **argv)
-{
- int i, ret, success = 0;
- uint64_t total_size = 0, total_avail = 0, total_vdi_size = 0;
- char total_str[8], avail_str[8], vdi_size_str[8];
-
- if (!raw_output)
- printf("Id\tSize\tUsed\tUse%%\n");
-
- for (i = 0; i < nr_nodes; i++) {
- char name[128];
- int fd;
- unsigned wlen, rlen;
- struct sd_node_req req;
- struct sd_node_rsp *rsp = (struct sd_node_rsp *)&req;
- char store_str[8], free_str[8];
-
- addr_to_str(name, sizeof(name), node_list_entries[i].addr, 0);
-
- fd = connect_to(name, node_list_entries[i].port);
- if (fd < 0)
- return 1;
-
- memset(&req, 0, sizeof(req));
-
- req.opcode = SD_OP_STAT_SHEEP;
- req.epoch = node_list_version;
-
- wlen = 0;
- rlen = 0;
- ret = exec_req(fd, (struct sd_req *)&req, NULL, &wlen, &rlen);
- close(fd);
-
- size_to_str(rsp->store_size, store_str, sizeof(store_str));
- size_to_str(rsp->store_size - rsp->store_free, free_str,
- sizeof(free_str));
- if (!ret && rsp->result == SD_RES_SUCCESS) {
- printf(raw_output ? "%d %s %s %d%%\n" : "%2d\t%s\t%s\t%3d%%\n",
- i, store_str, free_str,
- (int)(((double)(rsp->store_size - rsp->store_free) / rsp->store_size) * 100));
- success++;
- }
-
- total_size += rsp->store_size;
- total_avail += rsp->store_free;
- }
-
- if (success == 0) {
- fprintf(stderr, "cannot get information from any nodes\n");
- return EXIT_SYSFAIL;
- }
-
- parse_vdi(cal_total_vdi_size, SD_INODE_HEADER_SIZE, &total_vdi_size);
-
- size_to_str(total_size, total_str, sizeof(total_str));
- size_to_str(total_size - total_avail, avail_str, sizeof(avail_str));
- size_to_str(total_vdi_size, vdi_size_str, sizeof(vdi_size_str));
- printf(raw_output ? "Total %s %s %d%% %s\n"
- : "\nTotal\t%s\t%s\t%3d%%, total virtual VDI Size\t%s\n",
- total_str, avail_str,
- (int)(((double)(total_size - total_avail) / total_size) * 100),
- vdi_size_str);
-
- return EXIT_SUCCESS;
-}
-
-static struct subcommand node_cmd[] = {
- {"list", NULL, "aprh", "list nodes",
- SUBCMD_FLAG_NEED_NODELIST, node_list},
- {"info", NULL, "aprh", "show each node information",
- SUBCMD_FLAG_NEED_NODELIST, node_info},
- {NULL,},
-};
-
-static int vdi_list(int argc, char **argv)
-{
- char *vdiname = argv[optind];
-
- if (!raw_output) {
- printf(" name id size used shared creation time vdi id\n");
- printf("------------------------------------------------------------------\n");
- }
-
- if (vdiname) {
- struct get_vdi_info info;
- memset(&info, 0, sizeof(info));
- info.name = vdiname;
- parse_vdi(print_vdi_list, SD_INODE_SIZE, &info);
- return EXIT_SUCCESS;
- } else {
- parse_vdi(print_vdi_list, SD_INODE_SIZE, NULL);
- return EXIT_SUCCESS;
- }
-}
-
-static int vdi_tree(int argc, char **argv)
-{
- init_tree();
- parse_vdi(print_vdi_tree, SD_INODE_HEADER_SIZE, NULL);
- dump_tree();
-
- return EXIT_SUCCESS;
-}
-
-static int vdi_graph(int argc, char **argv)
-{
- /* print a header */
- printf("digraph G {\n");
- printf(" node [shape = \"box\", fontname = \"Courier\"];\n\n");
- printf(" \"0\" [shape = \"ellipse\", label = \"root\"];\n\n");
-
- parse_vdi(print_vdi_graph, SD_INODE_HEADER_SIZE, NULL);
-
- /* print a footer */
- printf("}\n");
-
- return EXIT_SUCCESS;
-}
-
-static int find_vdi_name(char *vdiname, uint32_t snapid, const char *tag,
- uint32_t *vid, int for_snapshot)
-{
- int ret, fd;
- struct sd_vdi_req hdr;
- struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
- unsigned int wlen, rlen = 0;
- char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
-
- fd = connect_to(sdhost, sdport);
- if (fd < 0)
- return -1;
-
- memset(buf, 0, sizeof(buf));
- strncpy(buf, vdiname, SD_MAX_VDI_LEN);
- strncpy(buf + SD_MAX_VDI_LEN, tag, SD_MAX_VDI_TAG_LEN);
-
- memset(&hdr, 0, sizeof(hdr));
- if (for_snapshot)
- hdr.opcode = SD_OP_GET_VDI_INFO;
- else
- hdr.opcode = SD_OP_LOCK_VDI;
- wlen = SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN;
- hdr.proto_ver = SD_PROTO_VER;
- hdr.data_length = wlen;
- hdr.snapid = snapid;
- hdr.flags = SD_FLAG_CMD_WRITE;
-
- ret = exec_req(fd, (struct sd_req *)&hdr, buf, &wlen, &rlen);
- if (ret) {
- ret = -1;
- goto out;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- fprintf(stderr, "cannot get vdi info, %s, %s %d %s\n",
- sd_strerror(rsp->result), vdiname, snapid, tag);
- ret = -1;
- goto out;
- }
- *vid = rsp->vdi_id;
-
- ret = 0;
-out:
- close(fd);
- return ret;
-}
-
-static int do_vdi_create(char *vdiname, int64_t vdi_size, uint32_t base_vid,
- uint32_t *vdi_id, int snapshot)
-{
- struct sd_vdi_req hdr;
- struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
- int fd, ret;
- unsigned int wlen, rlen = 0;
- char buf[SD_MAX_VDI_LEN];
-
- fd = connect_to(sdhost, sdport);
- if (fd < 0) {
- fprintf(stderr, "failed to connect\n");
- return EXIT_SYSFAIL;
- }
-
- memset(buf, 0, sizeof(buf));
- strncpy(buf, vdiname, SD_MAX_VDI_LEN);
-
- memset(&hdr, 0, sizeof(hdr));
- hdr.opcode = SD_OP_NEW_VDI;
- hdr.base_vdi_id = base_vid;
-
- wlen = SD_MAX_VDI_LEN;
-
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.snapid = snapshot;
-
- hdr.data_length = wlen;
- hdr.vdi_size = vdi_size;
-
- ret = exec_req(fd, (struct sd_req *)&hdr, buf, &wlen, &rlen);
-
- close(fd);
-
- if (ret) {
- fprintf(stderr, "failed to send a request\n");
- return EXIT_SYSFAIL;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- fprintf(stderr, "%s, %s\n", sd_strerror(rsp->result), vdiname);
- return EXIT_FAILURE;
- }
-
- if (vdi_id)
- *vdi_id = rsp->vdi_id;
-
- return EXIT_SUCCESS;
-}
-
-static int vdi_create(int argc, char **argv)
-{
- char *vdiname = argv[optind++];
- uint64_t size;
- uint32_t vid;
- uint64_t oid;
- int idx, max_idx, ret;
- struct sheepdog_inode *inode = NULL;
- char *buf = NULL;
-
- if (!argv[optind]) {
- fprintf(stderr, "please specify the size of vdi\n");
- return EXIT_USAGE;
- }
- ret = parse_option_size(argv[optind], &size);
- if (ret < 0)
- return EXIT_USAGE;
- if (size > SD_MAX_VDI_SIZE) {
- fprintf(stderr, "too big image size, %s\n", argv[optind]);
- return EXIT_USAGE;
- }
-
- ret = do_vdi_create(vdiname, size, 0, &vid, 0);
- if (ret != EXIT_SUCCESS || !vdi_cmd_data.prealloc)
- goto out;
-
- inode = malloc(sizeof(*inode));
- buf = zalloc(SD_DATA_OBJ_SIZE);
- if (!inode || !buf) {
- fprintf(stderr, "oom\n");
- ret = EXIT_SYSFAIL;
- goto out;
- }
-
- ret = sd_read_object(vid_to_vdi_oid(vid), inode, sizeof(*inode), 0);
- if (ret != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to read a newly created vdi object\n");
- ret = EXIT_FAILURE;
- goto out;
- }
- max_idx = DIV_ROUND_UP(size, SD_DATA_OBJ_SIZE);
-
- for (idx = 0; idx < max_idx; idx++) {
- oid = vid_to_data_oid(vid, idx);
-
- ret = sd_write_object(oid, buf, SD_DATA_OBJ_SIZE, 0, 0,
- inode->nr_copies, 1);
- if (ret != SD_RES_SUCCESS) {
- ret = EXIT_FAILURE;
- goto out;
- }
-
- inode->data_vdi_id[idx] = vid;
- ret = sd_write_object(vid_to_vdi_oid(vid), &vid, sizeof(vid),
- SD_INODE_HEADER_SIZE + sizeof(vid) * idx, 0,
- inode->nr_copies, 0);
- if (ret) {
- ret = EXIT_FAILURE;
- goto out;
- }
- }
- ret = EXIT_SUCCESS;
-out:
- free(inode);
- free(buf);
- return ret;
-}
-
-static int vdi_snapshot(int argc, char **argv)
-{
- char *vdiname = argv[optind++];
- uint32_t vid;
- int ret;
- char buf[SD_INODE_HEADER_SIZE];
- struct sheepdog_inode *inode = (struct sheepdog_inode *)buf;
-
- if (vdi_cmd_data.snapshot_id != 0) {
- fprintf(stderr, "please specify a non-integer value for "
- "a snapshot tag name\n");
- return EXIT_USAGE;
- }
-
- ret = find_vdi_name(vdiname, 0, "", &vid, 0);
- if (ret < 0) {
- fprintf(stderr, "failed to open vdi %s\n", vdiname);
- return EXIT_FAILURE;
- }
-
- ret = sd_read_object(vid_to_vdi_oid(vid), inode, SD_INODE_HEADER_SIZE, 0);
- if (ret != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to read an inode header\n");
- return EXIT_FAILURE;
- }
-
- if (vdi_cmd_data.snapshot_tag[0]) {
- ret = sd_write_object(vid_to_vdi_oid(vid), vdi_cmd_data.snapshot_tag,
- SD_MAX_VDI_TAG_LEN,
- offsetof(struct sheepdog_inode, tag),
- 0, inode->nr_copies, 0);
- }
-
- return do_vdi_create(vdiname, inode->vdi_size, vid, NULL, 1);
-}
-
-static int vdi_clone(int argc, char **argv)
-{
- char *src_vdi = argv[optind++], *dst_vdi;
- uint32_t base_vid, new_vid;
- uint64_t oid;
- int idx, max_idx, ret;
- struct sheepdog_inode *inode = NULL;
- char *buf = NULL;
-
- dst_vdi = argv[optind];
- if (!dst_vdi) {
- fprintf(stderr, "a dst vdi must be specified\n");
- ret = EXIT_USAGE;
- goto out;
- }
-
- if (!vdi_cmd_data.snapshot_id && !vdi_cmd_data.snapshot_tag[0]) {
- fprintf(stderr, "it is not supported to create a clone image of "
- "the non-snapshot vdi\n");
- fprintf(stderr, "please specify a '-s' option\n");
- ret = EXIT_USAGE;
- goto out;
- }
-
- ret = find_vdi_name(src_vdi, vdi_cmd_data.snapshot_id,
- vdi_cmd_data.snapshot_tag, &base_vid, 0);
- if (ret < 0) {
- fprintf(stderr, "failed to open vdi %s\n", src_vdi);
- ret = EXIT_FAILURE;
- goto out;
- }
-
- inode = malloc(sizeof(*inode));
- if (!inode) {
- fprintf(stderr, "oom\n");
- ret = EXIT_SYSFAIL;
- goto out;
- }
- ret = sd_read_object(vid_to_vdi_oid(base_vid), inode, SD_INODE_SIZE, 0);
- if (ret != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to read a base inode\n");
- ret = EXIT_FAILURE;
- goto out;
- }
-
- ret = do_vdi_create(dst_vdi, inode->vdi_size, base_vid, &new_vid, 0);
- if (ret != EXIT_SUCCESS || !vdi_cmd_data.prealloc)
- goto out;
-
- buf = zalloc(SD_DATA_OBJ_SIZE);
- if (!buf) {
- fprintf(stderr, "oom\n");
- ret = EXIT_SYSFAIL;
- goto out;
- }
-
- max_idx = DIV_ROUND_UP(inode->vdi_size, SD_DATA_OBJ_SIZE);
-
- for (idx = 0; idx < max_idx; idx++) {
- if (inode->data_vdi_id[idx]) {
- oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
- ret = sd_read_object(oid, buf, SD_DATA_OBJ_SIZE, 0);
- if (ret) {
- ret = EXIT_FAILURE;
- goto out;
- }
- } else
- memset(buf, 0, SD_DATA_OBJ_SIZE);
-
- oid = vid_to_data_oid(new_vid, idx);
- ret = sd_write_object(oid, buf, SD_DATA_OBJ_SIZE, 0, 0,
- inode->nr_copies, 1);
- if (ret != SD_RES_SUCCESS) {
- ret = EXIT_FAILURE;
- goto out;
- }
-
- ret = sd_write_object(vid_to_vdi_oid(new_vid), &new_vid, sizeof(new_vid),
- SD_INODE_HEADER_SIZE + sizeof(new_vid) * idx, 0,
- inode->nr_copies, 0);
- if (ret) {
- ret = EXIT_FAILURE;
- goto out;
- }
- }
- ret = EXIT_SUCCESS;
-out:
- free(inode);
- free(buf);
- return ret;
-}
-
-static int vdi_resize(int argc, char **argv)
-{
- char *vdiname = argv[optind++];
- uint64_t new_size;
- uint32_t vid;
- int ret;
- char buf[SD_INODE_HEADER_SIZE];
- struct sheepdog_inode *inode = (struct sheepdog_inode *)buf;
-
- if (!argv[optind]) {
- fprintf(stderr, "please specify a new size of vdi\n");
- return EXIT_USAGE;
- }
- ret = parse_option_size(argv[optind], &new_size);
- if (ret < 0)
- return EXIT_USAGE;
- if (new_size > SD_MAX_VDI_SIZE) {
- fprintf(stderr, "too big image size, %s\n", argv[optind]);
- return EXIT_USAGE;
- }
-
- ret = find_vdi_name(vdiname, 0, "", &vid, 0);
- if (ret < 0) {
- fprintf(stderr, "failed to open vdi %s\n", vdiname);
- return EXIT_FAILURE;
- }
-
- ret = sd_read_object(vid_to_vdi_oid(vid), inode, SD_INODE_HEADER_SIZE, 0);
- if (ret != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to read an inode header\n");
- return EXIT_FAILURE;
- }
-
- if (new_size < inode->vdi_size) {
- fprintf(stderr, "shrinking is not implemented\n");
- return EXIT_USAGE;
- }
- inode->vdi_size = new_size;
-
- ret = sd_write_object(vid_to_vdi_oid(vid), inode, SD_INODE_HEADER_SIZE, 0,
- 0, inode->nr_copies, 0);
- if (ret != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to update an inode header\n");
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int vdi_delete(int argc, char **argv)
-{
- char *data = argv[optind];
- int fd, ret;
- struct sd_vdi_req hdr;
- struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
- unsigned rlen, wlen;
- char vdiname[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
-
- fd = connect_to(sdhost, sdport);
- if (fd < 0)
- return EXIT_SYSFAIL;
-
- memset(&hdr, 0, sizeof(hdr));
-
- rlen = 0;
- wlen = sizeof(vdiname);
-
- hdr.opcode = SD_OP_DEL_VDI;
- hdr.snapid = vdi_cmd_data.snapshot_id;
- hdr.epoch = node_list_version;
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.data_length = wlen;
- memset(vdiname, 0, sizeof(vdiname));
- strncpy(vdiname, data, SD_MAX_VDI_LEN);
- strncpy(vdiname + SD_MAX_VDI_LEN, vdi_cmd_data.snapshot_tag,
- SD_MAX_VDI_TAG_LEN);
-
- ret = exec_req(fd, (struct sd_req *)&hdr, vdiname, &wlen, &rlen);
- close(fd);
-
- if (ret) {
- fprintf(stderr, "failed to connect\n");
- return EXIT_SYSFAIL;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- fprintf(stderr, "%s: %s\n", vdiname, sd_strerror(rsp->result));
- if (rsp->result == SD_RES_NO_VDI)
- return EXIT_MISSING;
- else
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int vdi_object(int argc, char **argv)
-{
- char *vdiname = argv[optind];
- unsigned idx = vdi_cmd_data.index;
- int ret;
- struct get_vdi_info info;
- uint32_t vid;
-
- memset(&info, 0, sizeof(info));
- info.name = vdiname;
- info.tag = vdi_cmd_data.snapshot_tag;
- info.vid = 0;
- info.snapid = vdi_cmd_data.snapshot_id;
-
- ret = parse_vdi(get_oid, SD_INODE_HEADER_SIZE, &info);
-
- vid = info.vid;
- if (vid == 0) {
- printf("No such vdi\n");
- return EXIT_MISSING;
- }
-
- if (idx == ~0) {
- printf("Looking for the inode object 0x%" PRIx32 " with %d nodes\n\n",
- vid, nr_nodes);
- parse_objs(vid_to_vdi_oid(vid), do_print_obj, NULL);
- } else {
- struct get_data_oid_info old_info;
-
- old_info.success = 0;
- old_info.idx = idx;
-
- if (idx >= MAX_DATA_OBJS) {
- printf("The offset is too large!\n");
- exit(EXIT_FAILURE);
- }
-
- parse_objs(vid_to_vdi_oid(vid), get_data_oid, &old_info);
-
- if (old_info.success) {
- if (old_info.data_oid) {
- printf("Looking for the object 0x%" PRIx64
- " (the inode vid 0x%" PRIx32 " idx %u) with %d nodes\n\n",
- old_info.data_oid, vid, idx, nr_nodes);
-
- parse_objs(old_info.data_oid, do_print_obj, NULL);
- } else
- printf("The inode object 0x%" PRIx32 " idx %u is not allocated\n",
- vid, idx);
- } else
- printf("failed to read the inode object 0x%" PRIx32 "\n", vid);
- }
-
- return EXIT_SUCCESS;
-}
-
-static int find_vdi_attr_oid(char *vdiname, char *tag, uint32_t snapid,
- char *key, uint32_t *vid, uint64_t *oid,
- unsigned int *nr_copies, int creat, int excl)
-{
- struct sd_vdi_req hdr;
- struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
- int fd, ret;
- unsigned int wlen, rlen;
- char buf[SD_ATTR_HEADER_SIZE];
-
- memset(buf, 0, sizeof(buf));
- strncpy(buf, vdiname, SD_MAX_VDI_LEN);
- strncpy(buf + SD_MAX_VDI_LEN, vdi_cmd_data.snapshot_tag,
- SD_MAX_VDI_TAG_LEN);
- memcpy(buf + SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN,
- &vdi_cmd_data.snapshot_id, sizeof(uint32_t));
- strncpy(buf + SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN + sizeof(uint32_t),
- key, SD_MAX_VDI_ATTR_KEY_LEN);
-
- fd = connect_to(sdhost, sdport);
- if (fd < 0) {
- fprintf(stderr, "failed to connect\n\n");
- return SD_RES_EIO;
- }
-
- memset(&hdr, 0, sizeof(hdr));
- hdr.opcode = SD_OP_GET_VDI_ATTR;
- wlen = SD_ATTR_HEADER_SIZE;
- rlen = 0;
- hdr.proto_ver = SD_PROTO_VER;
- hdr.data_length = wlen;
- hdr.snapid = vdi_cmd_data.snapshot_id;
- hdr.flags = SD_FLAG_CMD_WRITE;
- if (creat)
- hdr.flags |= SD_FLAG_CMD_CREAT;
- if (excl)
- hdr.flags |= SD_FLAG_CMD_EXCL;
-
- ret = exec_req(fd, (struct sd_req *)&hdr, buf, &wlen, &rlen);
- if (ret) {
- ret = SD_RES_EIO;
- goto out;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- ret = rsp->result;
- goto out;
- }
-
- *vid = rsp->vdi_id;
- *oid = vid_to_attr_oid(rsp->vdi_id, rsp->attr_id);
- *nr_copies = rsp->copies;
-
- ret = SD_RES_SUCCESS;
-out:
- close(fd);
- return ret;
-}
-
-static int vdi_setattr(int argc, char **argv)
-{
- int ret;
- uint64_t oid, attr_oid = 0;
- uint32_t vid = 0, nr_copies = 0;
- char *vdiname = argv[optind++], *key, *value;
- uint64_t offset;
-
- key = argv[optind++];
- if (!key) {
- fprintf(stderr, "please specify the name of key\n");
- return EXIT_USAGE;
- }
-
- value = argv[optind++];
- if (!value && !vdi_cmd_data.delete) {
- value = malloc(SD_MAX_VDI_ATTR_VALUE_LEN);
- if (!value) {
- fprintf(stderr, "failed to allocate memory\n");
- return EXIT_SYSFAIL;
- }
-
- offset = 0;
-reread:
- ret = read(STDIN_FILENO, value + offset,
- SD_MAX_VDI_ATTR_VALUE_LEN - offset);
- if (ret < 0) {
- fprintf(stderr, "failed to read from stdin, %m\n");
- return EXIT_SYSFAIL;
- }
- if (ret > 0) {
- offset += ret;
- goto reread;
- }
- }
-
- ret = find_vdi_attr_oid(vdiname, vdi_cmd_data.snapshot_tag,
- vdi_cmd_data.snapshot_id, key, &vid, &attr_oid,
- &nr_copies, !vdi_cmd_data.delete,
- vdi_cmd_data.exclusive);
- if (ret) {
- if (ret == SD_RES_VDI_EXIST) {
- fprintf(stderr, "the attribute already exists, %s\n", key);
- return EXIT_EXISTS;
- } else if (ret == SD_RES_NO_OBJ) {
- fprintf(stderr, "no such attribute, %s\n", key);
- return EXIT_MISSING;
- } else if (ret == SD_RES_NO_VDI) {
- fprintf(stderr, "vdi not found\n");
- return EXIT_MISSING;
- } else
- fprintf(stderr, "failed to find attr oid, %s\n",
- sd_strerror(ret));
- return EXIT_FAILURE;
- }
-
- oid = attr_oid;
-
- if (vdi_cmd_data.delete)
- ret = sd_write_object(oid, (char *)"", 1,
- offsetof(struct sheepdog_inode, name), 0,
- nr_copies, 0);
- else
- ret = sd_write_object(oid, value, strlen(value),
- SD_ATTR_HEADER_SIZE, SD_FLAG_CMD_TRUNCATE,
- nr_copies, 0);
-
- if (ret != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to set attribute\n");
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int vdi_getattr(int argc, char **argv)
-{
- struct sd_obj_req hdr;
- struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
- int ret;
- uint64_t oid, attr_oid = 0;
- uint32_t vid = 0, nr_copies = 0;
- char *vdiname = argv[optind++], *key, *value;
-
- key = argv[optind++];
- if (!key) {
- fprintf(stderr, "please specify the name of key\n");
- return EXIT_USAGE;
- }
-
- ret = find_vdi_attr_oid(vdiname, vdi_cmd_data.snapshot_tag,
- vdi_cmd_data.snapshot_id, key, &vid, &attr_oid,
- &nr_copies, 0, 0);
- if (ret == SD_RES_NO_OBJ) {
- fprintf(stderr, "no such attribute, %s\n", key);
- return EXIT_MISSING;
- } else if (ret == SD_RES_NO_VDI) {
- fprintf(stderr, "vdi not found\n");
- return EXIT_MISSING;
- } else if (ret) {
- fprintf(stderr, "failed to find attr oid, %s\n",
- sd_strerror(ret));
- return EXIT_MISSING;
- }
-
- oid = attr_oid;
- value = malloc(SD_MAX_VDI_ATTR_VALUE_LEN);
- if (!value) {
- fprintf(stderr, "failed to allocate memory\n");
- return EXIT_SYSFAIL;
- }
-
- ret = sd_read_object(oid, value, SD_MAX_VDI_ATTR_VALUE_LEN,
- SD_ATTR_HEADER_SIZE);
- if (rsp->result == SD_RES_SUCCESS) {
- printf("%s", value);
- free(value);
- return EXIT_SUCCESS;
- }
-
- free(value);
- return EXIT_FAILURE;
-}
-
-static struct subcommand vdi_cmd[] = {
- {"create", "<vdiname> <size>", "Paph", "create a image",
- SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_create},
- {"snapshot", "<vdiname>", "saph", "create a snapshot",
- SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_snapshot},
- {"clone", "<src vdi> <dst vdi>", "sPaph", "create a clone image",
- SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_clone},
- {"delete", "<vdiname>", "saph", "delete a image",
- SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_delete},
- {"list", "[vdiname]", "aprh", "list images",
- SUBCMD_FLAG_NEED_NODELIST, vdi_list},
- {"tree", NULL, "aph", "show images in tree view format",
- SUBCMD_FLAG_NEED_NODELIST, vdi_tree},
- {"graph", NULL, "aph", "show images with Graphviz dot format",
- SUBCMD_FLAG_NEED_NODELIST, vdi_graph},
- {"object", "<vdiname>", "isaph", "show object information in the image",
- SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_object},
- {"setattr", "<vdiname> <key> [value]", "dxaph", "set a vdi attribute",
- SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_setattr},
- {"getattr", "<vdiname> <key>", "aph", "get a vdi attribute",
- SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_getattr},
- {"resize", "<vdiname> <new size>", "aph", "resize a image",
- SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_resize},
- {NULL,},
-};
-
-static int vdi_parser(int ch, char *opt)
-{
- switch (ch) {
- case 'P':
- vdi_cmd_data.prealloc = 1;
- break;
- case 'i':
- vdi_cmd_data.index = atoi(opt);
- break;
- case 's':
- vdi_cmd_data.snapshot_id = atoi(opt);
- if (vdi_cmd_data.snapshot_id == 0)
- strncpy(vdi_cmd_data.snapshot_tag, opt,
- sizeof(vdi_cmd_data.snapshot_tag));
- break;
- case 'x':
- vdi_cmd_data.exclusive = 1;
- break;
- case 'd':
- vdi_cmd_data.delete = 1;
- break;
- }
-
- return 0;
-}
-
-static int cluster_info(int argc, char **argv)
-{
- int i, fd, ret;
- struct sd_vdi_req hdr;
- struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
- unsigned rlen, wlen;
- struct epoch_log logs[8];
- int nr_logs;
- time_t ti;
- struct tm tm;
- char time_str[128];
-
- fd = connect_to(sdhost, sdport);
- if (fd < 0)
- return EXIT_SYSFAIL;
-
- memset(&hdr, 0, sizeof(hdr));
-
- hdr.opcode = SD_OP_STAT_CLUSTER;
- hdr.epoch = node_list_version;
- hdr.data_length = sizeof(logs);
-
- rlen = hdr.data_length;
- wlen = 0;
- ret = exec_req(fd, (struct sd_req *)&hdr, logs, &wlen, &rlen);
- close(fd);
-
- if (ret != 0)
- return EXIT_SYSFAIL;
-
- if (!raw_output)
- printf("Cluster status: ");
- if (rsp->result == SD_RES_SUCCESS)
- printf("running\n");
- else
- printf("%s\n", sd_strerror(rsp->result));
-
- if (!raw_output)
- printf("\nCreation time Epoch Nodes\n");
-
- nr_logs = rsp->data_length / sizeof(struct epoch_log);
- for (i = 0; i < nr_logs; i++) {
- int j;
- char name[128];
- struct sheepdog_node_list_entry *entry;
-
- ti = logs[i].ctime >> 32;
- if (raw_output) {
- snprintf(time_str, sizeof(time_str), "%" PRIu64, (uint64_t) ti);
- } else {
- localtime_r(&ti, &tm);
- strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm);
- }
-
- printf(raw_output ? "%s %d" : "%s %6d", time_str, logs[i].epoch);
- printf(" [");
- for (j = 0; j < logs[i].nr_nodes; j++) {
- entry = logs[i].nodes + j;
- printf("%s%s",
- (j == 0) ? "" : ", ",
- addr_to_str(name, sizeof(name),
- entry->addr, entry->port));
- }
- printf("]\n");
- }
-
- return EXIT_SUCCESS;
-}
-
-static int cluster_parser(int ch, char *opt)
-{
- switch (ch) {
- case 'c':
- cluster_cmd_data.copies = atoi(opt);
- break;
- }
-
- return 0;
-}
-
-static int cluster_shutdown(int argc, char **argv)
-{
- return shutdown_sheepdog();
-}
-
-static struct subcommand cluster_cmd[] = {
- {"info", NULL, "aprh", "show cluster information",
- 0, cluster_info},
- {"format", NULL, "caph", "create a Sheepdog storage",
- 0, cluster_format},
- {"shutdown", NULL, "aph", "stop Sheepdog",
- SUBCMD_FLAG_NEED_NODELIST, cluster_shutdown},
- {NULL,},
-};
-
-static struct {
- const char *name;
- struct subcommand *sub;
- int (*parser)(int, char *);
-} commands[] = {
- {"vdi", vdi_cmd,
- vdi_parser,},
- {"node", node_cmd,},
- {"cluster", cluster_cmd,
- cluster_parser,},
-};
-
static int (*command_parser)(int, char *);
static int (*command_fn)(int, char **);
static const char *command_options;
@@ -1697,13 +171,13 @@ static struct option *build_long_options(const char *opts)
return lopts;
}
-static unsigned long setup_command(char *cmd, char *subcmd)
+static unsigned long setup_command(struct command *commands, char *cmd, char *subcmd)
{
int i, found = 0;
struct subcommand *s;
unsigned long flags = 0;
- for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ for (i = 0; commands[i].name; i++) {
if (!strcmp(commands[i].name, cmd)) {
found = 1;
if (commands[i].parser)
@@ -1714,7 +188,7 @@ static unsigned long setup_command(char *cmd, char *subcmd)
if (!found) {
fprintf(stderr, "'%s' is not a valid command\n", cmd);
- usage(EXIT_USAGE);
+ usage(commands, EXIT_USAGE);
}
for (s = commands[i].sub; s->name; s++) {
@@ -1739,7 +213,7 @@ static unsigned long setup_command(char *cmd, char *subcmd)
return flags;
}
-static void usage(int status)
+static void usage(struct command *commands, int status)
{
int i;
struct subcommand *s;
@@ -1752,7 +226,7 @@ static void usage(int status)
printf("Sheepdog Administrator Utilty\n");
printf("\n");
printf("Command syntax:\n");
- for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ for (i = 0; commands[i].name; i++) {
for (s = commands[i].sub; s->name; s++) {
sprintf(name, "%s %s", commands[i].name, s->name);
printf(" %-24s%s\n", name, s->desc);
@@ -1804,11 +278,18 @@ int main(int argc, char **argv)
unsigned long flags;
struct option *long_options;
const char *short_options;
+ struct command commands[] = {
+ vdi_command,
+ node_command,
+ cluster_command,
+ {NULL,}
+ };
+
if (argc < 3)
- usage(0);
+ usage(commands, 0);
- flags = setup_command(argv[1], argv[2]);
+ flags = setup_command(commands, argv[1], argv[2]);
optind = 3;
@@ -1832,13 +313,13 @@ int main(int argc, char **argv)
subcommand_usage(argv[1], argv[2], EXIT_SUCCESS);
break;
case '?':
- usage(EXIT_USAGE);
+ usage(commands, EXIT_USAGE);
break;
default:
if (command_parser)
command_parser(ch, optarg);
else
- usage(EXIT_USAGE);
+ usage(commands, EXIT_USAGE);
break;
}
}
diff --git a/collie/collie.h b/collie/collie.h
new file mode 100644
index 0000000..98fba4c
--- /dev/null
+++ b/collie/collie.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __COLLIE_H__
+#define __COLLIE_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sheepdog_proto.h"
+#include "sheep.h"
+#include "exits.h"
+
+#define SUBCMD_FLAG_NEED_NODELIST (1 << 0)
+#define SUBCMD_FLAG_NEED_THIRD_ARG (1 << 1)
+
+#define TEXT_NORMAL "\033[0m"
+#define TEXT_BOLD "\033[1m"
+
+struct sd_option {
+ int val;
+ const char *name;
+ int has_arg;
+ const char *desc;
+};
+
+struct command {
+ const char *name;
+ struct subcommand *sub;
+ int (*parser)(int, char *);
+};
+
+struct subcommand {
+ const char *name;
+ const char *arg;
+ const char *opts;
+ const char *desc;
+ unsigned long flags;
+ int (*fn)(int, char **);
+};
+
+extern const char *sdhost;
+extern int sdport;
+extern int highlight;
+extern int raw_output;
+
+extern uint64_t node_list_version;
+extern struct sheepdog_node_list_entry node_list_entries[SD_MAX_NODES];
+extern struct sheepdog_vnode_list_entry vnode_list_entries[SD_MAX_VNODES];
+extern int nr_nodes, nr_vnodes;
+extern unsigned master_idx;
+
+int is_current(struct sheepdog_inode *i);
+char *size_to_str(uint64_t _size, char *str, int str_size);
+typedef void (*vdi_parser_func_t)(uint32_t vid, char *name, char *tag,
+ uint32_t snapid, uint32_t flags,
+ struct sheepdog_inode *i, void *data);
+int parse_vdi(vdi_parser_func_t func, size_t size, void *data);
+int sd_read_object(uint64_t oid, void *data, unsigned int datalen,
+ uint64_t offset);
+int sd_write_object(uint64_t oid, void *data, unsigned int datalen,
+ uint64_t offset, uint32_t flags, int copies, int create);
+
+extern struct command vdi_command;
+extern struct command node_command;
+extern struct command cluster_command;
+
+#endif
diff --git a/collie/common.c b/collie/common.c
new file mode 100644
index 0000000..b58c192
--- /dev/null
+++ b/collie/common.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "collie.h"
+
+int is_current(struct sheepdog_inode *i)
+{
+ return !i->snap_ctime;
+}
+
+char *size_to_str(uint64_t _size, char *str, int str_size)
+{
+ const char *units[] = {"MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
+ int i = 0;
+ double size;
+
+ if (raw_output) {
+ snprintf(str, str_size, "%" PRIu64, _size);
+ return str;
+ }
+
+ size = (double)_size;
+ size /= 1024 * 1024;
+ while (i < ARRAY_SIZE(units) && size >= 1024) {
+ i++;
+ size /= 1024;
+ }
+
+ if (size >= 10)
+ snprintf(str, str_size, "%.0lf %s", size, units[i]);
+ else
+ snprintf(str, str_size, "%.1lf %s", size, units[i]);
+
+ return str;
+}
+
+int sd_read_object(uint64_t oid, void *data, unsigned int datalen,
+ uint64_t offset)
+{
+ struct sd_obj_req hdr;
+ struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
+ char name[128];
+ int n, fd, ret;
+ unsigned wlen = 0, rlen = datalen;
+
+ n = obj_to_sheep(vnode_list_entries, nr_vnodes, oid, 0);
+
+ addr_to_str(name, sizeof(name), vnode_list_entries[n].addr, 0);
+
+ fd = connect_to(name, vnode_list_entries[n].port);
+ if (fd < 0) {
+ fprintf(stderr, "failed to connect %s:%d\n", name,
+ vnode_list_entries[n].port);
+ return SD_RES_EIO;
+ }
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.epoch = node_list_version;
+ hdr.opcode = SD_OP_READ_OBJ;
+ hdr.oid = oid;
+ /* use direct to avoid checking consistency */
+ hdr.flags = SD_FLAG_CMD_DIRECT;
+ hdr.data_length = rlen;
+ hdr.offset = offset;
+
+ ret = exec_req(fd, (struct sd_req *)&hdr, data, &wlen, &rlen);
+ close(fd);
+
+ if (ret) {
+ fprintf(stderr, "failed to read object, %lx\n", oid);
+ return SD_RES_EIO;
+ }
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to read object, %lx %s\n", oid,
+ sd_strerror(rsp->result));
+ return rsp->result;
+ }
+
+ return SD_RES_SUCCESS;
+}
+
+int sd_write_object(uint64_t oid, void *data, unsigned int datalen,
+ uint64_t offset, uint32_t flags, int copies, int create)
+{
+ struct sd_obj_req hdr;
+ struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
+ int fd, ret;
+ unsigned wlen = datalen, rlen;
+
+ fd = connect_to(sdhost, sdport);
+ if (fd < 0) {
+ fprintf(stderr, "failed to connect\n");
+ return SD_RES_EIO;
+ }
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.epoch = node_list_version;
+ if (create)
+ hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
+ else
+ hdr.opcode = SD_OP_WRITE_OBJ;
+ hdr.oid = oid;
+ hdr.copies = copies;
+ hdr.data_length = wlen;
+ hdr.flags = (flags & ~SD_FLAG_CMD_DIRECT) | SD_FLAG_CMD_WRITE;
+ hdr.offset = offset;
+
+ ret = exec_req(fd, (struct sd_req *)&hdr, data, &wlen, &rlen);
+ close(fd);
+
+ if (ret) {
+ fprintf(stderr, "failed to write object, %lx\n", oid);
+ return SD_RES_EIO;
+ }
+ if (rsp->result != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to write object, %lx %s\n", oid,
+ sd_strerror(rsp->result));
+ return rsp->result;
+ }
+
+ return SD_RES_SUCCESS;
+}
+
+int parse_vdi(vdi_parser_func_t func, size_t size, void *data)
+{
+ int ret, fd;
+ unsigned long nr;
+ static struct sheepdog_inode i;
+ struct sd_req req;
+ static DECLARE_BITMAP(vdi_inuse, SD_NR_VDIS);
+ unsigned int rlen, wlen = 0;
+
+ fd = connect_to(sdhost, sdport);
+ if (fd < 0)
+ return fd;
+
+ memset(&req, 0, sizeof(req));
+
+ req.opcode = SD_OP_READ_VDIS;
+ req.data_length = sizeof(vdi_inuse);
+ req.epoch = node_list_version;
+
+ rlen = sizeof(vdi_inuse);
+ ret = exec_req(fd, &req, vdi_inuse, &wlen, &rlen);
+ if (ret < 0) {
+ close(fd);
+ return ret;
+ }
+ close(fd);
+
+ for (nr = 0; nr < SD_NR_VDIS; nr++) {
+ uint64_t oid;
+
+ if (!test_bit(nr, vdi_inuse))
+ continue;
+
+ oid = vid_to_vdi_oid(nr);
+
+ memset(&i, 0, sizeof(i));
+ ret = sd_read_object(oid, &i, SD_INODE_HEADER_SIZE, 0);
+ if (ret != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to read a inode header\n");
+ continue;
+ }
+
+ if (i.name[0] == '\0') /* this vdi is deleted */
+ continue;
+
+ if (size > SD_INODE_HEADER_SIZE) {
+ rlen = DIV_ROUND_UP(i.vdi_size, SD_DATA_OBJ_SIZE) *
+ sizeof(i.data_vdi_id[0]);
+ if (rlen > size - SD_INODE_HEADER_SIZE)
+ rlen = size - SD_INODE_HEADER_SIZE;
+
+ ret = sd_read_object(oid, ((char *)&i) + SD_INODE_HEADER_SIZE,
+ rlen, SD_INODE_HEADER_SIZE);
+
+ if (ret != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to read inode\n");
+ continue;
+ }
+ }
+
+ func(i.vdi_id, i.name, i.tag, i.snap_id, 0, &i, data);
+ }
+
+ return 0;
+}
diff --git a/collie/node.c b/collie/node.c
new file mode 100644
index 0000000..a30a013
--- /dev/null
+++ b/collie/node.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "collie.h"
+
+static void cal_total_vdi_size(uint32_t vid, char *name, char * tag,
+ uint32_t snapid, uint32_t flags,
+ struct sheepdog_inode *i, void *data)
+{
+ uint64_t *size = data;
+
+ if (is_current(i))
+ *size += i->vdi_size;
+}
+
+static int node_list(int argc, char **argv)
+{
+ int i;
+
+ if (!raw_output) {
+ printf(" Idx - Host:Port Vnodes Zone\n");
+ printf("---------------------------------------------\n");
+ }
+ for (i = 0; i < nr_nodes; i++) {
+ char data[128];
+
+ addr_to_str(data, sizeof(data), node_list_entries[i].addr,
+ node_list_entries[i].port);
+
+ if (i == master_idx) {
+ if (highlight)
+ printf(TEXT_BOLD);
+ printf(raw_output ? "* %d %s %d %d\n" : "* %4d - %-20s\t%d%11d\n",
+ i, data, node_list_entries[i].nr_vnodes,
+ node_list_entries[i].zone);
+ if (highlight)
+ printf(TEXT_NORMAL);
+ } else
+ printf(raw_output ? "- %d %s %d %d\n" : " %4d - %-20s\t%d%11d\n",
+ i, data, node_list_entries[i].nr_vnodes,
+ node_list_entries[i].zone);
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int node_info(int argc, char **argv)
+{
+ int i, ret, success = 0;
+ uint64_t total_size = 0, total_avail = 0, total_vdi_size = 0;
+ char total_str[8], avail_str[8], vdi_size_str[8];
+
+ if (!raw_output)
+ printf("Id\tSize\tUsed\tUse%%\n");
+
+ for (i = 0; i < nr_nodes; i++) {
+ char name[128];
+ int fd;
+ unsigned wlen, rlen;
+ struct sd_node_req req;
+ struct sd_node_rsp *rsp = (struct sd_node_rsp *)&req;
+ char store_str[8], free_str[8];
+
+ addr_to_str(name, sizeof(name), node_list_entries[i].addr, 0);
+
+ fd = connect_to(name, node_list_entries[i].port);
+ if (fd < 0)
+ return 1;
+
+ memset(&req, 0, sizeof(req));
+
+ req.opcode = SD_OP_STAT_SHEEP;
+ req.epoch = node_list_version;
+
+ wlen = 0;
+ rlen = 0;
+ ret = exec_req(fd, (struct sd_req *)&req, NULL, &wlen, &rlen);
+ close(fd);
+
+ size_to_str(rsp->store_size, store_str, sizeof(store_str));
+ size_to_str(rsp->store_size - rsp->store_free, free_str,
+ sizeof(free_str));
+ if (!ret && rsp->result == SD_RES_SUCCESS) {
+ printf(raw_output ? "%d %s %s %d%%\n" : "%2d\t%s\t%s\t%3d%%\n",
+ i, store_str, free_str,
+ (int)(((double)(rsp->store_size - rsp->store_free) / rsp->store_size) * 100));
+ success++;
+ }
+
+ total_size += rsp->store_size;
+ total_avail += rsp->store_free;
+ }
+
+ if (success == 0) {
+ fprintf(stderr, "cannot get information from any nodes\n");
+ return EXIT_SYSFAIL;
+ }
+
+ parse_vdi(cal_total_vdi_size, SD_INODE_HEADER_SIZE, &total_vdi_size);
+
+ size_to_str(total_size, total_str, sizeof(total_str));
+ size_to_str(total_size - total_avail, avail_str, sizeof(avail_str));
+ size_to_str(total_vdi_size, vdi_size_str, sizeof(vdi_size_str));
+ printf(raw_output ? "Total %s %s %d%% %s\n"
+ : "\nTotal\t%s\t%s\t%3d%%, total virtual VDI Size\t%s\n",
+ total_str, avail_str,
+ (int)(((double)(total_size - total_avail) / total_size) * 100),
+ vdi_size_str);
+
+ return EXIT_SUCCESS;
+}
+
+static struct subcommand node_cmd[] = {
+ {"list", NULL, "aprh", "list nodes",
+ SUBCMD_FLAG_NEED_NODELIST, node_list},
+ {"info", NULL, "aprh", "show each node information",
+ SUBCMD_FLAG_NEED_NODELIST, node_info},
+ {NULL,},
+};
+
+struct command node_command = {
+ "node",
+ node_cmd,
+};
diff --git a/collie/vdi.c b/collie/vdi.c
new file mode 100644
index 0000000..5ab6c25
--- /dev/null
+++ b/collie/vdi.c
@@ -0,0 +1,1025 @@
+/*
+ * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "collie.h"
+#include "treeview.h"
+
+struct vdi_cmd_data {
+ unsigned int index;
+ int snapshot_id;
+ char snapshot_tag[SD_MAX_VDI_TAG_LEN];
+ int exclusive;
+ int delete;
+ int prealloc;
+} vdi_cmd_data = { ~0, };
+
+struct get_vdi_info {
+ char *name;
+ char *tag;
+ uint32_t vid;
+ uint32_t snapid;
+};
+
+static int parse_option_size(const char *value, uint64_t *ret)
+{
+ char *postfix;
+ double sizef;
+
+ sizef = strtod(value, &postfix);
+ switch (*postfix) {
+ case 'T':
+ sizef *= 1024;
+ case 'G':
+ sizef *= 1024;
+ case 'M':
+ sizef *= 1024;
+ case 'K':
+ case 'k':
+ sizef *= 1024;
+ case 'b':
+ case '\0':
+ *ret = (uint64_t) sizef;
+ break;
+ default:
+ fprintf(stderr, "invalid parameter, %s\n", value);
+ fprintf(stderr, "You may use k, M, G or T suffixes for "
+ "kilobytes, megabytes, gigabytes and terabytes.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void print_vdi_list(uint32_t vid, char *name, char *tag, uint32_t snapid,
+ uint32_t flags, struct sheepdog_inode *i, void *data)
+{
+ int idx;
+ uint64_t my_objs, cow_objs;
+ char vdi_size_str[16], my_objs_str[16], cow_objs_str[16];
+ time_t ti;
+ struct tm tm;
+ char dbuf[128];
+ struct get_vdi_info *info = data;
+
+ if (info && strcmp(name, info->name) != 0)
+ return;
+
+ ti = i->ctime >> 32;
+ if (raw_output) {
+ snprintf(dbuf, sizeof(dbuf), "%" PRIu64, (uint64_t) ti);
+ } else {
+ localtime_r(&ti, &tm);
+ strftime(dbuf, sizeof(dbuf),
+ "%Y-%m-%d %H:%M", &tm);
+ }
+
+ my_objs = 0;
+ cow_objs = 0;
+ for (idx = 0; idx < MAX_DATA_OBJS; idx++) {
+ if (!i->data_vdi_id[idx])
+ continue;
+ if (is_data_obj_writeable(i, idx))
+ my_objs++;
+ else
+ cow_objs++;
+ }
+
+ size_to_str(i->vdi_size, vdi_size_str, sizeof(vdi_size_str));
+ size_to_str(my_objs * SD_DATA_OBJ_SIZE, my_objs_str, sizeof(my_objs_str));
+ size_to_str(cow_objs * SD_DATA_OBJ_SIZE, cow_objs_str, sizeof(cow_objs_str));
+
+ if (raw_output) {
+ printf("%c ", is_current(i) ? '=' : 's');
+ while (*name) {
+ if (isspace(*name) || *name == '\\')
+ putchar('\\');
+ putchar(*name++);
+ }
+ printf(" %d %s %s %s %s %" PRIx32 "\n", snapid,
+ vdi_size_str, my_objs_str, cow_objs_str, dbuf, vid);
+ } else {
+ printf("%c %-8s %5d %7s %7s %7s %s %7" PRIx32 "\n",
+ is_current(i) ? ' ' : 's', name, snapid,
+ vdi_size_str, my_objs_str, cow_objs_str, dbuf, vid);
+ }
+}
+
+static void print_vdi_tree(uint32_t vid, char *name, char * tag, uint32_t snapid,
+ uint32_t flags, struct sheepdog_inode *i, void *data)
+{
+ time_t ti;
+ struct tm tm;
+ char buf[128];
+
+ if (is_current(i))
+ strcpy(buf, "(You Are Here)");
+ else {
+ ti = i->ctime >> 32;
+ localtime_r(&ti, &tm);
+
+ strftime(buf, sizeof(buf),
+ "[%Y-%m-%d %H:%M]", &tm);
+ }
+
+ add_vdi_tree(name, buf, vid, i->parent_vdi_id, highlight && is_current(i));
+}
+
+static void print_vdi_graph(uint32_t vid, char *name, char * tag, uint32_t snapid,
+ uint32_t flags, struct sheepdog_inode *i, void *data)
+{
+ time_t ti;
+ struct tm tm;
+ char dbuf[128], tbuf[128], size_str[128];
+
+ ti = i->ctime >> 32;
+ localtime_r(&ti, &tm);
+
+ strftime(dbuf, sizeof(dbuf), "%Y-%m-%d", &tm);
+ strftime(tbuf, sizeof(tbuf), "%H:%M:%S", &tm);
+ size_to_str(i->vdi_size, size_str, sizeof(size_str));
+
+ printf(" \"%x\" -> \"%x\";\n", i->parent_vdi_id, vid);
+ printf(" \"%x\" [\n"
+ " group = \"%s\",\n"
+ " label = \"",
+ vid, name);
+ printf("name: %10s\\n"
+ "tag : %10x\\n"
+ "size: %10s\\n"
+ "date: %10s\\n"
+ "time: %10s",
+ name, snapid, size_str, dbuf, tbuf);
+
+ if (is_current(i))
+ printf("\",\n color=\"red\"\n ];\n\n");
+ else
+ printf("\"\n ];\n\n");
+
+}
+
+static void get_oid(uint32_t vid, char *name, char *tag, uint32_t snapid,
+ uint32_t flags, struct sheepdog_inode *i, void *data)
+{
+ struct get_vdi_info *info = data;
+
+ if (info->name) {
+ if (info->tag) {
+ if (!strcmp(name, info->name) && !strcmp(tag, info->tag))
+ info->vid = vid;
+ } else if (info->snapid) {
+ if (!strcmp(name, info->name) && snapid == info->snapid)
+ info->vid = vid;
+ } else {
+ if (!strcmp(name, info->name))
+ info->vid = vid;
+ }
+ }
+}
+
+typedef void (*obj_parser_func_t)(char *sheep, uint64_t oid,
+ struct sd_obj_rsp *rsp, char *buf, void *data);
+
+static void do_print_obj(char *sheep, uint64_t oid, struct sd_obj_rsp *rsp,
+ char *buf, void *data)
+{
+ switch (rsp->result) {
+ case SD_RES_SUCCESS:
+ printf("%s: has the object (should be %d copies)\n",
+ sheep, rsp->copies);
+ break;
+ case SD_RES_NO_OBJ:
+ printf("%s: doesn't have\n", sheep);
+ break;
+ case SD_RES_OLD_NODE_VER:
+ case SD_RES_NEW_NODE_VER:
+ printf("the node list has changed, try again\n");
+ break;
+ default:
+ printf("%s: hit an expected error, %d\n",
+ sheep, rsp->result);
+ break;
+ }
+}
+
+struct get_data_oid_info {
+ int success;
+ uint64_t data_oid;
+ unsigned idx;
+};
+
+static void get_data_oid(char *sheep, uint64_t oid, struct sd_obj_rsp *rsp,
+ char *buf, void *data)
+{
+ struct get_data_oid_info *info = data;
+ struct sheepdog_inode *inode = (struct sheepdog_inode *)buf;
+
+ switch (rsp->result) {
+ case SD_RES_SUCCESS:
+ if (info->success)
+ break;
+ info->success = 1;
+ if (inode->data_vdi_id[info->idx])
+ info->data_oid = vid_to_data_oid(inode->data_vdi_id[info->idx], info->idx);
+ break;
+ case SD_RES_NO_OBJ:
+ break;
+ case SD_RES_OLD_NODE_VER:
+ case SD_RES_NEW_NODE_VER:
+ printf("the node list has changed, try again\n");
+ break;
+ default:
+ printf("%s: hit an expected error, %d\n",
+ sheep, rsp->result);
+ break;
+ }
+}
+
+static void parse_objs(uint64_t oid, obj_parser_func_t func, void *data)
+{
+ char name[128];
+ int i, fd, ret;
+ char *buf;
+
+ buf = zalloc(sizeof(struct sheepdog_inode));
+ if (!buf) {
+ fprintf(stderr, "out of memory\n");
+ return;
+ }
+
+ for (i = 0; i < nr_nodes; i++) {
+ unsigned wlen = 0, rlen = sizeof(struct sheepdog_inode);
+ struct sd_obj_req hdr;
+ struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
+
+ addr_to_str(name, sizeof(name), node_list_entries[i].addr, 0);
+
+ fd = connect_to(name, node_list_entries[i].port);
+ if (fd < 0)
+ break;
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ hdr.opcode = SD_OP_READ_OBJ;
+ hdr.data_length = rlen;
+ hdr.flags = SD_FLAG_CMD_DIRECT;
+ hdr.oid = oid;
+ hdr.epoch = node_list_version;
+
+ ret = exec_req(fd, (struct sd_req *)&hdr, buf, &wlen, &rlen);
+ close(fd);
+
+ sprintf(name + strlen(name), ":%d", node_list_entries[i].port);
+
+ if (ret)
+ printf("%s: can't connect\n", name);
+ else
+ func(name, oid, rsp, buf, data);
+ }
+
+ free(buf);
+}
+
+
+static int vdi_list(int argc, char **argv)
+{
+ char *vdiname = argv[optind];
+
+ if (!raw_output) {
+ printf(" name id size used shared creation time vdi id\n");
+ printf("------------------------------------------------------------------\n");
+ }
+
+ if (vdiname) {
+ struct get_vdi_info info;
+ memset(&info, 0, sizeof(info));
+ info.name = vdiname;
+ parse_vdi(print_vdi_list, SD_INODE_SIZE, &info);
+ return EXIT_SUCCESS;
+ } else {
+ parse_vdi(print_vdi_list, SD_INODE_SIZE, NULL);
+ return EXIT_SUCCESS;
+ }
+}
+
+static int vdi_tree(int argc, char **argv)
+{
+ init_tree();
+ parse_vdi(print_vdi_tree, SD_INODE_HEADER_SIZE, NULL);
+ dump_tree();
+
+ return EXIT_SUCCESS;
+}
+
+static int vdi_graph(int argc, char **argv)
+{
+ /* print a header */
+ printf("digraph G {\n");
+ printf(" node [shape = \"box\", fontname = \"Courier\"];\n\n");
+ printf(" \"0\" [shape = \"ellipse\", label = \"root\"];\n\n");
+
+ parse_vdi(print_vdi_graph, SD_INODE_HEADER_SIZE, NULL);
+
+ /* print a footer */
+ printf("}\n");
+
+ return EXIT_SUCCESS;
+}
+
+static int find_vdi_name(char *vdiname, uint32_t snapid, const char *tag,
+ uint32_t *vid, int for_snapshot)
+{
+ int ret, fd;
+ struct sd_vdi_req hdr;
+ struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
+ unsigned int wlen, rlen = 0;
+ char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
+
+ fd = connect_to(sdhost, sdport);
+ if (fd < 0)
+ return -1;
+
+ memset(buf, 0, sizeof(buf));
+ strncpy(buf, vdiname, SD_MAX_VDI_LEN);
+ strncpy(buf + SD_MAX_VDI_LEN, tag, SD_MAX_VDI_TAG_LEN);
+
+ memset(&hdr, 0, sizeof(hdr));
+ if (for_snapshot)
+ hdr.opcode = SD_OP_GET_VDI_INFO;
+ else
+ hdr.opcode = SD_OP_LOCK_VDI;
+ wlen = SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN;
+ hdr.proto_ver = SD_PROTO_VER;
+ hdr.data_length = wlen;
+ hdr.snapid = snapid;
+ hdr.flags = SD_FLAG_CMD_WRITE;
+
+ ret = exec_req(fd, (struct sd_req *)&hdr, buf, &wlen, &rlen);
+ if (ret) {
+ ret = -1;
+ goto out;
+ }
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ fprintf(stderr, "cannot get vdi info, %s, %s %d %s\n",
+ sd_strerror(rsp->result), vdiname, snapid, tag);
+ ret = -1;
+ goto out;
+ }
+ *vid = rsp->vdi_id;
+
+ ret = 0;
+out:
+ close(fd);
+ return ret;
+}
+
+static int do_vdi_create(char *vdiname, int64_t vdi_size, uint32_t base_vid,
+ uint32_t *vdi_id, int snapshot)
+{
+ struct sd_vdi_req hdr;
+ struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
+ int fd, ret;
+ unsigned int wlen, rlen = 0;
+ char buf[SD_MAX_VDI_LEN];
+
+ fd = connect_to(sdhost, sdport);
+ if (fd < 0) {
+ fprintf(stderr, "failed to connect\n");
+ return EXIT_SYSFAIL;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ strncpy(buf, vdiname, SD_MAX_VDI_LEN);
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.opcode = SD_OP_NEW_VDI;
+ hdr.base_vdi_id = base_vid;
+
+ wlen = SD_MAX_VDI_LEN;
+
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ hdr.snapid = snapshot;
+
+ hdr.data_length = wlen;
+ hdr.vdi_size = vdi_size;
+
+ ret = exec_req(fd, (struct sd_req *)&hdr, buf, &wlen, &rlen);
+
+ close(fd);
+
+ if (ret) {
+ fprintf(stderr, "failed to send a request\n");
+ return EXIT_SYSFAIL;
+ }
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ fprintf(stderr, "%s, %s\n", sd_strerror(rsp->result), vdiname);
+ return EXIT_FAILURE;
+ }
+
+ if (vdi_id)
+ *vdi_id = rsp->vdi_id;
+
+ return EXIT_SUCCESS;
+}
+
+static int vdi_create(int argc, char **argv)
+{
+ char *vdiname = argv[optind++];
+ uint64_t size;
+ uint32_t vid;
+ uint64_t oid;
+ int idx, max_idx, ret;
+ struct sheepdog_inode *inode = NULL;
+ char *buf = NULL;
+
+ if (!argv[optind]) {
+ fprintf(stderr, "please specify the size of vdi\n");
+ return EXIT_USAGE;
+ }
+ ret = parse_option_size(argv[optind], &size);
+ if (ret < 0)
+ return EXIT_USAGE;
+ if (size > SD_MAX_VDI_SIZE) {
+ fprintf(stderr, "too big image size, %s\n", argv[optind]);
+ return EXIT_USAGE;
+ }
+
+ ret = do_vdi_create(vdiname, size, 0, &vid, 0);
+ if (ret != EXIT_SUCCESS || !vdi_cmd_data.prealloc)
+ goto out;
+
+ inode = malloc(sizeof(*inode));
+ buf = zalloc(SD_DATA_OBJ_SIZE);
+ if (!inode || !buf) {
+ fprintf(stderr, "oom\n");
+ ret = EXIT_SYSFAIL;
+ goto out;
+ }
+
+ ret = sd_read_object(vid_to_vdi_oid(vid), inode, sizeof(*inode), 0);
+ if (ret != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to read a newly created vdi object\n");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ max_idx = DIV_ROUND_UP(size, SD_DATA_OBJ_SIZE);
+
+ for (idx = 0; idx < max_idx; idx++) {
+ oid = vid_to_data_oid(vid, idx);
+
+ ret = sd_write_object(oid, buf, SD_DATA_OBJ_SIZE, 0, 0,
+ inode->nr_copies, 1);
+ if (ret != SD_RES_SUCCESS) {
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ inode->data_vdi_id[idx] = vid;
+ ret = sd_write_object(vid_to_vdi_oid(vid), &vid, sizeof(vid),
+ SD_INODE_HEADER_SIZE + sizeof(vid) * idx, 0,
+ inode->nr_copies, 0);
+ if (ret) {
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ }
+ ret = EXIT_SUCCESS;
+out:
+ free(inode);
+ free(buf);
+ return ret;
+}
+
+static int vdi_snapshot(int argc, char **argv)
+{
+ char *vdiname = argv[optind++];
+ uint32_t vid;
+ int ret;
+ char buf[SD_INODE_HEADER_SIZE];
+ struct sheepdog_inode *inode = (struct sheepdog_inode *)buf;
+
+ if (vdi_cmd_data.snapshot_id != 0) {
+ fprintf(stderr, "please specify a non-integer value for "
+ "a snapshot tag name\n");
+ return EXIT_USAGE;
+ }
+
+ ret = find_vdi_name(vdiname, 0, "", &vid, 0);
+ if (ret < 0) {
+ fprintf(stderr, "failed to open vdi %s\n", vdiname);
+ return EXIT_FAILURE;
+ }
+
+ ret = sd_read_object(vid_to_vdi_oid(vid), inode, SD_INODE_HEADER_SIZE, 0);
+ if (ret != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to read an inode header\n");
+ return EXIT_FAILURE;
+ }
+
+ if (vdi_cmd_data.snapshot_tag[0]) {
+ ret = sd_write_object(vid_to_vdi_oid(vid), vdi_cmd_data.snapshot_tag,
+ SD_MAX_VDI_TAG_LEN,
+ offsetof(struct sheepdog_inode, tag),
+ 0, inode->nr_copies, 0);
+ }
+
+ return do_vdi_create(vdiname, inode->vdi_size, vid, NULL, 1);
+}
+
+static int vdi_clone(int argc, char **argv)
+{
+ char *src_vdi = argv[optind++], *dst_vdi;
+ uint32_t base_vid, new_vid;
+ uint64_t oid;
+ int idx, max_idx, ret;
+ struct sheepdog_inode *inode = NULL;
+ char *buf = NULL;
+
+ dst_vdi = argv[optind];
+ if (!dst_vdi) {
+ fprintf(stderr, "a dst vdi must be specified\n");
+ ret = EXIT_USAGE;
+ goto out;
+ }
+
+ if (!vdi_cmd_data.snapshot_id && !vdi_cmd_data.snapshot_tag[0]) {
+ fprintf(stderr, "it is not supported to create a clone image of "
+ "the non-snapshot vdi\n");
+ fprintf(stderr, "please specify a '-s' option\n");
+ ret = EXIT_USAGE;
+ goto out;
+ }
+
+ ret = find_vdi_name(src_vdi, vdi_cmd_data.snapshot_id,
+ vdi_cmd_data.snapshot_tag, &base_vid, 0);
+ if (ret < 0) {
+ fprintf(stderr, "failed to open vdi %s\n", src_vdi);
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ inode = malloc(sizeof(*inode));
+ if (!inode) {
+ fprintf(stderr, "oom\n");
+ ret = EXIT_SYSFAIL;
+ goto out;
+ }
+ ret = sd_read_object(vid_to_vdi_oid(base_vid), inode, SD_INODE_SIZE, 0);
+ if (ret != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to read a base inode\n");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ ret = do_vdi_create(dst_vdi, inode->vdi_size, base_vid, &new_vid, 0);
+ if (ret != EXIT_SUCCESS || !vdi_cmd_data.prealloc)
+ goto out;
+
+ buf = zalloc(SD_DATA_OBJ_SIZE);
+ if (!buf) {
+ fprintf(stderr, "oom\n");
+ ret = EXIT_SYSFAIL;
+ goto out;
+ }
+
+ max_idx = DIV_ROUND_UP(inode->vdi_size, SD_DATA_OBJ_SIZE);
+
+ for (idx = 0; idx < max_idx; idx++) {
+ if (inode->data_vdi_id[idx]) {
+ oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
+ ret = sd_read_object(oid, buf, SD_DATA_OBJ_SIZE, 0);
+ if (ret) {
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ } else
+ memset(buf, 0, SD_DATA_OBJ_SIZE);
+
+ oid = vid_to_data_oid(new_vid, idx);
+ ret = sd_write_object(oid, buf, SD_DATA_OBJ_SIZE, 0, 0,
+ inode->nr_copies, 1);
+ if (ret != SD_RES_SUCCESS) {
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ ret = sd_write_object(vid_to_vdi_oid(new_vid), &new_vid, sizeof(new_vid),
+ SD_INODE_HEADER_SIZE + sizeof(new_vid) * idx, 0,
+ inode->nr_copies, 0);
+ if (ret) {
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ }
+ ret = EXIT_SUCCESS;
+out:
+ free(inode);
+ free(buf);
+ return ret;
+}
+
+static int vdi_resize(int argc, char **argv)
+{
+ char *vdiname = argv[optind++];
+ uint64_t new_size;
+ uint32_t vid;
+ int ret;
+ char buf[SD_INODE_HEADER_SIZE];
+ struct sheepdog_inode *inode = (struct sheepdog_inode *)buf;
+
+ if (!argv[optind]) {
+ fprintf(stderr, "please specify a new size of vdi\n");
+ return EXIT_USAGE;
+ }
+ ret = parse_option_size(argv[optind], &new_size);
+ if (ret < 0)
+ return EXIT_USAGE;
+ if (new_size > SD_MAX_VDI_SIZE) {
+ fprintf(stderr, "too big image size, %s\n", argv[optind]);
+ return EXIT_USAGE;
+ }
+
+ ret = find_vdi_name(vdiname, 0, "", &vid, 0);
+ if (ret < 0) {
+ fprintf(stderr, "failed to open vdi %s\n", vdiname);
+ return EXIT_FAILURE;
+ }
+
+ ret = sd_read_object(vid_to_vdi_oid(vid), inode, SD_INODE_HEADER_SIZE, 0);
+ if (ret != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to read an inode header\n");
+ return EXIT_FAILURE;
+ }
+
+ if (new_size < inode->vdi_size) {
+ fprintf(stderr, "shrinking is not implemented\n");
+ return EXIT_USAGE;
+ }
+ inode->vdi_size = new_size;
+
+ ret = sd_write_object(vid_to_vdi_oid(vid), inode, SD_INODE_HEADER_SIZE, 0,
+ 0, inode->nr_copies, 0);
+ if (ret != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to update an inode header\n");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int vdi_delete(int argc, char **argv)
+{
+ char *data = argv[optind];
+ int fd, ret;
+ struct sd_vdi_req hdr;
+ struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
+ unsigned rlen, wlen;
+ char vdiname[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
+
+ fd = connect_to(sdhost, sdport);
+ if (fd < 0)
+ return EXIT_SYSFAIL;
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ rlen = 0;
+ wlen = sizeof(vdiname);
+
+ hdr.opcode = SD_OP_DEL_VDI;
+ hdr.snapid = vdi_cmd_data.snapshot_id;
+ hdr.epoch = node_list_version;
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ hdr.data_length = wlen;
+ memset(vdiname, 0, sizeof(vdiname));
+ strncpy(vdiname, data, SD_MAX_VDI_LEN);
+ strncpy(vdiname + SD_MAX_VDI_LEN, vdi_cmd_data.snapshot_tag,
+ SD_MAX_VDI_TAG_LEN);
+
+ ret = exec_req(fd, (struct sd_req *)&hdr, vdiname, &wlen, &rlen);
+ close(fd);
+
+ if (ret) {
+ fprintf(stderr, "failed to connect\n");
+ return EXIT_SYSFAIL;
+ }
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ fprintf(stderr, "%s: %s\n", vdiname, sd_strerror(rsp->result));
+ if (rsp->result == SD_RES_NO_VDI)
+ return EXIT_MISSING;
+ else
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int vdi_object(int argc, char **argv)
+{
+ char *vdiname = argv[optind];
+ unsigned idx = vdi_cmd_data.index;
+ int ret;
+ struct get_vdi_info info;
+ uint32_t vid;
+
+ memset(&info, 0, sizeof(info));
+ info.name = vdiname;
+ info.tag = vdi_cmd_data.snapshot_tag;
+ info.vid = 0;
+ info.snapid = vdi_cmd_data.snapshot_id;
+
+ ret = parse_vdi(get_oid, SD_INODE_HEADER_SIZE, &info);
+
+ vid = info.vid;
+ if (vid == 0) {
+ printf("No such vdi\n");
+ return EXIT_MISSING;
+ }
+
+ if (idx == ~0) {
+ printf("Looking for the inode object 0x%" PRIx32 " with %d nodes\n\n",
+ vid, nr_nodes);
+ parse_objs(vid_to_vdi_oid(vid), do_print_obj, NULL);
+ } else {
+ struct get_data_oid_info old_info;
+
+ old_info.success = 0;
+ old_info.idx = idx;
+
+ if (idx >= MAX_DATA_OBJS) {
+ printf("The offset is too large!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ parse_objs(vid_to_vdi_oid(vid), get_data_oid, &old_info);
+
+ if (old_info.success) {
+ if (old_info.data_oid) {
+ printf("Looking for the object 0x%" PRIx64
+ " (the inode vid 0x%" PRIx32 " idx %u) with %d nodes\n\n",
+ old_info.data_oid, vid, idx, nr_nodes);
+
+ parse_objs(old_info.data_oid, do_print_obj, NULL);
+ } else
+ printf("The inode object 0x%" PRIx32 " idx %u is not allocated\n",
+ vid, idx);
+ } else
+ printf("failed to read the inode object 0x%" PRIx32 "\n", vid);
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int find_vdi_attr_oid(char *vdiname, char *tag, uint32_t snapid,
+ char *key, uint32_t *vid, uint64_t *oid,
+ unsigned int *nr_copies, int creat, int excl)
+{
+ struct sd_vdi_req hdr;
+ struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
+ int fd, ret;
+ unsigned int wlen, rlen;
+ char buf[SD_ATTR_HEADER_SIZE];
+
+ memset(buf, 0, sizeof(buf));
+ strncpy(buf, vdiname, SD_MAX_VDI_LEN);
+ strncpy(buf + SD_MAX_VDI_LEN, vdi_cmd_data.snapshot_tag,
+ SD_MAX_VDI_TAG_LEN);
+ memcpy(buf + SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN,
+ &vdi_cmd_data.snapshot_id, sizeof(uint32_t));
+ strncpy(buf + SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN + sizeof(uint32_t),
+ key, SD_MAX_VDI_ATTR_KEY_LEN);
+
+ fd = connect_to(sdhost, sdport);
+ if (fd < 0) {
+ fprintf(stderr, "failed to connect\n\n");
+ return SD_RES_EIO;
+ }
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.opcode = SD_OP_GET_VDI_ATTR;
+ wlen = SD_ATTR_HEADER_SIZE;
+ rlen = 0;
+ hdr.proto_ver = SD_PROTO_VER;
+ hdr.data_length = wlen;
+ hdr.snapid = vdi_cmd_data.snapshot_id;
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ if (creat)
+ hdr.flags |= SD_FLAG_CMD_CREAT;
+ if (excl)
+ hdr.flags |= SD_FLAG_CMD_EXCL;
+
+ ret = exec_req(fd, (struct sd_req *)&hdr, buf, &wlen, &rlen);
+ if (ret) {
+ ret = SD_RES_EIO;
+ goto out;
+ }
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ ret = rsp->result;
+ goto out;
+ }
+
+ *vid = rsp->vdi_id;
+ *oid = vid_to_attr_oid(rsp->vdi_id, rsp->attr_id);
+ *nr_copies = rsp->copies;
+
+ ret = SD_RES_SUCCESS;
+out:
+ close(fd);
+ return ret;
+}
+
+static int vdi_setattr(int argc, char **argv)
+{
+ int ret;
+ uint64_t oid, attr_oid = 0;
+ uint32_t vid = 0, nr_copies = 0;
+ char *vdiname = argv[optind++], *key, *value;
+ uint64_t offset;
+
+ key = argv[optind++];
+ if (!key) {
+ fprintf(stderr, "please specify the name of key\n");
+ return EXIT_USAGE;
+ }
+
+ value = argv[optind++];
+ if (!value && !vdi_cmd_data.delete) {
+ value = malloc(SD_MAX_VDI_ATTR_VALUE_LEN);
+ if (!value) {
+ fprintf(stderr, "failed to allocate memory\n");
+ return EXIT_SYSFAIL;
+ }
+
+ offset = 0;
+reread:
+ ret = read(STDIN_FILENO, value + offset,
+ SD_MAX_VDI_ATTR_VALUE_LEN - offset);
+ if (ret < 0) {
+ fprintf(stderr, "failed to read from stdin, %m\n");
+ return EXIT_SYSFAIL;
+ }
+ if (ret > 0) {
+ offset += ret;
+ goto reread;
+ }
+ }
+
+ ret = find_vdi_attr_oid(vdiname, vdi_cmd_data.snapshot_tag,
+ vdi_cmd_data.snapshot_id, key, &vid, &attr_oid,
+ &nr_copies, !vdi_cmd_data.delete,
+ vdi_cmd_data.exclusive);
+ if (ret) {
+ if (ret == SD_RES_VDI_EXIST) {
+ fprintf(stderr, "the attribute already exists, %s\n", key);
+ return EXIT_EXISTS;
+ } else if (ret == SD_RES_NO_OBJ) {
+ fprintf(stderr, "no such attribute, %s\n", key);
+ return EXIT_MISSING;
+ } else if (ret == SD_RES_NO_VDI) {
+ fprintf(stderr, "vdi not found\n");
+ return EXIT_MISSING;
+ } else
+ fprintf(stderr, "failed to find attr oid, %s\n",
+ sd_strerror(ret));
+ return EXIT_FAILURE;
+ }
+
+ oid = attr_oid;
+
+ if (vdi_cmd_data.delete)
+ ret = sd_write_object(oid, (char *)"", 1,
+ offsetof(struct sheepdog_inode, name), 0,
+ nr_copies, 0);
+ else
+ ret = sd_write_object(oid, value, strlen(value),
+ SD_ATTR_HEADER_SIZE, SD_FLAG_CMD_TRUNCATE,
+ nr_copies, 0);
+
+ if (ret != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to set attribute\n");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int vdi_getattr(int argc, char **argv)
+{
+ struct sd_obj_req hdr;
+ struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
+ int ret;
+ uint64_t oid, attr_oid = 0;
+ uint32_t vid = 0, nr_copies = 0;
+ char *vdiname = argv[optind++], *key, *value;
+
+ key = argv[optind++];
+ if (!key) {
+ fprintf(stderr, "please specify the name of key\n");
+ return EXIT_USAGE;
+ }
+
+ ret = find_vdi_attr_oid(vdiname, vdi_cmd_data.snapshot_tag,
+ vdi_cmd_data.snapshot_id, key, &vid, &attr_oid,
+ &nr_copies, 0, 0);
+ if (ret == SD_RES_NO_OBJ) {
+ fprintf(stderr, "no such attribute, %s\n", key);
+ return EXIT_MISSING;
+ } else if (ret == SD_RES_NO_VDI) {
+ fprintf(stderr, "vdi not found\n");
+ return EXIT_MISSING;
+ } else if (ret) {
+ fprintf(stderr, "failed to find attr oid, %s\n",
+ sd_strerror(ret));
+ return EXIT_MISSING;
+ }
+
+ oid = attr_oid;
+ value = malloc(SD_MAX_VDI_ATTR_VALUE_LEN);
+ if (!value) {
+ fprintf(stderr, "failed to allocate memory\n");
+ return EXIT_SYSFAIL;
+ }
+
+ ret = sd_read_object(oid, value, SD_MAX_VDI_ATTR_VALUE_LEN,
+ SD_ATTR_HEADER_SIZE);
+ if (rsp->result == SD_RES_SUCCESS) {
+ printf("%s", value);
+ free(value);
+ return EXIT_SUCCESS;
+ }
+
+ free(value);
+ return EXIT_FAILURE;
+}
+
+static struct subcommand vdi_cmd[] = {
+ {"create", "<vdiname> <size>", "Paph", "create a image",
+ SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_create},
+ {"snapshot", "<vdiname>", "saph", "create a snapshot",
+ SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_snapshot},
+ {"clone", "<src vdi> <dst vdi>", "sPaph", "create a clone image",
+ SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_clone},
+ {"delete", "<vdiname>", "saph", "delete a image",
+ SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_delete},
+ {"list", "[vdiname]", "aprh", "list images",
+ SUBCMD_FLAG_NEED_NODELIST, vdi_list},
+ {"tree", NULL, "aph", "show images in tree view format",
+ SUBCMD_FLAG_NEED_NODELIST, vdi_tree},
+ {"graph", NULL, "aph", "show images with Graphviz dot format",
+ SUBCMD_FLAG_NEED_NODELIST, vdi_graph},
+ {"object", "<vdiname>", "isaph", "show object information in the image",
+ SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_object},
+ {"setattr", "<vdiname> <key> [value]", "dxaph", "set a vdi attribute",
+ SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_setattr},
+ {"getattr", "<vdiname> <key>", "aph", "get a vdi attribute",
+ SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_getattr},
+ {"resize", "<vdiname> <new size>", "aph", "resize a image",
+ SUBCMD_FLAG_NEED_NODELIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_resize},
+ {NULL,},
+};
+
+static int vdi_parser(int ch, char *opt)
+{
+ switch (ch) {
+ case 'P':
+ vdi_cmd_data.prealloc = 1;
+ break;
+ case 'i':
+ vdi_cmd_data.index = atoi(opt);
+ break;
+ case 's':
+ vdi_cmd_data.snapshot_id = atoi(opt);
+ if (vdi_cmd_data.snapshot_id == 0)
+ strncpy(vdi_cmd_data.snapshot_tag, opt,
+ sizeof(vdi_cmd_data.snapshot_tag));
+ break;
+ case 'x':
+ vdi_cmd_data.exclusive = 1;
+ break;
+ case 'd':
+ vdi_cmd_data.delete = 1;
+ break;
+ }
+
+ return 0;
+}
+
+struct command vdi_command = {
+ "vdi",
+ vdi_cmd,
+ vdi_parser
+};
--
1.7.2.5
More information about the sheepdog
mailing list