fs/cifs: fix parsing of dfs referrals
[pandora-kernel.git] / fs / cifs / cifssmb.c
index a80f7bd..e89803b 100644 (file)
@@ -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)
@@ -452,9 +458,11 @@ 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->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
-                               (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
+               server->maxReq = min_t(unsigned int,
+                                      le16_to_cpu(rsp->MaxMpxCount),
+                                      cifs_max_pending);
+               server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
+               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
                accurately, in case we ever find a need for it */
@@ -559,10 +567,11 @@ 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);
+       server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
        /* probably no need to store and check maxvcs */
-       server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
-                       (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
+       server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
        server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
        cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
        server->capabilities = le32_to_cpu(pSMBr->Capabilities);
@@ -739,7 +748,8 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
        iov.iov_base = smb;
        iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 
-       rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true);
+       rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
+                            server, true);
        if (rc)
                cFYI(1, "Echo request failed: %d", rc);
 
@@ -1376,6 +1386,359 @@ 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=%zu",
+                       __func__, server->total_read, sizeof(READ_RSP));
+               rdata->result = -EIO;
+               return cifs_readv_discard(server, mid);
+       }
+
+       data_offset = le16_to_cpu(rsp->DataOffset) + 4;
+       if (data_offset < server->total_read) {
+               /*
+                * win2k8 sometimes sends an offset of 0 when the read
+                * is beyond the EOF. Treat it as if the data starts just after
+                * the header.
+                */
+               cFYI(1, "%s: data offset (%u) inside read response header",
+                       __func__, data_offset);
+               data_offset = server->total_read;
+       } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
+               /* data_offset is beyond the end of smallbuf */
+               cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
+                       __func__, data_offset);
+               rdata->result = -EIO;
+               return cifs_readv_discard(server, mid);
+       }
+
+       cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
+               server->total_read, data_offset);
+
+       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_len = len;
+               length = cifs_readv_from_socket(server, rdata->iov, 1, len);
+               if (length < 0)
+                       return length;
+               server->total_read += length;
+       }
+
+       /* set up first iov for signature check */
+       rdata->iov[0].iov_base = server->smallbuf;
+       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 is corrupt -- discard frame */
+               rdata->result = -EIO;
+               return cifs_readv_discard(server, 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);
+               }
+       }
+
+       /* issue the read if we have any iovecs left to fill */
+       if (rdata->nr_iov > 1) {
+               length = cifs_readv_from_socket(server, &rdata->iov[1],
+                                               rdata->nr_iov - 1, len);
+               if (length < 0)
+                       return length;
+               server->total_read += length;
+       } else {
+               length = 0;
+       }
+
+       rdata->bytes = length;
+
+       cFYI(1, "total_read=%u rfclen=%u remaining=%u", server->total_read,
+               rfclen, remaining);
+
+       /* discard anything left over */
+       if (server->total_read < rfclen)
+               return cifs_readv_discard(server, mid);
+
+       dequeue_mid(mid, false);
+       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)
+{
+       struct cifs_readdata *rdata = mid->callback_data;
+       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);
+
+       switch (mid->midState) {
+       case MID_RESPONSE_RECEIVED:
+               /* result already set, check signature */
+               if (server->sec_mode &
+                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+                       if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
+                                         server, mid->sequence_number + 1))
+                               cERROR(1, "Unexpected SMB signature");
+               }
+               /* FIXME: should this be counted toward the initiating task? */
+               task_io_account_read(rdata->bytes);
+               cifs_stats_bytes_read(tcon, rdata->bytes);
+               break;
+       case MID_REQUEST_SUBMITTED:
+       case MID_RETRY_NEEDED:
+               rdata->result = -EAGAIN;
+               break;
+       default:
+               rdata->result = -EIO;
+       }
+
+       queue_work(system_nrt_wq, &rdata->work);
+       DeleteMidQEntry(mid);
+       atomic_dec(&server->inFlight);
+       wake_up(&server->request_q);
+}
+
+/* cifs_async_readv - send an async write, and set up mid to handle result */
+int
+cifs_async_readv(struct cifs_readdata *rdata)
+{
+       int rc;
+       READ_REQ *smb = NULL;
+       int wct;
+       struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
+
+       cFYI(1, "%s: offset=%llu bytes=%u", __func__,
+               rdata->offset, rdata->bytes);
+
+       if (tcon->ses->capabilities & CAP_LARGE_FILES)
+               wct = 12;
+       else {
+               wct = 10; /* old style read */
+               if ((rdata->offset >> 32) > 0)  {
+                       /* can not handle this big offset for old */
+                       return -EIO;
+               }
+       }
+
+       rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
+       if (rc)
+               return rc;
+
+       smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
+       smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
+
+       smb->AndXCommand = 0xFF;        /* none */
+       smb->Fid = rdata->cfile->netfid;
+       smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
+       if (wct == 12)
+               smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
+       smb->Remaining = 0;
+       smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
+       smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
+       if (wct == 12)
+               smb->ByteCount = 0;
+       else {
+               /* old style read */
+               struct smb_com_readx_req *smbr =
+                       (struct smb_com_readx_req *)smb;
+               smbr->ByteCount = 0;
+       }
+
+       /* 4 for RFC1001 length + 1 for BCC */
+       rdata->iov[0].iov_base = smb;
+       rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
+
+       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);
+
+       cifs_small_buf_release(smb);
+       return rc;
+}
+
 int
 CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
            char **buf, int *pbuf_type)
@@ -1836,7 +2199,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
 
        kref_get(&wdata->refcount);
        rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
-                            cifs_writev_callback, wdata, false);
+                            NULL, cifs_writev_callback, wdata, false);
 
        if (rc == 0)
                cifs_stats_inc(&tcon->num_writes);
@@ -1962,10 +2325,50 @@ CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
        return rc;
 }
 
+int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
+              const __u8 lock_type, const __u32 num_unlock,
+              const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
+{
+       int rc = 0;
+       LOCK_REQ *pSMB = NULL;
+       struct kvec iov[2];
+       int resp_buf_type;
+       __u16 count;
+
+       cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
+
+       rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
+       if (rc)
+               return rc;
+
+       pSMB->Timeout = 0;
+       pSMB->NumberOfLocks = cpu_to_le16(num_lock);
+       pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
+       pSMB->LockType = lock_type;
+       pSMB->AndXCommand = 0xFF; /* none */
+       pSMB->Fid = netfid; /* netfid stays le */
+
+       count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
+       inc_rfc1001_len(pSMB, count);
+       pSMB->ByteCount = cpu_to_le16(count);
+
+       iov[0].iov_base = (char *)pSMB;
+       iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
+                        (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
+       iov[1].iov_base = (char *)buf;
+       iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
+
+       cifs_stats_inc(&tcon->num_locks);
+       rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
+       if (rc)
+               cFYI(1, "Send error in cifs_lockv = %d", rc);
+
+       return rc;
+}
 
 int
 CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
-           const __u16 smb_file_id, const __u64 len,
+           const __u16 smb_file_id, const __u32 netpid, const __u64 len,
            const __u64 offset, const __u32 numUnlock,
            const __u32 numLock, const __u8 lockType,
            const bool waitFlag, const __u8 oplock_level)
@@ -2001,7 +2404,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
        pSMB->Fid = smb_file_id; /* netfid stays le */
 
        if ((numLock != 0) || (numUnlock != 0)) {
-               pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
+               pSMB->Locks[0].Pid = cpu_to_le16(netpid);
                /* BB where to store pid high? */
                pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
                pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
@@ -2035,9 +2438,9 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
 
 int
 CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
-               const __u16 smb_file_id, const int get_flag, const __u64 len,
-               struct file_lock *pLockData, const __u16 lock_type,
-               const bool waitFlag)
+               const __u16 smb_file_id, const __u32 netpid, const int get_flag,
+               const __u64 len, struct file_lock *pLockData,
+               const __u16 lock_type, const bool waitFlag)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
@@ -2095,7 +2498,7 @@ CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
        } else
                pSMB->Timeout = 0;
 
-       parm_data->pid = cpu_to_le32(current->tgid);
+       parm_data->pid = cpu_to_le32(netpid);
        parm_data->start = cpu_to_le64(pLockData->fl_start);
        parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
 
@@ -2812,8 +3215,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le32(2);
        /* BB find exact data count max from sess structure BB */
-       pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
-                                         MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+       pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
        pSMB->MaxSetupCount = 4;
        pSMB->Reserved = 0;
        pSMB->ParameterOffset = 0;
@@ -3306,8 +3708,7 @@ smb_init_nttransact(const __u16 sub_command, const int setup_count,
        pSMB->Reserved = 0;
        pSMB->TotalParameterCount = cpu_to_le32(parm_len);
        pSMB->TotalDataCount  = 0;
-       pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
-                                         MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+       pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
        pSMB->DataCount  = pSMB->TotalDataCount;
        temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
@@ -3467,7 +3868,7 @@ qsec_out:
 
 int
 CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
-                       struct cifs_ntsd *pntsd, __u32 acllen)
+                       struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
 {
        __u16 byte_count, param_count, data_count, param_offset, data_offset;
        int rc = 0;
@@ -3504,7 +3905,7 @@ setCifsAclRetry:
 
        pSMB->Fid = fid; /* file handle always le */
        pSMB->Reserved2 = 0;
-       pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
+       pSMB->AclFlags = cpu_to_le32(aclflag);
 
        if (pntsd && acllen) {
                memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
@@ -3977,8 +4378,7 @@ findFirstRetry:
        params = 12 + name_len /* includes null */ ;
        pSMB->TotalDataCount = 0;       /* no EAs */
        pSMB->MaxParameterCount = cpu_to_le16(10);
-       pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
-                                         MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+       pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -4052,8 +4452,7 @@ findFirstRetry:
                        psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
                                psrch_inf->entries_in_buffer;
                        lnoff = le16_to_cpu(parms->LastNameOffset);
-                       if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
-                             lnoff) {
+                       if (CIFSMaxBufSize < lnoff) {
                                cERROR(1, "ignoring corrupt resume name");
                                psrch_inf->last_entry = NULL;
                                return rc;
@@ -4097,9 +4496,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
        byte_count = 0;
        pSMB->TotalDataCount = 0;       /* no EAs */
        pSMB->MaxParameterCount = cpu_to_le16(8);
-       pSMB->MaxDataCount =
-               cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
-                               0xFFFFFF00);
+       pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -4181,8 +4578,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
                        psrch_inf->index_of_last_entry +=
                                psrch_inf->entries_in_buffer;
                        lnoff = le16_to_cpu(parms->LastNameOffset);
-                       if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
-                             lnoff) {
+                       if (CIFSMaxBufSize < lnoff) {
                                cERROR(1, "ignoring corrupt resume name");
                                psrch_inf->last_entry = NULL;
                                return rc;
@@ -4430,8 +4826,12 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
                max_len = data_end - temp;
                node->node_name = cifs_strndup_from_ucs(temp, max_len,
                                                      is_unicode, nls_codepage);
-               if (!node->node_name)
+               if (!node->node_name) {
                        rc = -ENOMEM;
+                       goto parse_DFS_referrals_exit;
+               }
+
+               ref++;
        }
 
 parse_DFS_referrals_exit:
@@ -5840,7 +6240,7 @@ QAllEAsRetry:
 
                if (ea_name) {
                        if (ea_name_len == name_len &&
-                           strncmp(ea_name, temp_ptr, name_len) == 0) {
+                           memcmp(ea_name, temp_ptr, name_len) == 0) {
                                temp_ptr += name_len + 1;
                                rc = value_len;
                                if (buf_size == 0)
@@ -6035,12 +6435,7 @@ int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
        pSMB->TotalParameterCount = 0 ;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le32(2);
-       /* BB find exact data count max from sess structure BB */
-       pSMB->MaxDataCount = 0; /* same in little endian or be */
-/* BB VERIFY verify which is correct for above BB */
-       pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
-                                            MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
-
+       pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
        pSMB->MaxSetupCount = 4;
        pSMB->Reserved = 0;
        pSMB->ParameterOffset = 0;