From 3ded1a3176bb803e016e79d0e6db5e1f3ea30473 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 18 Aug 2006 18:43:50 +0000 Subject: [PATCH] statfs improvement --- ChangeLog | 4 ++++ include/fuse.h | 27 ++++++++++++++++++++++++--- include/fuse_lowlevel.h | 7 ++++++- kernel/.cvsignore | 1 + kernel/configure.ac | 4 +++- kernel/control.c | 7 ++++++- lib/fuse.c | 25 ++++++++++++++++++------- lib/fuse_lowlevel.c | 2 +- 8 files changed, 63 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2244e89..8ddf026 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,10 @@ initialization. Bug found and original patch from Alexander Zarochentsev + * For linux kernels >=2.6.18 (2.6.19 if using the fuse module from + the kernel tree) the statfs method will receive the path within + the filesystem on which the stat(v)fs syscall was called. + 2006-07-30 Miklos Szeredi * fusermount: if selinux is active, restore the original file's diff --git a/include/fuse.h b/include/fuse.h index ad2ef00..d9041b2 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -68,9 +68,9 @@ typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type, * * All methods are optional, but some are essential for a useful * filesystem (e.g. getattr). Open, flush, release, fsync, opendir, - * releasedir, fsyncdir, access, create, ftruncate, fgetattr, init and - * destroy are special purpose methods, without which a full featured - * filesystem can still be implemented. + * releasedir, fsyncdir, access, create, ftruncate, fgetattr, lock, + * init and destroy are special purpose methods, without which a full + * featured filesystem can still be implemented. */ struct fuse_operations { /** Get file attributes. @@ -363,6 +363,27 @@ struct fuse_operations { */ int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); + /** + * Perform POSIX file locking operation + * + * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW. + * + * For the meaning of fields in 'struct flock' see the man page + * for fcntl(2). The l_whence field will always be set to + * SEEK_SET. + * + * Unlike fcntl, the l_pid will be set in F_SETLK and F_SETLKW, + * and should be used by the filesystem to initialize this field + * in F_GETLK. + * + * For checking lock ownership, the 'owner' argument must be used. + * + * Note: if this method is not implemented, the kernel will still + * allow file locking to work locally. Hence it is only + * interesting for network filesystems and similar. + * + * Introduced in version 2.6 + */ int (*lock) (const char *, struct fuse_file_info *, int cmd, struct flock *, uint64_t owner); }; diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index ede1307..a676830 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -600,8 +600,9 @@ struct fuse_lowlevel_ops { * fuse_reply_err * * @param req request handle + * @param ino the inode number, zero means "undefined" */ - void (*statfs) (fuse_req_t req); + void (*statfs) (fuse_req_t req, fuse_ino_t ino); /** * Set an extended attribute @@ -754,6 +755,10 @@ struct fuse_lowlevel_ops { * 'struct flock' should only be used to fill in this field in * getlk(). * + * Note: if the locking methods are not implemented, the kernel + * will still allow file locking to work locally. Hence these are + * only interesting for network filesystems and similar. + * * Valid replies: * fuse_reply_err * diff --git a/kernel/.cvsignore b/kernel/.cvsignore index 907cdec..ed24c33 100644 --- a/kernel/.cvsignore +++ b/kernel/.cvsignore @@ -9,3 +9,4 @@ config.* *.s .tmp_versions .*.d +*.symvers diff --git a/kernel/configure.ac b/kernel/configure.ac index 21dc036..c3c1f3f 100644 --- a/kernel/configure.ac +++ b/kernel/configure.ac @@ -76,8 +76,10 @@ if test "$ENABLE_FUSE_MODULE" = y; then AC_MSG_RESULT([$kernelbuild]) AC_MSG_CHECKING([kernel source version]) - if test -r $kernelbuild/include/linux/version.h; then + if test -r $kernelbuild/include/linux/version.h && fgrep -q UTS_RELEASE $kernelbuild/include/linux/version.h; then kernsrcver=`(echo "#include "; echo "kernsrcver=UTS_RELEASE") | cpp -I $kernelbuild/include | grep "^kernsrcver=" | cut -d \" -f 2` + elif test -r $kernelbuild/include/linux/utsrelease.h && fgrep -q UTS_RELEASE $kernelbuild/include/linux/utsrelease.h; then + kernsrcver=`(echo "#include "; echo "kernsrcver=UTS_RELEASE") | cpp -I $kernelbuild/include | grep "^kernsrcver=" | cut -d \" -f 2` fi if test -z "$kernsrcver"; then AC_MSG_RESULT([Not found]) diff --git a/kernel/control.c b/kernel/control.c index b17adb3..28956ef 100644 --- a/kernel/control.c +++ b/kernel/control.c @@ -74,7 +74,12 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, const char *name, int mode, int nlink, struct inode_operations *iop, - struct file_operations *fop) +#ifdef KERNEL_2_6_17_PLUS + const struct file_operations *fop +#else + struct file_operations *fop +#endif +) { struct dentry *dentry; struct inode *inode; diff --git a/lib/fuse.c b/lib/fuse.c index 00f34fb..4895192 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -108,7 +108,7 @@ static struct fuse_context *(*fuse_getcontext)(void) = NULL; static int fuse_do_open(struct fuse *, char *, struct fuse_file_info *); static void fuse_do_release(struct fuse *, char *, struct fuse_file_info *); static int fuse_do_opendir(struct fuse *, char *, struct fuse_file_info *); -static int fuse_do_statfs(struct fuse *, char *, struct statvfs *); +static int fuse_do_statfs(struct fuse *, struct statvfs *); #ifndef USE_UCLIBC #define mutex_init(mut) pthread_mutex_init(mut, NULL) @@ -1669,7 +1669,7 @@ static int default_statfs(struct statvfs *buf) return 0; } -static void fuse_statfs(fuse_req_t req) +static void fuse_statfs(fuse_req_t req, fuse_ino_t ino) { struct fuse *f = req_fuse_prepare(req); struct statvfs buf; @@ -1677,7 +1677,18 @@ static void fuse_statfs(fuse_req_t req) memset(&buf, 0, sizeof(buf)); if (f->op.statfs) { - err = fuse_do_statfs(f, "/", &buf); + if (ino && (!f->compat || f->compat >= 26)) { + char *path; + pthread_rwlock_rdlock(&f->tree_lock); + err = -ENOENT; + path = get_path(f, ino); + if (path) { + err = f->op.statfs(path, &buf); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + } else + err = fuse_do_statfs(f, &buf); } else err = default_statfs(&buf); @@ -2294,12 +2305,12 @@ static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf) stbuf->f_namemax = oldbuf->f_namelen; } -static int fuse_do_statfs(struct fuse *f, char *path, struct statvfs *buf) +static int fuse_do_statfs(struct fuse *f, struct statvfs *buf) { int err; if (!f->compat || f->compat >= 25) { - err = f->op.statfs(path, buf); + err = f->op.statfs("/", buf); } else if (f->compat > 11) { struct statfs oldbuf; err = ((struct fuse_operations_compat22 *) &f->op)->statfs("/", &oldbuf); @@ -2386,9 +2397,9 @@ static int fuse_do_opendir(struct fuse *f, char *path, return f->op.opendir(path, fi); } -static int fuse_do_statfs(struct fuse *f, char *path, struct statvfs *buf) +static int fuse_do_statfs(struct fuse *f, struct statvfs *buf) { - return f->op.statfs(path, buf); + return f->op.statfs("/", buf); } #endif /* __FreeBSD__ */ diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 5076a5b..04a34f3 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -719,7 +719,7 @@ static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) (void) inarg; if (req->f->op.statfs) - req->f->op.statfs(req); + req->f->op.statfs(req, nodeid); else { struct statvfs buf = { .f_namemax = 255, -- 2.30.2