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 > |