fuse: save space in struct fuse_req
[sfrench/cifs-2.6.git] / fs / fuse / file.c
index 0fcdba9d47c090ba5b6dae59abfdc41897d5b7f1..676b0bc8a86dba3e3c048a1a35320d3931a65f20 100644 (file)
@@ -55,9 +55,10 @@ struct fuse_file *fuse_file_alloc(void)
                if (!ff->reserved_req) {
                        kfree(ff);
                        ff = NULL;
+               } else {
+                       INIT_LIST_HEAD(&ff->write_entry);
+                       atomic_set(&ff->count, 0);
                }
-               INIT_LIST_HEAD(&ff->write_entry);
-               atomic_set(&ff->count, 0);
        }
        return ff;
 }
@@ -76,8 +77,8 @@ static struct fuse_file *fuse_file_get(struct fuse_file *ff)
 
 static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
 {
-       dput(req->dentry);
-       mntput(req->vfsmount);
+       dput(req->misc.release.dentry);
+       mntput(req->misc.release.vfsmount);
        fuse_put_request(fc, req);
 }
 
@@ -85,7 +86,8 @@ static void fuse_file_put(struct fuse_file *ff)
 {
        if (atomic_dec_and_test(&ff->count)) {
                struct fuse_req *req = ff->reserved_req;
-               struct fuse_conn *fc = get_fuse_conn(req->dentry->d_inode);
+               struct inode *inode = req->misc.release.dentry->d_inode;
+               struct fuse_conn *fc = get_fuse_conn(inode);
                req->end = fuse_release_end;
                request_send_background(fc, req);
                kfree(ff);
@@ -136,7 +138,7 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
 void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode)
 {
        struct fuse_req *req = ff->reserved_req;
-       struct fuse_release_in *inarg = &req->misc.release_in;
+       struct fuse_release_in *inarg = &req->misc.release.in;
 
        inarg->fh = ff->fh;
        inarg->flags = flags;
@@ -152,13 +154,14 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir)
        struct fuse_file *ff = file->private_data;
        if (ff) {
                struct fuse_conn *fc = get_fuse_conn(inode);
+               struct fuse_req *req = ff->reserved_req;
 
                fuse_release_fill(ff, get_node_id(inode), file->f_flags,
                                  isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
 
                /* Hold vfsmount and dentry until release is finished */
-               ff->reserved_req->vfsmount = mntget(file->f_path.mnt);
-               ff->reserved_req->dentry = dget(file->f_path.dentry);
+               req->misc.release.vfsmount = mntget(file->f_path.mnt);
+               req->misc.release.dentry = dget(file->f_path.dentry);
 
                spin_lock(&fc->lock);
                list_del(&ff->write_entry);
@@ -288,14 +291,16 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
        return fuse_fsync_common(file, de, datasync, 0);
 }
 
-void fuse_read_fill(struct fuse_req *req, struct fuse_file *ff,
+void fuse_read_fill(struct fuse_req *req, struct file *file,
                    struct inode *inode, loff_t pos, size_t count, int opcode)
 {
        struct fuse_read_in *inarg = &req->misc.read_in;
+       struct fuse_file *ff = file->private_data;
 
        inarg->fh = ff->fh;
        inarg->offset = pos;
        inarg->size = count;
+       inarg->flags = file->f_flags;
        req->in.h.opcode = opcode;
        req->in.h.nodeid = get_node_id(inode);
        req->in.numargs = 1;
@@ -312,9 +317,8 @@ static size_t fuse_send_read(struct fuse_req *req, struct file *file,
                             fl_owner_t owner)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
-       struct fuse_file *ff = file->private_data;
 
-       fuse_read_fill(req, ff, inode, pos, count, FUSE_READ);
+       fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
        if (owner != NULL) {
                struct fuse_read_in *inarg = &req->misc.read_in;
 
@@ -375,15 +379,16 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
        fuse_put_request(fc, req);
 }
 
-static void fuse_send_readpages(struct fuse_req *req, struct fuse_file *ff,
+static void fuse_send_readpages(struct fuse_req *req, struct file *file,
                                struct inode *inode)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
        loff_t pos = page_offset(req->pages[0]);
        size_t count = req->num_pages << PAGE_CACHE_SHIFT;
        req->out.page_zeroing = 1;
-       fuse_read_fill(req, ff, inode, pos, count, FUSE_READ);
+       fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
        if (fc->async_read) {
+               struct fuse_file *ff = file->private_data;
                req->ff = fuse_file_get(ff);
                req->end = fuse_readpages_end;
                request_send_background(fc, req);
@@ -395,7 +400,7 @@ static void fuse_send_readpages(struct fuse_req *req, struct fuse_file *ff,
 
 struct fuse_fill_data {
        struct fuse_req *req;
-       struct fuse_file *ff;
+       struct file *file;
        struct inode *inode;
 };
 
@@ -410,7 +415,7 @@ static int fuse_readpages_fill(void *_data, struct page *page)
            (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
             (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
             req->pages[req->num_pages - 1]->index + 1 != page->index)) {
-               fuse_send_readpages(req, data->ff, inode);
+               fuse_send_readpages(req, data->file, inode);
                data->req = req = fuse_get_req(fc);
                if (IS_ERR(req)) {
                        unlock_page(page);
@@ -434,7 +439,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,
        if (is_bad_inode(inode))
                goto out;
 
-       data.ff = file->private_data;
+       data.file = file;
        data.inode = inode;
        data.req = fuse_get_req(fc);
        err = PTR_ERR(data.req);
@@ -444,7 +449,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,
        err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
        if (!err) {
                if (data.req->num_pages)
-                       fuse_send_readpages(data.req, data.ff, inode);
+                       fuse_send_readpages(data.req, file, inode);
                else
                        fuse_put_request(fc, data.req);
        }
@@ -452,11 +457,31 @@ out:
        return err;
 }
 
-static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
+static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
+                                 unsigned long nr_segs, loff_t pos)
+{
+       struct inode *inode = iocb->ki_filp->f_mapping->host;
+
+       if (pos + iov_length(iov, nr_segs) > i_size_read(inode)) {
+               int err;
+               /*
+                * If trying to read past EOF, make sure the i_size
+                * attribute is up-to-date.
+                */
+               err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL);
+               if (err)
+                       return err;
+       }
+
+       return generic_file_aio_read(iocb, iov, nr_segs, pos);
+}
+
+static void fuse_write_fill(struct fuse_req *req, struct file *file,
                            struct inode *inode, loff_t pos, size_t count,
                            int writepage)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_file *ff = file->private_data;
        struct fuse_write_in *inarg = &req->misc.write.in;
        struct fuse_write_out *outarg = &req->misc.write.out;
 
@@ -465,6 +490,7 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
        inarg->offset = pos;
        inarg->size = count;
        inarg->write_flags = writepage ? FUSE_WRITE_CACHE : 0;
+       inarg->flags = file->f_flags;
        req->in.h.opcode = FUSE_WRITE;
        req->in.h.nodeid = get_node_id(inode);
        req->in.argpages = 1;
@@ -485,7 +511,7 @@ static size_t fuse_send_write(struct fuse_req *req, struct file *file,
                              fl_owner_t owner)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
-       fuse_write_fill(req, file->private_data, inode, pos, count, 0);
+       fuse_write_fill(req, file, inode, pos, count, 0);
        if (owner != NULL) {
                struct fuse_write_in *inarg = &req->misc.write.in;
                inarg->write_flags |= FUSE_WRITE_LOCKOWNER;
@@ -886,7 +912,7 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
 static const struct file_operations fuse_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = do_sync_read,
-       .aio_read       = generic_file_aio_read,
+       .aio_read       = fuse_file_aio_read,
        .write          = do_sync_write,
        .aio_write      = generic_file_aio_write,
        .mmap           = fuse_file_mmap,