2005-10-24 17:16:54

by Miklos Szeredi

[permalink] [raw]
Subject: [PATCH 8/8] FUSE: per inode statfs

This patch makes FUSE based filesystems able to return filesystem
statistics based on path. While breaks with the tradition of
homogeneous statistics per _local_ filesystem, however adds useful
ability to user to differentiate statistics from different _remote_
filesystem served by the same userspace server.

Signed-off-by: Miklos Szeredi <[email protected]>

Index: linux/fs/fuse/inode.c
===================================================================
--- linux.orig/fs/fuse/inode.c 2005-10-24 15:43:02.000000000 +0200
+++ linux/fs/fuse/inode.c 2005-10-24 15:43:16.000000000 +0200
@@ -16,7 +16,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/parser.h>
-#include <linux/statfs.h>

MODULE_AUTHOR("Miklos Szeredi <[email protected]>");
MODULE_DESCRIPTION("Filesystem in Userspace");
@@ -25,8 +24,6 @@ MODULE_LICENSE("GPL");
spinlock_t fuse_lock;
static kmem_cache_t *fuse_inode_cachep;

-#define FUSE_SUPER_MAGIC 0x65735546
-
struct fuse_mount_data {
int fd;
unsigned rootmode;
@@ -214,43 +211,6 @@ static void fuse_put_super(struct super_
spin_unlock(&fuse_lock);
}

-static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
-{
- stbuf->f_type = FUSE_SUPER_MAGIC;
- stbuf->f_bsize = attr->bsize;
- stbuf->f_blocks = attr->blocks;
- stbuf->f_bfree = attr->bfree;
- stbuf->f_bavail = attr->bavail;
- stbuf->f_files = attr->files;
- stbuf->f_ffree = attr->ffree;
- stbuf->f_namelen = attr->namelen;
- /* fsid is left zero */
-}
-
-static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
-{
- struct fuse_conn *fc = get_fuse_conn_super(sb);
- struct fuse_req *req;
- struct fuse_statfs_out outarg;
- int err;
-
- req = fuse_get_request(fc);
- if (!req)
- return -EINTR;
-
- req->in.numargs = 0;
- req->in.h.opcode = FUSE_STATFS;
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(outarg);
- req->out.args[0].value = &outarg;
- request_send(fc, req);
- err = req->out.h.error;
- if (!err)
- convert_fuse_statfs(buf, &outarg.st);
- fuse_put_request(fc, req);
- return err;
-}
-
enum {
OPT_FD,
OPT_ROOTMODE,
@@ -446,7 +406,6 @@ static struct super_operations fuse_supe
.read_inode = fuse_read_inode,
.clear_inode = fuse_clear_inode,
.put_super = fuse_put_super,
- .statfs = fuse_statfs,
.show_options = fuse_show_options,
};

Index: linux/fs/fuse/dir.c
===================================================================
--- linux.orig/fs/fuse/dir.c 2005-10-24 15:43:14.000000000 +0200
+++ linux/fs/fuse/dir.c 2005-10-24 15:43:16.000000000 +0200
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/namei.h>
#include <linux/mount.h>
+#include <linux/statfs.h>

static inline unsigned long time_to_jiffies(unsigned long sec,
unsigned long nsec)
@@ -1061,6 +1062,46 @@ static int fuse_removexattr(struct dentr
return err;
}

+static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
+{
+ stbuf->f_type = FUSE_SUPER_MAGIC;
+ stbuf->f_bsize = attr->bsize;
+ stbuf->f_blocks = attr->blocks;
+ stbuf->f_bfree = attr->bfree;
+ stbuf->f_bavail = attr->bavail;
+ stbuf->f_files = attr->files;
+ stbuf->f_ffree = attr->ffree;
+ stbuf->f_namelen = attr->namelen;
+ /* fsid is left zero */
+}
+
+static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ struct inode *inode = dentry->d_inode;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_req *req;
+ struct fuse_statfs_out outarg;
+ int err;
+
+ req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
+
+ req->in.h.opcode = FUSE_STATFS;
+ req->in.h.nodeid = get_node_id(inode);
+ req->inode = inode;
+ req->in.numargs = 0;
+ req->out.numargs = 1;
+ req->out.args[0].size = sizeof(outarg);
+ req->out.args[0].value = &outarg;
+ request_send(fc, req);
+ err = req->out.h.error;
+ if (!err)
+ convert_fuse_statfs(buf, &outarg.st);
+ fuse_put_request(fc, req);
+ return err;
+}
+
static struct inode_operations fuse_dir_inode_operations = {
.lookup = fuse_lookup,
.mkdir = fuse_mkdir,
@@ -1078,6 +1119,7 @@ static struct inode_operations fuse_dir_
.getxattr = fuse_getxattr,
.listxattr = fuse_listxattr,
.removexattr = fuse_removexattr,
+ .statfs = fuse_statfs,
};

static struct file_operations fuse_dir_operations = {
@@ -1097,6 +1139,7 @@ static struct inode_operations fuse_comm
.getxattr = fuse_getxattr,
.listxattr = fuse_listxattr,
.removexattr = fuse_removexattr,
+ .statfs = fuse_statfs,
};

static struct inode_operations fuse_symlink_inode_operations = {
@@ -1109,6 +1152,7 @@ static struct inode_operations fuse_syml
.getxattr = fuse_getxattr,
.listxattr = fuse_listxattr,
.removexattr = fuse_removexattr,
+ .statfs = fuse_statfs,
};

void fuse_init_common(struct inode *inode)
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h 2005-10-24 15:43:09.000000000 +0200
+++ linux/fs/fuse/fuse_i.h 2005-10-24 15:43:16.000000000 +0200
@@ -15,6 +15,8 @@
#include <linux/backing-dev.h>
#include <asm/semaphore.h>

+#define FUSE_SUPER_MAGIC 0x65735546
+
/** Max number of pages that can be used in a single read request */
#define FUSE_MAX_PAGES_PER_REQ 32



2005-10-24 17:25:53

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 8/8] FUSE: per inode statfs

On Mon, Oct 24, 2005 at 07:16:29PM +0200, Miklos Szeredi wrote:
> This patch makes FUSE based filesystems able to return filesystem
> statistics based on path. While breaks with the tradition of
> homogeneous statistics per _local_ filesystem, however adds useful
> ability to user to differentiate statistics from different _remote_
> filesystem served by the same userspace server.

Wouldn't it make more sense to create more mountpoints (on demand, if
necessary) to handle this case?

--b.

2005-10-24 19:06:55

by Miklos Szeredi

[permalink] [raw]
Subject: Re: [PATCH 8/8] FUSE: per inode statfs

> > This patch makes FUSE based filesystems able to return filesystem
> > statistics based on path. While breaks with the tradition of
> > homogeneous statistics per _local_ filesystem, however adds useful
> > ability to user to differentiate statistics from different _remote_
> > filesystem served by the same userspace server.
>
> Wouldn't it make more sense to create more mountpoints (on demand, if
> necessary) to handle this case?

Only if

a) it's possible to find out about remote mountpoints

b) not prohibitively expensive to do so on each lookup

Miklos

2005-10-25 04:32:50

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH 8/8] FUSE: per inode statfs

On Mon, Oct 24, 2005 at 09:05:35PM +0200, Miklos Szeredi wrote:
> > > This patch makes FUSE based filesystems able to return filesystem
> > > statistics based on path. While breaks with the tradition of
> > > homogeneous statistics per _local_ filesystem, however adds useful
> > > ability to user to differentiate statistics from different _remote_
> > > filesystem served by the same userspace server.
> >
> > Wouldn't it make more sense to create more mountpoints (on demand, if
> > necessary) to handle this case?
>
> Only if
>
> a) it's possible to find out about remote mountpoints
>
> b) not prohibitively expensive to do so on each lookup

And finding the pathnames to call statfs() on is by some magic cheaper?

2005-10-25 05:52:51

by Miklos Szeredi

[permalink] [raw]
Subject: Re: [PATCH 8/8] FUSE: per inode statfs

> > > > statistics based on path. While breaks with the tradition of
> > > > homogeneous statistics per _local_ filesystem, however adds useful
> > > > ability to user to differentiate statistics from different _remote_
> > > > filesystem served by the same userspace server.
> > >
> > > Wouldn't it make more sense to create more mountpoints (on demand, if
> > > necessary) to handle this case?
> >
> > Only if
> >
> > a) it's possible to find out about remote mountpoints
> >
> > b) not prohibitively expensive to do so on each lookup
>
> And finding the pathnames to call statfs() on is by some magic cheaper?

statfs() is called infrequently. If it's expensive, it's expensive.
OTOH lookup is done for every operation. The filesystem would have to
check for a remote mountpoint before doing _any_ operation, just so
that the occasional statfs() would return valid results.

Oh, and what if remote mountpoints go away, and the (unprivileged
userspace) server is not notified. How will the local mount structure
always correctly reflect the remote one?

It's far simpler just to let statfs() return different results based
on path within the filesystem. What's your problem with it?

Miklos