[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