Merge tag 'regmap-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
[cascardo/linux.git] / fs / cifs / cifssmb.c
index da2f544..5b40073 100644 (file)
@@ -87,7 +87,6 @@ static struct {
 #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 */
@@ -269,7 +268,7 @@ small_smb_init_no_tc(const int smb_command, const int wct,
                return rc;
 
        buffer = (struct smb_hdr *)*request_buf;
-       buffer->Mid = GetNextMid(ses->server);
+       buffer->Mid = get_next_mid(ses->server);
        if (ses->capabilities & CAP_UNICODE)
                buffer->Flags2 |= SMBFLG2_UNICODE;
        if (ses->capabilities & CAP_STATUS32)
@@ -403,7 +402,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
 
        cFYI(1, "secFlags 0x%x", secFlags);
 
-       pSMB->hdr.Mid = GetNextMid(server);
+       pSMB->hdr.Mid = get_next_mid(server);
        pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
 
        if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
@@ -461,7 +460,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
                server->maxReq = min_t(unsigned int,
                                       le16_to_cpu(rsp->MaxMpxCount),
                                       cifs_max_pending);
-               cifs_set_credits(server, server->maxReq);
+               set_credits(server, server->maxReq);
                server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
                server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
                /* even though we do not use raw we might as well set this
@@ -569,7 +568,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
           little endian */
        server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
                               cifs_max_pending);
-       cifs_set_credits(server, server->maxReq);
+       set_credits(server, server->maxReq);
        /* probably no need to store and check maxvcs */
        server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
        server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
@@ -721,7 +720,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
        struct TCP_Server_Info *server = mid->callback_data;
 
        DeleteMidQEntry(mid);
-       cifs_add_credits(server, 1);
+       add_credits(server, 1);
 }
 
 int
@@ -783,7 +782,7 @@ CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
                return rc;
        }
 
-       pSMB->hdr.Mid = GetNextMid(ses->server);
+       pSMB->hdr.Mid = get_next_mid(ses->server);
 
        if (ses->server->sec_mode &
                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
@@ -1385,28 +1384,6 @@ 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.
@@ -1423,7 +1400,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
                length = cifs_read_from_socket(server, server->bigbuf,
                                min_t(unsigned int, remaining,
-                                       CIFSMaxBufSize + max_header_size()));
+                                   CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
                if (length < 0)
                        return length;
                server->total_read += length;
@@ -1434,38 +1411,14 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        return 0;
 }
 
-static inline size_t
-read_rsp_size(void)
-{
-       return sizeof(READ_RSP);
-}
-
-static inline unsigned int
-read_data_offset(char *buf)
-{
-       READ_RSP *rsp = (READ_RSP *)buf;
-       return le16_to_cpu(rsp->DataOffset);
-}
-
-static inline unsigned int
-read_data_length(char *buf)
-{
-       READ_RSP *rsp = (READ_RSP *)buf;
-       return (le16_to_cpu(rsp->DataLengthHigh) << 16) +
-              le16_to_cpu(rsp->DataLength);
-}
-
 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;
+       unsigned int data_offset, data_len;
        struct cifs_readdata *rdata = mid->callback_data;
        char *buf = server->smallbuf;
        unsigned int buflen = get_rfc1002_length(buf) + 4;
-       u64 eof;
-       pgoff_t eof_index;
-       struct page *page, *tpage;
 
        cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
                mid->mid, rdata->offset, rdata->bytes);
@@ -1475,9 +1428,10 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
         * can if there's not enough data. At this point, we've read down to
         * the Mid.
         */
-       len = min_t(unsigned int, buflen, read_rsp_size()) - header_size() + 1;
+       len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
+                                                       HEADER_SIZE(server) + 1;
 
-       rdata->iov[0].iov_base = buf + header_size() - 1;
+       rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
        rdata->iov[0].iov_len = len;
 
        length = cifs_readv_from_socket(server, rdata->iov, 1, len);
@@ -1486,7 +1440,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        server->total_read += length;
 
        /* Was the SMB read successful? */
-       rdata->result = map_smb_to_linux_error(buf, false);
+       rdata->result = server->ops->map_error(buf, false);
        if (rdata->result != 0) {
                cFYI(1, "%s: server returned error %d", __func__,
                        rdata->result);
@@ -1494,14 +1448,15 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        }
 
        /* Is there enough to get to the rest of the READ_RSP header? */
-       if (server->total_read < read_rsp_size()) {
+       if (server->total_read < server->vals->read_rsp_size) {
                cFYI(1, "%s: server returned short header. got=%u expected=%zu",
-                       __func__, server->total_read, read_rsp_size());
+                       __func__, server->total_read,
+                       server->vals->read_rsp_size);
                rdata->result = -EIO;
                return cifs_readv_discard(server, mid);
        }
 
-       data_offset = read_data_offset(buf) + 4;
+       data_offset = server->ops->read_data_offset(buf) + 4;
        if (data_offset < server->total_read) {
                /*
                 * win2k8 sometimes sends an offset of 0 when the read
@@ -1540,7 +1495,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
                rdata->iov[0].iov_base, rdata->iov[0].iov_len);
 
        /* how much data is in the response? */
-       data_len = read_data_length(buf);
+       data_len = server->ops->read_data_length(buf);
        if (data_offset + data_len > buflen) {
                /* data_len is corrupt -- discard frame */
                rdata->result = -EIO;
@@ -1548,64 +1503,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        }
 
        /* marshal up the page array */
-       len = 0;
-       remaining = data_len;
-       rdata->nr_iov = 1;
-
-       /* determine the eof that the server (probably) has */
-       eof = CIFS_I(rdata->mapping->host)->server_eof;
-       eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0;
-       cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index);
-
-       list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
-               if (remaining >= PAGE_CACHE_SIZE) {
-                       /* enough data to fill the page */
-                       rdata->iov[rdata->nr_iov].iov_base = kmap(page);
-                       rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE;
-                       cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
-                               rdata->nr_iov, page->index,
-                               rdata->iov[rdata->nr_iov].iov_base,
-                               rdata->iov[rdata->nr_iov].iov_len);
-                       ++rdata->nr_iov;
-                       len += PAGE_CACHE_SIZE;
-                       remaining -= PAGE_CACHE_SIZE;
-               } else if (remaining > 0) {
-                       /* enough for partial page, fill and zero the rest */
-                       rdata->iov[rdata->nr_iov].iov_base = kmap(page);
-                       rdata->iov[rdata->nr_iov].iov_len = remaining;
-                       cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu",
-                               rdata->nr_iov, page->index,
-                               rdata->iov[rdata->nr_iov].iov_base,
-                               rdata->iov[rdata->nr_iov].iov_len);
-                       memset(rdata->iov[rdata->nr_iov].iov_base + remaining,
-                               '\0', PAGE_CACHE_SIZE - remaining);
-                       ++rdata->nr_iov;
-                       len += remaining;
-                       remaining = 0;
-               } else if (page->index > eof_index) {
-                       /*
-                        * The VFS will not try to do readahead past the
-                        * i_size, but it's possible that we have outstanding
-                        * writes with gaps in the middle and the i_size hasn't
-                        * caught up yet. Populate those with zeroed out pages
-                        * to prevent the VFS from repeatedly attempting to
-                        * fill them until the writes are flushed.
-                        */
-                       zero_user(page, 0, PAGE_CACHE_SIZE);
-                       list_del(&page->lru);
-                       lru_cache_add_file(page);
-                       flush_dcache_page(page);
-                       SetPageUptodate(page);
-                       unlock_page(page);
-                       page_cache_release(page);
-               } else {
-                       /* no need to hold page hostage */
-                       list_del(&page->lru);
-                       lru_cache_add_file(page);
-                       unlock_page(page);
-                       page_cache_release(page);
-               }
-       }
+       len = rdata->marshal_iov(rdata, data_len);
+       data_len -= len;
 
        /* issue the read if we have any iovecs left to fill */
        if (rdata->nr_iov > 1) {
@@ -1621,7 +1520,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        rdata->bytes = length;
 
        cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
-               buflen, remaining);
+               buflen, data_len);
 
        /* discard anything left over */
        if (server->total_read < buflen)
@@ -1631,33 +1530,6 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        return length;
 }
 
-static void
-cifs_readv_complete(struct work_struct *work)
-{
-       struct cifs_readdata *rdata = container_of(work,
-                                               struct cifs_readdata, work);
-       struct page *page, *tpage;
-
-       list_for_each_entry_safe(page, tpage, &rdata->pages, lru) {
-               list_del(&page->lru);
-               lru_cache_add_file(page);
-
-               if (rdata->result == 0) {
-                       kunmap(page);
-                       flush_dcache_page(page);
-                       SetPageUptodate(page);
-               }
-
-               unlock_page(page);
-
-               if (rdata->result == 0)
-                       cifs_readpage_to_fscache(rdata->mapping->host, page);
-
-               page_cache_release(page);
-       }
-       cifs_readdata_free(rdata);
-}
-
 static void
 cifs_readv_callback(struct mid_q_entry *mid)
 {
@@ -1691,7 +1563,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
 
        queue_work(cifsiod_wq, &rdata->work);
        DeleteMidQEntry(mid);
-       cifs_add_credits(server, 1);
+       add_credits(server, 1);
 }
 
 /* cifs_async_readv - send an async write, and set up mid to handle result */
@@ -1744,12 +1616,15 @@ cifs_async_readv(struct cifs_readdata *rdata)
        rdata->iov[0].iov_base = smb;
        rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 
+       kref_get(&rdata->refcount);
        rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
                             cifs_readv_receive, cifs_readv_callback,
                             rdata, false);
 
        if (rc == 0)
                cifs_stats_inc(&tcon->num_reads);
+       else
+               kref_put(&rdata->refcount, cifs_readdata_release);
 
        cifs_small_buf_release(smb);
        return rc;
@@ -2135,7 +2010,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
 
        queue_work(cifsiod_wq, &wdata->work);
        DeleteMidQEntry(mid);
-       cifs_add_credits(tcon->ses->server, 1);
+       add_credits(tcon->ses->server, 1);
 }
 
 /* cifs_async_writev - send an async write, and set up mid to handle result */
@@ -4344,7 +4219,7 @@ int
 CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
              const char *searchName,
              const struct nls_table *nls_codepage,
-             __u16 *pnetfid,
+             __u16 *pnetfid, __u16 search_flags,
              struct cifs_search_info *psrch_inf, int remap, const char dirsep)
 {
 /* level 257 SMB_ */
@@ -4416,8 +4291,7 @@ findFirstRetry:
            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
                        ATTR_DIRECTORY);
        pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
-       pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
-               CIFS_SEARCH_RETURN_RESUME);
+       pSMB->SearchFlags = cpu_to_le16(search_flags);
        pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
 
        /* BB what should we set StorageType to? Does it matter? BB */
@@ -4487,8 +4361,8 @@ findFirstRetry:
        return rc;
 }
 
-int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
-                __u16 searchHandle, struct cifs_search_info *psrch_inf)
+int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle,
+                __u16 search_flags, struct cifs_search_info *psrch_inf)
 {
        TRANSACTION2_FNEXT_REQ *pSMB = NULL;
        TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
@@ -4531,8 +4405,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
                cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
        pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
        pSMB->ResumeKey = psrch_inf->resume_key;
-       pSMB->SearchFlags =
-             cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
+       pSMB->SearchFlags = cpu_to_le16(search_flags);
 
        name_len = psrch_inf->resume_name_len;
        params += name_len;
@@ -4889,7 +4762,7 @@ getDFSRetry:
 
        /* server pointer checked in called function,
        but should never be null here anyway */
-       pSMB->hdr.Mid = GetNextMid(ses->server);
+       pSMB->hdr.Mid = get_next_mid(ses->server);
        pSMB->hdr.Tid = ses->ipc_tid;
        pSMB->hdr.Uid = ses->Suid;
        if (ses->capabilities & CAP_STATUS32)