]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/fuse/inode.c
fuse: fix max i/o size calculation
[linux-2.6-omap-h63xx.git] / fs / fuse / inode.c
index 574707409bbfafc92d91006fd74d065085170d43..0cef5ea319f3dfa03953c48d402ca897f4288e98 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;
@@ -57,7 +59,11 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
        fi->nodeid = 0;
        fi->nlookup = 0;
        fi->attr_version = 0;
+       fi->writectr = 0;
        INIT_LIST_HEAD(&fi->write_files);
+       INIT_LIST_HEAD(&fi->queued_writes);
+       INIT_LIST_HEAD(&fi->writepages);
+       init_waitqueue_head(&fi->page_waitq);
        fi->forget_req = fuse_request_alloc();
        if (!fi->forget_req) {
                kmem_cache_free(fuse_inode_cachep, inode);
@@ -71,6 +77,7 @@ static void fuse_destroy_inode(struct inode *inode)
 {
        struct fuse_inode *fi = get_fuse_inode(inode);
        BUG_ON(!list_empty(&fi->write_files));
+       BUG_ON(!list_empty(&fi->queued_writes));
        if (fi->forget_req)
                fuse_request_free(fi->forget_req);
        kmem_cache_free(fuse_inode_cachep, inode);
@@ -107,7 +114,7 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
        return 0;
 }
 
-static void fuse_truncate(struct address_space *mapping, loff_t offset)
+void fuse_truncate(struct address_space *mapping, loff_t offset)
 {
        /* See vmtruncate() */
        unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
@@ -115,19 +122,12 @@ static void fuse_truncate(struct address_space *mapping, loff_t 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)
+void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
+                                  u64 attr_valid)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
        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;
 
@@ -157,6 +157,22 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
        fi->orig_i_mode = inode->i_mode;
        if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
                inode->i_mode &= ~S_ISVTX;
+}
+
+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);
+       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;
+       }
+
+       fuse_change_attributes_common(inode, attr, attr_valid);
 
        oldsize = inode->i_size;
        i_size_write(inode, attr->size);
@@ -240,10 +256,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
        return inode;
 }
 
-static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
+static void fuse_umount_begin(struct super_block *sb)
 {
-       if (flags & MNT_FORCE)
-               fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
+       fuse_abort_conn(get_fuse_conn_super(sb));
 }
 
 static void fuse_send_destroy(struct fuse_conn *fc)
@@ -355,7 +370,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;
@@ -440,10 +455,13 @@ 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)
+static struct fuse_conn *new_conn(struct super_block *sb)
 {
        struct fuse_conn *fc;
        int err;
@@ -464,19 +482,41 @@ 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;
+               /* fuse does it's own writeback accounting */
+               fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
+               fc->dev = sb->s_dev;
                err = bdi_init(&fc->bdi);
-               if (err) {
-                       kfree(fc);
-                       fc = NULL;
-                       goto out;
-               }
+               if (err)
+                       goto error_kfree;
+               err = bdi_register_dev(&fc->bdi, fc->dev);
+               if (err)
+                       goto error_bdi_destroy;
+               /*
+                * For a single fuse filesystem use max 1% of dirty +
+                * writeback threshold.
+                *
+                * This gives about 1M of write buffer for memory maps on a
+                * machine with 1G and 10% dirty_ratio, which should be more
+                * than enough.
+                *
+                * Privileged users can raise it by writing to
+                *
+                *    /sys/class/bdi/<bdi>/max_ratio
+                */
+               bdi_set_max_ratio(&fc->bdi, 1);
                fc->reqctr = 0;
                fc->blocked = 1;
                fc->attr_version = 1;
                get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
        }
-out:
        return fc;
+
+error_bdi_destroy:
+       bdi_destroy(&fc->bdi);
+error_kfree:
+       mutex_destroy(&fc->inst_mutex);
+       kfree(fc);
+       return NULL;
 }
 
 void fuse_conn_put(struct fuse_conn *fc)
@@ -544,6 +584,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
                fc->minor = arg->minor;
                fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
+               fc->max_write = min_t(unsigned, 4096, fc->max_write);
                fc->conn_init = 1;
        }
        fuse_put_request(fc, req);
@@ -574,12 +615,6 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        request_send_background(fc, req);
 }
 
-static u64 conn_id(void)
-{
-       static u64 ctr = 1;
-       return ctr++;
-}
-
 static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct fuse_conn *fc;
@@ -617,14 +652,14 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
        if (file->f_op != &fuse_dev_operations)
                return -EINVAL;
 
-       fc = new_conn();
+       fc = new_conn(sb);
        if (!fc)
                return -ENOMEM;
 
        fc->flags = d.flags;
        fc->user_id = d.user_id;
        fc->group_id = d.group_id;
-       fc->max_read = d.max_read;
+       fc->max_read = min_t(unsigned, 4096, d.max_read);
 
        /* Used by get_root_inode() */
        sb->s_fs_info = fc;
@@ -655,7 +690,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
        if (file->private_data)
                goto err_unlock;
 
-       fc->id = conn_id();
        err = fuse_ctl_add_conn(fc);
        if (err)
                goto err_unlock;