]> Pileus Git - ~andy/linux/blobdiff - fs/cifs/cifssmb.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[~andy/linux] / fs / cifs / cifssmb.c
index 8b7794c315919c5328a5bffbcb2aa5a9d7ad5b30..f52c5ab78f9dde7fa782bbb2ca26e7da70e450af 100644 (file)
@@ -458,7 +458,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
                        goto neg_err_exit;
                }
                server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
-               server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
+               server->maxReq = min_t(unsigned int,
+                                      le16_to_cpu(rsp->MaxMpxCount),
+                                      cifs_max_pending);
+               cifs_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
@@ -564,7 +567,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
 
        /* one byte, so no need to convert this or EncryptionKeyLen from
           little endian */
-       server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
+       server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
+                              cifs_max_pending);
+       cifs_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);
@@ -691,7 +696,7 @@ CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
        if (rc)
                return rc;
 
-       rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
+       rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
        if (rc)
                cFYI(1, "Tree disconnect failed %d", rc);
 
@@ -716,8 +721,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
        struct TCP_Server_Info *server = mid->callback_data;
 
        DeleteMidQEntry(mid);
-       atomic_dec(&server->inFlight);
-       wake_up(&server->request_q);
+       cifs_add_credits(server, 1);
 }
 
 int
@@ -788,7 +792,7 @@ CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
        pSMB->hdr.Uid = ses->Suid;
 
        pSMB->AndXCommand = 0xFF;
-       rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
+       rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
 session_already_dead:
        mutex_unlock(&ses->session_mutex);
 
@@ -1410,8 +1414,7 @@ cifs_readdata_free(struct cifs_readdata *rdata)
 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);
+       unsigned int rfclen = get_rfc1002_length(server->smallbuf);
        int remaining = rfclen + 4 - server->total_read;
        struct cifs_readdata *rdata = mid->callback_data;
 
@@ -1420,7 +1423,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_CIFS_HDR_SIZE));
+                                       CIFSMaxBufSize + max_header_size()));
                if (length < 0)
                        return length;
                server->total_read += length;
@@ -1431,19 +1434,40 @@ 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;
        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;
+       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=%u offset=%llu bytes=%u", __func__,
+       cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
                mid->mid, rdata->offset, rdata->bytes);
 
        /*
@@ -1451,10 +1475,9 @@ 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, rfclen, sizeof(*rsp)) -
-                       sizeof(struct smb_hdr) + 1;
+       len = min_t(unsigned int, buflen, read_rsp_size()) - header_size() + 1;
 
-       rdata->iov[0].iov_base = server->smallbuf + sizeof(struct smb_hdr) - 1;
+       rdata->iov[0].iov_base = buf + header_size() - 1;
        rdata->iov[0].iov_len = len;
 
        length = cifs_readv_from_socket(server, rdata->iov, 1, len);
@@ -1463,7 +1486,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(&rsp->hdr, false);
+       rdata->result = map_smb_to_linux_error(buf, false);
        if (rdata->result != 0) {
                cFYI(1, "%s: server returned error %d", __func__,
                        rdata->result);
@@ -1471,14 +1494,14 @@ 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 < sizeof(READ_RSP)) {
+       if (server->total_read < read_rsp_size()) {
                cFYI(1, "%s: server returned short header. got=%u expected=%zu",
-                       __func__, server->total_read, sizeof(READ_RSP));
+                       __func__, server->total_read, read_rsp_size());
                rdata->result = -EIO;
                return cifs_readv_discard(server, mid);
        }
 
-       data_offset = le16_to_cpu(rsp->DataOffset) + 4;
+       data_offset = read_data_offset(buf) + 4;
        if (data_offset < server->total_read) {
                /*
                 * win2k8 sometimes sends an offset of 0 when the read
@@ -1502,7 +1525,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        len = data_offset - server->total_read;
        if (len > 0) {
                /* read any junk before data into the rest of smallbuf */
-               rdata->iov[0].iov_base = server->smallbuf + server->total_read;
+               rdata->iov[0].iov_base = buf + server->total_read;
                rdata->iov[0].iov_len = len;
                length = cifs_readv_from_socket(server, rdata->iov, 1, len);
                if (length < 0)
@@ -1511,15 +1534,14 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        }
 
        /* set up first iov for signature check */
-       rdata->iov[0].iov_base = server->smallbuf;
+       rdata->iov[0].iov_base = buf;
        rdata->iov[0].iov_len = server->total_read;
        cFYI(1, "0: iov_base=%p iov_len=%zu",
                rdata->iov[0].iov_base, rdata->iov[0].iov_len);
 
        /* how much data is in the response? */
-       data_len = le16_to_cpu(rsp->DataLengthHigh) << 16;
-       data_len += le16_to_cpu(rsp->DataLength);
-       if (data_offset + data_len > rfclen) {
+       data_len = read_data_length(buf);
+       if (data_offset + data_len > buflen) {
                /* data_len is corrupt -- discard frame */
                rdata->result = -EIO;
                return cifs_readv_discard(server, mid);
@@ -1598,11 +1620,11 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
        rdata->bytes = length;
 
-       cFYI(1, "total_read=%u rfclen=%u remaining=%u", server->total_read,
-               rfclen, remaining);
+       cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
+               buflen, remaining);
 
        /* discard anything left over */
-       if (server->total_read < rfclen)
+       if (server->total_read < buflen)
                return cifs_readv_discard(server, mid);
 
        dequeue_mid(mid, false);
@@ -1643,10 +1665,10 @@ cifs_readv_callback(struct mid_q_entry *mid)
        struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
        struct TCP_Server_Info *server = tcon->ses->server;
 
-       cFYI(1, "%s: mid=%u state=%d result=%d bytes=%u", __func__,
-               mid->mid, mid->midState, rdata->result, rdata->bytes);
+       cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
+               mid->mid, mid->mid_state, rdata->result, rdata->bytes);
 
-       switch (mid->midState) {
+       switch (mid->mid_state) {
        case MID_RESPONSE_RECEIVED:
                /* result already set, check signature */
                if (server->sec_mode &
@@ -1667,10 +1689,9 @@ cifs_readv_callback(struct mid_q_entry *mid)
                rdata->result = -EIO;
        }
 
-       queue_work(system_nrt_wq, &rdata->work);
+       queue_work(cifsiod_wq, &rdata->work);
        DeleteMidQEntry(mid);
-       atomic_dec(&server->inFlight);
-       wake_up(&server->request_q);
+       cifs_add_credits(server, 1);
 }
 
 /* cifs_async_readv - send an async write, and set up mid to handle result */
@@ -2014,7 +2035,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
        kref_put(&wdata->refcount, cifs_writedata_release);
 }
 
-static void
+void
 cifs_writev_complete(struct work_struct *work)
 {
        struct cifs_writedata *wdata = container_of(work,
@@ -2023,7 +2044,9 @@ cifs_writev_complete(struct work_struct *work)
        int i = 0;
 
        if (wdata->result == 0) {
+               spin_lock(&inode->i_lock);
                cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
+               spin_unlock(&inode->i_lock);
                cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
                                         wdata->bytes);
        } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
@@ -2044,7 +2067,7 @@ cifs_writev_complete(struct work_struct *work)
 }
 
 struct cifs_writedata *
-cifs_writedata_alloc(unsigned int nr_pages)
+cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
 {
        struct cifs_writedata *wdata;
 
@@ -2058,14 +2081,16 @@ cifs_writedata_alloc(unsigned int nr_pages)
        wdata = kzalloc(sizeof(*wdata) +
                        sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
        if (wdata != NULL) {
-               INIT_WORK(&wdata->work, cifs_writev_complete);
                kref_init(&wdata->refcount);
+               INIT_LIST_HEAD(&wdata->list);
+               init_completion(&wdata->done);
+               INIT_WORK(&wdata->work, complete);
        }
        return wdata;
 }
 
 /*
- * Check the midState and signature on received buffer (if any), and queue the
+ * Check the mid_state and signature on received buffer (if any), and queue the
  * workqueue completion task.
  */
 static void
@@ -2076,7 +2101,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
        unsigned int written;
        WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
 
-       switch (mid->midState) {
+       switch (mid->mid_state) {
        case MID_RESPONSE_RECEIVED:
                wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
                if (wdata->result != 0)
@@ -2108,10 +2133,9 @@ cifs_writev_callback(struct mid_q_entry *mid)
                break;
        }
 
-       queue_work(system_nrt_wq, &wdata->work);
+       queue_work(cifsiod_wq, &wdata->work);
        DeleteMidQEntry(mid);
-       atomic_dec(&tcon->ses->server->inFlight);
-       wake_up(&tcon->ses->server->request_q);
+       cifs_add_credits(tcon->ses->server, 1);
 }
 
 /* cifs_async_writev - send an async write, and set up mid to handle result */
@@ -2122,7 +2146,6 @@ cifs_async_writev(struct cifs_writedata *wdata)
        WRITE_REQ *smb = NULL;
        int wct;
        struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
-       struct inode *inode = wdata->cfile->dentry->d_inode;
        struct kvec *iov = NULL;
 
        if (tcon->ses->capabilities & CAP_LARGE_FILES) {
@@ -2146,8 +2169,8 @@ cifs_async_writev(struct cifs_writedata *wdata)
                goto async_writev_out;
        }
 
-       smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
-       smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
+       smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
+       smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
 
        smb->AndXCommand = 0xFF;        /* none */
        smb->Fid = wdata->cfile->netfid;
@@ -2165,15 +2188,13 @@ cifs_async_writev(struct cifs_writedata *wdata)
        iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
        iov[0].iov_base = smb;
 
-       /* marshal up the pages into iov array */
-       wdata->bytes = 0;
-       for (i = 0; i < wdata->nr_pages; i++) {
-               iov[i + 1].iov_len = min(inode->i_size -
-                                     page_offset(wdata->pages[i]),
-                                       (loff_t)PAGE_CACHE_SIZE);
-               iov[i + 1].iov_base = kmap(wdata->pages[i]);
-               wdata->bytes += iov[i + 1].iov_len;
-       }
+       /*
+        * This function should marshal up the page array into the kvec
+        * array, reserving [0] for the header. It should kmap the pages
+        * and set the iov_len properly for each one. It may also set
+        * wdata->bytes too.
+        */
+       wdata->marshal_iov(iov, wdata);
 
        cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
 
@@ -2418,8 +2439,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
                        (struct smb_hdr *) pSMB, &bytes_returned);
                cifs_small_buf_release(pSMB);
        } else {
-               rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
-                                     timeout);
+               rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, timeout);
                /* SMB buffer freed by function above */
        }
        cifs_stats_inc(&tcon->num_locks);
@@ -2586,7 +2606,7 @@ CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
        pSMB->FileID = (__u16) smb_file_id;
        pSMB->LastWriteTime = 0xFFFFFFFF;
        pSMB->ByteCount = 0;
-       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
        cifs_stats_inc(&tcon->num_closes);
        if (rc) {
                if (rc != -EINTR) {
@@ -2615,7 +2635,7 @@ CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
 
        pSMB->FileID = (__u16) smb_file_id;
        pSMB->ByteCount = 0;
-       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
        cifs_stats_inc(&tcon->num_flushes);
        if (rc)
                cERROR(1, "Send error in Flush = %d", rc);
@@ -3872,13 +3892,12 @@ CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
        int rc = 0;
        int bytes_returned = 0;
        SET_SEC_DESC_REQ *pSMB = NULL;
-       NTRANSACT_RSP *pSMBr = NULL;
+       void *pSMBr;
 
 setCifsAclRetry:
-       rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
-                       (void **) &pSMBr);
+       rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
        if (rc)
-                       return (rc);
+               return rc;
 
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
@@ -3906,9 +3925,8 @@ setCifsAclRetry:
        pSMB->AclFlags = cpu_to_le32(aclflag);
 
        if (pntsd && acllen) {
-               memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
-                       (char *) pntsd,
-                       acllen);
+               memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
+                               data_offset, pntsd, acllen);
                inc_rfc1001_len(pSMB, byte_count + data_count);
        } else
                inc_rfc1001_len(pSMB, byte_count);
@@ -4623,7 +4641,7 @@ CIFSFindClose(const int xid, struct cifs_tcon *tcon,
 
        pSMB->FileID = searchHandle;
        pSMB->ByteCount = 0;
-       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
        if (rc)
                cERROR(1, "Send error in FindClose = %d", rc);
 
@@ -5644,7 +5662,7 @@ CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
        pSMB->Reserved4 = 0;
        inc_rfc1001_len(pSMB, byte_count);
        pSMB->ByteCount = cpu_to_le16(byte_count);
-       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
        if (rc) {
                cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
        }
@@ -5688,7 +5706,8 @@ CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
        offset = param_offset + params;
 
-       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+       data_offset = (char *)pSMB +
+                       offsetof(struct smb_hdr, Protocol) + offset;
 
        count = sizeof(FILE_BASIC_INFO);
        pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -5713,7 +5732,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
        inc_rfc1001_len(pSMB, byte_count);
        pSMB->ByteCount = cpu_to_le16(byte_count);
        memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
-       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
        if (rc)
                cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
 
@@ -5772,7 +5791,7 @@ CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
        inc_rfc1001_len(pSMB, byte_count);
        pSMB->ByteCount = cpu_to_le16(byte_count);
        *data_offset = delete_file ? 1 : 0;
-       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
        if (rc)
                cFYI(1, "Send error in SetFileDisposition = %d", rc);
 
@@ -5957,7 +5976,7 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
                       u16 fid, u32 pid_of_opener)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
-       FILE_UNIX_BASIC_INFO *data_offset;
+       char *data_offset;
        int rc = 0;
        u16 params, param_offset, offset, byte_count, count;
 
@@ -5979,8 +5998,9 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
        offset = param_offset + params;
 
-       data_offset = (FILE_UNIX_BASIC_INFO *)
-                               ((char *)(&pSMB->hdr.Protocol) + offset);
+       data_offset = (char *)pSMB +
+                       offsetof(struct smb_hdr, Protocol) + offset;
+
        count = sizeof(FILE_UNIX_BASIC_INFO);
 
        pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -6002,9 +6022,9 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
        inc_rfc1001_len(pSMB, byte_count);
        pSMB->ByteCount = cpu_to_le16(byte_count);
 
-       cifs_fill_unix_set_info(data_offset, args);
+       cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
 
-       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
        if (rc)
                cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);