]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/fuse/inode.c
[PATCH] fuse: support caching negative dentries
[karo-tx-linux.git] / fs / fuse / inode.c
index 458c62ca0fec1692a6e9917183716c2ebccb59ea..3b928a02af04f71acd8e283e8f44cd8957708c05 100644 (file)
@@ -31,7 +31,13 @@ struct fuse_mount_data {
        int fd;
        unsigned rootmode;
        unsigned user_id;
+       unsigned group_id;
+       unsigned fd_present : 1;
+       unsigned rootmode_present : 1;
+       unsigned user_id_present : 1;
+       unsigned group_id_present : 1;
        unsigned flags;
+       unsigned max_read;
 };
 
 static struct inode *fuse_alloc_inode(struct super_block *sb)
@@ -167,6 +173,7 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
                return NULL;
 
        if ((inode->i_state & I_NEW)) {
+               inode->i_flags |= S_NOATIME|S_NOCMTIME;
                inode->i_generation = generation;
                inode->i_data.backing_dev_info = &fc->bdi;
                fuse_init_inode(inode, attr);
@@ -198,6 +205,7 @@ static void fuse_put_super(struct super_block *sb)
        spin_lock(&fuse_lock);
        fc->mounted = 0;
        fc->user_id = 0;
+       fc->group_id = 0;
        fc->flags = 0;
        /* Flush all readers on this fs */
        wake_up_all(&fc->waitq);
@@ -210,6 +218,7 @@ 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_frsize  = attr->frsize;
        stbuf->f_blocks  = attr->blocks;
        stbuf->f_bfree   = attr->bfree;
        stbuf->f_bavail  = attr->bavail;
@@ -228,12 +237,14 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
 
         req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTSYS;
+               return -EINTR;
 
+       memset(&outarg, 0, sizeof(outarg));
        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].size =
+               fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
        req->out.args[0].value = &outarg;
        request_send(fc, req);
        err = req->out.h.error;
@@ -247,9 +258,10 @@ enum {
        OPT_FD,
        OPT_ROOTMODE,
        OPT_USER_ID,
+       OPT_GROUP_ID,
        OPT_DEFAULT_PERMISSIONS,
        OPT_ALLOW_OTHER,
-       OPT_KERNEL_CACHE,
+       OPT_MAX_READ,
        OPT_ERR
 };
 
@@ -257,9 +269,10 @@ static match_table_t tokens = {
        {OPT_FD,                        "fd=%u"},
        {OPT_ROOTMODE,                  "rootmode=%o"},
        {OPT_USER_ID,                   "user_id=%u"},
+       {OPT_GROUP_ID,                  "group_id=%u"},
        {OPT_DEFAULT_PERMISSIONS,       "default_permissions"},
        {OPT_ALLOW_OTHER,               "allow_other"},
-       {OPT_KERNEL_CACHE,              "kernel_cache"},
+       {OPT_MAX_READ,                  "max_read=%u"},
        {OPT_ERR,                       NULL}
 };
 
@@ -267,7 +280,7 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
 {
        char *p;
        memset(d, 0, sizeof(struct fuse_mount_data));
-       d->fd = -1;
+       d->max_read = ~0;
 
        while ((p = strsep(&opt, ",")) != NULL) {
                int token;
@@ -282,18 +295,28 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
                        if (match_int(&args[0], &value))
                                return 0;
                        d->fd = value;
+                       d->fd_present = 1;
                        break;
 
                case OPT_ROOTMODE:
                        if (match_octal(&args[0], &value))
                                return 0;
                        d->rootmode = value;
+                       d->rootmode_present = 1;
                        break;
 
                case OPT_USER_ID:
                        if (match_int(&args[0], &value))
                                return 0;
                        d->user_id = value;
+                       d->user_id_present = 1;
+                       break;
+
+               case OPT_GROUP_ID:
+                       if (match_int(&args[0], &value))
+                               return 0;
+                       d->group_id = value;
+                       d->group_id_present = 1;
                        break;
 
                case OPT_DEFAULT_PERMISSIONS:
@@ -304,15 +327,19 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
                        d->flags |= FUSE_ALLOW_OTHER;
                        break;
 
-               case OPT_KERNEL_CACHE:
-                       d->flags |= FUSE_KERNEL_CACHE;
+               case OPT_MAX_READ:
+                       if (match_int(&args[0], &value))
+                               return 0;
+                       d->max_read = value;
                        break;
 
                default:
                        return 0;
                }
        }
-       if (d->fd == -1)
+
+       if (!d->fd_present || !d->rootmode_present ||
+           !d->user_id_present || !d->group_id_present)
                return 0;
 
        return 1;
@@ -323,12 +350,13 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
        struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
 
        seq_printf(m, ",user_id=%u", fc->user_id);
+       seq_printf(m, ",group_id=%u", fc->group_id);
        if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
                seq_puts(m, ",default_permissions");
        if (fc->flags & FUSE_ALLOW_OTHER)
                seq_puts(m, ",allow_other");
-       if (fc->flags & FUSE_KERNEL_CACHE)
-               seq_puts(m, ",kernel_cache");
+       if (fc->max_read != ~0)
+               seq_printf(m, ",max_read=%u", fc->max_read);
        return 0;
 }
 
@@ -453,6 +481,11 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 
        fc->flags = d.flags;
        fc->user_id = d.user_id;
+       fc->group_id = d.group_id;
+       fc->max_read = d.max_read;
+       if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
+               fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
+       fc->max_write = FUSE_MAX_IN / 2;
 
        err = -ENOMEM;
        root = get_root_inode(sb, d.rootmode);