]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
fuse: create fuse_conn_operations
authorMiklos Szeredi <mszeredi@suse.cz>
Tue, 13 Dec 2011 10:58:49 +0000 (11:58 +0100)
committerMiklos Szeredi <mszeredi@suse.cz>
Tue, 13 Dec 2011 10:58:49 +0000 (11:58 +0100)
Create a fuse_conn_operations structure that lets cuse implement its
own notify_store and notify_retrieve operations.

The "release" operation is also moved to this structure.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
fs/fuse/cuse.c
fs/fuse/dev.c
fs/fuse/fuse_i.h
fs/fuse/inode.c

index 3426521f3205cce09a98b8a1bd01ffe9e44f84c0..53df9fe088f12731fc8c68b3b4e5c0523db3a79c 100644 (file)
@@ -461,6 +461,10 @@ static void cuse_fc_release(struct fuse_conn *fc)
        kfree(cc);
 }
 
+static const struct fuse_conn_operations cuse_ops = {
+       .release = cuse_fc_release,
+};
+
 /**
  * cuse_channel_open - open method for /dev/cuse
  * @inode: inode for /dev/cuse
@@ -489,7 +493,7 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
        fuse_conn_init(&cc->fc);
 
        INIT_LIST_HEAD(&cc->list);
-       cc->fc.release = cuse_fc_release;
+       cc->fc.ops = &cuse_ops;
 
        cc->fc.connected = 1;
        cc->fc.blocked = 0;
index 5f3368ab0fa9d44ff8b5121db33d158ef5989da9..f1f59948c3b49debe70351652e7053e95e421fc3 100644 (file)
@@ -201,6 +201,7 @@ struct fuse_req *fuse_get_req_nofail(struct fuse_conn *fc, struct file *file)
        req->waiting = 1;
        return req;
 }
+EXPORT_SYMBOL_GPL(fuse_get_req_nofail);
 
 void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
 {
@@ -463,8 +464,8 @@ void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req)
 }
 EXPORT_SYMBOL_GPL(fuse_request_send_background);
 
-static int fuse_request_send_notify_reply(struct fuse_conn *fc,
-                                         struct fuse_req *req, u64 unique)
+int fuse_request_send_notify_reply(struct fuse_conn *fc,
+                                  struct fuse_req *req, u64 unique)
 {
        int err = -ENODEV;
 
@@ -813,8 +814,8 @@ static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
  * Copy a page in the request to/from the userspace buffer.  Must be
  * done atomically
  */
-static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
-                         unsigned offset, unsigned count, int zeroing)
+int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
+                  unsigned offset, unsigned count, int zeroing)
 {
        int err;
        struct page *page = *pagep;
@@ -1445,15 +1446,7 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
                             struct fuse_copy_state *cs)
 {
        struct fuse_notify_store_out outarg;
-       struct inode *inode;
-       struct address_space *mapping;
-       u64 nodeid;
        int err;
-       pgoff_t index;
-       unsigned int offset;
-       unsigned int num;
-       loff_t file_size;
-       loff_t end;
 
        err = -EINVAL;
        if (size < sizeof(outarg))
@@ -1467,137 +1460,18 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
        if (size - sizeof(outarg) != outarg.size)
                goto out_finish;
 
-       nodeid = outarg.nodeid;
-
-       down_read(&fc->killsb);
+       err = fc->ops->notify_store(fc, cs, outarg.nodeid, outarg.size,
+                                      outarg.offset);
 
-       err = -ENOENT;
-       if (!fc->sb)
-               goto out_up_killsb;
-
-       inode = ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid);
-       if (!inode)
-               goto out_up_killsb;
-
-       mapping = inode->i_mapping;
-       index = outarg.offset >> PAGE_CACHE_SHIFT;
-       offset = outarg.offset & ~PAGE_CACHE_MASK;
-       file_size = i_size_read(inode);
-       end = outarg.offset + outarg.size;
-       if (end > file_size) {
-               file_size = end;
-               fuse_write_update_size(inode, file_size);
-       }
-
-       num = outarg.size;
-       while (num) {
-               struct page *page;
-               unsigned int this_num;
-
-               err = -ENOMEM;
-               page = find_or_create_page(mapping, index,
-                                          mapping_gfp_mask(mapping));
-               if (!page)
-                       goto out_iput;
-
-               this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
-               err = fuse_copy_page(cs, &page, offset, this_num, 0);
-               if (!err && offset == 0 && (num != 0 || file_size == end))
-                       SetPageUptodate(page);
-               unlock_page(page);
-               page_cache_release(page);
-
-               if (err)
-                       goto out_iput;
-
-               num -= this_num;
-               offset = 0;
-               index++;
-       }
-
-       err = 0;
-
-out_iput:
-       iput(inode);
-out_up_killsb:
-       up_read(&fc->killsb);
 out_finish:
        fuse_copy_finish(cs);
        return err;
 }
 
-static void fuse_retrieve_end(struct fuse_conn *fc, struct fuse_req *req)
-{
-       release_pages(req->pages, req->num_pages, 0);
-}
-
-static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
-                        struct fuse_notify_retrieve_out *outarg)
-{
-       int err;
-       struct address_space *mapping = inode->i_mapping;
-       struct fuse_req *req;
-       pgoff_t index;
-       loff_t file_size;
-       unsigned int num;
-       unsigned int offset;
-       size_t total_len = 0;
-
-       req = fuse_get_req(fc);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
-
-       offset = outarg->offset & ~PAGE_CACHE_MASK;
-
-       req->in.h.opcode = FUSE_NOTIFY_REPLY;
-       req->in.h.nodeid = outarg->nodeid;
-       req->in.numargs = 2;
-       req->in.argpages = 1;
-       req->page_offset = offset;
-       req->end = fuse_retrieve_end;
-
-       index = outarg->offset >> PAGE_CACHE_SHIFT;
-       file_size = i_size_read(inode);
-       num = outarg->size;
-       if (outarg->offset > file_size)
-               num = 0;
-       else if (outarg->offset + num > file_size)
-               num = file_size - outarg->offset;
-
-       while (num && req->num_pages < FUSE_MAX_PAGES_PER_REQ) {
-               struct page *page;
-               unsigned int this_num;
-
-               page = find_get_page(mapping, index);
-               if (!page)
-                       break;
-
-               this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
-               req->pages[req->num_pages] = page;
-               req->num_pages++;
-
-               num -= this_num;
-               total_len += this_num;
-               index++;
-       }
-       req->misc.retrieve_in.offset = outarg->offset;
-       req->misc.retrieve_in.size = total_len;
-       req->in.args[0].size = sizeof(req->misc.retrieve_in);
-       req->in.args[0].value = &req->misc.retrieve_in;
-       req->in.args[1].size = total_len;
-
-       err = fuse_request_send_notify_reply(fc, req, outarg->notify_unique);
-       if (err)
-               fuse_retrieve_end(fc, req);
-
-       return err;
-}
-
 static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size,
                                struct fuse_copy_state *cs)
 {
        struct fuse_notify_retrieve_out outarg;
-       struct inode *inode;
        int err;
 
        err = -EINVAL;
@@ -1610,18 +1484,7 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size,
 
        fuse_copy_finish(cs);
 
-       down_read(&fc->killsb);
-       err = -ENOENT;
-       if (fc->sb) {
-               u64 nodeid = outarg.nodeid;
-
-               inode = ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid);
-               if (inode) {
-                       err = fuse_retrieve(fc, inode, &outarg);
-                       iput(inode);
-               }
-       }
-       up_read(&fc->killsb);
+       err = fc->ops->notify_retrieve(fc, &outarg);
 
        return err;
 
index a571584a091ad0539cc9d393d5ada4a8adc92565..9542f5bd725809ce18f6ee76684a1d8e079c3c24 100644 (file)
@@ -312,6 +312,21 @@ struct fuse_req {
        struct file *stolen_file;
 };
 
+struct fuse_copy_state;
+
+struct fuse_conn_operations {
+       /** Called on final put */
+       void (*release)(struct fuse_conn *);
+
+       /** Called to store data into a mapping */
+       int (*notify_store)(struct fuse_conn *, struct fuse_copy_state *,
+                           u64 nodeid, u32 size, u64 pos);
+
+       /** Called to retrieve data from a mapping */
+       int (*notify_retrieve)(struct fuse_conn *,
+                              struct fuse_notify_retrieve_out *);
+};
+
 /**
  * A Fuse connection.
  *
@@ -511,14 +526,14 @@ struct fuse_conn {
        /** Version counter for attribute changes */
        u64 attr_version;
 
-       /** Called on final put */
-       void (*release)(struct fuse_conn *);
-
        /** Super block for this connection. */
        struct super_block *sb;
 
        /** Read/write semaphore to hold when accessing sb. */
        struct rw_semaphore killsb;
+
+       /** Operations that fuse and cuse can implement differently */
+       const struct fuse_conn_operations *ops;
 };
 
 static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
@@ -778,4 +793,11 @@ int fuse_dev_release(struct inode *inode, struct file *file);
 
 void fuse_write_update_size(struct inode *inode, loff_t pos);
 
+int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
+                  unsigned offset, unsigned count, int zeroing);
+
+int fuse_request_send_notify_reply(struct fuse_conn *fc,
+                                  struct fuse_req *req, u64 unique);
+
+
 #endif /* _FS_FUSE_I_H */
index 3e6d727564792edd3b59dd6c509db3173e7a082f..4bf887f33663c8f72bed1fb54d81e0cffabe8d96 100644 (file)
@@ -551,7 +551,7 @@ void fuse_conn_put(struct fuse_conn *fc)
                if (fc->destroy_req)
                        fuse_request_free(fc->destroy_req);
                mutex_destroy(&fc->inst_mutex);
-               fc->release(fc);
+               fc->ops->release(fc);
        }
 }
 EXPORT_SYMBOL_GPL(fuse_conn_put);
@@ -915,6 +915,168 @@ static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
        return 0;
 }
 
+static int fuse_notify_store_to_inode(struct fuse_conn *fc,
+                                     struct fuse_copy_state *cs,
+                                     u64 nodeid, u32 size, u64 pos)
+{
+       struct inode *inode;
+       struct address_space *mapping;
+       pgoff_t index;
+       unsigned int off;
+       loff_t file_size;
+       loff_t end;
+       int err;
+
+       down_read(&fc->killsb);
+
+       err = -ENOENT;
+       if (!fc->sb)
+               goto out_up_killsb;
+
+       inode = ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid);
+       if (!inode)
+               goto out_up_killsb;
+
+       mapping = inode->i_mapping;
+       index = pos >> PAGE_CACHE_SHIFT;
+       off = pos & ~PAGE_CACHE_MASK;
+       file_size = i_size_read(inode);
+       end = pos + size;
+       if (end > file_size) {
+               file_size = end;
+               fuse_write_update_size(inode, file_size);
+       }
+
+       while (size) {
+               struct page *page;
+               unsigned int this_num;
+
+               err = -ENOMEM;
+               page = find_or_create_page(mapping, index,
+                                          mapping_gfp_mask(mapping));
+               if (!page)
+                       goto out_iput;
+
+               this_num = min_t(unsigned, size, PAGE_CACHE_SIZE - off);
+               err = fuse_copy_page(cs, &page, off, this_num, 0);
+               if (!err && off == 0 && (size != 0 || file_size == end))
+                       SetPageUptodate(page);
+               unlock_page(page);
+               page_cache_release(page);
+
+               if (err)
+                       goto out_iput;
+
+               size -= this_num;
+               off = 0;
+               index++;
+       }
+
+       err = 0;
+
+out_iput:
+       iput(inode);
+out_up_killsb:
+       up_read(&fc->killsb);
+
+       return err;
+}
+
+static void fuse_retrieve_end(struct fuse_conn *fc, struct fuse_req *req)
+{
+       release_pages(req->pages, req->num_pages, 0);
+}
+
+static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
+                        struct fuse_notify_retrieve_out *outarg)
+{
+       int err;
+       struct address_space *mapping = inode->i_mapping;
+       struct fuse_req *req;
+       pgoff_t index;
+       loff_t file_size;
+       unsigned int num;
+       unsigned int offset;
+       size_t total_len = 0;
+
+       req = fuse_get_req(fc);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       offset = outarg->offset & ~PAGE_CACHE_MASK;
+
+       req->in.h.opcode = FUSE_NOTIFY_REPLY;
+       req->in.h.nodeid = outarg->nodeid;
+       req->in.numargs = 2;
+       req->in.argpages = 1;
+       req->page_offset = offset;
+       req->end = fuse_retrieve_end;
+
+       index = outarg->offset >> PAGE_CACHE_SHIFT;
+       file_size = i_size_read(inode);
+       num = outarg->size;
+       if (outarg->offset > file_size)
+               num = 0;
+       else if (outarg->offset + num > file_size)
+               num = file_size - outarg->offset;
+
+       while (num && req->num_pages < FUSE_MAX_PAGES_PER_REQ) {
+               struct page *page;
+               unsigned int this_num;
+
+               page = find_get_page(mapping, index);
+               if (!page)
+                       break;
+
+               this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
+               req->pages[req->num_pages] = page;
+               req->num_pages++;
+
+               num -= this_num;
+               total_len += this_num;
+               index++;
+       }
+       req->misc.retrieve_in.offset = outarg->offset;
+       req->misc.retrieve_in.size = total_len;
+       req->in.args[0].size = sizeof(req->misc.retrieve_in);
+       req->in.args[0].value = &req->misc.retrieve_in;
+       req->in.args[1].size = total_len;
+
+       err = fuse_request_send_notify_reply(fc, req, outarg->notify_unique);
+       if (err)
+               fuse_retrieve_end(fc, req);
+
+       return err;
+}
+
+static int fuse_notify_retrieve_from_inode(struct fuse_conn *fc,
+                               struct fuse_notify_retrieve_out *outarg)
+{
+       struct inode *inode;
+       int err;
+
+       down_read(&fc->killsb);
+       err = -ENOENT;
+       if (fc->sb) {
+               u64 nodeid = outarg->nodeid;
+
+               inode = ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid);
+               if (inode) {
+                       err = fuse_retrieve(fc, inode, outarg);
+                       iput(inode);
+               }
+       }
+       up_read(&fc->killsb);
+
+       return err;
+}
+
+static const struct fuse_conn_operations fuse_default_ops = {
+       .release = fuse_free_conn,
+       .notify_store = fuse_notify_store_to_inode,
+       .notify_retrieve = fuse_notify_retrieve_from_inode,
+};
+
 static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct fuse_conn *fc;
@@ -978,7 +1140,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
                fc->dont_mask = 1;
        sb->s_flags |= MS_POSIXACL;
 
-       fc->release = fuse_free_conn;
+       fc->ops = &fuse_default_ops;
        fc->flags = d.flags;
        fc->user_id = d.user_id;
        fc->group_id = d.group_id;