diff options
| author | Anand V. Avati <avati@dev.gluster.com> | 2009-08-17 15:25:44 -0700 | 
|---|---|---|
| committer | Anand V. Avati <avati@dev.gluster.com> | 2009-08-17 15:25:44 -0700 | 
| commit | a31b0016347b3bc9b341fa0f4541ed137224f593 (patch) | |
| tree | 3e1faf06a3e14e5022048886ecfa49267c92c986 | |
| parent | 862cbb38375f0176582b06019ba406818d236828 (diff) | |
| parent | 10824751f8669e7c39ebd46ab698ed0abd4e5165 (diff) | |
Merge branch 'fusilli' of /data/git/users/csaba/glusterfs-fusilli
Conflicts:
	xlators/mount/fuse/src/fuse-bridge.c
| -rw-r--r-- | Makefile.am | 2 | ||||
| -rw-r--r-- | configure.ac | 63 | ||||
| -rw-r--r-- | contrib/Makefile.am | 3 | ||||
| -rw-r--r-- | contrib/fuse-include/fuse-misc.h | 13 | ||||
| -rw-r--r-- | contrib/fuse-include/fuse-mount.h | 11 | ||||
| -rw-r--r-- | contrib/fuse-include/fuse_kernel.h | 573 | ||||
| -rw-r--r-- | contrib/fuse-lib/COPYING.LIB | 482 | ||||
| -rw-r--r-- | contrib/fuse-lib/misc.c | 51 | ||||
| -rw-r--r-- | contrib/fuse-lib/mount.c | 616 | ||||
| -rw-r--r-- | contrib/fuse-util/COPYING | 340 | ||||
| -rw-r--r-- | contrib/fuse-util/Makefile.am | 12 | ||||
| -rw-r--r-- | contrib/fuse-util/fusermount.c | 965 | ||||
| -rw-r--r-- | contrib/fuse-util/mount_util.h | 17 | ||||
| -rw-r--r-- | doc/user-guide/user-guide.texi | 45 | ||||
| -rw-r--r-- | glusterfsd/src/glusterfsd.c | 3 | ||||
| -rw-r--r-- | xlators/mount/fuse/src/Makefile.am | 11 | ||||
| -rw-r--r-- | xlators/mount/fuse/src/fuse-bridge.c | 1758 | ||||
| -rw-r--r-- | xlators/mount/fuse/src/fuse-extra.c | 155 | ||||
| -rw-r--r-- | xlators/mount/fuse/src/fuse-extra.h | 42 | 
19 files changed, 4146 insertions, 1016 deletions
diff --git a/Makefile.am b/Makefile.am index b4f0587ca3f..44506dfd0e1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@  EXTRA_DIST = autogen.sh COPYING INSTALL README AUTHORS THANKS NEWS glusterfs.spec -SUBDIRS = argp-standalone libglusterfs $(LIBGLUSTERFSCLIENT_SUBDIR) xlators scheduler transport auth glusterfsd $(GF_BOOSTER_SUBDIR) doc extras +SUBDIRS = argp-standalone libglusterfs $(LIBGLUSTERFSCLIENT_SUBDIR) xlators scheduler transport auth glusterfsd $(GF_BOOSTER_SUBDIR) $(FUSERMOUNT_SUBDIR) doc extras  CLEANFILES =  diff --git a/configure.ac b/configure.ac index 71f663fa710..6a951096822 100644 --- a/configure.ac +++ b/configure.ac @@ -124,6 +124,8 @@ AC_CONFIG_FILES([Makefile                  extras/init.d/glusterfsd-Redhat                  extras/init.d/glusterfsd-SuSE  		extras/benchmarking/Makefile +		contrib/Makefile +		contrib/fuse-util/Makefile  		glusterfs.spec])  AC_CANONICAL_HOST @@ -206,53 +208,32 @@ AC_ARG_ENABLE([fuse-client],  	      AC_HELP_STRING([--disable-fuse-client],  			     [Do not build the fuse client. NOTE: you cannot mount glusterfs without the client])) +BUILD_FUSE_CLIENT=no  if test "x$enable_fuse_client" != "xno"; then -   AC_CHECK_LIB([fuse], -                 [fuse_req_interrupt_func], -	         [HAVE_LIBFUSE="yes"], -	         [HAVE_LIBFUSE="no"]) - -   if test "x$HAVE_LIBFUSE" = "xyes"; then -      AC_TRY_COMPILE([#define FUSE_USE_VERSION 26  -                      #define _FILE_OFFSET_BITS 64  -                      #include <fuse.h>], -		      #define _GLFS_FUSE_VERSION_28 28 -       	 	      #if (FUSE_VERSION < _GLFS_FUSE_VERSION_28) -                      #error "fuse version 2.8 not found"  -		      #endif -		      , -		     [HAVE_FUSE_VERSION_28="yes"], -		     [HAVE_FUSE_VERSION_28="no"]) - -      AC_CHECK_LIB([fuse], -                    [fuse_reply_iov], -	            [HAVE_FUSE_REPLY_IOV="yes"], -	            [HAVE_FUSE_REPLY_IOV="no"]) - -   fi      +   FUSE_CLIENT_SUBDIR=fuse +   BUILD_FUSE_CLIENT="yes"  fi -if test "x$HAVE_FUSE_REPLY_IOV" = "xyes"; then -   AC_DEFINE(HAVE_FUSE_REPLY_IOV, 1, [found fuse_reply_iov]) -fi +AC_SUBST(FUSE_CLIENT_SUBDIR) +# end FUSE section -if test "x$HAVE_LIBFUSE" = "xyes" -a "x$HAVE_FUSE_VERSION_28" = "xyes"; then -   AC_DEFINE(HAVE_FUSE_VERSION_28, 1, [found fuse 2.8 version]) -fi -if test "x$enable_fuse_client" = "xyes" -a "x$HAVE_LIBFUSE" = "xno"; then -   echo "FUSE requested but not found." -   exit 1 -fi +# FUSERMOUNT section +AC_ARG_ENABLE([fusermount], +              AC_HELP_STRING([--enable-fusermount], +                             [Build fusermount]), +              [], [enable_fusermount=no]) -BUILD_FUSE_CLIENT=no -if test "x$enable_fuse_client" != "xno" -a "x$HAVE_LIBFUSE" = "xyes"; then -   FUSE_CLIENT_SUBDIR=fuse -   BUILD_FUSE_CLIENT="yes" +BUILD_FUSERMOUNT="no" + +if test "x$enable_fusermount" != "xno"; then +  FUSERMOUNT_SUBDIR="contrib" +  BUILD_FUSERMOUNT="yes" +  AC_DEFINE(GF_FUSERMOUNT, 1, [Use our own fusermount])  fi -AC_SUBST(FUSE_CLIENT_SUBDIR) -# end FUSE section +AC_SUBST(FUSERMOUNT_SUBDIR) +#end FUSERMOUNT section  # EPOLL section @@ -493,6 +474,9 @@ AC_SUBST(GF_LDADD)  AC_SUBST(GF_FUSE_LDADD)  AC_SUBST(GF_BOOSTER_SUBDIR) +CONTRIBDIR='$(top_srcdir)/contrib' +AC_SUBST(CONTRIBDIR) +  AM_CONDITIONAL([GF_DARWIN_HOST_OS], test "${GF_HOST_OS}" = "GF_DARWIN_HOST_OS")	  AC_OUTPUT @@ -506,4 +490,5 @@ echo "epoll IO multiplex : $BUILD_EPOLL"  echo "Berkeley-DB        : $BUILD_BDB"  echo "libglusterfsclient : $BUILD_LIBGLUSTERFSCLIENT"  echo "argp-standalone    : $BUILD_ARGP_STANDALONE" +echo "fusermount         : $BUILD_FUSERMOUNT"  echo diff --git a/contrib/Makefile.am b/contrib/Makefile.am new file mode 100644 index 00000000000..a3d5cfbf855 --- /dev/null +++ b/contrib/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = fuse-util + +CLEANFILES = diff --git a/contrib/fuse-include/fuse-misc.h b/contrib/fuse-include/fuse-misc.h new file mode 100644 index 00000000000..16b47347262 --- /dev/null +++ b/contrib/fuse-include/fuse-misc.h @@ -0,0 +1,13 @@ +/* +  FUSE: Filesystem in Userspace +  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu> + +  This program can be distributed under the terms of the GNU LGPLv2. +  See the file COPYING.LIB +*/ + +#define OFFSET_MAX 0x7fffffffffffffffLL + +unsigned long calc_timeout_sec (double t); +unsigned int calc_timeout_nsec (double t); +void convert_fuse_file_lock (struct fuse_file_lock *fl, struct flock *flock); diff --git a/contrib/fuse-include/fuse-mount.h b/contrib/fuse-include/fuse-mount.h new file mode 100644 index 00000000000..d263a80390a --- /dev/null +++ b/contrib/fuse-include/fuse-mount.h @@ -0,0 +1,11 @@ +/* +  FUSE: Filesystem in Userspace +  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu> +  Copyright (c) 2009 Z RESEARCH, Inc. <http://www.zresearch.com> + +  This program can be distributed under the terms of the GNU LGPLv2. +  See the file COPYING.LIB. +*/ + +void gf_fuse_unmount (const char *mountpoint, int fd); +int gf_fuse_mount (const char *mountpoint, char *fsname, char *mnt_param); diff --git a/contrib/fuse-include/fuse_kernel.h b/contrib/fuse-include/fuse_kernel.h new file mode 100644 index 00000000000..dac35d8b9b1 --- /dev/null +++ b/contrib/fuse-include/fuse_kernel.h @@ -0,0 +1,573 @@ +/* +    This file defines the kernel interface of FUSE +    Copyright (C) 2001-2008  Miklos Szeredi <miklos@szeredi.hu> + +    This program can be distributed under the terms of the GNU GPL. +    See the file COPYING. + +    This -- and only this -- header file may also be distributed under +    the terms of the BSD Licence as follows: + +    Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. + +    Redistribution and use in source and binary forms, with or without +    modification, are permitted provided that the following conditions +    are met: +    1. Redistributions of source code must retain the above copyright +       notice, this list of conditions and the following disclaimer. +    2. Redistributions in binary form must reproduce the above copyright +       notice, this list of conditions and the following disclaimer in the +       documentation and/or other materials provided with the distribution. + +    THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +    ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +    SUCH DAMAGE. +*/ + +/* + * This file defines the kernel interface of FUSE + * + * Protocol changelog: + * + * 7.9: + *  - new fuse_getattr_in input argument of GETATTR + *  - add lk_flags in fuse_lk_in + *  - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in + *  - add blksize field to fuse_attr + *  - add file flags field to fuse_read_in and fuse_write_in + * + * 7.10 + *  - add nonseekable open flag + * + * 7.11 + *  - add IOCTL message + *  - add unsolicited notification support + *  - add POLL message and NOTIFY_POLL notification + * + * 7.12 + *  - add umask flag to input argument of open, mknod and mkdir + *  - add notification messages for invalidation of inodes and + *    directory entries + */ + +#ifndef _LINUX_FUSE_H +#define _LINUX_FUSE_H + +#include <sys/types.h> +#define __u64 uint64_t +#define __s64 int64_t +#define __u32 uint32_t +#define __s32 int32_t + +/** Version number of this interface */ +#define FUSE_KERNEL_VERSION 7 + +/** Minor version number of this interface */ +#define FUSE_KERNEL_MINOR_VERSION 12 + +/** The node ID of the root inode */ +#define FUSE_ROOT_ID 1 + +/* Make sure all structures are padded to 64bit boundary, so 32bit +   userspace works under 64bit kernels */ + +struct fuse_attr { +	__u64	ino; +	__u64	size; +	__u64	blocks; +	__u64	atime; +	__u64	mtime; +	__u64	ctime; +	__u32	atimensec; +	__u32	mtimensec; +	__u32	ctimensec; +	__u32	mode; +	__u32	nlink; +	__u32	uid; +	__u32	gid; +	__u32	rdev; +	__u32	blksize; +	__u32	padding; +}; + +struct fuse_kstatfs { +	__u64	blocks; +	__u64	bfree; +	__u64	bavail; +	__u64	files; +	__u64	ffree; +	__u32	bsize; +	__u32	namelen; +	__u32	frsize; +	__u32	padding; +	__u32	spare[6]; +}; + +struct fuse_file_lock { +	__u64	start; +	__u64	end; +	__u32	type; +	__u32	pid; /* tgid */ +}; + +/** + * Bitmasks for fuse_setattr_in.valid + */ +#define FATTR_MODE	(1 << 0) +#define FATTR_UID	(1 << 1) +#define FATTR_GID	(1 << 2) +#define FATTR_SIZE	(1 << 3) +#define FATTR_ATIME	(1 << 4) +#define FATTR_MTIME	(1 << 5) +#define FATTR_FH	(1 << 6) +#define FATTR_ATIME_NOW	(1 << 7) +#define FATTR_MTIME_NOW	(1 << 8) +#define FATTR_LOCKOWNER	(1 << 9) + +/** + * Flags returned by the OPEN request + * + * FOPEN_DIRECT_IO: bypass page cache for this open file + * FOPEN_KEEP_CACHE: don't invalidate the data cache on open + * FOPEN_NONSEEKABLE: the file is not seekable + */ +#define FOPEN_DIRECT_IO		(1 << 0) +#define FOPEN_KEEP_CACHE	(1 << 1) +#define FOPEN_NONSEEKABLE	(1 << 2) + +/** + * INIT request/reply flags + * + * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." + * FUSE_DONT_MASK: don't apply umask to file mode on create operations + */ +#define FUSE_ASYNC_READ		(1 << 0) +#define FUSE_POSIX_LOCKS	(1 << 1) +#define FUSE_FILE_OPS		(1 << 2) +#define FUSE_ATOMIC_O_TRUNC	(1 << 3) +#define FUSE_EXPORT_SUPPORT	(1 << 4) +#define FUSE_BIG_WRITES		(1 << 5) +#define FUSE_DONT_MASK		(1 << 6) + +/** + * CUSE INIT request/reply flags + * + * CUSE_UNRESTRICTED_IOCTL:  use unrestricted ioctl + */ +#define CUSE_UNRESTRICTED_IOCTL	(1 << 0) + +/** + * Release flags + */ +#define FUSE_RELEASE_FLUSH	(1 << 0) + +/** + * Getattr flags + */ +#define FUSE_GETATTR_FH		(1 << 0) + +/** + * Lock flags + */ +#define FUSE_LK_FLOCK		(1 << 0) + +/** + * WRITE flags + * + * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed + * FUSE_WRITE_LOCKOWNER: lock_owner field is valid + */ +#define FUSE_WRITE_CACHE	(1 << 0) +#define FUSE_WRITE_LOCKOWNER	(1 << 1) + +/** + * Read flags + */ +#define FUSE_READ_LOCKOWNER	(1 << 1) + +/** + * Ioctl flags + * + * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine + * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed + * FUSE_IOCTL_RETRY: retry with new iovecs + * + * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs + */ +#define FUSE_IOCTL_COMPAT	(1 << 0) +#define FUSE_IOCTL_UNRESTRICTED	(1 << 1) +#define FUSE_IOCTL_RETRY	(1 << 2) + +#define FUSE_IOCTL_MAX_IOV	256 + +/** + * Poll flags + * + * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify + */ +#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0) + +enum fuse_opcode { +	FUSE_LOOKUP	   = 1, +	FUSE_FORGET	   = 2,  /* no reply */ +	FUSE_GETATTR	   = 3, +	FUSE_SETATTR	   = 4, +	FUSE_READLINK	   = 5, +	FUSE_SYMLINK	   = 6, +	FUSE_MKNOD	   = 8, +	FUSE_MKDIR	   = 9, +	FUSE_UNLINK	   = 10, +	FUSE_RMDIR	   = 11, +	FUSE_RENAME	   = 12, +	FUSE_LINK	   = 13, +	FUSE_OPEN	   = 14, +	FUSE_READ	   = 15, +	FUSE_WRITE	   = 16, +	FUSE_STATFS	   = 17, +	FUSE_RELEASE       = 18, +	FUSE_FSYNC         = 20, +	FUSE_SETXATTR      = 21, +	FUSE_GETXATTR      = 22, +	FUSE_LISTXATTR     = 23, +	FUSE_REMOVEXATTR   = 24, +	FUSE_FLUSH         = 25, +	FUSE_INIT          = 26, +	FUSE_OPENDIR       = 27, +	FUSE_READDIR       = 28, +	FUSE_RELEASEDIR    = 29, +	FUSE_FSYNCDIR      = 30, +	FUSE_GETLK         = 31, +	FUSE_SETLK         = 32, +	FUSE_SETLKW        = 33, +	FUSE_ACCESS        = 34, +	FUSE_CREATE        = 35, +	FUSE_INTERRUPT     = 36, +	FUSE_BMAP          = 37, +	FUSE_DESTROY       = 38, +	FUSE_IOCTL         = 39, +	FUSE_POLL          = 40, + +	/* CUSE specific operations */ +	CUSE_INIT          = 4096, +}; + +enum fuse_notify_code { +	FUSE_NOTIFY_POLL   = 1, +	FUSE_NOTIFY_INVAL_INODE = 2, +	FUSE_NOTIFY_INVAL_ENTRY = 3, +	FUSE_NOTIFY_CODE_MAX, +}; + +/* The read buffer is required to be at least 8k, but may be much larger */ +#define FUSE_MIN_READ_BUFFER 8192 + +#define FUSE_COMPAT_ENTRY_OUT_SIZE 120 + +struct fuse_entry_out { +	__u64	nodeid;		/* Inode ID */ +	__u64	generation;	/* Inode generation: nodeid:gen must +				   be unique for the fs's lifetime */ +	__u64	entry_valid;	/* Cache timeout for the name */ +	__u64	attr_valid;	/* Cache timeout for the attributes */ +	__u32	entry_valid_nsec; +	__u32	attr_valid_nsec; +	struct fuse_attr attr; +}; + +struct fuse_forget_in { +	__u64	nlookup; +}; + +struct fuse_getattr_in { +	__u32	getattr_flags; +	__u32	dummy; +	__u64	fh; +}; + +#define FUSE_COMPAT_ATTR_OUT_SIZE 96 + +struct fuse_attr_out { +	__u64	attr_valid;	/* Cache timeout for the attributes */ +	__u32	attr_valid_nsec; +	__u32	dummy; +	struct fuse_attr attr; +}; + +#define FUSE_COMPAT_MKNOD_IN_SIZE 8 + +struct fuse_mknod_in { +	__u32	mode; +	__u32	rdev; +	__u32	umask; +	__u32	padding; +}; + +struct fuse_mkdir_in { +	__u32	mode; +	__u32	umask; +}; + +struct fuse_rename_in { +	__u64	newdir; +}; + +struct fuse_link_in { +	__u64	oldnodeid; +}; + +struct fuse_setattr_in { +	__u32	valid; +	__u32	padding; +	__u64	fh; +	__u64	size; +	__u64	lock_owner; +	__u64	atime; +	__u64	mtime; +	__u64	unused2; +	__u32	atimensec; +	__u32	mtimensec; +	__u32	unused3; +	__u32	mode; +	__u32	unused4; +	__u32	uid; +	__u32	gid; +	__u32	unused5; +}; + +struct fuse_open_in { +	__u32	flags; +	__u32	unused; +}; + +struct fuse_create_in { +	__u32	flags; +	__u32	mode; +	__u32	umask; +	__u32	padding; +}; + +struct fuse_open_out { +	__u64	fh; +	__u32	open_flags; +	__u32	padding; +}; + +struct fuse_release_in { +	__u64	fh; +	__u32	flags; +	__u32	release_flags; +	__u64	lock_owner; +}; + +struct fuse_flush_in { +	__u64	fh; +	__u32	unused; +	__u32	padding; +	__u64	lock_owner; +}; + +struct fuse_read_in { +	__u64	fh; +	__u64	offset; +	__u32	size; +	__u32	read_flags; +	__u64	lock_owner; +	__u32	flags; +	__u32	padding; +}; + +#define FUSE_COMPAT_WRITE_IN_SIZE 24 + +struct fuse_write_in { +	__u64	fh; +	__u64	offset; +	__u32	size; +	__u32	write_flags; +	__u64	lock_owner; +	__u32	flags; +	__u32	padding; +}; + +struct fuse_write_out { +	__u32	size; +	__u32	padding; +}; + +#define FUSE_COMPAT_STATFS_SIZE 48 + +struct fuse_statfs_out { +	struct fuse_kstatfs st; +}; + +struct fuse_fsync_in { +	__u64	fh; +	__u32	fsync_flags; +	__u32	padding; +}; + +struct fuse_setxattr_in { +	__u32	size; +	__u32	flags; +}; + +struct fuse_getxattr_in { +	__u32	size; +	__u32	padding; +}; + +struct fuse_getxattr_out { +	__u32	size; +	__u32	padding; +}; + +struct fuse_lk_in { +	__u64	fh; +	__u64	owner; +	struct fuse_file_lock lk; +	__u32	lk_flags; +	__u32	padding; +}; + +struct fuse_lk_out { +	struct fuse_file_lock lk; +}; + +struct fuse_access_in { +	__u32	mask; +	__u32	padding; +}; + +struct fuse_init_in { +	__u32	major; +	__u32	minor; +	__u32	max_readahead; +	__u32	flags; +}; + +struct fuse_init_out { +	__u32	major; +	__u32	minor; +	__u32	max_readahead; +	__u32	flags; +	__u32	unused; +	__u32	max_write; +}; + +#define CUSE_INIT_INFO_MAX 4096 + +struct cuse_init_in { +	__u32	major; +	__u32	minor; +	__u32	unused; +	__u32	flags; +}; + +struct cuse_init_out { +	__u32	major; +	__u32	minor; +	__u32	unused; +	__u32	flags; +	__u32	max_read; +	__u32	max_write; +	__u32	dev_major;		/* chardev major */ +	__u32	dev_minor;		/* chardev minor */ +	__u32	spare[10]; +}; + +struct fuse_interrupt_in { +	__u64	unique; +}; + +struct fuse_bmap_in { +	__u64	block; +	__u32	blocksize; +	__u32	padding; +}; + +struct fuse_bmap_out { +	__u64	block; +}; + +struct fuse_ioctl_in { +	__u64	fh; +	__u32	flags; +	__u32	cmd; +	__u64	arg; +	__u32	in_size; +	__u32	out_size; +}; + +struct fuse_ioctl_out { +	__s32	result; +	__u32	flags; +	__u32	in_iovs; +	__u32	out_iovs; +}; + +struct fuse_poll_in { +	__u64	fh; +	__u64	kh; +	__u32	flags; +	__u32   padding; +}; + +struct fuse_poll_out { +	__u32	revents; +	__u32	padding; +}; + +struct fuse_notify_poll_wakeup_out { +	__u64	kh; +}; + +struct fuse_in_header { +	__u32	len; +	__u32	opcode; +	__u64	unique; +	__u64	nodeid; +	__u32	uid; +	__u32	gid; +	__u32	pid; +	__u32	padding; +}; + +struct fuse_out_header { +	__u32	len; +	__s32	error; +	__u64	unique; +}; + +struct fuse_dirent { +	__u64	ino; +	__u64	off; +	__u32	namelen; +	__u32	type; +	char name[0]; +}; + +#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name) +#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1)) +#define FUSE_DIRENT_SIZE(d) \ +	FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) + +struct fuse_notify_inval_inode_out { +	__u64	ino; +	__s64	off; +	__s64	len; +}; + +struct fuse_notify_inval_entry_out { +	__u64	parent; +	__u32	namelen; +	__u32	padding; +}; + +#endif /* _LINUX_FUSE_H */ diff --git a/contrib/fuse-lib/COPYING.LIB b/contrib/fuse-lib/COPYING.LIB new file mode 100644 index 00000000000..161a3d1d47b --- /dev/null +++ b/contrib/fuse-lib/COPYING.LIB @@ -0,0 +1,482 @@ +		  GNU LIBRARY GENERAL PUBLIC LICENSE +		       Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL.  It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + +			    Preamble + +  The licenses for most software are designed to take away your +freedom to share and change it.  By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + +  This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it.  You can use it for +your libraries, too. + +  When we speak of free software, we are referring to freedom, not +price.  Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +  To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + +  For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you.  You must make sure that they, too, receive or can get the source +code.  If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it.  And you must show them these terms so they know their rights. + +  Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + +  Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library.  If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + +  Finally, any free program is threatened constantly by software +patents.  We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software.  To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + +  Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs.  This +license, the GNU Library General Public License, applies to certain +designated libraries.  This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + +  The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it.  Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program.  However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + +  Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries.  We +concluded that weaker conditions might promote sharing better. + +  However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves.  This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them.  (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.)  The hope is that this +will lead to faster development of free libraries. + +  The precise terms and conditions for copying, distribution and +modification follow.  Pay close attention to the difference between a +"work based on the library" and a "work that uses the library".  The +former contains code derived from the library, while the latter only +works together with the library. + +  Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + +		  GNU LIBRARY GENERAL PUBLIC LICENSE +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +  0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License").  Each licensee is +addressed as "you". + +  A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + +  The "Library", below, refers to any such software library or work +which has been distributed under these terms.  A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language.  (Hereinafter, translation is +included without limitation in the term "modification".) + +  "Source code" for a work means the preferred form of the work for +making modifications to it.  For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + +  Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope.  The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it).  Whether that is true depends on what the Library does +and what the program that uses the Library does. +   +  1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + +  You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + +  2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +    a) The modified work must itself be a software library. + +    b) You must cause the files modified to carry prominent notices +    stating that you changed the files and the date of any change. + +    c) You must cause the whole of the work to be licensed at no +    charge to all third parties under the terms of this License. + +    d) If a facility in the modified Library refers to a function or a +    table of data to be supplied by an application program that uses +    the facility, other than as an argument passed when the facility +    is invoked, then you must make a good faith effort to ensure that, +    in the event an application does not supply such function or +    table, the facility still operates, and performs whatever part of +    its purpose remains meaningful. + +    (For example, a function in a library to compute square roots has +    a purpose that is entirely well-defined independent of the +    application.  Therefore, Subsection 2d requires that any +    application-supplied function or table used by this function must +    be optional: if the application does not supply it, the square +    root function must still compute square roots.) + +These requirements apply to the modified work as a whole.  If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works.  But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +  3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library.  To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License.  (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.)  Do not make any other change in +these notices. + +  Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + +  This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + +  4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + +  If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + +  5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library".  Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + +  However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library".  The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + +  When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library.  The +threshold for this to be true is not precisely defined by law. + +  If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work.  (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + +  Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + +  6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + +  You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License.  You must supply a copy of this License.  If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License.  Also, you must do one +of these things: + +    a) Accompany the work with the complete corresponding +    machine-readable source code for the Library including whatever +    changes were used in the work (which must be distributed under +    Sections 1 and 2 above); and, if the work is an executable linked +    with the Library, with the complete machine-readable "work that +    uses the Library", as object code and/or source code, so that the +    user can modify the Library and then relink to produce a modified +    executable containing the modified Library.  (It is understood +    that the user who changes the contents of definitions files in the +    Library will not necessarily be able to recompile the application +    to use the modified definitions.) + +    b) Accompany the work with a written offer, valid for at +    least three years, to give the same user the materials +    specified in Subsection 6a, above, for a charge no more +    than the cost of performing this distribution. + +    c) If distribution of the work is made by offering access to copy +    from a designated place, offer equivalent access to copy the above +    specified materials from the same place. + +    d) Verify that the user has already received a copy of these +    materials or that you have already sent this user a copy. + +  For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it.  However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + +  It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system.  Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + +  7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + +    a) Accompany the combined library with a copy of the same work +    based on the Library, uncombined with any other library +    facilities.  This must be distributed under the terms of the +    Sections above. + +    b) Give prominent notice with the combined library of the fact +    that part of it is a work based on the Library, and explaining +    where to find the accompanying uncombined form of the same work. + +  8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License.  Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License.  However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + +  9. You are not required to accept this License, since you have not +signed it.  However, nothing else grants you permission to modify or +distribute the Library or its derivative works.  These actions are +prohibited by law if you do not accept this License.  Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +  10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions.  You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +  11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License.  If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all.  For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices.  Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +  12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded.  In such case, this License incorporates the limitation as if +written in the body of this License. + +  13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number.  If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation.  If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + +  14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission.  For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this.  Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + +			    NO WARRANTY + +  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +		     END OF TERMS AND CONDITIONS + +     Appendix: How to Apply These Terms to Your New Libraries + +  If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change.  You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + +  To apply these terms, attach the following notices to the library.  It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + +    <one line to give the library's name and a brief idea of what it does.> +    Copyright (C) <year>  <name of author> + +    This library is free software; you can redistribute it and/or +    modify it under the terms of the GNU Library General Public +    License as published by the Free Software Foundation; either +    version 2 of the License, or (at your option) any later version. + +    This library is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +    Library General Public License for more details. + +    You should have received a copy of the GNU Library General Public +    License along with this library; if not, write to the Free +    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +    MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary.  Here is a sample; alter the names: + +  Yoyodyne, Inc., hereby disclaims all copyright interest in the +  library `Frob' (a library for tweaking knobs) written by James Random Hacker. + +  <signature of Ty Coon>, 1 April 1990 +  Ty Coon, President of Vice + +That's all there is to it! diff --git a/contrib/fuse-lib/misc.c b/contrib/fuse-lib/misc.c new file mode 100644 index 00000000000..877c3880de0 --- /dev/null +++ b/contrib/fuse-lib/misc.c @@ -0,0 +1,51 @@ +/* +  FUSE: Filesystem in Userspace +  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu> + +  This program can be distributed under the terms of the GNU LGPLv2. +  See the file COPYING.LIB +*/ + +#include <stdint.h> +#include <string.h> +#include <limits.h> +#include <fcntl.h> +#include "fuse_kernel.h" +#include "fuse-misc.h" + +unsigned long +calc_timeout_sec (double t) +{ +        if (t > (double) ULONG_MAX) +                return ULONG_MAX; +        else if (t < 0.0) +                return 0; +        else +                return (unsigned long) t; +} + +unsigned int +calc_timeout_nsec (double t) +{ +        double f = t - (double) calc_timeout_sec (t); +        if (f < 0.0) +                return 0; +        else if (f >= 0.999999999) +                return 999999999; +        else +                return (unsigned int) (f * 1.0e9); +} + +void +convert_fuse_file_lock (struct fuse_file_lock *fl, struct flock *flock) +{ +        memset (flock, 0, sizeof (struct flock)); +        flock->l_type = fl->type; +        flock->l_whence = SEEK_SET; +        flock->l_start = fl->start; +        if (fl->end == OFFSET_MAX) +                flock->l_len = 0; +        else +                flock->l_len = fl->end - fl->start + 1; +        flock->l_pid = fl->pid; +} diff --git a/contrib/fuse-lib/mount.c b/contrib/fuse-lib/mount.c new file mode 100644 index 00000000000..c6de43607f3 --- /dev/null +++ b/contrib/fuse-lib/mount.c @@ -0,0 +1,616 @@ +/* +  FUSE: Filesystem in Userspace +  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu> +  Copyright (c) 2009 Z RESEARCH, Inc. <http://www.zresearch.com> + +  This program can be distributed under the terms of the GNU LGPLv2. +  See the file COPYING.LIB. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <limits.h> +#include <fcntl.h> +#include <errno.h> +#include <dirent.h> +#include <mntent.h> +#include <sys/stat.h> +#include <sys/poll.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/wait.h> +#include <sys/mount.h> + +#ifdef FUSE_UTIL +#define MALLOC(size) malloc (size) +#define FREE(ptr) free (ptr) +#define GFFUSE_LOGERR(...) fprintf (stderr, ## __VA_ARGS__) +#else /* FUSE_UTIL */ +#include "glusterfs.h" +#include "logging.h" +#include "common-utils.h" + +#ifdef GF_FUSERMOUNT +#define FUSERMOUNT_PROG FUSERMOUNT_DIR "/fusermount-glusterfs" +#else +#define FUSERMOUNT_PROG "fusermount" +#endif +#define FUSE_COMMFD_ENV "_FUSE_COMMFD" + +#define GFFUSE_LOGERR(...) \ +        gf_log ("glusterfs-fuse", GF_LOG_ERROR, ## __VA_ARGS__) +#endif /* !FUSE_UTIL */ + +/* + * Functions below, until following note, were taken from libfuse + * (http://git.gluster.com/?p=users/csaba/fuse.git;a=commit;h=b988bbf9) + * almost verbatim. What has been changed: + * - style adopted to that of glusterfs + * - s/fprintf/gf_log/ + * - s/free/FREE/, s/malloc/MALLOC/ + * - there are some other minor things + */ + +static int +mtab_needs_update (const char *mnt) +{ +        int res; +        struct stat stbuf; + +        /* If mtab is within new mount, don't touch it */ +        if (strncmp (mnt, _PATH_MOUNTED, strlen (mnt)) == 0 && +            _PATH_MOUNTED[strlen (mnt)] == '/') +                return 0; + +        /* +         * Skip mtab update if /etc/mtab: +         * +         *  - doesn't exist, +         *  - is a symlink, +         *  - is on a read-only filesystem. +         */ +        res = lstat (_PATH_MOUNTED, &stbuf); +        if (res == -1) { +                if (errno == ENOENT) +                        return 0; +        } else { +                if (S_ISLNK (stbuf.st_mode)) +                        return 0; + +                res = access (_PATH_MOUNTED, W_OK); +                if (res == -1 && errno == EROFS) +                        return 0; +        } + +        return 1; +} + +#ifndef FUSE_UTIL +static +#endif +int +fuse_mnt_add_mount (const char *progname, const char *fsname, +                    const char *mnt, const char *type, const char *opts) +{ +        int res; +        int status; +        sigset_t blockmask; +        sigset_t oldmask; + +        if (!mtab_needs_update (mnt)) +                return 0; + +        sigemptyset (&blockmask); +        sigaddset (&blockmask, SIGCHLD); +        res = sigprocmask (SIG_BLOCK, &blockmask, &oldmask); +        if (res == -1) { +                GFFUSE_LOGERR ("%s: sigprocmask: %s", +                               progname, strerror (errno)); +                return -1; +        } + +        res = fork (); +        if (res == -1) { +                GFFUSE_LOGERR ("%s: fork: %s", progname, strerror (errno)); +                goto out_restore; +        } +        if (res == 0) { +                char templ[] = "/tmp/fusermountXXXXXX"; +                char *tmp; + +                sigprocmask (SIG_SETMASK, &oldmask, NULL); +                setuid (geteuid ()); + +                /* +                 * hide in a directory, where mount isn't able to resolve +                 * fsname as a valid path +                 */ +                tmp = mkdtemp (templ); +                if (!tmp) { +                        GFFUSE_LOGERR ("%s: failed to create temporary directory", +                                       progname); +                        exit (1); +                } +                if (chdir (tmp)) { +                        GFFUSE_LOGERR ("%s: failed to chdir to %s: %s", +                                       progname, tmp, strerror (errno)); +                        exit (1); +                } +                rmdir (tmp); +                execl ("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, +                       "-o", opts, fsname, mnt, NULL); +                GFFUSE_LOGERR ("%s: failed to execute /bin/mount: %s", +                               progname, strerror (errno)); +                exit (1); +        } +        res = waitpid (res, &status, 0); +        if (res == -1) +                GFFUSE_LOGERR ("%s: waitpid: %s", progname, strerror (errno)); + +        if (status != 0) +                res = -1; + + out_restore: +        sigprocmask (SIG_SETMASK, &oldmask, NULL); +        return res; +} + +#ifndef FUSE_UTIL +static +#endif +char +*fuse_mnt_resolve_path (const char *progname, const char *orig) +{ +        char buf[PATH_MAX]; +        char *copy; +        char *dst; +        char *end; +        char *lastcomp; +        const char *toresolv; + +        if (!orig[0]) { +                GFFUSE_LOGERR ("%s: invalid mountpoint '%s'", progname, orig); +                return NULL; +        } + +        copy = strdup (orig); +        if (copy == NULL) { +                GFFUSE_LOGERR ("%s: failed to allocate memory", progname); +                return NULL; +        } + +        toresolv = copy; +        lastcomp = NULL; +        for (end = copy + strlen (copy) - 1; end > copy && *end == '/'; end --); +        if (end[0] != '/') { +                char *tmp; +                end[1] = '\0'; +                tmp = strrchr (copy, '/'); +                if (tmp == NULL) { +                        lastcomp = copy; +                        toresolv = "."; +                } else { +                        lastcomp = tmp + 1; +                        if (tmp == copy) +                                toresolv = "/"; +                } +                if (strcmp (lastcomp, ".") == 0 || strcmp (lastcomp, "..") == 0) { +                        lastcomp = NULL; +                        toresolv = copy; +                } +                else if (tmp) +                        tmp[0] = '\0'; +        } +        if (realpath (toresolv, buf) == NULL) { +                GFFUSE_LOGERR ("%s: bad mount point %s: %s", progname, orig, +                               strerror (errno)); +                FREE (copy); +                return NULL; +        } +        if (lastcomp == NULL) +                dst = strdup (buf); +        else { +                dst = (char *) MALLOC (strlen (buf) + 1 + strlen (lastcomp) + 1); +                if (dst) { +                        unsigned buflen = strlen (buf); +                        if (buflen && buf[buflen-1] == '/') +                                sprintf (dst, "%s%s", buf, lastcomp); +                        else +                                sprintf (dst, "%s/%s", buf, lastcomp); +                } +        } +        FREE (copy); +        if (dst == NULL) +                GFFUSE_LOGERR ("%s: failed to allocate memory", progname); +        return dst; +} + +#ifndef FUSE_UTIL +/* return value: + * >= 0         => fd + * -1         => error + */ +static int +receive_fd (int fd) +{ +        struct msghdr msg; +        struct iovec iov; +        char buf[1]; +        int rv; +        size_t ccmsg[CMSG_SPACE (sizeof (int)) / sizeof (size_t)]; +        struct cmsghdr *cmsg; + +        iov.iov_base = buf; +        iov.iov_len = 1; + +        msg.msg_name = 0; +        msg.msg_namelen = 0; +        msg.msg_iov = &iov; +        msg.msg_iovlen = 1; +        /* old BSD implementations should use msg_accrights instead of +         * msg_control; the interface is different. */ +        msg.msg_control = ccmsg; +        msg.msg_controllen = sizeof (ccmsg); + +        while (((rv = recvmsg (fd, &msg, 0)) == -1) && errno == EINTR); +        if (rv == -1) { +                GFFUSE_LOGERR ("recvmsg failed: %s", strerror (errno)); +                return -1; +        } +        if (!rv) { +                /* EOF */ +                return -1; +        } + +        cmsg = CMSG_FIRSTHDR (&msg); +        if (!cmsg->cmsg_type == SCM_RIGHTS) { +                GFFUSE_LOGERR ("got control message of unknown type %d", +                               cmsg->cmsg_type); +                return -1; +        } +        return *(int*)CMSG_DATA (cmsg); +} + +static int +fuse_mount_fusermount (const char *mountpoint, const char *opts) +{ +        int fds[2], pid; +        int res; +        int rv; + +        res = socketpair (PF_UNIX, SOCK_STREAM, 0, fds); +        if (res == -1) { +                GFFUSE_LOGERR ("socketpair() failed: %s", strerror (errno)); +                return -1; +        } + +        pid = fork (); +        if (pid == -1) { +                GFFUSE_LOGERR ("fork() failed: %s", strerror (errno)); +                close (fds[0]); +                close (fds[1]); +                return -1; +        } + +        if (pid == 0) { +                char env[10]; +                const char *argv[32]; +                int a = 0; + +                argv[a++] = FUSERMOUNT_PROG; +                if (opts) { +                        argv[a++] = "-o"; +                        argv[a++] = opts; +                } +                argv[a++] = "--"; +                argv[a++] = mountpoint; +                argv[a++] = NULL; + +                close (fds[1]); +                fcntl (fds[0], F_SETFD, 0); +                snprintf (env, sizeof (env), "%i", fds[0]); +                setenv (FUSE_COMMFD_ENV, env, 1); +                execvp (FUSERMOUNT_PROG, (char **)argv); +                GFFUSE_LOGERR ("failed to exec fusermount: %s", +                               strerror (errno)); +                _exit (1); +        } + +        close (fds[0]); +        rv = receive_fd (fds[1]); +        close (fds[1]); +        waitpid (pid, NULL, 0); /* bury zombie */ + +        return rv; +} +#endif + +#ifndef FUSE_UTIL +static +#endif +int +fuse_mnt_umount (const char *progname, const char *mnt, int lazy) +{ +        int res; +        int status; +        sigset_t blockmask; +        sigset_t oldmask; + +        if (!mtab_needs_update (mnt)) { +                res = umount2 (mnt, lazy ? 2 : 0); +                if (res == -1) +                        GFFUSE_LOGERR ("%s: failed to unmount %s: %s", +                                       progname, mnt, strerror (errno)); +                return res; +        } + +        sigemptyset (&blockmask); +        sigaddset (&blockmask, SIGCHLD); +        res = sigprocmask (SIG_BLOCK, &blockmask, &oldmask); +        if (res == -1) { +                GFFUSE_LOGERR ("%s: sigprocmask: %s", progname, +                               strerror (errno)); +                return -1; +        } + +        res = fork (); +        if (res == -1) { +                GFFUSE_LOGERR ("%s: fork: %s", progname, strerror (errno)); +                goto out_restore; +        } +        if (res == 0) { +                sigprocmask (SIG_SETMASK, &oldmask, NULL); +                setuid (geteuid ()); +                execl ("/bin/umount", "/bin/umount", "-i", mnt, +                      lazy ? "-l" : NULL, NULL); +                GFFUSE_LOGERR ("%s: failed to execute /bin/umount: %s", +                               progname, strerror (errno)); +                exit (1); +        } +        res = waitpid (res, &status, 0); +        if (res == -1) +                GFFUSE_LOGERR ("%s: waitpid: %s", progname, strerror (errno)); + +        if (status != 0) +                res = -1; + + out_restore: +        sigprocmask (SIG_SETMASK, &oldmask, NULL); +        return res; +} + +#ifdef FUSE_UTIL +int +fuse_mnt_check_empty (const char *progname, const char *mnt, +                      mode_t rootmode, off_t rootsize) +{ +        int isempty = 1; + +        if (S_ISDIR (rootmode)) { +                struct dirent *ent; +                DIR *dp = opendir (mnt); +                if (dp == NULL) { +                        fprintf (stderr, +                                 "%s: failed to open mountpoint for reading: %s\n", +                                 progname, strerror (errno)); +                        return -1; +                } +                while ((ent = readdir (dp)) != NULL) { +                        if (strcmp (ent->d_name, ".") != 0 && +                            strcmp (ent->d_name, "..") != 0) { +                                isempty = 0; +                                break; +                        } +                } +                closedir (dp); +        } else if (rootsize) +                isempty = 0; + +        if (!isempty) { +                fprintf (stderr, "%s: mountpoint is not empty\n", progname); +                fprintf (stderr, "%s: if you are sure this is safe, " +                         "use the 'nonempty' mount option\n", progname); +                return -1; +        } +        return 0; +} + +int +fuse_mnt_check_fuseblk (void) +{ +        char buf[256]; +        FILE *f = fopen ("/proc/filesystems", "r"); +        if (!f) +                return 1; + +        while (fgets (buf, sizeof (buf), f)) +                if (strstr (buf, "fuseblk\n")) { +                        fclose (f); +                        return 1; +                } + +        fclose (f); +        return 0; +} +#endif + +#ifndef FUSE_UTIL +void +gf_fuse_unmount (const char *mountpoint, int fd) +{ +        int res; +        int pid; + +        if (!mountpoint) +                return; + +        if (fd != -1) { +                struct pollfd pfd; + +                pfd.fd = fd; +                pfd.events = 0; +                res = poll (&pfd, 1, 0); +                /* If file poll returns POLLERR on the device file descriptor, +                   then the filesystem is already unmounted */ +                if (res == 1 && (pfd.revents & POLLERR)) +                        return; + +                /* Need to close file descriptor, otherwise synchronous umount +                   would recurse into filesystem, and deadlock */ +                close (fd); +        } + +        if (geteuid () == 0) { +                fuse_mnt_umount ("fuse", mountpoint, 1); +                return; +        } + +        res = umount2 (mountpoint, 2); +        if (res == 0) +                return; + +        pid = fork (); +        if (pid == -1) +                return; + +        if (pid == 0) { +                const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z", +                                       "--", mountpoint, NULL }; + +                execvp (FUSERMOUNT_PROG, (char **)argv); +                _exit (1); +        } +        waitpid (pid, NULL, 0); +} +#endif + +/* + * Functions below are loosely modelled after similar functions of libfuse + */ + +#ifndef FUSE_UTIL +static int +fuse_mount_sys (const char *mountpoint, char *fsname, char *mnt_param) +{ +        int fd = -1, ret = -1; +        unsigned mounted = 0; +        char *mnt_param_mnt = NULL; +        char *fstype = "fuse.glusterfs"; +        char *source = fsname; + +        fd = open ("/dev/fuse", O_RDWR); +        if (fd == -1) { +                GFFUSE_LOGERR ("cannot open /dev/fuse (%s)", strerror (errno)); + +                return -1; +        } + +        ret = asprintf (&mnt_param_mnt, +                        "%s,fd=%i,rootmode=%o,user_id=%i,group_id=%i", +                        mnt_param, fd, S_IFDIR, getuid (), getgid ()); +        if (ret == -1) { +                GFFUSE_LOGERR ("Out of memory"); + +                goto out; +        } +        ret = mount (source, mountpoint, fstype, 0, +                     mnt_param_mnt); +        if (ret == -1 && errno == ENODEV) { +                /* fs subtype support was added by 79c0b2df aka +                   v2.6.21-3159-g79c0b2d. Probably we have an +                   older kernel ... */ +                fstype = "fuse"; +                ret = asprintf (&source, "glusterfs#%s", fsname); +                if (ret == -1) { +                        GFFUSE_LOGERR ("Out of memory"); + +                        goto out; +                } +                ret = mount (source, mountpoint, fstype, 0, +                             mnt_param_mnt); +        } +        if (ret == -1) +                goto out; +        else +                mounted = 1; + +        if (geteuid () == 0) { +                char *newmnt = fuse_mnt_resolve_path ("fuse", mountpoint); + +                if (!newmnt) { +                        ret = -1; + +                        goto out; +                } + +                ret = fuse_mnt_add_mount ("fuse", source, newmnt, fstype, +                                          mnt_param); +                FREE (newmnt); +                if (ret == -1) { +                        GFFUSE_LOGERR ("failed to add mtab entry"); + +                        goto out; +                } +        } + + out: +        if (ret == -1) { +                if (mounted) +                        umount2 (mountpoint, 2); /* lazy umount */ +                close (fd); +                fd = -1; +        } +        FREE (mnt_param_mnt); +        if (source != fsname) +                FREE (source); +        return fd; +} + +int +gf_fuse_mount (const char *mountpoint, char *fsname, char *mnt_param) +{ +        int fd = -1, rv = -1; +        char *fm_mnt_params = NULL, *p = NULL; + +        fd = fuse_mount_sys (mountpoint, fsname, mnt_param); +        if (fd == -1) { +                gf_log ("glusterfs-fuse", GF_LOG_NORMAL, +                        "direct mount failed (%s), " +                        "retry to mount via fusermount", +                        strerror (errno)); + +                rv = asprintf (&fm_mnt_params, +                               "%s,fsname=%s,nonempty,subtype=glusterfs", +                               mnt_param, fsname); + +                if (rv == -1) { +                        GFFUSE_LOGERR ("Out of memory"); + +                        return -1; +                } + +                fd = fuse_mount_fusermount (mountpoint, fm_mnt_params); +                if (fd == -1) { +                        p = fm_mnt_params + strlen (fm_mnt_params); +                        while (*--p != ','); +                        *p = '\0'; + +                        fd = fuse_mount_fusermount (mountpoint, fm_mnt_params); +                } + +                FREE (fm_mnt_params); + +                if (fd == -1) +                       GFFUSE_LOGERR ("mount failed"); +        } + +        return fd; +} +#endif diff --git a/contrib/fuse-util/COPYING b/contrib/fuse-util/COPYING new file mode 100644 index 00000000000..d60c31a97a5 --- /dev/null +++ b/contrib/fuse-util/COPYING @@ -0,0 +1,340 @@ +		    GNU GENERAL PUBLIC LICENSE +		       Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. +     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +			    Preamble + +  The licenses for most software are designed to take away your +freedom to share and change it.  By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users.  This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it.  (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.)  You can apply it to +your programs, too. + +  When we speak of free software, we are referring to freedom, not +price.  Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +  To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +  For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have.  You must make sure that they, too, receive or can get the +source code.  And you must show them these terms so they know their +rights. + +  We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +  Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software.  If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +  Finally, any free program is threatened constantly by software +patents.  We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary.  To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + +  The precise terms and conditions for copying, distribution and +modification follow. + +		    GNU GENERAL PUBLIC LICENSE +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +  0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License.  The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language.  (Hereinafter, translation is included without limitation in +the term "modification".)  Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope.  The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +  1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +  2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +    a) You must cause the modified files to carry prominent notices +    stating that you changed the files and the date of any change. + +    b) You must cause any work that you distribute or publish, that in +    whole or in part contains or is derived from the Program or any +    part thereof, to be licensed as a whole at no charge to all third +    parties under the terms of this License. + +    c) If the modified program normally reads commands interactively +    when run, you must cause it, when started running for such +    interactive use in the most ordinary way, to print or display an +    announcement including an appropriate copyright notice and a +    notice that there is no warranty (or else, saying that you provide +    a warranty) and that users may redistribute the program under +    these conditions, and telling the user how to view a copy of this +    License.  (Exception: if the Program itself is interactive but +    does not normally print such an announcement, your work based on +    the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole.  If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works.  But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +  3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + +    a) Accompany it with the complete corresponding machine-readable +    source code, which must be distributed under the terms of Sections +    1 and 2 above on a medium customarily used for software interchange; or, + +    b) Accompany it with a written offer, valid for at least three +    years, to give any third party, for a charge no more than your +    cost of physically performing source distribution, a complete +    machine-readable copy of the corresponding source code, to be +    distributed under the terms of Sections 1 and 2 above on a medium +    customarily used for software interchange; or, + +    c) Accompany it with the information you received as to the offer +    to distribute corresponding source code.  (This alternative is +    allowed only for noncommercial distribution and only if you +    received the program in object code or executable form with such +    an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it.  For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable.  However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +  4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License.  Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + +  5. You are not required to accept this License, since you have not +signed it.  However, nothing else grants you permission to modify or +distribute the Program or its derivative works.  These actions are +prohibited by law if you do not accept this License.  Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +  6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions.  You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +  7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License.  If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all.  For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices.  Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +  8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded.  In such case, this License incorporates +the limitation as if written in the body of this License. + +  9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time.  Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number.  If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation.  If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + +  10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission.  For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this.  Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + +			    NO WARRANTY + +  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +		     END OF TERMS AND CONDITIONS + +	    How to Apply These Terms to Your New Programs + +  If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +  To do so, attach the following notices to the program.  It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + +    <one line to give the program's name and a brief idea of what it does.> +    Copyright (C) <year>  <name of author> + +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 2 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + +    Gnomovision version 69, Copyright (C) year  name of author +    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. +    This is free software, and you are welcome to redistribute it +    under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License.  Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary.  Here is a sample; alter the names: + +  Yoyodyne, Inc., hereby disclaims all copyright interest in the program +  `Gnomovision' (which makes passes at compilers) written by James Hacker. + +  <signature of Ty Coon>, 1 April 1989 +  Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs.  If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library.  If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/fuse-util/Makefile.am b/contrib/fuse-util/Makefile.am new file mode 100644 index 00000000000..06b6cb6da72 --- /dev/null +++ b/contrib/fuse-util/Makefile.am @@ -0,0 +1,12 @@ +bin_PROGRAMS = fusermount-glusterfs + +fusermount_glusterfs_SOURCES = fusermount.c $(CONTRIBDIR)/fuse-lib/mount.c +noinst_HEADERS = mount_util.h + +AM_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -DFUSE_UTIL $(GF_CFLAGS) + +install-exec-hook: +	chown root $(DESTDIR)$(bindir)/fusermount-glusterfs +	chmod u+s $(DESTDIR)$(bindir)/fusermount-glusterfs + +CLEANFILES = diff --git a/contrib/fuse-util/fusermount.c b/contrib/fuse-util/fusermount.c new file mode 100644 index 00000000000..c3ecc86cc44 --- /dev/null +++ b/contrib/fuse-util/fusermount.c @@ -0,0 +1,965 @@ +/* +  FUSE: Filesystem in Userspace +  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu> + +  This program can be distributed under the terms of the GNU GPL. +  See the file COPYING. +*/ +/* This program does the mounting and unmounting of FUSE filesystems */ + +#include <config.h> + +#include "mount_util.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <getopt.h> +#include <errno.h> +#include <fcntl.h> +#include <pwd.h> +#include <mntent.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <sys/mount.h> +#include <sys/fsuid.h> +#include <sys/socket.h> +#include <sys/utsname.h> + +#define FUSE_COMMFD_ENV		"_FUSE_COMMFD" + +#define FUSE_DEV_OLD "/proc/fs/fuse/dev" +#define FUSE_DEV_NEW "/dev/fuse" +#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version" +#define FUSE_CONF "/etc/fuse.conf" + +#ifndef MS_DIRSYNC +#define MS_DIRSYNC 128 +#endif + +static const char *progname; + +static int user_allow_other = 0; +static int mount_max = 1000; + +static const char *get_user_name(void) +{ +	struct passwd *pw = getpwuid(getuid()); +	if (pw != NULL && pw->pw_name != NULL) +		return pw->pw_name; +	else { +		fprintf(stderr, "%s: could not determine username\n", progname); +		return NULL; +	} +} + +static uid_t oldfsuid; +static gid_t oldfsgid; + +static void drop_privs(void) +{ +	if (getuid() != 0) { +		oldfsuid = setfsuid(getuid()); +		oldfsgid = setfsgid(getgid()); +	} +} + +static void restore_privs(void) +{ +	if (getuid() != 0) { +		setfsuid(oldfsuid); +		setfsgid(oldfsgid); +	} +} + +#ifndef IGNORE_MTAB +static int add_mount(const char *source, const char *mnt, const char *type, +		     const char *opts) +{ +	return fuse_mnt_add_mount(progname, source, mnt, type, opts); +} + +static int unmount_fuse(const char *mnt, int quiet, int lazy) +{ +	if (getuid() != 0) { +		struct mntent *entp; +		FILE *fp; +		const char *user = NULL; +		char uidstr[32]; +		unsigned uidlen = 0; +		int found; +		const char *mtab = _PATH_MOUNTED; + +		user = get_user_name(); +		if (user == NULL) +			return -1; + +		fp = setmntent(mtab, "r"); +		if (fp == NULL) { +			fprintf(stderr, +				"%s: failed to open %s: %s\n", progname, mtab, +				strerror(errno)); +			return -1; +		} + +		uidlen = sprintf(uidstr, "%u", getuid()); + +		found = 0; +		while ((entp = getmntent(fp)) != NULL) { +			if (!found && strcmp(entp->mnt_dir, mnt) == 0 && +			    (strcmp(entp->mnt_type, "fuse") == 0 || +			     strcmp(entp->mnt_type, "fuseblk") == 0 || +			     strncmp(entp->mnt_type, "fuse.", 5) == 0 || +			     strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) { +				char *p = strstr(entp->mnt_opts, "user="); +				if (p && +				    (p == entp->mnt_opts || *(p-1) == ',') && +				    strcmp(p + 5, user) == 0) { +					found = 1; +					break; +				} +				/* /etc/mtab is a link pointing to +				   /proc/mounts: */ +				else if ((p = +					  strstr(entp->mnt_opts, "user_id=")) && +					 (p == entp->mnt_opts || +					  *(p-1) == ',') && +					 strncmp(p + 8, uidstr, uidlen) == 0 && +					 (*(p+8+uidlen) == ',' || +					  *(p+8+uidlen) == '\0')) { +					found = 1; +					break; +				} +			} +		} +		endmntent(fp); + +		if (!found) { +			if (!quiet) +				fprintf(stderr, +					"%s: entry for %s not found in %s\n", +					progname, mnt, mtab); +			return -1; +		} +	} + +	return fuse_mnt_umount(progname, mnt, lazy); +} + +static int count_fuse_fs(void) +{ +	struct mntent *entp; +	int count = 0; +	const char *mtab = _PATH_MOUNTED; +	FILE *fp = setmntent(mtab, "r"); +	if (fp == NULL) { +		fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, +			strerror(errno)); +		return -1; +	} +	while ((entp = getmntent(fp)) != NULL) { +		if (strcmp(entp->mnt_type, "fuse") == 0 || +		    strncmp(entp->mnt_type, "fuse.", 5) == 0) +			count ++; +	} +	endmntent(fp); +	return count; +} + + +#else /* IGNORE_MTAB */ +static int count_fuse_fs() +{ +	return 0; +} + +static int add_mount(const char *source, const char *mnt, const char *type, +		     const char *opts) +{ +	(void) source; +	(void) mnt; +	(void) type; +	(void) opts; +	return 0; +} + +static int unmount_fuse(const char *mnt, int quiet, int lazy) +{ +	return fuse_mnt_umount(progname, mnt, lazy); +} +#endif /* IGNORE_MTAB */ + +static void strip_line(char *line) +{ +	char *s = strchr(line, '#'); +	if (s != NULL) +		s[0] = '\0'; +	for (s = line + strlen(line) - 1; +	     s >= line && isspace((unsigned char) *s); s--); +	s[1] = '\0'; +	for (s = line; isspace((unsigned char) *s); s++); +	if (s != line) +		memmove(line, s, strlen(s)+1); +} + +static void parse_line(char *line, int linenum) +{ +	int tmp; +	if (strcmp(line, "user_allow_other") == 0) +		user_allow_other = 1; +	else if (sscanf(line, "mount_max = %i", &tmp) == 1) +		mount_max = tmp; +	else if(line[0]) +		fprintf(stderr, +			"%s: unknown parameter in %s at line %i: '%s'\n", +			progname, FUSE_CONF, linenum, line); +} + +static void read_conf(void) +{ +	FILE *fp = fopen(FUSE_CONF, "r"); +	if (fp != NULL) { +		int linenum = 1; +		char line[256]; +		int isnewline = 1; +		while (fgets(line, sizeof(line), fp) != NULL) { +			if (isnewline) { +				if (line[strlen(line)-1] == '\n') { +					strip_line(line); +					parse_line(line, linenum); +				} else { +					isnewline = 0; +				} +			} else if(line[strlen(line)-1] == '\n') { +				fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum); + +				isnewline = 1; +			} +			if (isnewline) +				linenum ++; +		} +		if (!isnewline) { +			fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF); + +		} +		fclose(fp); +	} else if (errno != ENOENT) { +		fprintf(stderr, "%s: failed to open %s: %s\n", +			progname, FUSE_CONF, strerror(errno)); +	} +} + +static int begins_with(const char *s, const char *beg) +{ +	if (strncmp(s, beg, strlen(beg)) == 0) +		return 1; +	else +		return 0; +} + +struct mount_flags { +	const char *opt; +	unsigned long flag; +	int on; +	int safe; +}; + +static struct mount_flags mount_flags[] = { +	{"rw",	    MS_RDONLY,	    0, 1}, +	{"ro",	    MS_RDONLY,	    1, 1}, +	{"suid",    MS_NOSUID,	    0, 0}, +	{"nosuid",  MS_NOSUID,	    1, 1}, +	{"dev",	    MS_NODEV,	    0, 0}, +	{"nodev",   MS_NODEV,	    1, 1}, +	{"exec",    MS_NOEXEC,	    0, 1}, +	{"noexec",  MS_NOEXEC,	    1, 1}, +	{"async",   MS_SYNCHRONOUS, 0, 1}, +	{"sync",    MS_SYNCHRONOUS, 1, 1}, +	{"atime",   MS_NOATIME,	    0, 1}, +	{"noatime", MS_NOATIME,	    1, 1}, +	{"dirsync", MS_DIRSYNC,	    1, 1}, +	{NULL,	    0,		    0, 0} +}; + +static int find_mount_flag(const char *s, unsigned len, int *on, int *flag) +{ +	int i; + +	for (i = 0; mount_flags[i].opt != NULL; i++) { +		const char *opt = mount_flags[i].opt; +		if (strlen(opt) == len && strncmp(opt, s, len) == 0) { +			*on = mount_flags[i].on; +			*flag = mount_flags[i].flag; +			if (!mount_flags[i].safe && getuid() != 0) { +				*flag = 0; +				fprintf(stderr, +					"%s: unsafe option %s ignored\n", +					progname, opt); +			} +			return 1; +		} +	} +	return 0; +} + +static int add_option(char **optsp, const char *opt, unsigned expand) +{ +	char *newopts; +	if (*optsp == NULL) +		newopts = strdup(opt); +	else { +		unsigned oldsize = strlen(*optsp); +		unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1; +		newopts = (char *) realloc(*optsp, newsize); +		if (newopts) +			sprintf(newopts + oldsize, ",%s", opt); +	} +	if (newopts == NULL) { +		fprintf(stderr, "%s: failed to allocate memory\n", progname); +		return -1; +	} +	*optsp = newopts; +	return 0; +} + +static int get_mnt_opts(int flags, char *opts, char **mnt_optsp) +{ +	int i; +	int l; + +	if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1) +		return -1; + +	for (i = 0; mount_flags[i].opt != NULL; i++) { +		if (mount_flags[i].on && (flags & mount_flags[i].flag) && +		    add_option(mnt_optsp, mount_flags[i].opt, 0) == -1) +			return -1; +	} + +	if (add_option(mnt_optsp, opts, 0) == -1) +		return -1; +	/* remove comma from end of opts*/ +	l = strlen(*mnt_optsp); +	if ((*mnt_optsp)[l-1] == ',') +		(*mnt_optsp)[l-1] = '\0'; +	if (getuid() != 0) { +		const char *user = get_user_name(); +		if (user == NULL) +			return -1; + +		if (add_option(mnt_optsp, "user=", strlen(user)) == -1) +			return -1; +		strcat(*mnt_optsp, user); +	} +	return 0; +} + +static int opt_eq(const char *s, unsigned len, const char *opt) +{ +	if(strlen(opt) == len && strncmp(s, opt, len) == 0) +		return 1; +	else +		return 0; +} + +static int get_string_opt(const char *s, unsigned len, const char *opt, +			  char **val) +{ +	unsigned opt_len = strlen(opt); + +	if (*val) +		free(*val); +	*val = (char *) malloc(len - opt_len + 1); +	if (!*val) { +		fprintf(stderr, "%s: failed to allocate memory\n", progname); +		return 0; +	} + +	memcpy(*val, s + opt_len, len - opt_len); +	(*val)[len - opt_len] = '\0'; +	return 1; +} + +static int do_mount(const char *mnt, char **typep, mode_t rootmode, +		    int fd, const char *opts, const char *dev, char **sourcep, +		    char **mnt_optsp, off_t rootsize) +{ +	int res; +	int flags = MS_NOSUID | MS_NODEV; +	char *optbuf; +	char *mnt_opts = NULL; +	const char *s; +	char *d; +	char *fsname = NULL; +	char *subtype = NULL; +	char *source = NULL; +	char *type = NULL; +	int check_empty = 1; +	int blkdev = 0; + +	optbuf = (char *) malloc(strlen(opts) + 128); +	if (!optbuf) { +		fprintf(stderr, "%s: failed to allocate memory\n", progname); +		return -1; +	} + +	for (s = opts, d = optbuf; *s;) { +		unsigned len; +		const char *fsname_str = "fsname="; +		const char *subtype_str = "subtype="; +		for (len = 0; s[len] && s[len] != ','; len++); +		if (begins_with(s, fsname_str)) { +			if (!get_string_opt(s, len, fsname_str, &fsname)) +				goto err; +		} else if (begins_with(s, subtype_str)) { +			if (!get_string_opt(s, len, subtype_str, &subtype)) +				goto err; +		} else if (opt_eq(s, len, "blkdev")) { +			if (getuid() != 0) { +				fprintf(stderr, +					"%s: option blkdev is privileged\n", +					progname); +				goto err; +			} +			blkdev = 1; +		} else if (opt_eq(s, len, "nonempty")) { +			check_empty = 0; +		} else if (!begins_with(s, "fd=") && +			   !begins_with(s, "rootmode=") && +			   !begins_with(s, "user_id=") && +			   !begins_with(s, "group_id=")) { +			int on; +			int flag; +			int skip_option = 0; +			if (opt_eq(s, len, "large_read")) { +				struct utsname utsname; +				unsigned kmaj, kmin; +				res = uname(&utsname); +				if (res == 0 && +				    sscanf(utsname.release, "%u.%u", +					   &kmaj, &kmin) == 2 && +				    (kmaj > 2 || (kmaj == 2 && kmin > 4))) { +					fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin); +					skip_option = 1; +				} +			} +			if (getuid() != 0 && !user_allow_other && +			    (opt_eq(s, len, "allow_other") || +			     opt_eq(s, len, "allow_root"))) { +				fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s); +				goto err; +			} +			if (!skip_option) { +				if (find_mount_flag(s, len, &on, &flag)) { +					if (on) +						flags |= flag; +					else +						flags  &= ~flag; +				} else { +					memcpy(d, s, len); +					d += len; +					*d++ = ','; +				} +			} +		} +		s += len; +		if (*s) +			s++; +	} +	*d = '\0'; +	res = get_mnt_opts(flags, optbuf, &mnt_opts); +	if (res == -1) +		goto err; + +	sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i", +		fd, rootmode, getuid(), getgid()); + +	if (check_empty && +	    fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1) +		goto err; + +	source = malloc((fsname ? strlen(fsname) : 0) + +			(subtype ? strlen(subtype) : 0) + strlen(dev) + 32); + +	type = malloc((subtype ? strlen(subtype) : 0) + 32); +	if (!type || !source) { +		fprintf(stderr, "%s: failed to allocate memory\n", progname); +		goto err; +	} + +	if (subtype) +		sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype); +	else +		strcpy(type, blkdev ? "fuseblk" : "fuse"); + +	if (fsname) +		strcpy(source, fsname); +	else +		strcpy(source, subtype ? subtype : dev); + +	res = mount(source, mnt, type, flags, optbuf); +	if (res == -1 && errno == ENODEV && subtype) { +		/* Probably missing subtype support */ +		strcpy(type, blkdev ? "fuseblk" : "fuse"); +		if (fsname) { +			if (!blkdev) +				sprintf(source, "%s#%s", subtype, fsname); +		} else { +			strcpy(source, type); +		} + +		res = mount(source, mnt, type, flags, optbuf); +	} +	if (res == -1 && errno == EINVAL) { +		/* It could be an old version not supporting group_id */ +		sprintf(d, "fd=%i,rootmode=%o,user_id=%i", +			fd, rootmode, getuid()); +		res = mount(source, mnt, type, flags, optbuf); +	} +	if (res == -1) { +		int errno_save = errno; +		if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) +			fprintf(stderr, "%s: 'fuseblk' support missing\n", +				progname); +		else +			fprintf(stderr, "%s: mount failed: %s\n", progname, +				strerror(errno_save)); +		goto err; +	} else { +		*sourcep = source; +		*typep = type; +		*mnt_optsp = mnt_opts; +	} +	free(fsname); +	free(optbuf); + +	return res; + +err: +	free(fsname); +	free(subtype); +	free(source); +	free(type); +	free(mnt_opts); +	free(optbuf); +	return -1; +} + +static int check_version(const char *dev) +{ +	int res; +	int majorver; +	int minorver; +	const char *version_file; +	FILE *vf; + +	if (strcmp(dev, FUSE_DEV_OLD) != 0) +		return 0; + +	version_file = FUSE_VERSION_FILE_OLD; +	vf = fopen(version_file, "r"); +	if (vf == NULL) { +		fprintf(stderr, "%s: kernel interface too old\n", progname); +		return -1; +	} +	res = fscanf(vf, "%i.%i", &majorver, &minorver); +	fclose(vf); +	if (res != 2) { +		fprintf(stderr, "%s: error reading %s\n", progname, +			version_file); +		return -1; +	} +	if (majorver < 3) { +		fprintf(stderr, "%s: kernel interface too old\n", progname); +		return -1; +	} +	return 0; +} + +static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd, +		      int *mountpoint_fd) +{ +	int res; +	const char *mnt = *mntp; +	const char *origmnt = mnt; + +	res = lstat(mnt, stbuf); +	if (res == -1) { +		fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", +			progname, mnt, strerror(errno)); +		return -1; +	} + +	/* No permission checking is done for root */ +	if (getuid() == 0) +		return 0; + +	if (S_ISDIR(stbuf->st_mode)) { +		*currdir_fd = open(".", O_RDONLY); +		if (*currdir_fd == -1) { +			fprintf(stderr, +				"%s: failed to open current directory: %s\n", +				progname, strerror(errno)); +			return -1; +		} +		res = chdir(mnt); +		if (res == -1) { +			fprintf(stderr, +				"%s: failed to chdir to mountpoint: %s\n", +				progname, strerror(errno)); +			return -1; +		} +		mnt = *mntp = "."; +		res = lstat(mnt, stbuf); +		if (res == -1) { +			fprintf(stderr, +				"%s: failed to access mountpoint %s: %s\n", +				progname, origmnt, strerror(errno)); +			return -1; +		} + +		if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) { +			fprintf(stderr, "%s: mountpoint %s not owned by user\n", +				progname, origmnt); +			return -1; +		} + +		res = access(mnt, W_OK); +		if (res == -1) { +			fprintf(stderr, "%s: user has no write access to mountpoint %s\n", +				progname, origmnt); +			return -1; +		} +	} else if (S_ISREG(stbuf->st_mode)) { +		static char procfile[256]; +		*mountpoint_fd = open(mnt, O_WRONLY); +		if (*mountpoint_fd == -1) { +			fprintf(stderr, "%s: failed to open %s: %s\n", +				progname, mnt, strerror(errno)); +			return -1; +		} +		res = fstat(*mountpoint_fd, stbuf); +		if (res == -1) { +			fprintf(stderr, +				"%s: failed to access mountpoint %s: %s\n", +				progname, mnt, strerror(errno)); +			return -1; +		} +		if (!S_ISREG(stbuf->st_mode)) { +			fprintf(stderr, +				"%s: mountpoint %s is no longer a regular file\n", +				progname, mnt); +			return -1; +		} + +		sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd); +		*mntp = procfile; +	} else { +		fprintf(stderr, +			"%s: mountpoint %s is not a directory or a regular file\n", +			progname, mnt); +		return -1; +	} + + +	return 0; +} + +static int try_open(const char *dev, char **devp, int silent) +{ +	int fd = open(dev, O_RDWR); +	if (fd != -1) { +		*devp = strdup(dev); +		if (*devp == NULL) { +			fprintf(stderr, "%s: failed to allocate memory\n", +				progname); +			close(fd); +			fd = -1; +		} +	} else if (errno == ENODEV || +		   errno == ENOENT)/* check for ENOENT too, for the udev case */ +		return -2; +	else if (!silent) { +		fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev, +			strerror(errno)); +	} +	return fd; +} + +static int try_open_fuse_device(char **devp) +{ +	int fd; +	int err; + +	drop_privs(); +	fd = try_open(FUSE_DEV_NEW, devp, 0); +	restore_privs(); +	if (fd >= 0) +		return fd; + +	err = fd; +	fd = try_open(FUSE_DEV_OLD, devp, 1); +	if (fd >= 0) +		return fd; + +	return err; +} + +static int open_fuse_device(char **devp) +{ +	int fd = try_open_fuse_device(devp); +	if (fd >= -1) +		return fd; + +	fprintf(stderr, +		"%s: fuse device not found, try 'modprobe fuse' first\n", +		progname); + +	return -1; +} + + +static int mount_fuse(const char *mnt, const char *opts) +{ +	int res; +	int fd; +	char *dev; +	struct stat stbuf; +	char *type = NULL; +	char *source = NULL; +	char *mnt_opts = NULL; +	const char *real_mnt = mnt; +	int currdir_fd = -1; +	int mountpoint_fd = -1; + +	fd = open_fuse_device(&dev); +	if (fd == -1) +		return -1; + +	drop_privs(); +	read_conf(); + +	if (getuid() != 0 && mount_max != -1) { +		int mount_count = count_fuse_fs(); +		if (mount_count >= mount_max) { +			fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname); +			close(fd); +			return -1; +		} +	} + +	res = check_version(dev); +	if (res != -1) { +		res = check_perm(&real_mnt, &stbuf, &currdir_fd, +				 &mountpoint_fd); +		restore_privs(); +		if (res != -1) +			res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, +				       fd, opts, dev, &source, &mnt_opts, +				       stbuf.st_size); +	} else +		restore_privs(); + +	if (currdir_fd != -1) { +		fchdir(currdir_fd); +		close(currdir_fd); +	} +	if (mountpoint_fd != -1) +		close(mountpoint_fd); + +	if (res == -1) { +		close(fd); +		return -1; +	} + +	if (geteuid() == 0) { +		res = add_mount(source, mnt, type, mnt_opts); +		if (res == -1) { +			umount2(mnt, 2); /* lazy umount */ +			close(fd); +			return -1; +		} +	} + +	free(source); +	free(type); +	free(mnt_opts); +	free(dev); + +	return fd; +} + +static int send_fd(int sock_fd, int fd) +{ +	int retval; +	struct msghdr msg; +	struct cmsghdr *p_cmsg; +	struct iovec vec; +	size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)]; +	int *p_fds; +	char sendchar = 0; + +	msg.msg_control = cmsgbuf; +	msg.msg_controllen = sizeof(cmsgbuf); +	p_cmsg = CMSG_FIRSTHDR(&msg); +	p_cmsg->cmsg_level = SOL_SOCKET; +	p_cmsg->cmsg_type = SCM_RIGHTS; +	p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); +	p_fds = (int *) CMSG_DATA(p_cmsg); +	*p_fds = fd; +	msg.msg_controllen = p_cmsg->cmsg_len; +	msg.msg_name = NULL; +	msg.msg_namelen = 0; +	msg.msg_iov = &vec; +	msg.msg_iovlen = 1; +	msg.msg_flags = 0; +	/* "To pass file descriptors or credentials you need to send/read at +	 * least one byte" (man 7 unix) */ +	vec.iov_base = &sendchar; +	vec.iov_len = sizeof(sendchar); +	while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR); +	if (retval != 1) { +		perror("sending file descriptor"); +		return -1; +	} +	return 0; +} + +static void usage(void) +{ +	fprintf(stderr, +		"%s: [options] mountpoint\n" +		"Options:\n" +		" -h		    print help\n" +		" -V		    print version\n" +		" -o opt[,opt...]   mount options\n" +		" -u		    unmount\n" +		" -q		    quiet\n" +		" -z		    lazy unmount\n", +		progname); +	exit(1); +} + +static void show_version(void) +{ +	printf("fusermount version: %s\n", PACKAGE_VERSION); +	exit(0); +} + +int main(int argc, char *argv[]) +{ +	int ch; +	int fd; +	int res; +	char *origmnt; +	char *mnt; +	static int unmount = 0; +	static int lazy = 0; +	static int quiet = 0; +	char *commfd; +	int cfd; +	const char *opts = ""; + +	static const struct option long_opts[] = { +		{"unmount", no_argument, NULL, 'u'}, +		{"lazy",    no_argument, NULL, 'z'}, +		{"quiet",   no_argument, NULL, 'q'}, +		{"help",    no_argument, NULL, 'h'}, +		{"version", no_argument, NULL, 'V'}, +		{0, 0, 0, 0}}; + +	progname = strdup(argv[0]); +	if (progname == NULL) { +		fprintf(stderr, "%s: failed to allocate memory\n", argv[0]); +		exit(1); +	} + +	while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts, +				 NULL)) != -1) { +		switch (ch) { +		case 'h': +			usage(); +			break; + +		case 'V': +			show_version(); +			break; + +		case 'o': +			opts = optarg; +			break; + +		case 'u': +			unmount = 1; +			break; + +		case 'z': +			lazy = 1; +			break; + +		case 'q': +			quiet = 1; +			break; + +		default: +			exit(1); +		} +	} + +	if (lazy && !unmount) { +		fprintf(stderr, "%s: -z can only be used with -u\n", progname); +		exit(1); +	} + +	if (optind >= argc) { +		fprintf(stderr, "%s: missing mountpoint argument\n", progname); +		exit(1); +	} else if (argc > optind + 1) { +		fprintf(stderr, "%s: extra arguments after the mountpoint\n", +			progname); +		exit(1); +	} + +	origmnt = argv[optind]; + +	drop_privs(); +	mnt = fuse_mnt_resolve_path(progname, origmnt); +	restore_privs(); +	if (mnt == NULL) +		exit(1); + +	umask(033); +	if (unmount) { +		if (geteuid() == 0) +			res = unmount_fuse(mnt, quiet, lazy); +		else { +			res = umount2(mnt, lazy ? 2 : 0); +			if (res == -1 && !quiet) +				fprintf(stderr, +					"%s: failed to unmount %s: %s\n", +					progname, mnt, strerror(errno)); +		} +		if (res == -1) +			exit(1); +		return 0; +	} + +	commfd = getenv(FUSE_COMMFD_ENV); +	if (commfd == NULL) { +		fprintf(stderr, "%s: old style mounting not supported\n", +			progname); +		exit(1); +	} + +	fd = mount_fuse(mnt, opts); +	if (fd == -1) +		exit(1); + +	cfd = atoi(commfd); +	res = send_fd(cfd, fd); +	if (res == -1) +		exit(1); + +	return 0; +} diff --git a/contrib/fuse-util/mount_util.h b/contrib/fuse-util/mount_util.h new file mode 100644 index 00000000000..cf54d9d0d02 --- /dev/null +++ b/contrib/fuse-util/mount_util.h @@ -0,0 +1,17 @@ +/* +  FUSE: Filesystem in Userspace +  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu> + +  This program can be distributed under the terms of the GNU LGPLv2. +  See the file COPYING.LIB. +*/ + +#include <sys/types.h> + +int fuse_mnt_add_mount(const char *progname, const char *fsname, +		       const char *mnt, const char *type, const char *opts); +int fuse_mnt_umount(const char *progname, const char *mnt, int lazy); +char *fuse_mnt_resolve_path(const char *progname, const char *orig); +int fuse_mnt_check_empty(const char *progname, const char *mnt, +			 mode_t rootmode, off_t rootsize); +int fuse_mnt_check_fuseblk(void); diff --git a/doc/user-guide/user-guide.texi b/doc/user-guide/user-guide.texi index 943b446d9d4..800354116a2 100644 --- a/doc/user-guide/user-guide.texi +++ b/doc/user-guide/user-guide.texi @@ -212,16 +212,39 @@ Before installing GlusterFS make sure you have the  following components installed.  @subsection @acronym{FUSE} -You'll need @acronym{FUSE} version 2.6.0 or higher to -use GlusterFS. You can omit installing @acronym{FUSE} if you want to -build @emph{only} the server. Note that you won't be able to mount -a GlusterFS filesystem on a machine that does not have @acronym{FUSE} -installed. +GlusterFS has now built-in support for the @acronym{FUSE} protocol. +You need a kernel with @acronym{FUSE} support to mount GlusterFS. +You do not need the @acronym{FUSE} package (library and utilities), +but be aware of the following issues: -@acronym{FUSE} can be downloaded from: @indicateurl{http://fuse.sourceforge.net/} +@itemize +@item If you want unprivileged users to be able to mount GlusterFS filesystems, +you need a recent version of the @command{fusermount} utility. You already have +it if you have @acronym{FUSE} version 2.7.0 or higher installed; if that's not +the case, one will be compiled along with GlusterFS if you pass +@command{--enable-fusermount} to the @command{configure} script.  @item You +need to ensure @acronym{FUSE} support is configured properly on your system. In +details: +@itemize +@item If your kernel has @acronym{FUSE} as a loadable module, make sure it's +loaded. +@item Create @command{/dev/fuse} (major 10, minor 229) either by means of udev +rules or by hand. +@item Optionally, if you want runtime control over your @acronym{FUSE} mounts, +mount the fusectl auxiliary filesystem: -To get the best performance from GlusterFS, however, it is recommended that you use -our patched version of @acronym{FUSE}. See Patched FUSE for details. +@example +# mount -t fusectl none /sys/fs/fuse/connections +@end example +@end itemize + +The @acronym{FUSE} packages shipped by the various distributions usually take care +about these things, so the easiest way to get the above tasks handled is still +installing the @acronym{FUSE} package(s). +@end itemize + +To get the best performance from GlusterFS,it is recommended that you use +our patched version of the @acronym{FUSE} kernel module. See Patched FUSE for details.  @subsection Patched FUSE @@ -323,6 +346,9 @@ Use poll instead of epoll.  @item --disable-libglusterfsclient  Disable building of libglusterfsclient +@item --enable-fusermount +Build fusermount +  @end table  @end cartouche @@ -483,7 +509,8 @@ Advanced Options         Attribute timeout for inodes in the kernel, in seconds. Defaults to 1 second.  @item  --disable-direct-io-mode -       Disable direct @acronym{I/O} mode in @acronym{FUSE} kernel module. +       Disable direct @acronym{I/O} mode in @acronym{FUSE} kernel module. This is set +       automatically if kernel supports big writes (>= 2.6.26).  @item  -e, --entry-timeout=<n>         Entry timeout for directory entries in the kernel, in seconds.  diff --git a/glusterfsd/src/glusterfsd.c b/glusterfsd/src/glusterfsd.c index 8995613729b..3c9e77822d3 100644 --- a/glusterfsd/src/glusterfsd.c +++ b/glusterfsd/src/glusterfsd.c @@ -140,7 +140,8 @@ static struct argp_option gf_options[] = {   	{0, 0, 0, 0, "Fuse options:"},   	{"disable-direct-io-mode", ARGP_DISABLE_DIRECT_IO_MODE_KEY, 0, 0,  - 	 "Disable direct I/O mode in fuse kernel module"}, + 	 "Disable direct I/O mode in fuse kernel module" +	 " [default if big writes are supported]"},   	{"entry-timeout", ARGP_ENTRY_TIMEOUT_KEY, "SECONDS", 0,    	 "Set entry timeout to SECONDS in fuse kernel module [default: 1]"},   	{"attribute-timeout", ARGP_ATTRIBUTE_TIMEOUT_KEY, "SECONDS", 0,  diff --git a/xlators/mount/fuse/src/Makefile.am b/xlators/mount/fuse/src/Makefile.am index 9d8d45e4f02..a4d1fd76064 100644 --- a/xlators/mount/fuse/src/Makefile.am +++ b/xlators/mount/fuse/src/Makefile.am @@ -1,13 +1,14 @@ - -noinst_HEADERS = fuse-extra.h +noinst_HEADERS = $(CONTRIBDIR)/fuse-include/fuse_kernel.h  xlator_LTLIBRARIES = fuse.la  xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/mount -fuse_la_SOURCES = fuse-bridge.c fuse-extra.c -fuse_la_LDFLAGS = -module -avoidversion -shared -nostartfiles $(GF_FUSE_LDADD)  +fuse_la_SOURCES = fuse-bridge.c $(CONTRIBDIR)/fuse-lib/misc.c \ +	$(CONTRIBDIR)/fuse-lib/mount.c +fuse_la_LDFLAGS = -module -avoidversion -shared -nostartfiles  AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS) -Wall \ -	-I$(top_srcdir)/libglusterfs/src $(GF_CFLAGS) -DFUSE_USE_VERSION=26 +	-I$(top_srcdir)/libglusterfs/src -I$(CONTRIBDIR)/fuse-include \ +	$(GF_CFLAGS) -DFUSERMOUNT_DIR=\"$(bindir)\"  CLEANFILES =  diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index b0ac84ea8de..d20876a3bba 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -28,6 +28,9 @@  #include <stdint.h>  #include <signal.h>  #include <pthread.h> +#include <stddef.h> +#include <dirent.h> +#include <sys/mount.h>  #ifndef _CONFIG_H  #define _CONFIG_H @@ -37,13 +40,13 @@  #include "glusterfs.h"  #include "logging.h"  #include "xlator.h" -#include "glusterfs.h"  #include "defaults.h"  #include "common-utils.h" -#include <fuse/fuse_lowlevel.h> +#include "fuse_kernel.h" +#include "fuse-misc.h" +#include "fuse-mount.h" -#include "fuse-extra.h"  #include "list.h"  #include "dict.h" @@ -57,11 +60,16 @@  #define ZR_DIRECT_IO_OPT        "direct-io-mode"  #define ZR_STRICT_VOLFILE_CHECK "strict-volfile-check" +#define FUSE_712_OP_HIGH (FUSE_POLL + 1) +#define GLUSTERFS_XATTR_LEN_MAX  65536 + +typedef struct fuse_in_header fuse_in_header_t; +typedef void (fuse_handler_t) (xlator_t *this, fuse_in_header_t *finh, +                               void *msg); +  struct fuse_private {          int                  fd; -        struct fuse         *fuse; -        struct fuse_session *se; -        struct fuse_chan    *ch; +        uint32_t             proto_minor;          char                *volfile;          size_t               volfile_size;          char                *mount_point; @@ -69,6 +77,7 @@ struct fuse_private {          pthread_t            fuse_thread;          char                 fuse_thread_started;          uint32_t             direct_io_mode; +        size_t              *msg0_len_p;          double               entry_timeout;          double               attribute_timeout;          pthread_cond_t       first_call_cond; @@ -78,16 +87,16 @@ struct fuse_private {  };  typedef struct fuse_private fuse_private_t; -#define _FI_TO_FD(fi) ((fd_t *)((long)fi->fh)) +#define _FH_TO_FD(fh) ((fd_t *)(uintptr_t)(fh)) -#define FI_TO_FD(fi) ((_FI_TO_FD (fi))?(fd_ref (_FI_TO_FD(fi))):((fd_t *) 0)) +#define FH_TO_FD(fh) ((_FH_TO_FD (fh))?(fd_ref (_FH_TO_FD (fh))):((fd_t *) 0))  #define FUSE_FOP(state, ret, op_num, fop, args ...)                     \          do {                                                            \                  call_frame_t *frame = NULL;                             \                  xlator_t *xl = NULL;                                    \                                                                          \ -                frame = get_call_frame_for_req (state, 1);              \ +                frame = get_call_frame_for_req (state);                 \                  if (!frame) {                                           \                           /* This is not completely clean, as some       \                            * earlier allocations might remain unfreed    \ @@ -97,9 +106,11 @@ typedef struct fuse_private fuse_private_t;                            */                                            \                          gf_log ("glusterfs-fuse",                       \                                  GF_LOG_ERROR,                           \ -                                "FUSE message unique %"PRIu64":"        \ +                                "FUSE message"                          \ +                                " unique %"PRIu64" opcode %d:"          \                                  " frame allocation failed",             \ -                                req_callid (state->req));               \ +                                state->finh->unique,                    \ +                                state->finh->opcode);                   \                          free_state (state);                             \                          return;                                         \                  }                                                       \ @@ -114,20 +125,21 @@ typedef struct fuse_private fuse_private_t;          (((_errno == ENOENT) || (_errno == ESTALE))?    \           GF_LOG_DEBUG) -#define STATE_FROM_REQ(req, state)                               \ -        do {                                                     \ -                state = state_from_req (req);                    \ -                if (!state) {                                    \ -                        gf_log ("glusterfs-fuse",                \ -                                GF_LOG_ERROR,                    \ -                                "FUSE message unique %"PRIu64":" \ -                                " state allocation failed",      \ -                                req_callid (req));               \ -                                                                 \ -                        fuse_reply_err (req, ENOMEM);            \ -                                                                 \ -                        return;                                  \ -                }                                                \ +#define GET_STATE(this, finh, state)                                       \ +        do {                                                               \ +                state = get_state (this, finh);                            \ +                if (!state) {                                              \ +                        gf_log ("glusterfs-fuse",                          \ +                                GF_LOG_ERROR,                              \ +                                "FUSE message unique %"PRIu64" opcode %d:" \ +                                " state allocation failed",                \ +                                finh->unique, finh->opcode);               \ +                                                                           \ +                        send_fuse_err (this, finh, ENOMEM);                \ +                        FREE (finh);                                       \ +                                                                           \ +                        return;                                            \ +                }                                                          \          } while (0) @@ -137,7 +149,7 @@ typedef struct {          inode_table_t *itable;          loc_t          loc;          loc_t          loc2; -        fuse_req_t     req; +        fuse_in_header_t *finh;          int32_t        flags;          off_t          off;          size_t         size; @@ -148,8 +160,6 @@ typedef struct {          char           is_revalidate;  } fuse_state_t; -int fuse_chan_receive (struct fuse_chan *ch, char *buf, int32_t size); -  static void  free_state (fuse_state_t *state) @@ -170,6 +180,10 @@ free_state (fuse_state_t *state)                  fd_unref (state->fd);                  state->fd = (void *)0xfdfdfdfd;          } +        if (state->finh) { +                FREE (state->finh); +                state->finh = NULL; +        }  #ifdef DEBUG          memset (state, 0x90, sizeof (*state));  #endif @@ -179,66 +193,45 @@ free_state (fuse_state_t *state)  fuse_state_t * -state_from_req (fuse_req_t req) +get_state (xlator_t *this, fuse_in_header_t *finh)  {          fuse_state_t *state = NULL; -        xlator_t     *this = NULL; - -        this = fuse_req_userdata (req);          state = (void *)calloc (1, sizeof (*state));          if (!state)                  return NULL;          state->pool = this->ctx->pool;          state->itable = this->itable; -        state->req = req; +        state->finh = finh;          state->this = this;          return state;  } -static pid_t -get_pid_from_req (fuse_req_t req) -{ -        const struct fuse_ctx *ctx = NULL; - -        ctx = fuse_req_ctx (req); -        return ctx->pid; -} - -  static call_frame_t * -get_call_frame_for_req (fuse_state_t *state, char d) +get_call_frame_for_req (fuse_state_t *state)  {          call_pool_t           *pool = NULL; -        fuse_req_t             req = NULL; -        const struct fuse_ctx *ctx = NULL; +        fuse_in_header_t      *finh = NULL;          call_frame_t          *frame = NULL;          xlator_t              *this = NULL;          fuse_private_t        *priv = NULL;          pool = state->pool; -        req  = state->req; - -        if (req) { -                this = fuse_req_userdata (req); -        } else { -                this = state->this; -        } +        finh = state->finh; +        this = state->this;          priv = this->private;          frame = create_frame (this, pool);          if (!frame)                  return NULL; -        if (req) { -                ctx = fuse_req_ctx (req); - -                frame->root->uid    = ctx->uid; -                frame->root->gid    = ctx->gid; -                frame->root->pid    = ctx->pid; -                frame->root->unique = req_callid (req); +        if (finh) { +                frame->root->uid    = finh->uid; +                frame->root->gid    = finh->gid; +                frame->root->pid    = finh->pid; +                frame->root->unique = finh->unique;          }          frame->root->type = GF_OP_TYPE_FOP_REQUEST; @@ -247,6 +240,66 @@ get_call_frame_for_req (fuse_state_t *state, char d)  } +/* + * iov_out should contain a fuse_out_header at zeroth position. + * The error value of this header is sent to kernel. + */ +static int +send_fuse_iov (xlator_t *this, fuse_in_header_t *finh, struct iovec *iov_out, +               int count) +{ +        fuse_private_t *priv = NULL; +        struct fuse_out_header *fouh = NULL; +        int res, i; + +        priv = this->private; + +        fouh = iov_out[0].iov_base; +        iov_out[0].iov_len = sizeof (*fouh); +        fouh->len = 0; +        for (i = 0; i < count; i++) +                fouh->len += iov_out[i].iov_len; +        fouh->unique = finh->unique; + +        res = writev (priv->fd, iov_out, count); + +        if (res == -1) +                return errno; +        if (res != fouh->len) +                return EINVAL; +        return 0; +} + +static int +send_fuse_data (xlator_t *this, fuse_in_header_t *finh, void *data, size_t size) +{ +        struct fuse_out_header fouh = {0, }; +        struct iovec iov_out[2]; + +        fouh.error = 0; +        iov_out[0].iov_base = &fouh; +        iov_out[1].iov_base = data; +        iov_out[1].iov_len = size; + +        return send_fuse_iov (this, finh, iov_out, 2); +} + +#define send_fuse_obj(this, finh, obj) \ +        send_fuse_data (this, finh, obj, sizeof (*(obj))) + +static int +send_fuse_err (xlator_t *this, fuse_in_header_t *finh, int error) +{ +        struct fuse_out_header fouh = {0, }; +        struct iovec iov_out; + +        fouh.error = -error; +        iov_out.iov_base = &fouh; + +        return send_fuse_iov (this, finh, &iov_out, 1); +} + +  GF_MUST_CHECK static int32_t  fuse_loc_fill (loc_t *loc, fuse_state_t *state, ino_t ino,                 ino_t par, const char *name) @@ -351,6 +404,26 @@ need_fresh_lookup (int32_t op_ret, int32_t op_errno,          return 0;  } +/* courtesy of folly */ +static void +stat2attr (struct stat *st, struct fuse_attr *fa) +{ +        fa->ino        = st->st_ino; +        fa->size       = st->st_size; +        fa->blocks     = st->st_blocks; +        fa->atime      = st->st_atime; +        fa->mtime      = st->st_mtime; +        fa->ctime      = st->st_ctime; +        fa->atimensec = ST_ATIM_NSEC (st); +        fa->mtimensec = ST_MTIM_NSEC (st); +        fa->ctimensec = ST_CTIM_NSEC (st); +        fa->mode       = st->st_mode; +        fa->nlink      = st->st_nlink; +        fa->uid        = st->st_uid; +        fa->gid        = st->st_gid; +        fa->rdev       = st->st_rdev; +        fa->blksize    = st->st_blksize; +}  static int  fuse_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, @@ -363,13 +436,14 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  inode_t *inode, struct stat *buf)  {          fuse_state_t            *state = NULL; -        fuse_req_t               req = NULL; -        struct fuse_entry_param  e = {0, }; +        fuse_in_header_t        *finh = NULL; +        struct fuse_entry_out    feo = {0, }; +        struct fuse_attr_out    *fao = NULL;          fuse_private_t          *priv = NULL;          priv = this->private;          state = frame->root->state; -        req = state->req; +        finh = state->finh;          if (!op_ret && state->loc.ino == 1) {                  buf->st_ino = 1; @@ -391,7 +465,7 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this,          if (op_ret == 0) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": %s() %s => %"PRId64" (%"PRId64")", +                        "%"PRIu64": %s() %s => %"PRId64" (%"PRId64")",                          frame->root->unique, gf_fop_list[frame->root->op],                          state->loc.path, buf->st_ino, state->loc.ino); @@ -399,38 +473,62 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  inode_lookup (inode); -                /* TODO: make these timeouts configurable (via meta?) */ -                e.ino = inode->ino; - -#ifdef GF_DARWIN_HOST_OS -                e.generation = 0; -#else -                e.generation = buf->st_ctime; -#endif -                  buf->st_blksize = this->ctx->page_size; -                e.entry_timeout = priv->entry_timeout; -                e.attr_timeout  = priv->attribute_timeout; -                e.attr = *buf; +                stat2attr (buf, &feo.attr); -                if (!e.ino || !buf->st_ino) { +                if (!inode->ino || !buf->st_ino) {                          gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                                "%"PRId64": %s() %s returning inode 0", +                                "%"PRIu64": %s() %s returning inode 0",                                  frame->root->unique,                                  gf_fop_list[frame->root->op], state->loc.path);                  } -                if (state->loc.parent) -                        fuse_reply_entry (req, &e); -                else -                        fuse_reply_attr (req, buf, priv->attribute_timeout); +                if (state->loc.parent) { +                        /* TODO: make these timeouts configurable (via meta?) */ +                        feo.nodeid = inode->ino; + +#ifdef GF_DARWIN_HOST_OS +                        feo.generation = 0; +#else +                        feo.generation = buf->st_ctime; +#endif + +                        feo.entry_valid = +                          calc_timeout_sec (priv->entry_timeout); +                        feo.entry_valid_nsec = +                          calc_timeout_nsec (priv->entry_timeout); +                        feo.attr_valid = +                          calc_timeout_sec (priv->attribute_timeout); +                        feo.attr_valid_nsec = +                          calc_timeout_nsec (priv->attribute_timeout); + +                        priv->proto_minor >= 9 ? +                        send_fuse_obj (this, finh, &feo) : +                        send_fuse_data (this, finh, &feo, +                                        FUSE_COMPAT_ENTRY_OUT_SIZE); +                } else { +                        /* Refurbish the entry_out as attr_out. Too hacky?... */ +                        fao = (struct fuse_attr_out *) +                               ((char *)&feo.attr - +                                offsetof (struct fuse_attr_out, attr)); + +                        fao->attr_valid = +                          calc_timeout_sec (priv->attribute_timeout); +                        fao->attr_valid_nsec = +                          calc_timeout_nsec (priv->attribute_timeout); + +                        priv->proto_minor >= 9 ? +                        send_fuse_obj (this, finh, fao) : +                        send_fuse_data (this, finh, fao, +                                        FUSE_COMPAT_ATTR_OUT_SIZE); +                }          } else {                  gf_log ("glusterfs-fuse",                          (op_errno == ENOENT ? GF_LOG_TRACE : GF_LOG_WARNING), -                        "%"PRId64": %s() %s => -1 (%s)", frame->root->unique, +                        "%"PRIu64": %s() %s => -1 (%s)", frame->root->unique,                          gf_fop_list[frame->root->op], state->loc.path,                          strerror (op_errno)); -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, state->finh, op_errno);          }          free_state (state); @@ -450,27 +548,29 @@ fuse_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  static void -fuse_lookup (fuse_req_t req, fuse_ino_t par, const char *name) +fuse_lookup (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        char *name = msg; +          fuse_state_t *state = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); +        GET_STATE (this, finh, state); -        ret = fuse_loc_fill (&state->loc, state, 0, par, name); +        ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, name);          if (ret < 0) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRIu64": LOOKUP %"PRId64"/%s (fuse_loc_fill() failed)", -                        req_callid (req), (ino_t)par, name); +                        "%"PRIu64": LOOKUP %"PRIu64"/%s (fuse_loc_fill() failed)", +                        finh->unique, finh->nodeid, name);                  free_state (state); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  return;          }          if (!state->loc.inode) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRIu64": LOOKUP %s", req_callid (req), +                        "%"PRIu64": LOOKUP %s", finh->unique,                          state->loc.path);                  state->loc.inode = inode_new (state->itable); @@ -478,7 +578,7 @@ fuse_lookup (fuse_req_t req, fuse_ino_t par, const char *name)                  state->is_revalidate = -1;          } else {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRIu64": LOOKUP %s(%"PRId64")", req_callid (req), +                        "%"PRIu64": LOOKUP %s(%"PRId64")", finh->unique,                          state->loc.path, state->loc.inode->ino);                  state->is_revalidate = 1;          } @@ -491,30 +591,30 @@ fuse_lookup (fuse_req_t req, fuse_ino_t par, const char *name)  static void -fuse_forget (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup) +fuse_forget (xlator_t *this, fuse_in_header_t *finh, void *msg) +  { -        inode_t      *fuse_inode; -        xlator_t *this = NULL; +        struct fuse_forget_in *ffi = msg; -        this = fuse_req_userdata (req); +        inode_t      *fuse_inode; -        if (ino == 1) { -                fuse_reply_none (req); +        if (finh->nodeid == 1) { +                FREE (finh);                  return;          } -        fuse_inode = inode_search (this->itable, ino, NULL); +        fuse_inode = inode_search (this->itable, finh->nodeid, NULL);          if (fuse_inode) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "got forget on inode (%lu)", ino); -                inode_forget (fuse_inode, nlookup); +                        "got forget on inode (%"PRIu64")", finh->nodeid); +                inode_forget (fuse_inode, ffi->nlookup);                  inode_unref (fuse_inode);          } else {                  gf_log ("glusterfs-fuse", GF_LOG_DEBUG, -                        "got forget, but inode (%lu) not found", ino); +                        "got forget, but inode (%"PRIu64") not found", finh->nodeid);          } -        fuse_reply_none (req); +        FREE (finh);  } @@ -522,17 +622,18 @@ static int  fuse_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                 int32_t op_ret, int32_t op_errno, struct stat *buf)  { -        fuse_state_t   *state; -        fuse_req_t      req; -        fuse_private_t *priv = NULL; +        fuse_state_t     *state; +        fuse_in_header_t *finh; +        fuse_private_t   *priv = NULL; +        struct fuse_attr_out fao;          priv  = this->private;          state = frame->root->state; -        req   = state->req; +        finh  = state->finh;          if (op_ret == 0) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": %s() %s => %"PRId64, frame->root->unique, +                        "%"PRIu64": %s() %s => %"PRId64, frame->root->unique,                          gf_fop_list[frame->root->op],                          state->loc.path ? state->loc.path : "ERR",                          buf->st_ino); @@ -540,16 +641,24 @@ fuse_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  /* TODO: make these timeouts configurable via meta */                  /* TODO: what if the inode number has changed by now */                  buf->st_blksize = this->ctx->page_size; +                stat2attr (buf, &fao.attr); + +                fao.attr_valid = calc_timeout_sec (priv->attribute_timeout); +                fao.attr_valid_nsec = +                  calc_timeout_nsec (priv->attribute_timeout); -                fuse_reply_attr (req, buf, priv->attribute_timeout); +                priv->proto_minor >= 9 ? +                send_fuse_obj (this, finh, &fao) : +                send_fuse_data (this, finh, &fao, +                                FUSE_COMPAT_ATTR_OUT_SIZE);          } else {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRId64": %s() %s => -1 (%s)", frame->root->unique, +                        "%"PRIu64": %s() %s => -1 (%s)", frame->root->unique,                          gf_fop_list[frame->root->op],                          state->loc.path ? state->loc.path : "ERR",                          strerror (op_errno)); -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);          }          free_state (state); @@ -559,21 +668,21 @@ fuse_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  static void -fuse_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +fuse_getattr (xlator_t *this, fuse_in_header_t *finh, void *msg)  {          fuse_state_t *state;          fd_t         *fd = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); +        GET_STATE (this, finh, state); -        if (ino == 1) { -                ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +        if (finh->nodeid == 1) { +                ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);                  if (ret < 0) {                          gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                                "%"PRIu64": GETATTR %"PRId64" (fuse_loc_fill() failed)", -                                req_callid (req), (ino_t)ino); -                        fuse_reply_err (req, ENOENT); +                                "%"PRIu64": GETATTR %"PRIu64" (fuse_loc_fill() failed)", +                                finh->unique, finh->nodeid); +                        send_fuse_err (this, finh, ENOENT);                          free_state (state);                          return;                  } @@ -590,17 +699,17 @@ fuse_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)                  return;          } -        ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +        ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);          if (!state->loc.inode) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRIu64": GETATTR %"PRId64" (%s) (fuse_loc_fill() returned NULL inode)", -                        req_callid (req), (int64_t)ino, state->loc.path); -                fuse_reply_err (req, ENOENT); +                        "%"PRIu64": GETATTR %"PRIu64" (%s) (fuse_loc_fill() returned NULL inode)", +                        finh->unique, finh->nodeid, state->loc.path); +                send_fuse_err (this, finh, ENOENT);                  return;          } -        fd = fd_lookup (state->loc.inode, get_pid_from_req (req)); +        fd = fd_lookup (state->loc.inode, finh->pid);          state->fd = fd;          if (!fd || S_ISDIR (state->loc.inode->st_mode)) {                  /* this is the @ret of fuse_loc_fill, checked here @@ -608,16 +717,16 @@ fuse_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)                  */                  if (ret < 0) {                          gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                                "%"PRIu64": GETATTR %"PRId64" (fuse_loc_fill() failed)", -                                req_callid (req), (ino_t)ino); -                        fuse_reply_err (req, ENOENT); +                                "%"PRIu64": GETATTR %"PRIu64" (fuse_loc_fill() failed)", +                                finh->unique, finh->nodeid); +                        send_fuse_err (this, finh, ENOENT);                          free_state (state);                          return;                  }                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRIu64": GETATTR %"PRId64" (%s)", -                        req_callid (req), (int64_t)ino, state->loc.path); +                        "%"PRIu64": GETATTR %"PRIu64" (%s)", +                        finh->unique, finh->nodeid, state->loc.path);                  FUSE_FOP (state, fuse_attr_cbk, GF_FOP_STAT, @@ -625,8 +734,8 @@ fuse_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)          } else {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRIu64": FGETATTR %"PRId64" (%s/%p)", -                        req_callid (req), (int64_t)ino, state->loc.path, fd); +                        "%"PRIu64": FGETATTR %"PRIu64" (%s/%p)", +                        finh->unique, finh->nodeid, state->loc.path, fd);                  FUSE_FOP (state,fuse_attr_cbk, GF_FOP_FSTAT,                            fstat, fd); @@ -639,30 +748,30 @@ fuse_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this,               int32_t op_ret, int32_t op_errno, fd_t *fd)  {          fuse_state_t          *state; -        fuse_req_t             req; +        fuse_in_header_t      *finh;          fuse_private_t        *priv = NULL; -        struct fuse_file_info  fi = {0, }; +        struct fuse_open_out   foo = {0, };          priv = this->private;          state = frame->root->state; -        req = state->req; +        finh = state->finh;          if (op_ret >= 0) { -                fi.fh = (unsigned long) fd; -                fi.flags = state->flags; +                foo.fh = (uintptr_t) fd; +                foo.open_flags = 0;                  if (!S_ISDIR (fd->inode->st_mode)) { -                        if (((fi.flags & O_ACCMODE) != O_RDONLY) && +                        if (((state->flags & O_ACCMODE) != O_RDONLY) &&                              priv->direct_io_mode) -                                fi.direct_io = 1; +                                foo.open_flags |= FOPEN_DIRECT_IO;                  }                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": %s() %s => %p", frame->root->unique, +                        "%"PRIu64": %s() %s => %p", frame->root->unique,                          gf_fop_list[frame->root->op], state->loc.path, fd);                  fd_ref (fd); -                if (fuse_reply_open (req, &fi) == -ENOENT) { +                if (send_fuse_obj (this, finh, &foo) == ENOENT) {                          gf_log ("glusterfs-fuse", GF_LOG_DEBUG,                                  "open(%s) got EINTR", state->loc.path);                          fd_unref (fd); @@ -672,11 +781,11 @@ fuse_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  fd_bind (fd);          } else {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRId64": %s() %s => -1 (%s)", frame->root->unique, +                        "%"PRIu64": %s() %s => -1 (%s)", frame->root->unique,                          gf_fop_list[frame->root->op], state->loc.path,                          strerror (op_errno)); -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);          }  out:          free_state (state); @@ -686,53 +795,51 @@ out:  static void -do_chmod (fuse_req_t req, fuse_ino_t ino, struct stat *attr, -          struct fuse_file_info *fi) +do_chmod (xlator_t *this, fuse_in_header_t *finh, struct fuse_setattr_in *fsi)  {          fuse_state_t *state = NULL;          fd_t         *fd = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); -        if (fi) { -                fd = FI_TO_FD (fi); +        GET_STATE (this, finh, state); +        if (fsi->valid & FATTR_FH) { +                fd = FH_TO_FD (fsi->fh);                  state->fd = fd;          }          if (fd) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRIu64": FCHMOD %p", req_callid (req), fd); +                        "%"PRIu64": FCHMOD %p", finh->unique, fd);                  FUSE_FOP (state, fuse_attr_cbk, GF_FOP_FCHMOD, -                          fchmod, fd, attr->st_mode); +                          fchmod, fd, fsi->mode);          } else { -                ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +                ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);                  if ((state->loc.inode == NULL) ||                      (ret < 0)) {                          gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                                "%"PRIu64": CHMOD %"PRId64" (%s) (fuse_loc_fill() failed)", -                                req_callid (req), (int64_t)ino, +                                "%"PRIu64": CHMOD %"PRIu64" (%s) (fuse_loc_fill() failed)", +                                finh->unique, finh->nodeid,                                  state->loc.path); -                        fuse_reply_err (req, ENOENT); +                        send_fuse_err (this, finh, ENOENT);                          free_state (state);                          return;                  }                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRIu64": CHMOD %s", req_callid (req), +                        "%"PRIu64": CHMOD %s", finh->unique,                          state->loc.path);                  FUSE_FOP (state, fuse_attr_cbk, GF_FOP_CHMOD, -                          chmod, &state->loc, attr->st_mode); +                          chmod, &state->loc, fsi->mode);          }  }  static void -do_chown (fuse_req_t req, fuse_ino_t ino, struct stat *attr, -          int valid, struct fuse_file_info *fi) +do_chown (xlator_t *this, fuse_in_header_t *finh, struct fuse_setattr_in *fsi)  {          fuse_state_t *state = NULL;          fd_t         *fd = NULL; @@ -740,36 +847,36 @@ do_chown (fuse_req_t req, fuse_ino_t ino, struct stat *attr,          uid_t         uid = 0;          gid_t         gid = 0; -        uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1; -        gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1; -        STATE_FROM_REQ (req, state); +        uid = (fsi->valid & FATTR_UID) ? fsi->uid : (uid_t) -1; +        gid = (fsi->valid & FATTR_GID) ? fsi->gid : (gid_t) -1; +        GET_STATE (this, finh, state); -        if (fi) { -                fd = FI_TO_FD (fi); +        if (fsi->valid & FATTR_FH) { +                fd = FH_TO_FD (fsi->fh);                  state->fd = fd;          }          if (fd) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRIu64": FCHOWN %p", req_callid (req), fd); +                        "%"PRIu64": FCHOWN %p", finh->unique, fd);                  FUSE_FOP (state, fuse_attr_cbk, GF_FOP_FCHOWN,                            fchown, fd, uid, gid);          } else { -                ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +                ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);                  if ((state->loc.inode == NULL) ||                      (ret < 0)) {                          gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                                "%"PRIu64": CHOWN %"PRId64" (%s) (fuse_loc_fill() failed)", -                                req_callid (req), (int64_t)ino, +                                "%"PRIu64": CHOWN %"PRIu64" (%s) (fuse_loc_fill() failed)", +                                finh->unique, finh->nodeid,                                  state->loc.path); -                        fuse_reply_err (req, ENOENT); +                        send_fuse_err (this, finh, ENOENT);                          free_state (state);                          return;                  }                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRIu64": CHOWN %s", req_callid (req), +                        "%"PRIu64": CHOWN %s", finh->unique,                          state->loc.path);                  FUSE_FOP (state, fuse_attr_cbk, GF_FOP_CHOWN, @@ -779,47 +886,46 @@ do_chown (fuse_req_t req, fuse_ino_t ino, struct stat *attr,  static void -do_truncate (fuse_req_t req, fuse_ino_t ino, struct stat *attr, -             struct fuse_file_info *fi) +do_truncate (xlator_t *this, fuse_in_header_t *finh, struct fuse_setattr_in *fsi)  {          fuse_state_t *state = NULL;          fd_t         *fd = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); +        GET_STATE (this, finh, state); -        if (fi) { -                fd = FI_TO_FD (fi); +        if (fsi->valid & FATTR_FH) { +                fd = FH_TO_FD (fsi->fh);                  state->fd = fd;          }          if (fd) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRIu64": FTRUNCATE %p/%"PRId64, req_callid (req), -                        fd, attr->st_size); +                        "%"PRIu64": FTRUNCATE %p/%"PRId64, finh->unique, +                        fd, fsi->size);                  FUSE_FOP (state, fuse_attr_cbk, GF_FOP_FTRUNCATE, -                          ftruncate, fd, attr->st_size); +                          ftruncate, fd, fsi->size);          } else { -                ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +                ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);                  if ((state->loc.inode == NULL) ||                      (ret < 0)) {                          gf_log ("glusterfs-fuse", GF_LOG_WARNING,                                  "%"PRIu64": TRUNCATE %s/%"PRId64" (fuse_loc_fill() failed)", -                                req_callid (req), state->loc.path, -                                attr->st_size); -                        fuse_reply_err (req, ENOENT); +                                finh->unique, state->loc.path, +                                fsi->size); +                        send_fuse_err (this, finh, ENOENT);                          free_state (state);                          return;                  }                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRIu64": TRUNCATE %s/%"PRId64"(%lu)", -                        req_callid (req), -                        state->loc.path, attr->st_size, ino); +                        "%"PRIu64": TRUNCATE %s/%"PRId64"(%"PRIu64")", +                        finh->unique, +                        state->loc.path, fsi->size, finh->nodeid);                  FUSE_FOP (state, fuse_attr_cbk, GF_FOP_TRUNCATE, -                          truncate, &state->loc, attr->st_size); +                          truncate, &state->loc, fsi->size);          }          return; @@ -827,32 +933,32 @@ do_truncate (fuse_req_t req, fuse_ino_t ino, struct stat *attr,  static void -do_utimes (fuse_req_t req, fuse_ino_t ino, struct stat *attr) +do_utimes (xlator_t *this, fuse_in_header_t *finh, struct fuse_setattr_in *fsi)  {          fuse_state_t    *state = NULL;          struct timespec  tv[2];          int32_t          ret = -1; -        tv[0].tv_sec  = attr->st_atime; -        tv[0].tv_nsec = ST_ATIM_NSEC (attr); -        tv[1].tv_sec  = attr->st_mtime; -        tv[1].tv_nsec = ST_ATIM_NSEC (attr); +        tv[0].tv_sec  = fsi->atime; +        tv[0].tv_nsec = fsi->atimensec; +        tv[1].tv_sec  = fsi->mtime; +        tv[1].tv_nsec = fsi->mtimensec; -        STATE_FROM_REQ (req, state); -        ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +        GET_STATE (this, finh, state); +        ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "%"PRIu64": UTIMENS %s (fuse_loc_fill() failed)", -                        req_callid (req), state->loc.path); -                fuse_reply_err (req, ENOENT); +                        finh->unique, state->loc.path); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          }          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": UTIMENS (%lu)%s", req_callid (req), -                ino, state->loc.path); +                "%"PRIu64": UTIMENS (%"PRIu64")%s", finh->unique, +                finh->nodeid, state->loc.path);          FUSE_FOP (state, fuse_attr_cbk, GF_FOP_UTIMENS,                    utimens, &state->loc, tv); @@ -860,20 +966,24 @@ do_utimes (fuse_req_t req, fuse_ino_t ino, struct stat *attr)  static void -fuse_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, -              int valid, struct fuse_file_info *fi) -{ - -        if (valid & FUSE_SET_ATTR_MODE) -                do_chmod (req, ino, attr, fi); -        else if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) -                do_chown (req, ino, attr, valid, fi); -        else if (valid & FUSE_SET_ATTR_SIZE) -                do_truncate (req, ino, attr, fi); -        else if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) -                do_utimes (req, ino, attr); +fuse_setattr (xlator_t *this, fuse_in_header_t *finh, void *msg) +{ +        struct fuse_setattr_in *fsi = msg; + +        if (fsi->valid & FATTR_MODE) +                do_chmod (this, finh, fsi); +        else if (fsi->valid & (FATTR_UID | FATTR_GID)) +                do_chown (this, finh, fsi); +        else if (fsi->valid & FATTR_SIZE) +                do_truncate (this, finh, fsi); +        else if (fsi->valid & (FATTR_ATIME | FATTR_MTIME)) +                do_utimes (this, finh, fsi);          else -                fuse_getattr (req, ino, fi); +                /* As of now, getattr uses only the header. +                 * If it happens to change, we'll have to +                 * do some refactoring... +                 */ +                fuse_getattr (this, finh, NULL);  } @@ -884,15 +994,15 @@ fuse_err_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                int32_t op_ret, int32_t op_errno)  {          fuse_state_t *state = frame->root->state; -        fuse_req_t req = state->req; +        fuse_in_header_t *finh = state->finh;          if (op_ret == 0) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": %s() %s => 0", frame->root->unique, +                        "%"PRIu64": %s() %s => 0", frame->root->unique,                          gf_fop_list[frame->root->op],                          state->loc.path ? state->loc.path : "ERR"); -                fuse_reply_err (req, 0); +                send_fuse_err (this, finh, 0);          } else {                  if (frame->root->op == GF_FOP_SETXATTR) {                          op_ret = gf_compat_setxattr (state->dict); @@ -913,7 +1023,7 @@ fuse_err_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                                  goto nolog;                          }                          gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                                "%"PRId64": %s() %s => -1 (%s)", +                                "%"PRIu64": %s() %s => -1 (%s)",                                  frame->root->unique,                                  gf_fop_list[frame->root->op],                                  state->loc.path ? state->loc.path : "ERR", @@ -921,7 +1031,7 @@ fuse_err_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  }          nolog: -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);          }          free_state (state); @@ -935,11 +1045,11 @@ static int  fuse_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                   int32_t op_ret, int32_t op_errno)  { -        fuse_state_t *state = NULL; -        fuse_req_t    req = NULL; +        fuse_state_t     *state = NULL; +        fuse_in_header_t *finh = NULL;          state = frame->root->state; -        req = state->req; +        finh = state->finh;          if (op_ret == 0)                  inode_unlink (state->loc.inode, state->loc.parent, @@ -947,18 +1057,18 @@ fuse_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,          if (op_ret == 0) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": %s() %s => 0", frame->root->unique, +                        "%"PRIu64": %s() %s => 0", frame->root->unique,                          gf_fop_list[frame->root->op], state->loc.path); -                fuse_reply_err (req, 0); +                send_fuse_err (this, finh, 0);          } else {                  gf_log ("glusterfs-fuse",                          op_errno == ENOTEMPTY ? GF_LOG_DEBUG : GF_LOG_WARNING, -                        "%"PRId64": %s() %s => -1 (%s)", frame->root->unique, +                        "%"PRIu64": %s() %s => -1 (%s)", frame->root->unique,                          gf_fop_list[frame->root->op], state->loc.path,                          strerror (op_errno)); -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);          }          free_state (state); @@ -969,31 +1079,33 @@ fuse_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  static void -fuse_access (fuse_req_t req, fuse_ino_t ino, int mask) +fuse_access (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_access_in *fai = msg; +          fuse_state_t *state = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); +        GET_STATE (this, finh, state); -        ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +        ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRIu64": ACCESS %"PRId64" (%s) (fuse_loc_fill() failed)", -                        req_callid (req), (int64_t)ino, state->loc.path); -                fuse_reply_err (req, ENOENT); +                        "%"PRIu64": ACCESS %"PRIu64" (%s) (fuse_loc_fill() failed)", +                        finh->unique, finh->nodeid, state->loc.path); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          }          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64" ACCESS %s/%lu mask=%d", req_callid (req), -                state->loc.path, ino, mask); +                "%"PRIu64" ACCESS %s/%"PRIu64" mask=%d", finh->unique, +                state->loc.path, finh->nodeid, fai->mask);          FUSE_FOP (state, fuse_err_cbk,                    GF_FOP_ACCESS, access, -                  &state->loc, mask); +                  &state->loc, fai->mask);          return;  } @@ -1003,26 +1115,26 @@ static int  fuse_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                     int32_t op_ret, int32_t op_errno, const char *linkname)  { -        fuse_state_t *state = NULL; -        fuse_req_t    req = NULL; +        fuse_state_t     *state = NULL; +        fuse_in_header_t *finh = NULL;          state = frame->root->state; -        req = state->req; +        finh = state->finh;          if (op_ret > 0) {                  ((char *)linkname)[op_ret] = '\0';                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": %s => %s", frame->root->unique, +                        "%"PRIu64": %s => %s", frame->root->unique,                          state->loc.path, linkname); -                fuse_reply_readlink (req, linkname); +                send_fuse_data (this, finh, (void *)linkname, op_ret + 1);          } else {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRId64": %s => -1 (%s)", frame->root->unique, +                        "%"PRIu64": %s => -1 (%s)", frame->root->unique,                          state->loc.path, strerror (op_errno)); -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);          }          free_state (state); @@ -1033,26 +1145,26 @@ fuse_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  static void -fuse_readlink (fuse_req_t req, fuse_ino_t ino) +fuse_readlink (xlator_t *this, fuse_in_header_t *finh, void *msg)  {          fuse_state_t *state = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); -        ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +        GET_STATE (this, finh, state); +        ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "%"PRIu64" READLINK %s/%"PRId64" (fuse_loc_fill() returned NULL inode)", -                        req_callid (req), state->loc.path, +                        finh->unique, state->loc.path,                          state->loc.inode->ino); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          }          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64" READLINK %s/%"PRId64, req_callid (req), +                "%"PRIu64" READLINK %s/%"PRId64, finh->unique,                  state->loc.path, state->loc.inode->ino);          FUSE_FOP (state, fuse_readlink_cbk, GF_FOP_READLINK, @@ -1063,19 +1175,26 @@ fuse_readlink (fuse_req_t req, fuse_ino_t ino)  static void -fuse_mknod (fuse_req_t req, fuse_ino_t par, const char *name, -            mode_t mode, dev_t rdev) +fuse_mknod (xlator_t *this, fuse_in_header_t *finh, void *msg)  { -        fuse_state_t *state = NULL; -        int32_t       ret = -1; +        struct fuse_mknod_in *fmi = msg; +        char         *name = (char *)(fmi + 1); + +        fuse_state_t   *state = NULL; +        fuse_private_t *priv = NULL; +        int32_t         ret = -1; + +        priv = this->private; +        if (priv->proto_minor < 12) +                name = (char *)msg + FUSE_COMPAT_MKNOD_IN_SIZE; -        STATE_FROM_REQ (req, state); -        ret = fuse_loc_fill (&state->loc, state, 0, par, name); +        GET_STATE (this, finh, state); +        ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, name);          if (ret < 0) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "%"PRIu64" MKNOD %s (fuse_loc_fill() failed)", -                        req_callid (req), state->loc.path); -                fuse_reply_err (req, ENOENT); +                        finh->unique, state->loc.path); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          } @@ -1083,29 +1202,32 @@ fuse_mknod (fuse_req_t req, fuse_ino_t par, const char *name,          state->loc.inode = inode_new (state->itable);          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": MKNOD %s", req_callid (req), +                "%"PRIu64": MKNOD %s", finh->unique,                  state->loc.path);          FUSE_FOP (state, fuse_entry_cbk, GF_FOP_MKNOD, -                  mknod, &state->loc, mode, rdev); +                  mknod, &state->loc, fmi->mode, fmi->rdev);          return;  }  static void -fuse_mkdir (fuse_req_t req, fuse_ino_t par, const char *name, mode_t mode) +fuse_mkdir (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_mknod_in *fmi = msg; +        char *name = (char *)(fmi + 1); +          fuse_state_t *state;          int32_t ret = -1; -        STATE_FROM_REQ (req, state); -        ret = fuse_loc_fill (&state->loc, state, 0, par, name); +        GET_STATE (this, finh, state); +        ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, name);          if (ret < 0) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "%"PRIu64" MKDIR %s (fuse_loc_fill() failed)", -                        req_callid (req), state->loc.path); -                fuse_reply_err (req, ENOENT); +                        finh->unique, state->loc.path); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          } @@ -1113,38 +1235,40 @@ fuse_mkdir (fuse_req_t req, fuse_ino_t par, const char *name, mode_t mode)          state->loc.inode = inode_new (state->itable);          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": MKDIR %s", req_callid (req), +                "%"PRIu64": MKDIR %s", finh->unique,                  state->loc.path);          FUSE_FOP (state, fuse_entry_cbk, GF_FOP_MKDIR, -                  mkdir, &state->loc, mode); +                  mkdir, &state->loc, fmi->mode);          return;  }  static void -fuse_unlink (fuse_req_t req, fuse_ino_t par, const char *name) +fuse_unlink (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        char         *name = msg; +          fuse_state_t *state = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); +        GET_STATE (this, finh, state); -        ret = fuse_loc_fill (&state->loc, state, 0, par, name); +        ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, name);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "%"PRIu64": UNLINK %s (fuse_loc_fill() returned NULL inode)", -                        req_callid (req), state->loc.path); -                fuse_reply_err (req, ENOENT); +                        finh->unique, state->loc.path); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          }          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": UNLINK %s", req_callid (req), +                "%"PRIu64": UNLINK %s", finh->unique,                  state->loc.path);          FUSE_FOP (state, fuse_unlink_cbk, GF_FOP_UNLINK, @@ -1155,25 +1279,27 @@ fuse_unlink (fuse_req_t req, fuse_ino_t par, const char *name)  static void -fuse_rmdir (fuse_req_t req, fuse_ino_t par, const char *name) +fuse_rmdir (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        char         *name = msg; +          fuse_state_t *state = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); -        ret = fuse_loc_fill (&state->loc, state, 0, par, name); +        GET_STATE (this, finh, state); +        ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, name);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "%"PRIu64": RMDIR %s (fuse_loc_fill() failed)", -                        req_callid (req), state->loc.path); -                fuse_reply_err (req, ENOENT); +                        finh->unique, state->loc.path); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          }          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": RMDIR %s", req_callid (req), +                "%"PRIu64": RMDIR %s", finh->unique,                  state->loc.path);          FUSE_FOP (state, fuse_unlink_cbk, GF_FOP_RMDIR, @@ -1184,19 +1310,21 @@ fuse_rmdir (fuse_req_t req, fuse_ino_t par, const char *name)  static void -fuse_symlink (fuse_req_t req, const char *linkname, fuse_ino_t par, -              const char *name) +fuse_symlink (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        char *name = msg; +        char *linkname = name + strlen (name) + 1; +          fuse_state_t *state = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); -        ret = fuse_loc_fill (&state->loc, state, 0, par, name); +        GET_STATE (this, finh, state); +        ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, name);          if (ret < 0) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "%"PRIu64" SYMLINK %s -> %s (fuse_loc_fill() failed)", -                        req_callid (req), state->loc.path, linkname); -                fuse_reply_err (req, ENOENT); +                        finh->unique, state->loc.path, linkname); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          } @@ -1204,7 +1332,7 @@ fuse_symlink (fuse_req_t req, const char *linkname, fuse_ino_t par,          state->loc.inode = inode_new (state->itable);          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": SYMLINK %s -> %s", req_callid (req), +                "%"PRIu64": SYMLINK %s -> %s", finh->unique,                  state->loc.path, linkname);          FUSE_FOP (state, fuse_entry_cbk, GF_FOP_SYMLINK, @@ -1218,15 +1346,15 @@ int  fuse_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                   int32_t op_ret, int32_t op_errno, struct stat *buf)  { -        fuse_state_t *state = NULL; -        fuse_req_t    req = NULL; +        fuse_state_t     *state = NULL; +        fuse_in_header_t *finh = NULL;          state = frame->root->state; -        req   = state->req; +        finh  = state->finh;          if (op_ret == 0) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": %s -> %s => 0 (buf->st_ino=%"PRId64" , loc->ino=%"PRId64")", +                        "%"PRIu64": %s -> %s => 0 (buf->st_ino=%"PRId64" , loc->ino=%"PRId64")",                          frame->root->unique, state->loc.path, state->loc2.path,                          buf->st_ino, state->loc.ino); @@ -1244,13 +1372,13 @@ fuse_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                                state->loc2.parent, state->loc2.name,                                state->loc.inode, buf); -                fuse_reply_err (req, 0); +                send_fuse_err (this, finh, 0);          } else {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRId64": %s -> %s => -1 (%s)", frame->root->unique, +                        "%"PRIu64": %s -> %s => -1 (%s)", frame->root->unique,                          state->loc.path, state->loc2.path,                          strerror (op_errno)); -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);          }          free_state (state); @@ -1260,42 +1388,45 @@ fuse_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  static void -fuse_rename (fuse_req_t req, fuse_ino_t oldpar, const char *oldname, -             fuse_ino_t newpar, const char *newname) +fuse_rename (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_rename_in  *fri = msg; +        char *oldname = (char *)(fri + 1); +        char *newname = oldname + strlen (oldname) + 1; +          fuse_state_t *state = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); +        GET_STATE (this, finh, state); -        ret = fuse_loc_fill (&state->loc, state, 0, oldpar, oldname); +        ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, oldname);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "for %s %"PRIu64": RENAME `%s' -> `%s' (fuse_loc_fill() failed)", -                        state->loc.path, req_callid (req), state->loc.path, +                        state->loc.path, finh->unique, state->loc.path,                          state->loc2.path); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          } -        ret = fuse_loc_fill (&state->loc2, state, 0, newpar, newname); +        ret = fuse_loc_fill (&state->loc2, state, 0, fri->newdir, newname);          if (ret < 0) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "for %s %"PRIu64": RENAME `%s' -> `%s' (fuse_loc_fill() failed)", -                        state->loc.path, req_callid (req), state->loc.path, +                        state->loc.path, finh->unique, state->loc.path,                          state->loc2.path); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;                 }          gf_log ("glusterfs-fuse", GF_LOG_TRACE,                  "%"PRIu64": RENAME `%s (%"PRId64")' -> `%s (%"PRId64")'", -                req_callid (req), state->loc.path, state->loc.ino, +                finh->unique, state->loc.path, state->loc.ino,                  state->loc2.path, state->loc2.ino);          FUSE_FOP (state, fuse_rename_cbk, GF_FOP_RENAME, @@ -1306,24 +1437,28 @@ fuse_rename (fuse_req_t req, fuse_ino_t oldpar, const char *oldname,  static void -fuse_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t par, const char *name) +fuse_link (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_link_in *fli = msg; +        char         *name = (char *)(fli + 1); +          fuse_state_t *state = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); +        GET_STATE (this, finh, state); -        ret = fuse_loc_fill (&state->loc, state, 0, par, name); +        ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, name);          if (ret == 0) -                ret = fuse_loc_fill (&state->loc2, state, ino, 0, NULL); +                ret = fuse_loc_fill (&state->loc2, state, fli->oldnodeid, 0, +                                     NULL);          if ((state->loc2.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "fuse_loc_fill() failed for %s %"PRIu64": LINK %s %s", -                        state->loc2.path, req_callid (req), +                        state->loc2.path, finh->unique,                          state->loc2.path, state->loc.path); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          } @@ -1331,7 +1466,7 @@ fuse_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t par, const char *name)          state->loc.inode = inode_ref (state->loc2.inode);          gf_log ("glusterfs-fuse", GF_LOG_TRACE,                  "%"PRIu64": LINK() %s (%"PRId64") -> %s (%"PRId64")", -                req_callid (req), state->loc2.path, state->loc2.ino, +                finh->unique, state->loc2.path, state->loc2.ino,                  state->loc.path, state->loc.ino);          FUSE_FOP (state, fuse_entry_cbk, GF_FOP_LINK, @@ -1347,42 +1482,46 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                   fd_t *fd, inode_t *inode, struct stat *buf)  {          fuse_state_t            *state = NULL; -        fuse_req_t               req = NULL; +        fuse_in_header_t        *finh = NULL;          fuse_private_t          *priv = NULL; -        struct fuse_file_info    fi = {0, }; -        struct fuse_entry_param  e = {0, }; +        struct fuse_out_header   fouh = {0, }; +        struct fuse_entry_out    feo = {0, }; +        struct fuse_open_out     foo = {0, }; +        struct iovec iov_out[3];          state    = frame->root->state;          priv     = this->private; -        req      = state->req; -        fi.flags = state->flags; +        finh     = state->finh; +        foo.open_flags = 0;          if (op_ret >= 0) { -                fi.fh = (unsigned long) fd; +                foo.fh = (uintptr_t) fd; -                if (((fi.flags & O_ACCMODE) != O_RDONLY) -                    && priv->direct_io_mode) -                        fi.direct_io = 1; +                if (((state->flags & O_ACCMODE) != O_RDONLY) && +                    priv->direct_io_mode) +                        foo.open_flags |= FOPEN_DIRECT_IO;                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": %s() %s => %p (ino=%"PRId64")", +                        "%"PRIu64": %s() %s => %p (ino=%"PRId64")",                          frame->root->unique, gf_fop_list[frame->root->op],                          state->loc.path, fd, buf->st_ino); -                e.ino = buf->st_ino; +                buf->st_blksize = this->ctx->page_size; +                stat2attr (buf, &feo.attr); + +                feo.nodeid = buf->st_ino;  #ifdef GF_DARWIN_HOST_OS -                e.generation = 0; +                feo.generation = 0;  #else -                e.generation = buf->st_ctime; +                feo.generation = buf->st_ctime;  #endif -                buf->st_blksize = this->ctx->page_size; -                e.entry_timeout = priv->entry_timeout; -                e.attr_timeout = priv->attribute_timeout; -                e.attr = *buf; - -                fi.keep_cache = 0; +                feo.entry_valid = calc_timeout_sec (priv->entry_timeout); +                feo.entry_valid_nsec = calc_timeout_nsec (priv->entry_timeout); +                feo.attr_valid = calc_timeout_sec (priv->attribute_timeout); +                feo.attr_valid_nsec = +                  calc_timeout_nsec (priv->attribute_timeout);                  inode_link (inode, state->loc.parent,                              state->loc.name, buf); @@ -1390,7 +1529,16 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  inode_lookup (inode);                  fd_ref (fd); -                if (fuse_reply_create (req, &e, &fi) == -ENOENT) { + +                fouh.error = 0; +                iov_out[0].iov_base = &fouh; +                iov_out[1].iov_base = &feo; +                iov_out[1].iov_len = priv->proto_minor >= 9 ? +                                     sizeof (feo) : +                                     FUSE_COMPAT_ENTRY_OUT_SIZE; +                iov_out[2].iov_base = &foo; +                iov_out[2].iov_len = sizeof (foo); +                if (send_fuse_iov (this, finh, iov_out, 3) == ENOENT) {                          gf_log ("glusterfs-fuse", GF_LOG_DEBUG,                                  "create(%s) got EINTR", state->loc.path);                          inode_forget (inode, 1); @@ -1401,9 +1549,9 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  fd_bind (fd);          } else {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRIu64": %s => -1 (%s)", req_callid (req), +                        "%"PRIu64": %s => -1 (%s)", finh->unique,                          state->loc.path, strerror (op_errno)); -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);          }  out:          free_state (state); @@ -1414,75 +1562,84 @@ out:  static void -fuse_create (fuse_req_t req, fuse_ino_t par, const char *name, -             mode_t mode, struct fuse_file_info *fi) +fuse_create (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_create_in *fci = msg; +        char         *name = (char *)(fci + 1); + +        fuse_private_t        *priv = NULL;          fuse_state_t *state = NULL;          fd_t         *fd = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); -        state->flags = fi->flags; +        priv = this->private; +        if (priv->proto_minor < 12) +                name = (char *)((struct fuse_open_in *)msg + 1); + +        GET_STATE (this, finh, state); +        state->flags = fci->flags; -        ret = fuse_loc_fill (&state->loc, state, 0, par, name); +        ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, name);          if (ret < 0) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "%"PRIu64" CREATE %s (fuse_loc_fill() failed)", -                        req_callid (req), state->loc.path); -                fuse_reply_err (req, ENOENT); +                        finh->unique, state->loc.path); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          }          state->loc.inode = inode_new (state->itable); -        fd = fd_create (state->loc.inode, get_pid_from_req (req)); +        fd = fd_create (state->loc.inode, finh->pid);          state->fd = fd;          fd->flags = state->flags;          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": CREATE %s", req_callid (req), +                "%"PRIu64": CREATE %s", finh->unique,                  state->loc.path);          FUSE_FOP (state, fuse_create_cbk, GF_FOP_CREATE, -                  create, &state->loc, state->flags, mode, fd); +                  create, &state->loc, state->flags, fci->mode, fd);          return;  }  static void -fuse_open (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +fuse_open (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_open_in *foi = msg; +          fuse_state_t *state = NULL;          fd_t         *fd = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); -        state->flags = fi->flags; +        GET_STATE (this, finh, state); +        state->flags = foi->flags; -        ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +        ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "%"PRIu64": OPEN %s (fuse_loc_fill() failed)", -                        req_callid (req), state->loc.path); +                        finh->unique, state->loc.path); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          } -        fd = fd_create (state->loc.inode, get_pid_from_req (req)); +        fd = fd_create (state->loc.inode, finh->pid);          state->fd = fd; -        fd->flags = fi->flags; +        fd->flags = foi->flags;          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": OPEN %s", req_callid (req), +                "%"PRIu64": OPEN %s", finh->unique,                  state->loc.path);          FUSE_FOP (state, fuse_fd_cbk, GF_FOP_OPEN, -                  open, &state->loc, fi->flags, fd); +                  open, &state->loc, foi->flags, fd);          return;  } @@ -1495,28 +1652,34 @@ fuse_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  struct stat *stbuf, struct iobref *iobref)  {          fuse_state_t *state = NULL; -        fuse_req_t    req = NULL; +        fuse_in_header_t *finh = NULL; +        struct fuse_out_header fouh = {0, }; +        struct iovec *iov_out = NULL;          state = frame->root->state; -        req = state->req; +        finh = state->finh;          if (op_ret >= 0) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": READ => %d/%"GF_PRI_SIZET",%"PRId64"/%"PRId64, +                        "%"PRIu64": READ => %d/%"GF_PRI_SIZET",%"PRId64"/%"PRId64,                          frame->root->unique,                          op_ret, state->size, state->off, stbuf->st_size); -#ifdef HAVE_FUSE_REPLY_IOV -                fuse_reply_iov (req, vector, count); -#else -                fuse_reply_vec (req, vector, count); -#endif +                iov_out = CALLOC (count + 1, sizeof (*iov_out)); +                if (iov_out) { +                        fouh.error = 0; +                        iov_out[0].iov_base = &fouh; +                        memcpy (iov_out + 1, vector, count * sizeof (*iov_out)); +                        send_fuse_iov (this, finh, iov_out, count + 1); +                        FREE (iov_out); +                } else +                        send_fuse_err (this, finh, ENOMEM);          } else {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRId64": READ => %d (%s)", frame->root->unique, +                        "%"PRIu64": READ => %d (%s)", frame->root->unique,                          op_ret, strerror (op_errno)); -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);          }          free_state (state); @@ -1527,25 +1690,26 @@ fuse_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  static void -fuse_readv (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, -            struct fuse_file_info *fi) +fuse_readv (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_read_in *fri = msg; +          fuse_state_t *state = NULL;          fd_t         *fd = NULL; -        STATE_FROM_REQ (req, state); -        state->size = size; -        state->off = off; +        GET_STATE (this, finh, state); +        state->size = fri->size; +        state->off = fri->offset; -        fd = FI_TO_FD (fi); +        fd = FH_TO_FD (fri->fh);          state->fd = fd;          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": READ (%p, size=%"GF_PRI_SIZET", offset=%"PRId64")", -                req_callid (req), fd, size, off); +                "%"PRIu64": READ (%p, size=%"PRIu32", offset=%"PRIu64")", +                finh->unique, fd, fri->size, fri->offset);          FUSE_FOP (state, fuse_readv_cbk, GF_FOP_READ, -                  readv, fd, size, off); +                  readv, fd, fri->size, fri->offset);  } @@ -1556,24 +1720,26 @@ fuse_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                   struct stat *stbuf)  {          fuse_state_t *state = NULL; -        fuse_req_t    req = NULL; +        fuse_in_header_t *finh = NULL; +        struct fuse_write_out fwo = {0, };          state = frame->root->state; -        req = state->req; +        finh = state->finh;          if (op_ret >= 0) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": WRITE => %d/%"GF_PRI_SIZET",%"PRId64"/%"PRId64, +                        "%"PRIu64": WRITE => %d/%"GF_PRI_SIZET",%"PRId64"/%"PRId64,                          frame->root->unique,                          op_ret, state->size, state->off, stbuf->st_size); -                fuse_reply_write (req, op_ret); +                fwo.size = op_ret; +                send_fuse_obj (this, finh, &fwo);          } else {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRId64": WRITE => -1 (%s)", frame->root->unique, +                        "%"PRIu64": WRITE => -1 (%s)", frame->root->unique,                          strerror (op_errno)); -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);          }          free_state (state); @@ -1584,33 +1750,40 @@ fuse_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  static void -fuse_write (fuse_req_t req, fuse_ino_t ino, const char *buf, -            size_t size, off_t off, -            struct fuse_file_info *fi) +fuse_write (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        /* WRITE is special, metadata is attached to in_header, +         * and msg is the payload as-is. +         */ +        struct fuse_write_in *fwi = (struct fuse_write_in *) +                                      (finh + 1); + +        fuse_private_t  *priv = NULL;          fuse_state_t    *state = NULL;          struct iovec     vector;          fd_t            *fd = NULL;          struct iobref   *iobref = NULL;          struct iobuf    *iobuf = NULL; -        STATE_FROM_REQ (req, state); -        state->size = size; -        state->off  = off; -        fd          = FI_TO_FD (fi); +        priv = this->private; + +        GET_STATE (this, finh, state); +        state->size = fwi->size; +        state->off  = fwi->offset; +        fd          = FH_TO_FD (fwi->fh);          state->fd   = fd; -        vector.iov_base = (void *)buf; -        vector.iov_len  = size; +        vector.iov_base = msg; +        vector.iov_len  = fwi->size;          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": WRITE (%p, size=%"GF_PRI_SIZET", offset=%"PRId64")", -                req_callid (req), fd, size, off); +                "%"PRIu64": WRITE (%p, size=%"PRIu32", offset=%"PRId64")", +                finh->unique, fd, fwi->size, fwi->offset);          iobref = iobref_new ();          if (!iobref) { -                gf_log("glusterfs-fuse", GF_LOG_ERROR, -                       "%"PRIu64": WRITE iobref allocation failed", -                       req_callid (req)); +                gf_log ("glusterfs-fuse", GF_LOG_ERROR, +                        "%"PRIu64": WRITE iobref allocation failed", +                        finh->unique);                  free_state (state);                  return; @@ -1619,7 +1792,7 @@ fuse_write (fuse_req_t req, fuse_ino_t ino, const char *buf,          iobref_add (iobref, iobuf);          FUSE_FOP (state, fuse_writev_cbk, GF_FOP_WRITE, -                  writev, fd, &vector, 1, off, iobref); +                  writev, fd, &vector, 1, fwi->offset, iobref);          iobref_unref (iobref);          return; @@ -1627,17 +1800,19 @@ fuse_write (fuse_req_t req, fuse_ino_t ino, const char *buf,  static void -fuse_flush (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +fuse_flush (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_flush_in *ffi = msg; +          fuse_state_t *state = NULL;          fd_t         *fd = NULL; -        STATE_FROM_REQ (req, state); -        fd = FI_TO_FD (fi); +        GET_STATE (this, finh, state); +        fd = FH_TO_FD (ffi->fh);          state->fd = fd;          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": FLUSH %p", req_callid (req), fd); +                "%"PRIu64": FLUSH %p", finh->unique, fd);          FUSE_FOP (state, fuse_err_cbk, GF_FOP_FLUSH,                    flush, fd); @@ -1647,19 +1822,21 @@ fuse_flush (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)  static void -fuse_release (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +fuse_release (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_release_in *fri = msg; +          fuse_state_t *state = NULL; -        STATE_FROM_REQ (req, state); -        state->fd = FI_TO_FD (fi); +        GET_STATE (this, finh, state); +        state->fd = FH_TO_FD (fri->fh);          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": RELEASE %p", req_callid (req), state->fd); +                "%"PRIu64": RELEASE %p", finh->unique, state->fd);          fd_unref (state->fd); -        fuse_reply_err (req, 0); +        send_fuse_err (this, finh, 0);          free_state (state);          return; @@ -1667,51 +1844,57 @@ fuse_release (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)  static void -fuse_fsync (fuse_req_t req, fuse_ino_t ino, int datasync, -            struct fuse_file_info *fi) +fuse_fsync (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_fsync_in *fsi = msg; +          fuse_state_t *state = NULL;          fd_t         *fd = NULL; -        STATE_FROM_REQ (req, state); -        fd = FI_TO_FD (fi); +        GET_STATE (this, finh, state); +        fd = FH_TO_FD (fsi->fh);          state->fd = fd;          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": FSYNC %p", req_callid (req), fd); +                "%"PRIu64": FSYNC %p", finh->unique, fd); +        /* fsync_flags: 1 means "datasync" (no defines for this) */          FUSE_FOP (state, fuse_err_cbk, GF_FOP_FSYNC, -                  fsync, fd, datasync); +                  fsync, fd, fsi->fsync_flags & 1);          return;  }  static void -fuse_opendir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +fuse_opendir (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        /* +        struct fuse_open_in *foi = msg; +         */ +          fuse_state_t *state = NULL;          fd_t         *fd = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); -        ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +        GET_STATE (this, finh, state); +        ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "%"PRIu64": OPENDIR %s (fuse_loc_fill() failed)", -                        req_callid (req), state->loc.path); +                        finh->unique, state->loc.path); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          } -        fd = fd_create (state->loc.inode, get_pid_from_req (req)); +        fd = fd_create (state->loc.inode, finh->pid);          state->fd = fd;          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": OPENDIR %s", req_callid (req), +                "%"PRIu64": OPENDIR %s", finh->unique,                  state->loc.path);          FUSE_FOP (state, fuse_fd_cbk, GF_FOP_OPENDIR, @@ -1724,53 +1907,54 @@ fuse_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                    int32_t op_ret, int32_t op_errno, gf_dirent_t *entries)  {          fuse_state_t *state = NULL; -        fuse_req_t    req = NULL; +        fuse_in_header_t *finh = NULL;          int           size = 0; -        int           entry_size = 0;          char         *buf = NULL;          gf_dirent_t  *entry = NULL; -        struct stat   stbuf = {0, }; +        struct fuse_dirent *fde = NULL;          state = frame->root->state; -        req   = state->req; +        finh  = state->finh;          if (op_ret < 0) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRId64": READDIR => -1 (%s)", frame->root->unique, +                        "%"PRIu64": READDIR => -1 (%s)", frame->root->unique,                          strerror (op_errno)); -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);                  goto out;          }          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRId64": READDIR => %d/%"GF_PRI_SIZET",%"PRId64, +                "%"PRIu64": READDIR => %d/%"GF_PRI_SIZET",%"PRId64,                  frame->root->unique, op_ret, state->size, state->off);          list_for_each_entry (entry, &entries->list, list) { -                size += fuse_dirent_size (strlen (entry->d_name)); +                size += FUSE_DIRENT_ALIGN (FUSE_NAME_OFFSET + +                                           strlen (entry->d_name));          }          buf = CALLOC (1, size);          if (!buf) {                  gf_log ("glusterfs-fuse", GF_LOG_DEBUG, -                        "%"PRId64": READDIR => -1 (%s)", frame->root->unique, +                        "%"PRIu64": READDIR => -1 (%s)", frame->root->unique,                          strerror (ENOMEM)); -                fuse_reply_err (req, ENOMEM); +                send_fuse_err (this, finh, ENOMEM);                  goto out;          }          size = 0;          list_for_each_entry (entry, &entries->list, list) { -                stbuf.st_ino = entry->d_ino; -                entry_size = fuse_dirent_size (strlen (entry->d_name)); -                fuse_add_direntry (req, buf + size, entry_size, -                                   entry->d_name, &stbuf, -                                   entry->d_off); -                size += entry_size; +                fde = (struct fuse_dirent *)(buf + size); +                fde->ino = entry->d_ino; +                fde->off = entry->d_off; +                fde->type = entry->d_type; +                fde->namelen = strlen (entry->d_name); +                strncpy (fde->name, entry->d_name, fde->namelen); +                size += FUSE_DIRENT_SIZE (fde);          } -        fuse_reply_buf (req, (void *)buf, size); +        send_fuse_data (this, finh, buf, size);  out:          free_state (state); @@ -1783,41 +1967,44 @@ out:  static void -fuse_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, -              struct fuse_file_info *fi) +fuse_readdir (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_read_in *fri = msg; +          fuse_state_t *state = NULL;          fd_t         *fd = NULL; -        STATE_FROM_REQ (req, state); -        state->size = size; -        state->off = off; -        fd = FI_TO_FD (fi); +        GET_STATE (this, finh, state); +        state->size = fri->size; +        state->off = fri->offset; +        fd = FH_TO_FD (fri->fh);          state->fd = fd;          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": READDIR (%p, size=%"GF_PRI_SIZET", offset=%"PRId64")", -                req_callid (req), fd, size, off); +                "%"PRIu64": READDIR (%p, size=%"PRIu32", offset=%"PRId64")", +                finh->unique, fd, fri->size, fri->offset);          FUSE_FOP (state, fuse_readdir_cbk, GF_FOP_READDIR, -                  readdir, fd, size, off); +                  readdir, fd, fri->size, fri->offset);  }  static void -fuse_releasedir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +fuse_releasedir (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_release_in *fri = msg; +          fuse_state_t *state = NULL; -        STATE_FROM_REQ (req, state); -        state->fd = FI_TO_FD (fi); +        GET_STATE (this, finh, state); +        state->fd = FH_TO_FD (fri->fh);          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": RELEASEDIR %p", req_callid (req), state->fd); +                "%"PRIu64": RELEASEDIR %p", finh->unique, state->fd);          fd_unref (state->fd); -        fuse_reply_err (req, 0); +        send_fuse_err (this, finh, 0);          free_state (state); @@ -1826,19 +2013,20 @@ fuse_releasedir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)  static void -fuse_fsyncdir (fuse_req_t req, fuse_ino_t ino, int datasync, -               struct fuse_file_info *fi) +fuse_fsyncdir (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_fsync_in *fsi = msg; +          fuse_state_t *state = NULL;          fd_t         *fd = NULL; -        fd = FI_TO_FD (fi); +        fd = FH_TO_FD (fsi->fh); -        STATE_FROM_REQ (req, state); +        GET_STATE (this, finh, state);          state->fd = fd;          FUSE_FOP (state, fuse_err_cbk, GF_FOP_FSYNCDIR, -                  fsyncdir, fd, datasync); +                  fsyncdir, fd, fsi->fsync_flags & 1);          return;  } @@ -1849,10 +2037,13 @@ fuse_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                   int32_t op_ret, int32_t op_errno, struct statvfs *buf)  {          fuse_state_t *state = NULL; -        fuse_req_t    req = NULL; +        fuse_in_header_t *finh = NULL; +        fuse_private_t   *priv = NULL; +        struct fuse_statfs_out fso = {{0, }, };          state = frame->root->state; -        req   = state->req; +        priv  = this->private; +        finh  = state->finh;          /*            Filesystems (like ZFS on solaris) reports            different ->f_frsize and ->f_bsize. Old coreutils @@ -1881,13 +2072,23 @@ fuse_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                  buf->f_frsize = buf->f_bsize =this->ctx->page_size;  #endif /* GF_DARWIN_HOST_OS */ -                fuse_reply_statfs (req, buf); - +                fso.st.bsize   = buf->f_bsize; +                fso.st.frsize  = buf->f_frsize; +                fso.st.blocks  = buf->f_blocks; +                fso.st.bfree   = buf->f_bfree; +                fso.st.bavail  = buf->f_bavail; +                fso.st.files   = buf->f_files; +                fso.st.ffree   = buf->f_ffree; +                fso.st.namelen = buf->f_namemax; + +                priv->proto_minor >= 4 ? +                send_fuse_obj (this, finh, &fso) : +                send_fuse_data (this, finh, &fso, FUSE_COMPAT_STATFS_SIZE);          } else {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRId64": ERR => -1 (%s)", frame->root->unique, +                        "%"PRIu64": ERR => -1 (%s)", frame->root->unique,                          strerror (op_errno)); -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);          }          free_state (state); @@ -1898,26 +2099,26 @@ fuse_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  static void -fuse_statfs (fuse_req_t req, fuse_ino_t ino) +fuse_statfs (xlator_t *this, fuse_in_header_t *finh, void *msg)  {          fuse_state_t *state = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); +        GET_STATE (this, finh, state);          ret = fuse_loc_fill (&state->loc, state, 1, 0, NULL);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING,                          "%"PRIu64": STATFS (fuse_loc_fill() fail)", -                        req_callid (req)); +                        finh->unique); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          }          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": STATFS", req_callid (req)); +                "%"PRIu64": STATFS", finh->unique);          FUSE_FOP (state, fuse_statfs_cbk, GF_FOP_STATFS,                    statfs, &state->loc); @@ -1925,77 +2126,84 @@ fuse_statfs (fuse_req_t req, fuse_ino_t ino)  static void -fuse_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name, -               const char *value, size_t size, int flags) +fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_setxattr_in *fsi = msg; +        char         *name = (char *)(fsi + 1); +        char         *value = name + strlen (name) + 1; +          fuse_state_t *state = NULL;          char         *dict_value = NULL;          int32_t       ret = -1;  #ifdef DISABLE_POSIX_ACL          if (!strncmp (name, "system.", 7)) { -                fuse_reply_err (req, EOPNOTSUPP); +                send_fuse_err (this, finh, EOPNOTSUPP);                  return;          }  #endif -        STATE_FROM_REQ (req, state); -        state->size = size; -        ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +        GET_STATE (this, finh, state); +        state->size = fsi->size; +        ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRIu64": SETXATTR %s/%"PRId64" (%s) (fuse_loc_fill() failed)", -                        req_callid (req), -                        state->loc.path, (int64_t)ino, name); +                        "%"PRIu64": SETXATTR %s/%"PRIu64" (%s) (fuse_loc_fill() failed)", +                        finh->unique, +                        state->loc.path, finh->nodeid, name); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          }          state->dict = get_new_dict ();          if (!state->dict) { -                gf_log("glusterfs-fuse", GF_LOG_ERROR, -                       "%"PRIu64": SETXATTR dict allocation failed", -                       req_callid (req)); +                gf_log ("glusterfs-fuse", GF_LOG_ERROR, +                        "%"PRIu64": SETXATTR dict allocation failed", +                        finh->unique);                  free_state (state);                  return;          } -        dict_value = memdup (value, size); +        dict_value = memdup (value, fsi->size);          dict_set (state->dict, (char *)name, -                  data_from_dynptr ((void *)dict_value, size)); +                  data_from_dynptr ((void *)dict_value, fsi->size));          dict_ref (state->dict);          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": SETXATTR %s/%"PRId64" (%s)", req_callid (req), -                state->loc.path, (int64_t)ino, name); +                "%"PRIu64": SETXATTR %s/%"PRIu64" (%s)", finh->unique, +                state->loc.path, finh->nodeid, name);          FUSE_FOP (state, fuse_err_cbk, GF_FOP_SETXATTR, -                  setxattr, &state->loc, state->dict, flags); +                  setxattr, &state->loc, state->dict, fsi->flags);          return;  }  static void -fuse_reply_xattr_buf (fuse_state_t *state, fuse_req_t req, const char *value, -                     size_t ret) +send_fuse_xattr (xlator_t *this, fuse_in_header_t *finh, const char *value, +                 size_t size, size_t expected)  { +        struct fuse_getxattr_out fgxo; +          /* linux kernel limits the size of xattr value to 64k */ -        if (ret > GLUSTERFS_XATTR_LEN_MAX) -                fuse_reply_err (req, E2BIG); -        else if (state->size) { +        if (size > GLUSTERFS_XATTR_LEN_MAX) +                send_fuse_err (this, finh, E2BIG); +        else if (expected) {                  /* if callback for getxattr and asks for value */ -                if (ret > state->size) +                if (size > expected)                          /* reply would be bigger than                           * what was asked by kernel */ -                        fuse_reply_err (req, ERANGE); +                        send_fuse_err (this, finh, ERANGE);                  else -                        fuse_reply_buf (req, value, ret); -        } else -                fuse_reply_xattr (req, ret); +                        send_fuse_data (this, finh, (void *)value, size); +        } else { +                fgxo.size = size; +                send_fuse_obj (this, finh, &fgxo); +        }  }  static int @@ -2005,7 +2213,7 @@ fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,          int             need_to_free_dict = 0;          char           *value = "";          fuse_state_t   *state = NULL; -        fuse_req_t      req = NULL; +        fuse_in_header_t *finh = NULL;          int32_t         dummy_ret = 0;          data_t         *value_data = NULL;          fuse_private_t *priv = NULL; @@ -2019,7 +2227,7 @@ fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,          priv  = this->private;          ret   = op_ret;          state = frame->root->state; -        req   = state->req; +        finh  = state->finh;          dummy_ret = 0;  #ifdef GF_DARWIN_HOST_OS @@ -2048,7 +2256,7 @@ fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,          if (ret >= 0) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": %s() %s => %d", frame->root->unique, +                        "%"PRIu64": %s() %s => %d", frame->root->unique,                          gf_fop_list[frame->root->op], state->loc.path, op_ret);                  /* if successful */ @@ -2059,7 +2267,7 @@ fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                                  ret = value_data->len; /* Don't return the value for '\0' */                                  value = value_data->data; -                                fuse_reply_xattr_buf (state, req, value, ret); +                                send_fuse_xattr (this, finh, value, ret, state->size);                                  /* if(ret >...)...else if...else */                          }  else if (!strcmp (state->name, "user.glusterfs-booster-volfile")) {                                  if (!priv->volfile) { @@ -2070,7 +2278,7 @@ fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                                                  gf_log (this->name,                                                          GF_LOG_ERROR,                                                          "fstat on fd (%d) failed (%s)", fd, strerror (errno)); -                                                fuse_reply_err (req, ENODATA); +                                                send_fuse_err (this, finh, ENODATA);                                          }                                          priv->volfile_size = st.st_size; @@ -2081,16 +2289,17 @@ fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                                          }                                  } -                                fuse_reply_xattr_buf (state, req, priv->volfile, priv->volfile_size); +                                send_fuse_xattr (this, finh, priv->volfile, +                                                 priv->volfile_size, state->size);                                  /* if(ret >...)...else if...else */                          } else if (!strcmp (state->name, "user.glusterfs-booster-path")) { -                                fuse_reply_xattr_buf (state, req, state->loc.path, -                                                      strlen (state->loc.path) + 1); +                                send_fuse_xattr (this, finh, state->loc.path, +                                                 strlen (state->loc.path) + 1, state->size);                          } else if (!strcmp (state->name, "user.glusterfs-booster-mount")) { -                                fuse_reply_xattr_buf (state, req, priv->mount_point, -                                                      strlen(priv->mount_point) + 1); +                                send_fuse_xattr (this, finh, priv->mount_point, +                                                 strlen (priv->mount_point) + 1, state->size);                          } else { -                                fuse_reply_err (req, ENODATA); +                                send_fuse_err (this, finh, ENODATA);                          } /* if(value_data)...else */                  } else {                          /* if callback for listxattr */ @@ -2109,7 +2318,7 @@ fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                                  len += strlen (trav->key) + 1;                                  trav = trav->next;                          } /* while(trav) */ -                        fuse_reply_xattr_buf (state, req, value, len); +                        send_fuse_xattr (this, finh, value, len, state->size);                  } /* if(state->name)...else */          } else {                  /* if failure - no need to check if listxattr or getxattr */ @@ -2126,20 +2335,20 @@ fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                          else                          {                                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                                        "%"PRId64": %s() %s => -1 (%s)", +                                        "%"PRIu64": %s() %s => -1 (%s)",                                          frame->root->unique,                                          gf_fop_list[frame->root->op],                                          state->loc.path, strerror (op_errno));                          }                  } else {                          gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                                "%"PRId64": %s() %s => -1 (%s)", +                                "%"PRIu64": %s() %s => -1 (%s)",                                  frame->root->unique,                                  gf_fop_list[frame->root->op], state->loc.path,                                  strerror (op_errno));                  } /* if(op_errno!= ENODATA)...else */ -                fuse_reply_err (req, op_errno); +                send_fuse_err (this, finh, op_errno);          } /* if(op_ret>=0)...else */          if (need_to_free_dict) @@ -2153,37 +2362,40 @@ fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  static void -fuse_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) +fuse_getxattr (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_getxattr_in *fgxi = msg; +        char         *name = (char *)(msg + 1); +          fuse_state_t *state = NULL;          int32_t       ret = -1;  #ifdef DISABLE_POSIX_ACL          if (!strncmp (name, "system.", 7)) { -                fuse_reply_err (req, ENODATA); +                send_fuse_err (this, finh, ENODATA);                  return;          }  #endif -        STATE_FROM_REQ (req, state); -        state->size = size; +        GET_STATE (this, finh, state); +        state->size = fgxi->size;          state->name = strdup (name); -        ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +        ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRIu64": GETXATTR %s/%"PRId64" (%s) (fuse_loc_fill() failed)", -                        req_callid (req), state->loc.path, (int64_t)ino, name); +                        "%"PRIu64": GETXATTR %s/%"PRIu64" (%s) (fuse_loc_fill() failed)", +                        finh->unique, state->loc.path, finh->nodeid, name); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          }          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": GETXATTR %s/%"PRId64" (%s)", req_callid (req), -                state->loc.path, (int64_t)ino, name); +                "%"PRIu64": GETXATTR %s/%"PRIu64" (%s)", finh->unique, +                state->loc.path, finh->nodeid, name);          FUSE_FOP (state, fuse_xattr_cbk, GF_FOP_GETXATTR,                    getxattr, &state->loc, name); @@ -2193,28 +2405,30 @@ fuse_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)  static void -fuse_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size) +fuse_listxattr (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_getxattr_in *fgxi = msg; +          fuse_state_t *state = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); -        state->size = size; -        ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +        GET_STATE (this, finh, state); +        state->size = fgxi->size; +        ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                        "%"PRIu64": LISTXATTR %s/%"PRId64" (fuse_loc_fill() failed)", -                        req_callid (req), state->loc.path, (int64_t)ino); +                        "%"PRIu64": LISTXATTR %s/%"PRIu64" (fuse_loc_fill() failed)", +                        finh->unique, state->loc.path, finh->nodeid); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          }          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": LISTXATTR %s/%"PRId64, req_callid (req), -                state->loc.path, (int64_t)ino); +                "%"PRIu64": LISTXATTR %s/%"PRIu64, finh->unique, +                state->loc.path, finh->nodeid);          FUSE_FOP (state, fuse_xattr_cbk, GF_FOP_GETXATTR,                    getxattr, &state->loc, NULL); @@ -2224,28 +2438,30 @@ fuse_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size)  static void -fuse_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name) +fuse_removexattr (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        char *name = msg; +          fuse_state_t *state = NULL;          int32_t       ret = -1; -        STATE_FROM_REQ (req, state); -        ret = fuse_loc_fill (&state->loc, state, ino, 0, NULL); +        GET_STATE (this, finh, state); +        ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL);          if ((state->loc.inode == NULL) ||              (ret < 0)) {                  gf_log ("glusterfs-fuse", GF_LOG_DEBUG, -                        "%"PRIu64": REMOVEXATTR %s/%"PRId64" (%s) (fuse_loc_fill() failed)", -                        req_callid (req), state->loc.path, (int64_t)ino, name); +                        "%"PRIu64": REMOVEXATTR %s/%"PRIu64" (%s) (fuse_loc_fill() failed)", +                        finh->unique, state->loc.path, finh->nodeid, name); -                fuse_reply_err (req, ENOENT); +                send_fuse_err (this, finh, ENOENT);                  free_state (state);                  return;          }          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": REMOVEXATTR %s/%"PRId64" (%s)", req_callid (req), -                state->loc.path, (int64_t)ino, name); +                "%"PRIu64": REMOVEXATTR %s/%"PRIu64" (%s)", finh->unique, +                state->loc.path, finh->nodeid, name);          FUSE_FOP (state, fuse_err_cbk, GF_FOP_REMOVEXATTR,                    removexattr, &state->loc, name); @@ -2263,11 +2479,22 @@ fuse_getlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,          fuse_state_t *state = NULL;          state = frame->root->state; +        struct fuse_lk_out flo = {{0, }, };          if (op_ret == 0) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": ERR => 0", frame->root->unique); -                fuse_reply_lock (state->req, lock); +                        "%"PRIu64": ERR => 0", frame->root->unique); +                flo.lk.type = lock->l_type; +                flo.lk.pid  = lock->l_pid; +                if (lock->l_type == F_UNLCK) +                        flo.lk.start = flo.lk.end = 0; +                else { +                        flo.lk.start = lock->l_start; +                        flo.lk.end = lock->l_len ? +                                     (lock->l_start + lock->l_len - 1) : +                                     OFFSET_MAX; +                } +                send_fuse_obj (this, state->finh, &flo);          } else {                  if (op_errno == ENOSYS) {                          gf_fuse_lk_enosys_log++; @@ -2279,10 +2506,10 @@ fuse_getlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                          }                  } else {                          gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                                "%"PRId64": ERR => -1 (%s)", +                                "%"PRIu64": ERR => -1 (%s)",                                  frame->root->unique, strerror (op_errno));                  } -                fuse_reply_err (state->req, op_errno); +                send_fuse_err (this, state->finh, op_errno);          }          free_state (state); @@ -2293,22 +2520,24 @@ fuse_getlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  static void -fuse_getlk (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, -            struct flock *lock) +fuse_getlk (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_lk_in *fli = msg; +          fuse_state_t *state = NULL;          fd_t         *fd = NULL; +        struct flock  lock = {0, }; -        fd = FI_TO_FD (fi); -        STATE_FROM_REQ (req, state); -        state->req = req; +        fd = FH_TO_FD (fli->fh); +        GET_STATE (this, finh, state);          state->fd = fd; +        convert_fuse_file_lock (&fli->lk, &lock);          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": GETLK %p", req_callid (req), fd); +                "%"PRIu64": GETLK %p", finh->unique, fd);          FUSE_FOP (state, fuse_getlk_cbk, GF_FOP_LK, -                  lk, fd, F_GETLK, lock); +                  lk, fd, F_GETLK, &lock);          return;  } @@ -2324,8 +2553,8 @@ fuse_setlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,          if (op_ret == 0) {                  gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                        "%"PRId64": ERR => 0", frame->root->unique); -                fuse_reply_err (state->req, 0); +                        "%"PRIu64": ERR => 0", frame->root->unique); +                send_fuse_err (this, state->finh, 0);          } else {                  if (op_errno == ENOSYS) {                          gf_fuse_lk_enosys_log++; @@ -2335,13 +2564,13 @@ fuse_setlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                                          "'features/posix-locks' on server side "                                          "will add SETLK support.");                          } -                } else  if (op_errno != EAGAIN) { -                        gf_log ("glusterfs-fuse", GF_LOG_ERROR, -                                "%"PRId64": ERR => -1 (%s)", +                } else  { +                        gf_log ("glusterfs-fuse", GF_LOG_WARNING, +                                "%"PRIu64": ERR => -1 (%s)",                                  frame->root->unique, strerror (op_errno));                  } -                fuse_reply_err (state->req, op_errno); +                send_fuse_err (this, state->finh, op_errno);          }          free_state (state); @@ -2352,77 +2581,111 @@ fuse_setlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this,  static void -fuse_setlk (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, -            struct flock *lock, int sleep) +fuse_setlk (xlator_t *this, fuse_in_header_t *finh, void *msg)  { +        struct fuse_lk_in *fli = msg; +          fuse_state_t *state = NULL;          fd_t         *fd = NULL; +        struct flock  lock = {0, }; -        fd = FI_TO_FD (fi); -        STATE_FROM_REQ (req, state); -        state->req = req; +        fd = FH_TO_FD (fli->fh); +        GET_STATE (this, finh, state); +        state->finh = finh;          state->fd = fd; +        convert_fuse_file_lock (&fli->lk, &lock);          gf_log ("glusterfs-fuse", GF_LOG_TRACE, -                "%"PRIu64": SETLK %p (sleep=%d)", req_callid (req), fd, -                sleep); +                "%"PRIu64": SETLK%s %p", finh->unique, +                finh->opcode == FUSE_SETLK ? "" : "W", fd);          FUSE_FOP (state, fuse_setlk_cbk, GF_FOP_LK, -                  lk, fd, (sleep ? F_SETLKW : F_SETLK), lock); +                  lk, fd, finh->opcode == FUSE_SETLK ? F_SETLK : F_SETLKW, +                  &lock);          return;  }  static void -fuse_init (void *data, struct fuse_conn_info *conn) +fuse_init (xlator_t *this, fuse_in_header_t *finh, void *msg)  { -        return; +        struct fuse_init_in *fini = msg; + +        struct fuse_init_out fino; +        fuse_private_t *priv = NULL; +        int ret; + +        priv = this->private; + +        if (!priv->first_call) { +                gf_log ("glusterfs-fuse", GF_LOG_ERROR, +                        "got INIT after first message"); + +                close (priv->fd); +                goto out; +        } + +        if (fini->major != FUSE_KERNEL_VERSION) { +                gf_log ("glusterfs-fuse", GF_LOG_ERROR, +                        "unsupported FUSE protocol version %d.%d", +                        fini->major, fini->minor); + +                close (priv->fd); +                goto out; +        } +        priv->proto_minor = fini->minor; + +        fino.major = FUSE_KERNEL_VERSION; +        fino.minor = FUSE_KERNEL_MINOR_VERSION; +        fino.max_readahead = 1 << 17; +        fino.max_write = 1 << 17; +        fino.flags = FUSE_ASYNC_READ | FUSE_POSIX_LOCKS; +        if (fini->minor >= 6 /* fuse_init_in has flags */ && +            fini->flags & FUSE_BIG_WRITES) { +                /* no need for direct I/O mode if big writes are supported */ +                priv->direct_io_mode = 0; +                fino.flags |= FUSE_BIG_WRITES; +        } +        if (fini->minor < 9) +                *priv->msg0_len_p = sizeof(*finh) + FUSE_COMPAT_WRITE_IN_SIZE; + +        ret = send_fuse_obj (this, finh, &fino); +        if (ret == 0) +                gf_log ("glusterfs-fuse", GF_LOG_INFO, +                        "FUSE inited with protocol versions:" +                        " glusterfs %d.%d kernel %d.%d", +                        FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION, +                        fini->major, fini->minor); +        else { +                gf_log ("glusterfs-fuse", GF_LOG_ERROR, +                        "FUSE init failed (%s)", strerror (ret)); + +                close (priv->fd); +        } + + out: +        FREE (finh);  } +  static void -fuse_destroy (void *data) -{ - -} - -static struct fuse_lowlevel_ops fuse_ops = { -        .init         = fuse_init, -        .destroy      = fuse_destroy, -        .lookup       = fuse_lookup, -        .forget       = fuse_forget, -        .getattr      = fuse_getattr, -        .setattr      = fuse_setattr, -        .opendir      = fuse_opendir, -        .readdir      = fuse_readdir, -        .releasedir   = fuse_releasedir, -        .access       = fuse_access, -        .readlink     = fuse_readlink, -        .mknod        = fuse_mknod, -        .mkdir        = fuse_mkdir, -        .unlink       = fuse_unlink, -        .rmdir        = fuse_rmdir, -        .symlink      = fuse_symlink, -        .rename       = fuse_rename, -        .link         = fuse_link, -        .create       = fuse_create, -        .open         = fuse_open, -        .read         = fuse_readv, -        .write        = fuse_write, -        .flush        = fuse_flush, -        .release      = fuse_release, -        .fsync        = fuse_fsync, -        .fsyncdir     = fuse_fsyncdir, -        .statfs       = fuse_statfs, -        .setxattr     = fuse_setxattr, -        .getxattr     = fuse_getxattr, -        .listxattr    = fuse_listxattr, -        .removexattr  = fuse_removexattr, -        .getlk        = fuse_getlk, -        .setlk        = fuse_setlk -}; +fuse_enosys (xlator_t *this, fuse_in_header_t *finh, void *msg) +{ +        send_fuse_err (this, finh, ENOSYS); + +        FREE (finh); +} +static void +fuse_discard (xlator_t *this, fuse_in_header_t *finh, void *msg) +{ +        FREE (finh); +} + +static fuse_handler_t *fuse_ops[FUSE_712_OP_HIGH]; +  int  fuse_root_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,                        int32_t op_ret, int32_t op_errno, @@ -2493,33 +2756,54 @@ fuse_root_lookup (xlator_t *this)  } +  static void *  fuse_thread_proc (void *data)  {          char           *mount_point = NULL;          xlator_t       *this = NULL;          fuse_private_t *priv = NULL; -        int32_t         res = 0; +        ssize_t         res = 0;          struct iobuf   *iobuf = NULL; -        size_t          chan_size = 0; +        fuse_in_header_t *finh; +        struct iovec iov_in[2]; +        void *msg = NULL; +        const size_t msg0_size = sizeof (*finh) + 128;          this = data;          priv = this->private; -        chan_size = fuse_chan_bufsize (priv->ch);          THIS = this; -        while (!fuse_session_exited (priv->se)) { +        iov_in[0].iov_len = sizeof (*finh) + sizeof (struct fuse_write_in); +        iov_in[1].iov_len = ((struct iobuf_pool *)this->ctx->iobuf_pool) +                              ->page_size; +        priv->msg0_len_p = &iov_in[0].iov_len; + +        for (;;) {                  iobuf = iobuf_get (this->ctx->iobuf_pool); +                /* Add extra 128 byte to the first iov so that it can +                 * accomodate "ordinary" non-write requests. It's not +                 * guaranteed to be big enough, as SETXATTR and namespace +                 * operations with very long names may grow behind it, +                 * but it's good enough in most cases (and we can handle +                 * rest via realloc). +                 */ +                iov_in[0].iov_base = CALLOC (1, msg0_size); -                if (!iobuf) { +                if (!iobuf || !iov_in[0].iov_base) {                          gf_log (this->name, GF_LOG_ERROR,                                  "Out of memory"); +                        if (iobuf) +                                iobuf_unref (iobuf); +                        FREE (iov_in[0].iov_base);                          sleep (10);                          continue;                  } -                res = fuse_chan_receive (priv->ch, iobuf->ptr, chan_size); +                iov_in[1].iov_base = iobuf->ptr; + +                res = readv (priv->fd, iov_in, 2);                  if (priv->first_call) {                          if (priv->first_call > 1) { @@ -2530,27 +2814,73 @@ fuse_thread_proc (void *data)                  }                  if (res == -1) { +                        if (errno == ENODEV || errno == EBADF) { +                                gf_log ("glusterfs-fuse", GF_LOG_NORMAL, +                                        "terminating upon getting %s when " +                                        "reading /dev/fuse", +                                        errno == ENODEV ? "ENODEV" : "EBADF"); + +                                break; +                        }                          if (errno != EINTR) {                                  gf_log ("glusterfs-fuse", GF_LOG_WARNING, -                                        "fuse_chan_receive() returned -1 (%d)", errno); -                        } -                        if (errno == ENODEV) { -                                iobuf_unref (iobuf); -                                break; +                                        "read from /dev/fuse returned -1 (%s)", +                                        strerror (errno));                          } -                        continue; + +                        goto cont_err; +                } +                if (res < sizeof (finh)) { +                        gf_log ("glusterfs-fuse", GF_LOG_WARNING, "short read on /dev/fuse"); +                        break; +                } + +                finh = (fuse_in_header_t *)iov_in[0].iov_base; +                if (res != finh->len) { +                        gf_log ("glusterfs-fuse", GF_LOG_WARNING, "inconsistent read on /dev/fuse"); +                        break;                  }                  priv->iobuf = iobuf; -                if (res && res != -1) { -                        fuse_session_process (priv->se, iobuf->ptr, -                                              res, priv->ch); +                if (finh->opcode == FUSE_WRITE) +                        msg = iov_in[1].iov_base; +                else { +                        if (res > msg0_size) { +                                iov_in[0].iov_base = +                                  realloc (iov_in[0].iov_base, res); +                                if (iov_in[0].iov_base) +                                        finh = (fuse_in_header_t *) +                                                 iov_in[0].iov_base; +                                else { +                                        gf_log ("glusterfs-fuse", GF_LOG_ERROR, +                                                "Out of memory"); +                                        send_fuse_err (this, finh, ENOMEM); + +                                        goto cont_err; +                                } +                        } + +                        if (res > iov_in[0].iov_len) +                                memcpy (iov_in[0].iov_base + iov_in[0].iov_len, +                                        iov_in[1].iov_base, +                                        res - iov_in[0].iov_len); + +                        msg = finh + 1;                  } +                fuse_ops[finh->opcode] (this, finh, msg);                  iobuf_unref (iobuf); +                continue; + + cont_err: +                iobuf_unref (iobuf); +                FREE (iov_in[0].iov_base);          } +        iobuf_unref (iobuf); +        FREE (iov_in[0].iov_base); +          if (dict_get (this->options, ZR_MOUNTPOINT_OPT))                  mount_point = data_to_str (dict_get (this->options,                                                       ZR_MOUNTPOINT_OPT)); @@ -2560,10 +2890,6 @@ fuse_thread_proc (void *data)                  dict_del (this->options, ZR_MOUNTPOINT_OPT);          } -        fuse_session_remove_chan (priv->ch); -        fuse_session_destroy (priv->se); -        //  fuse_unmount (priv->mount_point, priv->ch); -          raise (SIGTERM);          return NULL; @@ -2628,18 +2954,6 @@ notify (xlator_t *this, int32_t event, void *data, ...)          return 0;  } -static struct fuse_opt subtype_workaround[] = { -        FUSE_OPT_KEY ("subtype=", 0), -        FUSE_OPT_KEY ("fssubtype=", 0), -        FUSE_OPT_END -}; - -static int -subtype_workaround_optproc (void *data, const char *arg, int key, -                           struct fuse_args *outargs) -{ -        return key ? 1 : 0; -}  int  init (xlator_t *this_xl) @@ -2648,10 +2962,9 @@ init (xlator_t *this_xl)          dict_t            *options = NULL;          char              *value_string = NULL;          char              *fsname = NULL; -        char              *fsname_opt = NULL;          fuse_private_t    *priv = NULL;          struct stat        stbuf = {0,}; -        struct fuse_args   args = FUSE_ARGS_INIT (0, NULL); +        int                i = 0;          int                xl_name_allocated = 0;          if (this_xl == NULL) @@ -2665,78 +2978,24 @@ init (xlator_t *this_xl)          if (this_xl->name == NULL) {                  this_xl->name = strdup ("fuse");                  if (!this_xl->name) { -                        gf_log("glusterfs-fuse", GF_LOG_ERROR, -                               "Out of memory"); +                        gf_log ("glusterfs-fuse", GF_LOG_ERROR, +                                "Out of memory");                          goto cleanup_exit;                  }                  xl_name_allocated = 1;          } -        fsname = this_xl->ctx->cmd_args.volume_file; -        fsname = (fsname ? fsname : this_xl->ctx->cmd_args.volfile_server); -        fsname = (fsname ? fsname : "glusterfs"); -        ret = asprintf (&fsname_opt, "-ofsname=%s", fsname); - -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "glusterfs"); -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, fsname_opt); -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "-oallow_other"); -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "-odefault_permissions"); -#ifdef GF_DARWIN_HOST_OS -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "-ofssubtype=glusterfs"); -        if (ret != -1 && !dict_get (options, "macfuse-local")) -                /* This way, GlusterFS will be detected as 'servers' instead -                 *  of 'devices'. This method is useful if you want to do -                 * 'umount <mount_point>' over network,  instead of 'eject'ing -                 * it from desktop. Works better for servers -                 */ -                ret = fuse_opt_add_arg (&args, "-olocal"); -#else /* ! DARWIN_OS */ -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "-osubtype=glusterfs"); -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "-omax_readahead=131072"); -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "-omax_read=131072"); -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "-omax_write=131072"); -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "-osuid"); -#if GF_LINUX_HOST_OS /* LINUX */ -        /* '-o dev', '-o nonempty' is supported only on Linux */ -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "-ononempty"); -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "-odev"); -#ifdef HAVE_FUSE_VERSION_28 -        if (ret != -1) -                ret = fuse_opt_add_arg (&args, "-obig_writes"); -#endif /* FUSE 2.8 */ - -#endif /* LINUX */ -#endif /* ! DARWIN_OS */ - -        if (ret == -1) { -                gf_log("glusterfs-fuse", GF_LOG_ERROR, -                       "Out of memory"); - -                goto cleanup_exit; -        } -          priv = CALLOC (1, sizeof (*priv));          if (!priv) { -                gf_log("glusterfs-fuse", GF_LOG_ERROR, -                       "Out of memory"); +                gf_log ("glusterfs-fuse", GF_LOG_ERROR, +                        "Out of memory");                  goto cleanup_exit;          }          this_xl->private = (void *) priv;          priv->mount_point = NULL; +        priv->fd = -1;          /* get options from option dictionary */          ret = dict_get_str (options, ZR_MOUNTPOINT_OPT, &value_string); @@ -2773,8 +3032,8 @@ init (xlator_t *this_xl)          }          priv->mount_point = strdup (value_string);          if (!priv->mount_point) { -                gf_log("glusterfs-fuse", GF_LOG_ERROR, -                       "Out of memory"); +                gf_log ("glusterfs-fuse", GF_LOG_ERROR, +                        "Out of memory");                  goto cleanup_exit;          } @@ -2803,102 +3062,74 @@ init (xlator_t *this_xl)                                           &priv->strict_volfile_check);          } +        fsname = this_xl->ctx->cmd_args.volume_file; +        fsname = (fsname ? fsname : this_xl->ctx->cmd_args.volfile_server); +        fsname = (fsname ? fsname : "glusterfs"); +          this_xl->itable = inode_table_new (0, this_xl);          if (!this_xl->itable) { -                gf_log("glusterfs-fuse", GF_LOG_ERROR, -                       "Out of memory"); +                gf_log ("glusterfs-fuse", GF_LOG_ERROR, +                        "Out of memory");                  goto cleanup_exit;          } -        priv->ch = fuse_mount (priv->mount_point, &args); -        if (priv->ch == NULL) { -                if (errno == ENOTCONN) { -                        gf_log ("glusterfs-fuse", GF_LOG_ERROR, -                                "A stale mount is present on %s. " -                                "Run 'umount %s' and try again", -                                priv->mount_point, -                                priv->mount_point); -                } else { -                        if (errno == ENOENT) { -                                gf_log ("glusterfs-fuse", GF_LOG_ERROR, -                                        "Unable to mount on %s. Run " -                                        "'modprobe fuse' and try again", -                                        priv->mount_point); -                        } else { -                                gf_log ("glusterfs-fuse", GF_LOG_DEBUG, -                                        "fuse_mount() failed with error %s " -                                        "on mount point %s", -                                        strerror (errno), -                                        priv->mount_point); -                        } -                } - +        priv->fd = gf_fuse_mount (priv->mount_point, fsname, +                                  "allow_other,default_permissions," +                                  "max_read=131072"); +        if (priv->fd == -1)                  goto cleanup_exit; -        } - -        errno = 0; - -        priv->se = fuse_lowlevel_new (&args, &fuse_ops, -                                      sizeof (fuse_ops), this_xl); -        if (priv->se == NULL && !errno) { -                /* -                 * Option parsing misery. Can happen if libfuse is of -                 * FUSE < 2.7.0, as then the "-o subtype" option is not -                 * handled. -                 * -                 * Best we can do to is to handle it at runtime -- this is not -                 * a binary incompatibility issue (which should dealt with at -                 * compile time), but a behavioural incompatibility issue. Ie. -                 * we can't tell in advance whether the lib we use supports -                 * "-o subtype". So try to be clever now. -                 * -                 * Delete the subtype option, and try again. -                 */ -                if (fuse_opt_parse (&args, NULL, subtype_workaround, -                                   subtype_workaround_optproc) == 0) -                        priv->se = fuse_lowlevel_new (&args, &fuse_ops, -                                                      sizeof (fuse_ops), -                                                      this_xl); -        } - -        if (priv->se == NULL) { -                gf_log ("glusterfs-fuse", GF_LOG_DEBUG, -                        "fuse_lowlevel_new() failed with error %s on " -                        "mount point %s", -                        strerror (errno), priv->mount_point); -                goto umount_exit; -        } - -        ret = fuse_set_signal_handlers (priv->se); -        if (ret == -1) { -                gf_log ("glusterfs-fuse", GF_LOG_DEBUG, -                        "fuse_set_signal_handlers() failed on mount point %s", -                        priv->mount_point); -                goto umount_exit; -        } - -        fuse_opt_free_args (&args); -        FREE (fsname_opt); - -        fuse_session_add_chan (priv->se, priv->ch); - -        priv->fd = fuse_chan_fd (priv->ch);          this_xl->ctx->top = this_xl;          priv->first_call = 2; + +        for (i = 0; i < FUSE_712_OP_HIGH; i++) +                fuse_ops[i] = fuse_enosys; +        fuse_ops[FUSE_INIT]        = fuse_init; +        fuse_ops[FUSE_DESTROY]     = fuse_discard; +        fuse_ops[FUSE_LOOKUP]      = fuse_lookup; +        fuse_ops[FUSE_FORGET]      = fuse_forget; +        fuse_ops[FUSE_GETATTR]     = fuse_getattr; +        fuse_ops[FUSE_SETATTR]     = fuse_setattr; +        fuse_ops[FUSE_OPENDIR]     = fuse_opendir; +        fuse_ops[FUSE_READDIR]     = fuse_readdir; +        fuse_ops[FUSE_RELEASEDIR]  = fuse_releasedir; +        fuse_ops[FUSE_ACCESS]      = fuse_access; +        fuse_ops[FUSE_READLINK]    = fuse_readlink; +        fuse_ops[FUSE_MKNOD]       = fuse_mknod; +        fuse_ops[FUSE_MKDIR]       = fuse_mkdir; +        fuse_ops[FUSE_UNLINK]      = fuse_unlink; +        fuse_ops[FUSE_RMDIR]       = fuse_rmdir; +        fuse_ops[FUSE_SYMLINK]     = fuse_symlink; +        fuse_ops[FUSE_RENAME]      = fuse_rename; +        fuse_ops[FUSE_LINK]        = fuse_link; +        fuse_ops[FUSE_CREATE]      = fuse_create; +        fuse_ops[FUSE_OPEN]        = fuse_open; +        fuse_ops[FUSE_READ]        = fuse_readv; +        fuse_ops[FUSE_WRITE]       = fuse_write; +        fuse_ops[FUSE_FLUSH]       = fuse_flush; +        fuse_ops[FUSE_RELEASE]     = fuse_release; +        fuse_ops[FUSE_FSYNC]       = fuse_fsync; +        fuse_ops[FUSE_FSYNCDIR]    = fuse_fsyncdir; +        fuse_ops[FUSE_STATFS]      = fuse_statfs; +        fuse_ops[FUSE_SETXATTR]    = fuse_setxattr; +        fuse_ops[FUSE_GETXATTR]    = fuse_getxattr; +        fuse_ops[FUSE_LISTXATTR]   = fuse_listxattr; +        fuse_ops[FUSE_REMOVEXATTR] = fuse_removexattr; +        fuse_ops[FUSE_GETLK]       = fuse_getlk; +        fuse_ops[FUSE_SETLK]       = fuse_setlk; +        fuse_ops[FUSE_SETLKW]      = fuse_setlk; +          return 0; -umount_exit: -        fuse_unmount (priv->mount_point, priv->ch);  cleanup_exit:          if (xl_name_allocated)                  FREE (this_xl->name); -        fuse_opt_free_args (&args); -        FREE (fsname_opt); -        if (priv) +        if (priv) {                  FREE (priv->mount_point); +                close (priv->fd); +        }          FREE (priv);          return -1;  } @@ -2924,8 +3155,7 @@ fini (xlator_t *this_xl)                          "Unmounting '%s'.", mount_point);                  dict_del (this_xl->options, ZR_MOUNTPOINT_OPT); -                fuse_session_exit (priv->se); -                fuse_unmount (mount_point, priv->ch); +                gf_fuse_unmount (mount_point, priv->fd);          }  } diff --git a/xlators/mount/fuse/src/fuse-extra.c b/xlators/mount/fuse/src/fuse-extra.c deleted file mode 100644 index 422ff4b563d..00000000000 --- a/xlators/mount/fuse/src/fuse-extra.c +++ /dev/null @@ -1,155 +0,0 @@ -/* -   Copyright (c) 2006-2009 Z RESEARCH, Inc. <http://www.zresearch.com> -   This file is part of GlusterFS. - -   GlusterFS is free software; you can redistribute it and/or modify -   it under the terms of the GNU General Public License as published -   by the Free Software Foundation; either version 3 of the License, -   or (at your option) any later version. - -   GlusterFS is distributed in the hope that it will be useful, but -   WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -   General Public License for more details. - -   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 _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif /* _CONFIG_H */ - -#include "fuse-extra.h" -#include "common-utils.h" -#include <stdio.h> -#include <pthread.h> -#include <stdlib.h> -#include <string.h> -#include "common-utils.h" - -struct fuse_req; -struct fuse_ll; - -struct fuse_req { -    struct fuse_ll *f; -    uint64_t unique; -    int ctr; -    pthread_mutex_t lock; -    struct fuse_ctx ctx; -    struct fuse_chan *ch; -    int interrupted; -    union { -        struct { -            uint64_t unique; -        } i; -        struct { -            fuse_interrupt_func_t func; -            void *data; -        } ni; -    } u; -    struct fuse_req *next; -    struct fuse_req *prev; -}; - -#ifdef HAVE_FUSE_VERSION_28 -struct fuse_ll { -    int debug; -    int allow_root; -    int atomic_o_trunc; -    int big_writes; -    struct fuse_lowlevel_ops op; -    int got_init; -    void *userdata; -    uid_t owner; -    struct fuse_conn_info conn; -    struct fuse_req list; -    struct fuse_req interrupts; -    pthread_mutex_t lock; -    int got_destroy; -}; -#else  -struct fuse_ll { -    int debug; -    int allow_root; -    struct fuse_lowlevel_ops op; -    int got_init; -    void *userdata; -    uid_t owner; -    struct fuse_conn_info conn; -    struct fuse_req list; -    struct fuse_req interrupts; -    pthread_mutex_t lock; -    int got_destroy; -}; -#endif /* FUSE 2.8 */ - -struct fuse_out_header { -  uint32_t   len; -  int32_t    error; -  uint64_t   unique; -}; - -uint64_t req_callid (fuse_req_t req) -{ -  return req->unique; -} - -static void destroy_req(fuse_req_t req) -{ -    pthread_mutex_destroy (&req->lock); -    FREE (req); -} - -static void list_del_req(struct fuse_req *req) -{ -    struct fuse_req *prev = req->prev; -    struct fuse_req *next = req->next; -    prev->next = next; -    next->prev = prev; -} - -static void -free_req (fuse_req_t req) -{ -  int ctr; -  struct fuse_ll *f = req->f; -   -  pthread_mutex_lock(&req->lock); -  req->u.ni.func = NULL; -  req->u.ni.data = NULL; -  pthread_mutex_unlock(&req->lock); - -  pthread_mutex_lock(&f->lock); -  list_del_req(req); -  ctr = --req->ctr; -  pthread_mutex_unlock(&f->lock); -  if (!ctr) -    destroy_req(req); -} - -int32_t -fuse_reply_vec (fuse_req_t req, -		struct iovec *vector, -		int32_t count) -{ -  int32_t error = 0; -  struct fuse_out_header out; -  struct iovec *iov; -  int res; - -  iov = alloca ((count + 1) * sizeof (*vector)); -  out.unique = req->unique; -  out.error = error; -  iov[0].iov_base = &out; -  iov[0].iov_len = sizeof(struct fuse_out_header); -  memcpy (&iov[1], vector, count * sizeof (*vector)); -  count++; -  out.len = iov_length(iov, count); -  res = fuse_chan_send(req->ch, iov, count); -  free_req(req); - -  return res; -} diff --git a/xlators/mount/fuse/src/fuse-extra.h b/xlators/mount/fuse/src/fuse-extra.h deleted file mode 100644 index 5688e34c76d..00000000000 --- a/xlators/mount/fuse/src/fuse-extra.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -   Copyright (c) 2007-2009 Z RESEARCH, Inc. <http://www.zresearch.com> -   This file is part of GlusterFS. - -   GlusterFS is free software; you can redistribute it and/or modify -   it under the terms of the GNU General Public License as published -   by the Free Software Foundation; either version 3 of the License, -   or (at your option) any later version. - -   GlusterFS is distributed in the hope that it will be useful, but -   WITHOUT ANY WARRANTY; without even the implied warranty of -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -   General Public License for more details. - -   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 _FUSE_EXTRA_H -#define _FUSE_EXTRA_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif /* _CONFIG_H */ - -#include <stdlib.h> -#include <fuse/fuse_lowlevel.h> - -#define GLUSTERFS_XATTR_LEN_MAX  65536 - -uint64_t req_callid (fuse_req_t req); - -size_t fuse_dirent_size (size_t dname_len); - -int32_t -fuse_reply_vec (fuse_req_t req, -		struct iovec *vector, -		int32_t count); - -#endif /* _FUSE_EXTRA_H */  | 
