]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/fuse/inode.c
RealView: Change the IO_ADDRESS macro
[linux-2.6-omap-h63xx.git] / fs / fuse / inode.c
index cc5efc13496ab5eb431a3aafa4f91d7df5842eb2..033f7bdd47e80e2f659be152bd51e0441e607c3d 100644 (file)
@@ -29,6 +29,8 @@ DEFINE_MUTEX(fuse_mutex);
 
 #define FUSE_SUPER_MAGIC 0x65735546
 
+#define FUSE_DEFAULT_BLKSIZE 512
+
 struct fuse_mount_data {
        int fd;
        unsigned rootmode;
@@ -56,6 +58,8 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
        fi->i_time = 0;
        fi->nodeid = 0;
        fi->nlookup = 0;
+       fi->attr_version = 0;
+       INIT_LIST_HEAD(&fi->write_files);
        fi->forget_req = fuse_request_alloc();
        if (!fi->forget_req) {
                kmem_cache_free(fuse_inode_cachep, inode);
@@ -68,16 +72,12 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
 static void fuse_destroy_inode(struct inode *inode)
 {
        struct fuse_inode *fi = get_fuse_inode(inode);
+       BUG_ON(!list_empty(&fi->write_files));
        if (fi->forget_req)
                fuse_request_free(fi->forget_req);
        kmem_cache_free(fuse_inode_cachep, inode);
 }
 
-static void fuse_read_inode(struct inode *inode)
-{
-       /* No op */
-}
-
 void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
                      unsigned long nodeid, u64 nlookup)
 {
@@ -109,20 +109,35 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
        return 0;
 }
 
-void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
+static void fuse_truncate(struct address_space *mapping, loff_t offset)
+{
+       /* See vmtruncate() */
+       unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+       truncate_inode_pages(mapping, offset);
+       unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+}
+
+
+void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
+                           u64 attr_valid, u64 attr_version)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
-       if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
-               invalidate_mapping_pages(inode->i_mapping, 0, -1);
+       struct fuse_inode *fi = get_fuse_inode(inode);
+       loff_t oldsize;
+
+       spin_lock(&fc->lock);
+       if (attr_version != 0 && fi->attr_version > attr_version) {
+               spin_unlock(&fc->lock);
+               return;
+       }
+       fi->attr_version = ++fc->attr_version;
+       fi->i_time = attr_valid;
 
        inode->i_ino     = attr->ino;
-       inode->i_mode    = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
+       inode->i_mode    = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
        inode->i_nlink   = attr->nlink;
        inode->i_uid     = attr->uid;
        inode->i_gid     = attr->gid;
-       spin_lock(&fc->lock);
-       i_size_write(inode, attr->size);
-       spin_unlock(&fc->lock);
        inode->i_blocks  = attr->blocks;
        inode->i_atime.tv_sec   = attr->atime;
        inode->i_atime.tv_nsec  = attr->atimensec;
@@ -130,6 +145,30 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
        inode->i_mtime.tv_nsec  = attr->mtimensec;
        inode->i_ctime.tv_sec   = attr->ctime;
        inode->i_ctime.tv_nsec  = attr->ctimensec;
+
+       if (attr->blksize != 0)
+               inode->i_blkbits = ilog2(attr->blksize);
+       else
+               inode->i_blkbits = inode->i_sb->s_blocksize_bits;
+
+       /*
+        * Don't set the sticky bit in i_mode, unless we want the VFS
+        * to check permissions.  This prevents failures due to the
+        * check in may_delete().
+        */
+       fi->orig_i_mode = inode->i_mode;
+       if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
+               inode->i_mode &= ~S_ISVTX;
+
+       oldsize = inode->i_size;
+       i_size_write(inode, attr->size);
+       spin_unlock(&fc->lock);
+
+       if (S_ISREG(inode->i_mode) && oldsize != attr->size) {
+               if (attr->size < oldsize)
+                       fuse_truncate(inode->i_mapping, attr->size);
+               invalidate_inode_pages2(inode->i_mapping);
+       }
 }
 
 static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
@@ -169,7 +208,8 @@ static int fuse_inode_set(struct inode *inode, void *_nodeidp)
 }
 
 struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
-                       int generation, struct fuse_attr *attr)
+                       int generation, struct fuse_attr *attr,
+                       u64 attr_valid, u64 attr_version)
 {
        struct inode *inode;
        struct fuse_inode *fi;
@@ -197,7 +237,8 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
        spin_lock(&fc->lock);
        fi->nlookup ++;
        spin_unlock(&fc->lock);
-       fuse_change_attributes(inode, attr);
+       fuse_change_attributes(inode, attr, attr_valid, attr_version);
+
        return inode;
 }
 
@@ -232,6 +273,7 @@ static void fuse_put_super(struct super_block *sb)
        kill_fasync(&fc->fasync, SIGIO, POLL_IN);
        wake_up_all(&fc->waitq);
        wake_up_all(&fc->blocked_waitq);
+       wake_up_all(&fc->reserved_req_waitq);
        mutex_lock(&fuse_mutex);
        list_del(&fc->entry);
        fuse_ctl_remove_conn(fc);
@@ -261,6 +303,11 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct fuse_statfs_out outarg;
        int err;
 
+       if (!fuse_allow_task(fc, current)) {
+               buf->f_type = FUSE_SUPER_MAGIC;
+               return 0;
+       }
+
        req = fuse_get_req(fc);
        if (IS_ERR(req))
                return PTR_ERR(req);
@@ -310,7 +357,7 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev)
        char *p;
        memset(d, 0, sizeof(struct fuse_mount_data));
        d->max_read = ~0;
-       d->blksize = 512;
+       d->blksize = FUSE_DEFAULT_BLKSIZE;
 
        while ((p = strsep(&opt, ",")) != NULL) {
                int token;
@@ -395,12 +442,16 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
                seq_puts(m, ",allow_other");
        if (fc->max_read != ~0)
                seq_printf(m, ",max_read=%u", fc->max_read);
+       if (mnt->mnt_sb->s_bdev &&
+           mnt->mnt_sb->s_blocksize != FUSE_DEFAULT_BLKSIZE)
+               seq_printf(m, ",blksize=%lu", mnt->mnt_sb->s_blocksize);
        return 0;
 }
 
 static struct fuse_conn *new_conn(void)
 {
        struct fuse_conn *fc;
+       int err;
 
        fc = kzalloc(sizeof(*fc), GFP_KERNEL);
        if (fc) {
@@ -409,17 +460,27 @@ static struct fuse_conn *new_conn(void)
                atomic_set(&fc->count, 1);
                init_waitqueue_head(&fc->waitq);
                init_waitqueue_head(&fc->blocked_waitq);
+               init_waitqueue_head(&fc->reserved_req_waitq);
                INIT_LIST_HEAD(&fc->pending);
                INIT_LIST_HEAD(&fc->processing);
                INIT_LIST_HEAD(&fc->io);
                INIT_LIST_HEAD(&fc->interrupts);
+               INIT_LIST_HEAD(&fc->bg_queue);
                atomic_set(&fc->num_waiting, 0);
                fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
                fc->bdi.unplug_io_fn = default_unplug_io_fn;
+               err = bdi_init(&fc->bdi);
+               if (err) {
+                       kfree(fc);
+                       fc = NULL;
+                       goto out;
+               }
                fc->reqctr = 0;
                fc->blocked = 1;
+               fc->attr_version = 1;
                get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
        }
+out:
        return fc;
 }
 
@@ -429,6 +490,7 @@ void fuse_conn_put(struct fuse_conn *fc)
                if (fc->destroy_req)
                        fuse_request_free(fc->destroy_req);
                mutex_destroy(&fc->inst_mutex);
+               bdi_destroy(&fc->bdi);
                kfree(fc);
        }
 }
@@ -446,13 +508,13 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
 
        attr.mode = mode;
        attr.ino = FUSE_ROOT_ID;
-       return fuse_iget(sb, 1, 0, &attr);
+       attr.nlink = 1;
+       return fuse_iget(sb, 1, 0, &attr, 0, 0);
 }
 
 static const struct super_operations fuse_super_operations = {
        .alloc_inode    = fuse_alloc_inode,
        .destroy_inode  = fuse_destroy_inode,
-       .read_inode     = fuse_read_inode,
        .clear_inode    = fuse_clear_inode,
        .drop_inode     = generic_delete_inode,
        .remount_fs     = fuse_remount_fs,
@@ -477,6 +539,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                                fc->async_read = 1;
                        if (!(arg->flags & FUSE_POSIX_LOCKS))
                                fc->no_lock = 1;
+                       if (arg->flags & FUSE_ATOMIC_O_TRUNC)
+                               fc->atomic_o_trunc = 1;
                } else {
                        ra_pages = fc->max_read / PAGE_CACHE_SIZE;
                        fc->no_lock = 1;
@@ -499,7 +563,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        arg->major = FUSE_KERNEL_VERSION;
        arg->minor = FUSE_KERNEL_MINOR_VERSION;
        arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
-       arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS;
+       arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC;
        req->in.h.opcode = FUSE_INIT;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(*arg);
@@ -680,11 +744,7 @@ static inline void unregister_fuseblk(void)
 }
 #endif
 
-static decl_subsys(fuse, NULL, NULL);
-static decl_subsys(connections, NULL, NULL);
-
-static void fuse_inode_init_once(void *foo, struct kmem_cache *cachep,
-                                unsigned long flags)
+static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo)
 {
        struct inode * inode = foo;
 
@@ -706,7 +766,7 @@ static int __init fuse_fs_init(void)
        fuse_inode_cachep = kmem_cache_create("fuse_inode",
                                              sizeof(struct fuse_inode),
                                              0, SLAB_HWCACHE_ALIGN,
-                                             fuse_inode_init_once, NULL);
+                                             fuse_inode_init_once);
        err = -ENOMEM;
        if (!fuse_inode_cachep)
                goto out_unreg2;
@@ -728,32 +788,37 @@ static void fuse_fs_cleanup(void)
        kmem_cache_destroy(fuse_inode_cachep);
 }
 
+static struct kobject *fuse_kobj;
+static struct kobject *connections_kobj;
+
 static int fuse_sysfs_init(void)
 {
        int err;
 
-       kobj_set_kset_s(&fuse_subsys, fs_subsys);
-       err = subsystem_register(&fuse_subsys);
-       if (err)
+       fuse_kobj = kobject_create_and_add("fuse", fs_kobj);
+       if (!fuse_kobj) {
+               err = -ENOMEM;
                goto out_err;
+       }
 
-       kobj_set_kset_s(&connections_subsys, fuse_subsys);
-       err = subsystem_register(&connections_subsys);
-       if (err)
+       connections_kobj = kobject_create_and_add("connections", fuse_kobj);
+       if (!connections_kobj) {
+               err = -ENOMEM;
                goto out_fuse_unregister;
+       }
 
        return 0;
 
  out_fuse_unregister:
-       subsystem_unregister(&fuse_subsys);
+       kobject_put(fuse_kobj);
  out_err:
        return err;
 }
 
 static void fuse_sysfs_cleanup(void)
 {
-       subsystem_unregister(&connections_subsys);
-       subsystem_unregister(&fuse_subsys);
+       kobject_put(connections_kobj);
+       kobject_put(fuse_kobj);
 }
 
 static int __init fuse_init(void)