Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.24 /fs/fuse/inode.c

Filename:/fs/fuse/inode.c
Lines Added:76
Lines Deleted:13
Also changed in: (Previous) 2.6.24-rc8  2.6.24-rc7  2.6.24-rc6  2.6.24-rc5  2.6.24-rc4  2.6.24-rc3-git7 
(Following) 2.6.24-git1  2.6.24-git2  2.6.24-git3  2.6.24-git4  2.6.24-git5  2.6.24-git6 

Location
[  2.6.24
  [  fs
    [  fuse
       o  inode.c

Patch

diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 5448f62..84f9f7d 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -56,6 +56,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,6 +70,7 @@ 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);
@@ -109,20 +112,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 +148,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 +211,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 +240,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 +276,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 +306,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);
@@ -401,6 +451,7 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
 static struct fuse_conn *new_conn(void)
 {
    struct fuse_conn *fc;
+   int err;
 
    fc = kzalloc(sizeof(*fc), GFP_KERNEL);
    if (fc) {
@@ -409,6 +460,7 @@ 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);
@@ -416,10 +468,18 @@ static struct fuse_conn *new_conn(void)
       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 +489,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,7 +507,8 @@ 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 = {
@@ -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);
@@ -683,8 +747,7 @@ static inline void unregister_fuseblk(void)
 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;
 


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.