[sheepdog] [PATCH v2 03/15] sheepfs: core infrastructure
MORITA Kazutaka
morita.kazutaka at lab.ntt.co.jp
Sun May 20 11:25:41 CEST 2012
At Mon, 14 May 2012 17:47:28 +0800,
Liu Yuan wrote:
>
> From: Liu Yuan <tailai.ly at taobao.com>
>
> Sheepfs is FUSE-based pseudo file system in userland to access both sheepdog's
> internal state (for e.g, cluster info, vdi list) as well as sheepdog's high
> reliable stroage.
>
> This building block is supposed to be modular enough to allow us ease adding
> more powerful tools.
>
> Signed-off-by: Liu Yuan <tailai.ly at taobao.com>
> ---
> sheepfs/Makefile.am | 8 +-
> sheepfs/core.c | 293 +++++++++++++++++++++++++++++++++++++++++++++++++++
> sheepfs/sheepfs.h | 13 +++
> 3 files changed, 310 insertions(+), 4 deletions(-)
> create mode 100644 sheepfs/core.c
> create mode 100644 sheepfs/sheepfs.h
>
> diff --git a/sheepfs/Makefile.am b/sheepfs/Makefile.am
> index 0d4a42c..c6c6741 100644
> --- a/sheepfs/Makefile.am
> +++ b/sheepfs/Makefile.am
> @@ -17,18 +17,18 @@
>
> MAINTAINERCLEANFILES = Makefile.in
>
> -AM_CFLAGS =
> +AM_CFLAGS = $(fuse_CFLAGS) -DFUSE_USE_VERSION=26
>
> INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
>
> sbin_PROGRAMS = sheepfs
>
> -sheepfs_SOURCES =
> +sheepfs_SOURCES = core.c
>
> -sheepfs_LDADD = ../lib/libsheepdog.a
> +sheepfs_LDADD = ../lib/libsheepdog.a $(fuse_LIBS) $(LIBS)
> sheepfs_DEPENDENCIES = ../lib/libsheepdog.a
>
> -noinst_HEADERS =
> +noinst_HEADERS = sheepfs.h
>
> EXTRA_DIST =
>
> diff --git a/sheepfs/core.c b/sheepfs/core.c
> new file mode 100644
> index 0000000..230794d
> --- /dev/null
> +++ b/sheepfs/core.c
> @@ -0,0 +1,293 @@
> +/*
> + * Copyright (C) 2012 Taobao Inc.
> + *
> + * Liu Yuan <namei.unix at gmail.com>
> + *
> + * 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 <fuse.h>
> +#include <errno.h>
> +#include <sys/types.h>
> +#include <attr/xattr.h>
> +#include <dirent.h>
> +#include <pthread.h>
> +#include <getopt.h>
> +#include <syslog.h>
> +
> +#include "strbuf.h"
> +#include "util.h"
> +#include "sheepfs.h"
> +
> +#define SH_OP_NAME "user.sheepfs.opcode"
> +#define SH_OP_SIZE sizeof(uint32_t)
> +
> +char sheepfs_shadow[PATH_MAX];
> +
> +static int sheepfs_debug;
> +static int sheepfs_fg;
> +
> +static struct option const long_options[] = {
> + {"debug", no_argument, NULL, 'd'},
> + {"directio", no_argument, NULL, 'D'},
> + {"help", no_argument, NULL, 'h'},
> + {"foreground", no_argument, NULL, 'f'},
> + {NULL, 0, NULL, 0},
> +};
> +
> +static const char *short_options = "dDhf";
> +
> +static struct sheepfs_file_operation {
> + int (*read)(const char *path, char *buf, size_t size, off_t);
> + int (*write)(const char *path, const char *buf, size_t size, off_t);
> + size_t (*get_size)(const char *path);
> +} sheepfs_file_ops[] = {
> + [OP_NULL] = { NULL, NULL, NULL },
> +};
> +
> +int sheepfs_set_op(const char *path, unsigned opcode)
> +{
> + if (shadow_file_setxattr(path, SH_OP_NAME, &opcode, SH_OP_SIZE) < 0) {
> + shadow_file_delete(path);
> + return -1;
> + }
> + return 0;
> +}
> +
> +static unsigned sheepfs_get_op(const char *path)
> +{
> + unsigned opcode = 0;
> +
> + /* If fail, we simply return 0 to run NULL operation */
> + shadow_file_getxattr(path, SH_OP_NAME, &opcode, SH_OP_SIZE);
> +
> + return opcode;
> +}
> +
> +static size_t sheepfs_get_size(const char *path)
> +{
> + unsigned op = sheepfs_get_op(path);
> +
> + if (sheepfs_file_ops[op].get_size)
> + return sheepfs_file_ops[op].get_size(path);
> +
> + return 0;
> +}
> +
> +static int sheepfs_getattr(const char *path, struct stat *st)
> +{
> + struct strbuf p = STRBUF_INIT;
> + int ret;
> +
> + strbuf_addf(&p, "%s%s", sheepfs_shadow, path);
> + ret = stat(p.buf, st);
> + if (ret < 0) {
> + ret = -errno;
> + goto out;
> + }
> + if (S_ISREG(st->st_mode))
> + st->st_size = sheepfs_get_size(path);
> +out:
> + strbuf_release(&p);
> + return ret;
> +}
> +
> +static int sheepfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
> + off_t offset, struct fuse_file_info *fi)
> +{
> + DIR *dir;
> + struct dirent *dentry;
> + struct strbuf p = STRBUF_INIT;
> + int ret = 0;
> +
> + strbuf_addf(&p, "%s%s", sheepfs_shadow, path);
> + dir = opendir(p.buf);
> + if (!dir) {
> + ret = -errno;
> + syslog(LOG_ERR, "[%s] %m\n", __func__);
> + goto out;
> + }
> +
> + while ((dentry = readdir(dir))) {
> + if (filler(buf, dentry->d_name, NULL, 0) != 0) {
> + syslog(LOG_ERR, "[%s] out of memory\n", __func__);
> + ret = -ENOMEM;
> + goto out;
> + }
> + }
> +
> +out:
> + strbuf_release(&p);
> + return ret;
> +}
> +
> +static int sheepfs_read(const char *path, char *buf, size_t size,
> + off_t offset, struct fuse_file_info *fi)
> +{
> + int ret = 0;
> + unsigned op = sheepfs_get_op(path);
> +
> + if (sheepfs_file_ops[op].read)
> + ret = sheepfs_file_ops[op].read(path, buf, size, offset);
> +
> + return ret;
> +}
> +
> +static int sheepfs_write(const char *path, const char *buf, size_t size,
> + off_t offset, struct fuse_file_info *fi)
> +{
> + int ret = 0;
> + unsigned op = sheepfs_get_op(path);
> +
> + if (sheepfs_file_ops[op].write)
> + ret = sheepfs_file_ops[op].write(path, buf, size, offset);
> +
> + return ret;
> +}
> +
> +static int sheepfs_truncate(const char *path, off_t size)
> +{
> + struct strbuf p = STRBUF_INIT;
> + int ret = 0, fd;
> +
> + strbuf_addf(&p, "%s%s", sheepfs_shadow, path);
> + fd = open(p.buf, O_RDWR);
> + if (fd < 0)
> + ret = -ENOENT;
> + else
> + close(fd);
> +
> + strbuf_release(&p);
> + return ret;
> +}
> +
> +struct fuse_operations sheepfs_ops = {
> + .getattr = sheepfs_getattr,
> + .readdir = sheepfs_readdir,
> + .truncate = sheepfs_truncate,
> + .read = sheepfs_read,
> + .write = sheepfs_write,
> +};
> +
> +static int sheepfs_main_loop(char *mountpoint)
> +{
> + struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
> + int ret = -1;
> +
> + fuse_opt_add_arg(&args, "sheepfs"); /* placeholder for argv[0] */
> + fuse_opt_add_arg(&args, "-ofsname=sheepfs");
> + fuse_opt_add_arg(&args, mountpoint);
> + if (sheepfs_debug)
> + fuse_opt_add_arg(&args, "-odebug");
> + if (sheepfs_fg)
> + fuse_opt_add_arg(&args, "-f");
> +
> + syslog(LOG_INFO, "sheepfs daemon started\n");
> + ret = fuse_main(args.argc, args.argv, &sheepfs_ops, NULL);
> + rmdir_r(sheepfs_shadow);
> + syslog(LOG_INFO, "sheepfs daemon exited %d\n", ret);
> + return ret;
> +}
> +
> +static int create_sheepfs_layout(char *path)
> +{
> + return 0;
> +}
> +
> +static void usage(int inval)
> +{
> + if (inval)
> + fprintf(stderr, "Try 'sheepfs --help' for help.\n");
> + else
> + printf("\
> +Usage: sheepfs [OPTION]... MOUNTPOINT\n\
> +Options:\n\
> + -d, --debug enable debug output (implies -f)\n\
> + -D, --directio use direct IO to access volume\n\
> + -f, --foreground sheepfs run in the foreground\n\
> + -h, --help display this help and exit\n\
> +");
> + exit(inval);
> +}
> +
> +int main(int argc, char **argv)
> +{
> + struct strbuf path = STRBUF_INIT;
> + int ch, longindex;
> + char *dir = NULL, *cwd;
> +
> +
> + while ((ch = getopt_long(argc, argv, short_options, long_options,
> + &longindex)) >= 0) {
> + switch (ch) {
> + case 'd':
> + sheepfs_debug = 1;
> + break;
> + case 'D':
> + break;
> + case 'h':
> + usage(0);
> + break;
> + case 'f':
> + sheepfs_fg = 1;
> + break;
> + default:
> + usage(1);
> + }
> + }
> +
> + if (optind != argc)
> + dir = argv[optind];
> + else
> + usage(1);
> +
> + cwd = get_current_dir_name();
> + if (!cwd) {
> + fprintf(stderr, "%m\n");
> + exit(1);
> + }
> + strbuf_addf(&path, "%s/%s", cwd, ".sheepfs");
> + free(cwd);
> + memcpy(sheepfs_shadow, path.buf, path.len);
> + if (mkdir(sheepfs_shadow, 0755) < 0) {
> + if (errno != EEXIST) {
> + fprintf(stderr, "%m\n");
> + exit(1);
> + }
> + }
> +
> + strbuf_release(&path);
> + create_sheepfs_layout();
We should check the return value. Actually, if user_xattr is not
supported on the file system, this function will fail.
Thanks,
Kazutaka
> + openlog("sheepfs", LOG_CONS | LOG_PID, LOG_DAEMON);
> +
> + return sheepfs_main_loop(dir);
> +}
> +
> +struct strbuf *sheepfs_run_cmd(const char *command)
> +{
> + struct strbuf *buf = xmalloc(sizeof(*buf));
> + FILE *f = popen(command, "re");
> +
> + if (!f) {
> + syslog(LOG_ERR, "[%s] popen failed\n", __func__);
> + goto err;
> + }
> +
> + strbuf_init(buf, 4096);
> +
> + while (!feof(f))
> + strbuf_fread(buf, 4096, f);
> +
> + pclose(f);
> + return buf;
> +err:
> + strbuf_release(buf);
> + pclose(f);
> + free(buf);
> + return NULL;
> +}
> diff --git a/sheepfs/sheepfs.h b/sheepfs/sheepfs.h
> new file mode 100644
> index 0000000..d1b2a14
> --- /dev/null
> +++ b/sheepfs/sheepfs.h
> @@ -0,0 +1,13 @@
> +#ifndef SHEEPFS_H
> +#define SHEEPFS_H
> +
> +enum sheepfs_opcode {
> + OP_NULL = 0,
> +};
> +
> +extern char sheepfs_shadow[];
> +
> +extern struct strbuf *sheepfs_run_cmd(const char *command);
> +extern int sheepfs_set_op(const char *path, unsigned opcode);
> +
> +#endif
> --
> 1.7.8.2
>
More information about the sheepdog
mailing list