Maxim Patlasov <mpatla...@parallels.com> writes:

> Previously, anyone who set flag 'argpages' only filled req->pages[] and set
> per-request page_offset. This patch re-works all cases where argpages=1 to
> fill req->page_descs[] properly.
>
> Having req->page_descs[] filled properly allows to re-work fuse_copy_pages()
> to copy page fragments described by req->page_descs[]. This will be useful
> for next patches optimizing direct_IO.
>
> Signed-off-by: Maxim Patlasov <mpatla...@parallels.com>
> ---
>  fs/fuse/cuse.c |    1 +
>  fs/fuse/dev.c  |    7 +++----
>  fs/fuse/dir.c  |    1 +
>  fs/fuse/file.c |   20 ++++++++++++++++++++
>  4 files changed, 25 insertions(+), 4 deletions(-)
>
> diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
> index 2f1d5dd..38efe69 100644
> --- a/fs/fuse/cuse.c
> +++ b/fs/fuse/cuse.c
> @@ -441,6 +441,7 @@ static int cuse_send_init(struct cuse_conn *cc)
>       req->out.argvar = 1;
>       req->out.argpages = 1;
>       req->pages[0] = page;
> +     req->page_descs[0].length = req->out.args[1].size;
>       req->num_pages = 1;
>       req->end = cuse_process_init_reply;
>       fuse_request_send_background(fc, req);
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index ea63d39..21b6272 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -888,11 +888,11 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, 
> unsigned nbytes,
>  {
>       unsigned i;
>       struct fuse_req *req = cs->req;
> -     unsigned offset = req->page_descs[0].offset;
> -     unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset);
>  
>       for (i = 0; i < req->num_pages && (nbytes || zeroing); i++) {
>               int err;
> +             unsigned offset = req->page_descs[i].offset;
> +             unsigned count = min(nbytes, req->page_descs[i].length);

Wouldn't it be cleaner if callers calculated the last page's .length
value from the total number of bytes?  So this would just be

                unsigned count = req->page_descs[i].length;

And at the end of the function we can assert that nbytes went to exactly
zero with a WARN_ON().

But this is a change that needs careful testing, so maybe we're better
off having that as a separate incremental patch later...

>  
>               err = fuse_copy_page(cs, &req->pages[i], offset, count,
>                                    zeroing);
> @@ -900,8 +900,6 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, 
> unsigned nbytes,
>                       return err;
>  
>               nbytes -= count;
> -             count = min(nbytes, (unsigned) PAGE_SIZE);
> -             offset = 0;
>       }
>       return 0;
>  }
> @@ -1611,6 +1609,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct 
> inode *inode,
>  
>               this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
>               req->pages[req->num_pages] = page;
> +             req->page_descs[req->num_pages].length = this_num;
>               req->num_pages++;
>  
>               num -= this_num;
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index 1929bfb..95e4016 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -1179,6 +1179,7 @@ static int fuse_readdir(struct file *file, void 
> *dstbuf, filldir_t filldir)
>       req->out.argpages = 1;
>       req->num_pages = 1;
>       req->pages[0] = page;
> +     req->page_descs[0].length = PAGE_SIZE;
>       fuse_read_fill(req, file, file->f_pos, PAGE_SIZE, FUSE_READDIR);
>       fuse_request_send(fc, req);
>       nbytes = req->out.args[0].size;
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index b68cf3b..8a1f833 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -555,6 +555,7 @@ static int fuse_readpage(struct file *file, struct page 
> *page)
>       req->out.argpages = 1;
>       req->num_pages = 1;
>       req->pages[0] = page;
> +     req->page_descs[0].length = count;
>       num_read = fuse_send_read(req, file, pos, count, NULL);
>       err = req->out.h.error;
>       fuse_put_request(fc, req);
> @@ -674,6 +675,7 @@ static int fuse_readpages_fill(void *_data, struct page 
> *page)
>  
>       page_cache_get(page);
>       req->pages[req->num_pages] = page;
> +     req->page_descs[req->num_pages].length = PAGE_SIZE;
>       req->num_pages++;
>       data->nr_pages--;
>       return 0;
> @@ -869,6 +871,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req,
>  
>               err = 0;
>               req->pages[req->num_pages] = page;
> +             req->page_descs[req->num_pages].length = tmp;
>               req->num_pages++;
>  
>               iov_iter_advance(ii, tmp);
> @@ -1044,6 +1047,15 @@ static void fuse_release_user_pages(struct fuse_req 
> *req, int write)
>       }
>  }
>  
> +static inline void fuse_page_descs_length_init(struct fuse_req *req)
> +{
> +     int i;
> +
> +     for (i = 0; i < req->num_pages; i++)
> +             req->page_descs[i].length = PAGE_SIZE -
> +                     req->page_descs[i].offset;
> +}
> +
>  static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
>                              size_t *nbytesp, int write)
>  {
> @@ -1071,6 +1083,7 @@ static int fuse_get_user_pages(struct fuse_req *req, 
> const char __user *buf,
>  
>       req->num_pages = npages;
>       req->page_descs[0].offset = offset;
> +     fuse_page_descs_length_init(req);
>  
>       if (write)
>               req->in.argpages = 1;
> @@ -1078,6 +1091,11 @@ static int fuse_get_user_pages(struct fuse_req *req, 
> const char __user *buf,
>               req->out.argpages = 1;
>  
>       nbytes = (req->num_pages << PAGE_SHIFT) - req->page_descs[0].offset;
> +
> +     if (*nbytesp < nbytes)
> +             req->page_descs[req->num_pages - 1].length -=
> +                     nbytes - *nbytesp;
> +
>       *nbytesp = min(*nbytesp, nbytes);
>  
>       return 0;
> @@ -1315,6 +1333,7 @@ static int fuse_writepage_locked(struct page *page)
>       req->num_pages = 1;
>       req->pages[0] = tmp_page;
>       req->page_descs[0].offset = 0;
> +     req->page_descs[0].length = PAGE_SIZE;
>       req->end = fuse_writepage_end;
>       req->inode = inode;
>  
> @@ -1901,6 +1920,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, 
> unsigned long arg,
>       }
>       memcpy(req->pages, pages, sizeof(req->pages[0]) * num_pages);
>       req->num_pages = num_pages;
> +     fuse_page_descs_length_init(req);
>  
>       /* okay, let's send it to the client */
>       req->in.h.opcode = FUSE_IOCTL;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to