Re: [PATCH 2/5] cifs: add cifs_async_readv

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2011/10/11 Jeff Layton <jlayton@xxxxxxxxxx>:
> On Tue, 11 Oct 2011 13:30:14 +0400
> Pavel Shilovsky <piastryyy@xxxxxxxxx> wrote:
>
>> 2011/9/6 Jeff Layton <jlayton@xxxxxxxxxx>:
>> > ...which will allow cifs to do an asynchronous read call to the server.
>> > The caller will allocate and set up cifs_readdata for each READ_AND_X
>> > call that should be issued on the wire. The pages passed in are added
>> > to the pagecache, but not placed on the LRU list yet (as we need the
>> > page->lru to keep the pages on the list in the readdata).
>> >
>> > When cifsd identifies the mid, it will see that there is a special
>> > receive handler for the call, and use that to receive the rest of the
>> > frame. cifs_readv_receive will then marshal up a kvec array with
>> > kmapped pages from the pagecache, which eliminates one copy of the
>> > data. Once the data is received, the pages are added to the LRU list,
>> > set uptodate, and unlocked.
>> >
>> > Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
>> > ---
>> >  fs/cifs/cifsproto.h |   24 ++++
>> >  fs/cifs/cifssmb.c   |  356 +++++++++++++++++++++++++++++++++++++++++++++++++++
>> >  fs/cifs/connect.c   |   26 ++--
>> >  3 files changed, 393 insertions(+), 13 deletions(-)
>> >
>> > diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
>> > index 51c0ebc..38406e5 100644
>> > --- a/fs/cifs/cifsproto.h
>> > +++ b/fs/cifs/cifsproto.h
>> > @@ -152,6 +152,12 @@ extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
>> >  extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
>> >                                const char *);
>> >
>> > +extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
>> > +extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
>> > +                    unsigned int to_read);
>> > +extern int cifs_readv_from_socket(struct TCP_Server_Info *server,
>> > +               struct kvec *iov_orig, unsigned int nr_segs,
>> > +               unsigned int to_read);
>> >  extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
>> >                               struct cifs_sb_info *cifs_sb);
>> >  extern int cifs_match_super(struct super_block *, void *);
>> > @@ -441,6 +447,24 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16);
>> >  extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
>> >                        unsigned char *p24);
>> >
>> > +/* asynchronous read support */
>> > +struct cifs_readdata {
>> > +       struct cifsFileInfo             *cfile;
>> > +       struct address_space            *mapping;
>> > +       __u64                           offset;
>> > +       unsigned int                    bytes;
>> > +       pid_t                           pid;
>> > +       int                             result;
>> > +       struct list_head                pages;
>> > +       struct work_struct              work;
>> > +       unsigned int                    nr_iov;
>> > +       struct kvec                     iov[1];
>> > +};
>> > +
>> > +struct cifs_readdata *cifs_readdata_alloc(unsigned int nr_pages);
>> > +void cifs_readdata_free(struct cifs_readdata *rdata);
>> > +int cifs_async_readv(struct cifs_readdata *rdata);
>> > +
>> >  /* asynchronous write support */
>> >  struct cifs_writedata {
>> >        struct kref                     refcount;
>> > diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
>> > index ae1ce01..ac72f28 100644
>> > --- a/fs/cifs/cifssmb.c
>> > +++ b/fs/cifs/cifssmb.c
>> > @@ -33,6 +33,8 @@
>> >  #include <linux/slab.h>
>> >  #include <linux/posix_acl_xattr.h>
>> >  #include <linux/pagemap.h>
>> > +#include <linux/swap.h>
>> > +#include <linux/task_io_accounting_ops.h>
>> >  #include <asm/uaccess.h>
>> >  #include "cifspdu.h"
>> >  #include "cifsglob.h"
>> > @@ -40,6 +42,7 @@
>> >  #include "cifsproto.h"
>> >  #include "cifs_unicode.h"
>> >  #include "cifs_debug.h"
>> > +#include "fscache.h"
>> >
>> >  #ifdef CONFIG_CIFS_POSIX
>> >  static struct {
>> > @@ -83,6 +86,9 @@ static struct {
>> >  #endif /* CONFIG_CIFS_WEAK_PW_HASH */
>> >  #endif /* CIFS_POSIX */
>> >
>> > +/* Forward declarations */
>> > +static void cifs_readv_complete(struct work_struct *work);
>> > +
>> >  /* Mark as invalid, all open files on tree connections since they
>> >    were closed when session to server was lost */
>> >  static void mark_open_files_invalid(struct cifs_tcon *pTcon)
>> > @@ -1375,6 +1381,356 @@ openRetry:
>> >        return rc;
>> >  }
>> >
>> > +struct cifs_readdata *
>> > +cifs_readdata_alloc(unsigned int nr_pages)
>> > +{
>> > +       struct cifs_readdata *rdata;
>> > +
>> > +       /* readdata + 1 kvec for each page */
>> > +       rdata = kzalloc(sizeof(*rdata) +
>> > +                       sizeof(struct kvec) * nr_pages, GFP_KERNEL);
>> > +       if (rdata != NULL) {
>> > +               INIT_WORK(&rdata->work, cifs_readv_complete);
>> > +               INIT_LIST_HEAD(&rdata->pages);
>> > +       }
>> > +       return rdata;
>> > +}
>> > +
>> > +void
>> > +cifs_readdata_free(struct cifs_readdata *rdata)
>> > +{
>> > +       cifsFileInfo_put(rdata->cfile);
>> > +       kfree(rdata);
>> > +}
>> > +
>> > +/*
>> > + * Discard any remaining data in the current SMB. To do this, we borrow the
>> > + * current bigbuf.
>> > + */
>> > +static int
>> > +cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
>> > +{
>> > +       READ_RSP *rsp = (READ_RSP *)server->smallbuf;
>> > +       unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length);
>> > +       int remaining = rfclen + 4 - server->total_read;
>> > +       struct cifs_readdata *rdata = mid->callback_data;
>> > +
>> > +       while (remaining > 0) {
>> > +               int length;
>> > +
>> > +               length = cifs_read_from_socket(server, server->bigbuf,
>> > +                               min_t(unsigned int, remaining,
>> > +                                       CIFSMaxBufSize + MAX_CIFS_HDR_SIZE));
>> > +               if (length < 0)
>> > +                       return length;
>> > +               server->total_read += length;
>> > +               remaining -= length;
>> > +       }
>> > +
>> > +       dequeue_mid(mid, rdata->result);
>> > +       return 0;
>> > +}
>> > +
>> > +static int
>> > +cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
>> > +{
>> > +       int length, len;
>> > +       unsigned int data_offset, remaining, data_len;
>> > +       struct cifs_readdata *rdata = mid->callback_data;
>> > +       READ_RSP *rsp = (READ_RSP *)server->smallbuf;
>> > +       unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length) + 4;
>> > +       u64 eof;
>> > +       pgoff_t eof_index;
>> > +       struct page *page, *tpage;
>> > +
>> > +       cFYI(1, "%s: mid=%u offset=%llu bytes=%u", __func__,
>> > +               mid->mid, rdata->offset, rdata->bytes);
>> > +
>> > +       /*
>> > +        * read the rest of READ_RSP header (sans Data array), or whatever we
>> > +        * can if there's not enough data. At this point, we've read down to
>> > +        * the Mid.
>> > +        */
>> > +       len = min_t(unsigned int, rfclen, sizeof(*rsp)) -
>> > +                       sizeof(struct smb_hdr) + 1;
>> > +
>> > +       rdata->iov[0].iov_base = server->smallbuf + sizeof(struct smb_hdr) - 1;
>> > +       rdata->iov[0].iov_len = len;
>> > +
>> > +       length = cifs_readv_from_socket(server, rdata->iov, 1, len);
>> > +       if (length < 0)
>> > +               return length;
>> > +       server->total_read += length;
>> > +
>> > +       /* Was the SMB read successful? */
>> > +       rdata->result = map_smb_to_linux_error(&rsp->hdr, false);
>> > +       if (rdata->result != 0) {
>> > +               cFYI(1, "%s: server returned error %d", __func__,
>> > +                       rdata->result);
>> > +               return cifs_readv_discard(server, mid);
>> > +       }
>> > +
>> > +       /* Is there enough to get to the rest of the READ_RSP header? */
>> > +       if (server->total_read < sizeof(READ_RSP)) {
>> > +               cFYI(1, "%s: server returned short header. got=%u expected=%lu",
>> > +                       __func__, server->total_read, sizeof(READ_RSP));
>>
>> sizeof should be casted to unsigned long to prevent compiler warnings.
>>
>
> Actually...I think what I need to do here and in the other places you
> pointed out is to use "%z". I'll fix and respin.
>
> Thanks for the review...
> --
> Jeff Layton <jlayton@xxxxxxxxxx>
>

No problem. Yes, %z is ok too.

-- 
Best regards,
Pavel Shilovsky.
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux