cifs: fix error handling in parse_DFS_referrals
[safe/jmp/linux-2.6] / fs / cifs / cifssmb.c
index 3ab78b7..5759ba5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifssmb.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2007
+ *   Copyright (C) International Business Machines  Corp., 2002,2009
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   Contains the routines for constructing the SMB PDUs themselves
 #include <asm/uaccess.h>
 #include "cifspdu.h"
 #include "cifsglob.h"
+#include "cifsacl.h"
 #include "cifsproto.h"
 #include "cifs_unicode.h"
 #include "cifs_debug.h"
-#include "cifsacl.h"
 
 #ifdef CONFIG_CIFS_POSIX
 static struct {
@@ -81,7 +81,6 @@ static struct {
 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
 #endif /* CIFS_POSIX */
 
-
 /* 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 cifsTconInfo *pTcon)
@@ -94,19 +93,19 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
        write_lock(&GlobalSMBSeslock);
        list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
                open_file = list_entry(tmp, struct cifsFileInfo, tlist);
-               if (open_file) {
-                       open_file->invalidHandle = TRUE;
-               }
+               open_file->invalidHandle = true;
        }
        write_unlock(&GlobalSMBSeslock);
        /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
           to this tcon */
 }
 
-/* If the return code is zero, this function must fill in request_buf pointer */
+/* Allocate and return pointer to an SMB request buffer, and set basic
+   SMB information in the SMB header.  If the return code is zero, this
+   function must have filled in request_buf pointer */
 static int
 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
-        void **request_buf /* returned */)
+               void **request_buf)
 {
        int rc = 0;
 
@@ -132,12 +131,15 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                                /* Give Demultiplex thread up to 10 seconds to
                                   reconnect, should be greater than cifs socket
                                   timeout which is 7 seconds */
-                       while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+                       while (tcon->ses->server->tcpStatus ==
+                                                        CifsNeedReconnect) {
                                wait_event_interruptible_timeout(tcon->ses->server->response_q,
-                                       (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
-                               if (tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+                                       (tcon->ses->server->tcpStatus ==
+                                                       CifsGood), 10 * HZ);
+                               if (tcon->ses->server->tcpStatus ==
+                                                       CifsNeedReconnect) {
                                        /* on "soft" mounts we wait once */
-                                       if ((tcon->retry == FALSE) ||
+                                       if (!tcon->retry ||
                                           (tcon->ses->status == CifsExiting)) {
                                                cFYI(1, ("gave up waiting on "
                                                      "reconnect in smb_init"));
@@ -153,25 +155,27 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                /* need to prevent multiple threads trying to
                simultaneously reconnect the same SMB session */
                        down(&tcon->ses->sesSem);
-                       if (tcon->ses->status == CifsNeedReconnect)
+                       if (tcon->ses->need_reconnect)
                                rc = cifs_setup_session(0, tcon->ses,
                                                        nls_codepage);
-                       if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+                       if (!rc && (tcon->need_reconnect)) {
                                mark_open_files_invalid(tcon);
                                rc = CIFSTCon(0, tcon->ses, tcon->treeName,
                                              tcon, nls_codepage);
                                up(&tcon->ses->sesSem);
-                               /* tell server which Unix caps we support */
-                               if (tcon->ses->capabilities & CAP_UNIX)
-                                       reset_cifs_unix_caps(0 /* no xid */,
-                                               tcon,
-                                               NULL /* we do not know sb */,
-                                               NULL /* no vol info */);
                                /* BB FIXME add code to check if wsize needs
                                   update due to negotiated smb buffer size
                                   shrinking */
-                               if (rc == 0)
+                               if (rc == 0) {
                                        atomic_inc(&tconInfoReconnectCount);
+                                       /* tell server Unix caps we support */
+                                       if (tcon->ses->capabilities & CAP_UNIX)
+                                               reset_cifs_unix_caps(
+                                               0 /* no xid */,
+                                               tcon,
+                                               NULL /* we do not know sb */,
+                                               NULL /* no vol info */);
+                               }
 
                                cFYI(1, ("reconnect tcon rc = %d", rc));
                                /* Removed call to reopen open files here.
@@ -209,7 +213,8 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                return -ENOMEM;
        }
 
-       header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
+       header_assemble((struct smb_hdr *) *request_buf, smb_command,
+                       tcon, wct);
 
        if (tcon != NULL)
                cifs_stats_inc(&tcon->num_smbs_sent);
@@ -274,13 +279,15 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                                /* Give Demultiplex thread up to 10 seconds to
                                   reconnect, should be greater than cifs socket
                                   timeout which is 7 seconds */
-                       while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+                       while (tcon->ses->server->tcpStatus ==
+                                                       CifsNeedReconnect) {
                                wait_event_interruptible_timeout(tcon->ses->server->response_q,
-                                       (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
+                                       (tcon->ses->server->tcpStatus ==
+                                                       CifsGood), 10 * HZ);
                                if (tcon->ses->server->tcpStatus ==
                                                CifsNeedReconnect) {
                                        /* on "soft" mounts we wait once */
-                                       if ((tcon->retry == FALSE) ||
+                                       if (!tcon->retry ||
                                           (tcon->ses->status == CifsExiting)) {
                                                cFYI(1, ("gave up waiting on "
                                                      "reconnect in smb_init"));
@@ -295,25 +302,27 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                /* need to prevent multiple threads trying to
                simultaneously reconnect the same SMB session */
                        down(&tcon->ses->sesSem);
-                       if (tcon->ses->status == CifsNeedReconnect)
+                       if (tcon->ses->need_reconnect)
                                rc = cifs_setup_session(0, tcon->ses,
                                                        nls_codepage);
-                       if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+                       if (!rc && (tcon->need_reconnect)) {
                                mark_open_files_invalid(tcon);
                                rc = CIFSTCon(0, tcon->ses, tcon->treeName,
                                              tcon, nls_codepage);
                                up(&tcon->ses->sesSem);
-                               /* tell server which Unix caps we support */
-                               if (tcon->ses->capabilities & CAP_UNIX)
-                                       reset_cifs_unix_caps(0 /* no xid */,
-                                               tcon,
-                                               NULL /* do not know sb */,
-                                               NULL /* no vol info */);
                                /* BB FIXME add code to check if wsize needs
                                update due to negotiated smb buffer size
                                shrinking */
-                               if (rc == 0)
+                               if (rc == 0) {
                                        atomic_inc(&tconInfoReconnectCount);
+                                       /* tell server Unix caps we support */
+                                       if (tcon->ses->capabilities & CAP_UNIX)
+                                               reset_cifs_unix_caps(
+                                               0 /* no xid */,
+                                               tcon,
+                                               NULL /* do not know sb */,
+                                               NULL /* no vol info */);
+                               }
 
                                cFYI(1, ("reconnect tcon rc = %d", rc));
                                /* Removed call to reopen open files here.
@@ -358,7 +367,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                *response_buf = *request_buf;
 
        header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
-                       wct /*wct */ );
+                       wct);
 
        if (tcon != NULL)
                cifs_stats_inc(&tcon->num_smbs_sent);
@@ -381,7 +390,8 @@ static int validate_t2(struct smb_t2_rsp *pSMB)
                        /* check that bcc is less than negotiated smb buffer */
                        total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
                        if (total_size < 512) {
-                               total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
+                               total_size +=
+                                       le16_to_cpu(pSMB->t2_rsp.DataCount);
                                /* BCC le converted in SendReceive */
                                pBCC = (pSMB->hdr.WordCount * 2) +
                                        sizeof(struct smb_hdr) +
@@ -432,8 +442,21 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 
        pSMB->hdr.Mid = GetNextMid(server);
        pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
+
        if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
+       else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
+               cFYI(1, ("Kerberos only mechanism, enable extended security"));
+               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
+       }
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+       else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
+               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
+       else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
+               cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
+               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
+       }
+#endif
 
        count = 0;
        for (i = 0; i < CIFS_NUM_PROT; i++) {
@@ -478,14 +501,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
                server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
                                (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
+               server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
                GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
                /* even though we do not use raw we might as well set this
                accurately, in case we ever find a need for it */
                if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
-                       server->maxRw = 0xFF00;
+                       server->max_rw = 0xFF00;
                        server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
                } else {
-                       server->maxRw = 0;/* we do not need to use raw anyway */
+                       server->max_rw = 0;/* do not need to use raw anyway */
                        server->capabilities = CAP_MPX_MODE;
                }
                tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
@@ -506,13 +530,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                                (int)ts.tv_sec, (int)utc.tv_sec,
                                (int)(utc.tv_sec - ts.tv_sec)));
                        val = (int)(utc.tv_sec - ts.tv_sec);
-                       seconds = val < 0 ? -val : val;
+                       seconds = abs(val);
                        result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
                        remain = seconds % MIN_TZ_ADJ;
                        if (remain >= (MIN_TZ_ADJ / 2))
                                result += MIN_TZ_ADJ;
                        if (val < 0)
-                               result = - result;
+                               result = -result;
                        server->timeAdj = result;
                } else {
                        server->timeAdj = (int)tmp;
@@ -567,7 +591,22 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                server->secType = NTLM;
        else if (secFlags & CIFSSEC_MAY_NTLMV2)
                server->secType = NTLMv2;
-       /* else krb5 ... any others ... */
+       else if (secFlags & CIFSSEC_MAY_KRB5)
+               server->secType = Kerberos;
+       else if (secFlags & CIFSSEC_MAY_NTLMSSP)
+               server->secType = NTLMSSP;
+       else if (secFlags & CIFSSEC_MAY_LANMAN)
+               server->secType = LANMAN;
+/* #ifdef CONFIG_CIFS_EXPERIMENTAL
+       else if (secFlags & CIFSSEC_MAY_PLNTXT)
+               server->secType = ??
+#endif */
+       else {
+               rc = -EOPNOTSUPP;
+               cERROR(1, ("Invalid security type"));
+               goto neg_err_exit;
+       }
+       /* else ... any others ...? */
 
        /* one byte, so no need to convert this or EncryptionKeyLen from
           little endian */
@@ -575,8 +614,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        /* probably no need to store and check maxvcs */
        server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
                        (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
-       server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
-       cFYI(0, ("Max buf = %d", ses->server->maxBuf));
+       server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
+       cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
        GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
        server->capabilities = le32_to_cpu(pSMBr->Capabilities);
        server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
@@ -597,33 +636,38 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
                (server->capabilities & CAP_EXTENDED_SECURITY)) {
                count = pSMBr->ByteCount;
-               if (count < 16)
+               if (count < 16) {
                        rc = -EIO;
-               else if (count == 16) {
-                       server->secType = RawNTLMSSP;
-                       if (server->socketUseCount.counter > 1) {
-                               if (memcmp(server->server_GUID,
-                                          pSMBr->u.extended_response.
-                                          GUID, 16) != 0) {
-                                       cFYI(1, ("server UID changed"));
-                                       memcpy(server->server_GUID,
-                                               pSMBr->u.extended_response.GUID,
-                                               16);
-                               }
-                       } else
+                       goto neg_err_exit;
+               }
+               read_lock(&cifs_tcp_ses_lock);
+               if (server->srv_count > 1) {
+                       read_unlock(&cifs_tcp_ses_lock);
+                       if (memcmp(server->server_GUID,
+                                  pSMBr->u.extended_response.
+                                  GUID, 16) != 0) {
+                               cFYI(1, ("server UID changed"));
                                memcpy(server->server_GUID,
-                                      pSMBr->u.extended_response.GUID, 16);
+                                       pSMBr->u.extended_response.GUID,
+                                       16);
+                       }
+               } else {
+                       read_unlock(&cifs_tcp_ses_lock);
+                       memcpy(server->server_GUID,
+                              pSMBr->u.extended_response.GUID, 16);
+               }
+
+               if (count == 16) {
+                       server->secType = RawNTLMSSP;
                } else {
                        rc = decode_negTokenInit(pSMBr->u.extended_response.
                                                 SecurityBlob,
                                                 count - 16,
                                                 &server->secType);
-                       if (rc == 1) {
-                       /* BB Need to fill struct for sessetup here */
-                               rc = -EOPNOTSUPP;
-                       } else {
+                       if (rc == 1)
+                               rc = 0;
+                       else
                                rc = -EINVAL;
-                       }
                }
        } else
                server->capabilities &= ~CAP_EXTENDED_SECURITY;
@@ -635,10 +679,12 @@ signing_check:
                /* MUST_SIGN already includes the MAY_SIGN FLAG
                   so if this is zero it means that signing is disabled */
                cFYI(1, ("Signing disabled"));
-               if (server->secMode & SECMODE_SIGN_REQUIRED)
+               if (server->secMode & SECMODE_SIGN_REQUIRED) {
                        cERROR(1, ("Server requires "
-                                  "/proc/fs/cifs/PacketSigningEnabled "
-                                  "to be on"));
+                                  "packet signing to be enabled in "
+                                  "/proc/fs/cifs/SecurityFlags."));
+                       rc = -EOPNOTSUPP;
+               }
                server->secMode &=
                        ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
        } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
@@ -669,59 +715,34 @@ int
 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
 {
        struct smb_hdr *smb_buffer;
-       struct smb_hdr *smb_buffer_response; /* BB removeme BB */
        int rc = 0;
-       int length;
 
        cFYI(1, ("In tree disconnect"));
-       /*
-        *  If last user of the connection and
-        *  connection alive - disconnect it
-        *  If this is the last connection on the server session disconnect it
-        *  (and inside session disconnect we should check if tcp socket needs
-        *  to be freed and kernel thread woken up).
-        */
-       if (tcon)
-               down(&tcon->tconSem);
-       else
-               return -EIO;
 
-       atomic_dec(&tcon->useCount);
-       if (atomic_read(&tcon->useCount) > 0) {
-               up(&tcon->tconSem);
-               return -EBUSY;
-       }
+       /* BB: do we need to check this? These should never be NULL. */
+       if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
+               return -EIO;
 
-       /* No need to return error on this operation if tid invalidated and
-       closed on server already e.g. due to tcp session crashing */
-       if (tcon->tidStatus == CifsNeedReconnect) {
-               up(&tcon->tconSem);
+       /*
+        * No need to return error on this operation if tid invalidated and
+        * closed on server already e.g. due to tcp session crashing. Also,
+        * the tcon is no longer on the list, so no need to take lock before
+        * checking this.
+        */
+       if (tcon->need_reconnect)
                return 0;
-       }
 
-       if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
-               up(&tcon->tconSem);
-               return -EIO;
-       }
        rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
                            (void **)&smb_buffer);
-       if (rc) {
-               up(&tcon->tconSem);
+       if (rc)
                return rc;
-       } else {
-               smb_buffer_response = smb_buffer; /* BB removeme BB */
-       }
-       rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
-                        &length, 0);
+
+       rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
        if (rc)
                cFYI(1, ("Tree disconnect failed %d", rc));
 
-       if (smb_buffer)
-               cifs_small_buf_release(smb_buffer);
-       up(&tcon->tconSem);
-
        /* No need to return error on this operation if tid invalidated and
-       closed on server already e.g. due to tcp session crashing */
+          closed on server already e.g. due to tcp session crashing */
        if (rc == -EAGAIN)
                rc = 0;
 
@@ -731,54 +752,41 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
 int
 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
 {
-       struct smb_hdr *smb_buffer_response;
        LOGOFF_ANDX_REQ *pSMB;
        int rc = 0;
-       int length;
 
        cFYI(1, ("In SMBLogoff for session disconnect"));
-       if (ses)
-               down(&ses->sesSem);
-       else
+
+       /*
+        * BB: do we need to check validity of ses and server? They should
+        * always be valid since we have an active reference. If not, that
+        * should probably be a BUG()
+        */
+       if (!ses || !ses->server)
                return -EIO;
 
-       atomic_dec(&ses->inUse);
-       if (atomic_read(&ses->inUse) > 0) {
-               up(&ses->sesSem);
-               return -EBUSY;
-       }
+       down(&ses->sesSem);
+       if (ses->need_reconnect)
+               goto session_already_dead; /* no need to send SMBlogoff if uid
+                                             already closed due to reconnect */
        rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
        if (rc) {
                up(&ses->sesSem);
                return rc;
        }
 
-       smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
-
-       if (ses->server) {
-               pSMB->hdr.Mid = GetNextMid(ses->server);
+       pSMB->hdr.Mid = GetNextMid(ses->server);
 
-               if (ses->server->secMode &
+       if (ses->server->secMode &
                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-       }
 
        pSMB->hdr.Uid = ses->Suid;
 
        pSMB->AndXCommand = 0xFF;
-       rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
-                        smb_buffer_response, &length, 0);
-       if (ses->server) {
-               atomic_dec(&ses->server->socketUseCount);
-               if (atomic_read(&ses->server->socketUseCount) == 0) {
-                       spin_lock(&GlobalMid_Lock);
-                       ses->server->tcpStatus = CifsExiting;
-                       spin_unlock(&GlobalMid_Lock);
-                       rc = -ESHUTDOWN;
-               }
-       }
+       rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
+session_already_dead:
        up(&ses->sesSem);
-       cifs_small_buf_release(pSMB);
 
        /* if session dead then we do not need to do ulogoff,
                since server closed smb session, no sense reporting
@@ -789,6 +797,81 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
 }
 
 int
+CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+                __u16 type, const struct nls_table *nls_codepage, int remap)
+{
+       TRANSACTION2_SPI_REQ *pSMB = NULL;
+       TRANSACTION2_SPI_RSP *pSMBr = NULL;
+       struct unlink_psx_rq *pRqD;
+       int name_len;
+       int rc = 0;
+       int bytes_returned = 0;
+       __u16 params, param_offset, offset, byte_count;
+
+       cFYI(1, ("In POSIX delete"));
+PsxDelete:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+               name_len =
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
+                                    PATH_MAX, nls_codepage, remap);
+               name_len++;     /* trailing null */
+               name_len *= 2;
+       } else { /* BB add path length overrun check */
+               name_len = strnlen(fileName, PATH_MAX);
+               name_len++;     /* trailing null */
+               strncpy(pSMB->FileName, fileName, name_len);
+       }
+
+       params = 6 + name_len;
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       pSMB->MaxDataCount = 0; /* BB double check this with jra */
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       param_offset = offsetof(struct smb_com_transaction2_spi_req,
+                               InformationLevel) - 4;
+       offset = param_offset + params;
+
+       /* Setup pointer to Request Data (inode type) */
+       pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
+       pRqD->type = cpu_to_le16(type);
+       pSMB->ParameterOffset = cpu_to_le16(param_offset);
+       pSMB->DataOffset = cpu_to_le16(offset);
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+       byte_count = 3 /* pad */  + params + sizeof(struct unlink_psx_rq);
+
+       pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
+       pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
+       pSMB->ParameterCount = cpu_to_le16(params);
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
+       pSMB->Reserved4 = 0;
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->ByteCount = cpu_to_le16(byte_count);
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc)
+               cFYI(1, ("Posix delete returned %d", rc));
+       cifs_buf_release(pSMB);
+
+       cifs_stats_inc(&tcon->num_deletes);
+
+       if (rc == -EAGAIN)
+               goto PsxDelete;
+
+       return rc;
+}
+
+int
 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
               const struct nls_table *nls_codepage, int remap)
 {
@@ -823,9 +906,8 @@ DelFileRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_deletes);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Error in RMFile = %d", rc));
-       }
 
        cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
@@ -868,9 +950,8 @@ RmDirRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_rmdirs);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Error in RMDir = %d", rc));
-       }
 
        cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
@@ -912,9 +993,8 @@ MkDirRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_mkdirs);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Error in Mkdir = %d", rc));
-       }
 
        cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
@@ -924,7 +1004,7 @@ MkDirRetry:
 
 int
 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
-               __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
+               __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
                __u32 *pOplock, const char *name,
                const struct nls_table *nls_codepage, int remap)
 {
@@ -933,10 +1013,9 @@ CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
        int name_len;
        int rc = 0;
        int bytes_returned = 0;
-       char *data_offset;
        __u16 params, param_offset, offset, byte_count, count;
-       OPEN_PSX_REQ * pdata;
-       OPEN_PSX_RSP * psx_rsp;
+       OPEN_PSX_REQ *pdata;
+       OPEN_PSX_RSP *psx_rsp;
 
        cFYI(1, ("In POSIX Create"));
 PsxCreat:
@@ -969,9 +1048,8 @@ PsxCreat:
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
                                InformationLevel) - 4;
        offset = param_offset + params;
-       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
        pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
-       pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
+       pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
        pdata->Permissions = cpu_to_le64(mode);
        pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
        pdata->OpenFlags =  cpu_to_le32(*pOplock);
@@ -1017,21 +1095,19 @@ PsxCreat:
        if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
                *pOplock |= CIFS_CREATE_ACTION;
        /* check to make sure response data is there */
-       if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
-               pRetData->Type = -1; /* unknown */
-#ifdef CONFIG_CIFS_DEBUG2
-               cFYI(1, ("unknown type"));
-#endif
+       if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
+               pRetData->Type = cpu_to_le32(-1); /* unknown */
+               cFYI(DBG2, ("unknown type"));
        } else {
                if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
                                        + sizeof(FILE_UNIX_BASIC_INFO)) {
                        cERROR(1, ("Open response data too small"));
-                       pRetData->Type = -1;
+                       pRetData->Type = cpu_to_le32(-1);
                        goto psx_create_err;
                }
                memcpy((char *) pRetData,
                        (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
-                       sizeof (FILE_UNIX_BASIC_INFO));
+                       sizeof(FILE_UNIX_BASIC_INFO));
        }
 
 psx_create_err:
@@ -1075,11 +1151,25 @@ static __u16 convert_disposition(int disposition)
        return ofun;
 }
 
+static int
+access_flags_to_smbopen_mode(const int access_flags)
+{
+       int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
+
+       if (masked_flags == GENERIC_READ)
+               return SMBOPEN_READ;
+       else if (masked_flags == GENERIC_WRITE)
+               return SMBOPEN_WRITE;
+
+       /* just go for read/write */
+       return SMBOPEN_READWRITE;
+}
+
 int
 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
            const char *fileName, const int openDisposition,
-           const int access_flags, const int create_options, __u16 * netfid,
-           int *pOplock, FILE_ALL_INFO * pfile_info,
+           const int access_flags, const int create_options, __u16 *netfid,
+           int *pOplock, FILE_ALL_INFO *pfile_info,
            const struct nls_table *nls_codepage, int remap)
 {
        int rc = -EACCES;
@@ -1112,17 +1202,11 @@ OldOpenRetry:
        }
        if (*pOplock & REQ_OPLOCK)
                pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
-       else if (*pOplock & REQ_BATCHOPLOCK) {
+       else if (*pOplock & REQ_BATCHOPLOCK)
                pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
-       }
+
        pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
-       /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
-       /* 0 = read
-          1 = write
-          2 = rw
-          3 = execute
-        */
-       pSMB->Mode = cpu_to_le16(2);
+       pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
        pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
        /* set file as system file if special file such
           as fifo and server expecting SFU style and
@@ -1130,14 +1214,11 @@ OldOpenRetry:
 
        if (create_options & CREATE_OPTION_SPECIAL)
                pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
-       else
-                pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
+       else /* BB FIXME BB */
+               pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
 
-       /* if ((omode & S_IWUGO) == 0)
-               pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
-       /*  Above line causes problems due to vfs splitting create into two
-           pieces - need to set mode after file created not while it is
-           being created */
+       if (create_options & CREATE_OPTION_READONLY)
+               pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
 
        /* BB FIXME BB */
 /*     pSMB->CreateOptions = cpu_to_le32(create_options &
@@ -1152,14 +1233,14 @@ OldOpenRetry:
        pSMB->ByteCount = cpu_to_le16(count);
        /* long_op set to 1 to allow for oplock break timeouts */
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, 1);
+                       (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
        cifs_stats_inc(&tcon->num_opens);
        if (rc) {
                cFYI(1, ("Error in Open = %d", rc));
        } else {
        /* BB verify if wct == 15 */
 
-/*             *pOplock = pSMBr->OplockLevel; */  /* BB take from action field BB */
+/*             *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
 
                *netfid = pSMBr->Fid;   /* cifs fid stays in le */
                /* Let caller know file was created so we can set the mode. */
@@ -1181,6 +1262,7 @@ OldOpenRetry:
                                cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
                        pfile_info->EndOfFile = pfile_info->AllocationSize;
                        pfile_info->NumberOfLinks = cpu_to_le32(1);
+                       pfile_info->DeletePending = 0;
                }
        }
 
@@ -1193,8 +1275,8 @@ OldOpenRetry:
 int
 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
            const char *fileName, const int openDisposition,
-           const int access_flags, const int create_options, __u16 * netfid,
-           int *pOplock, FILE_ALL_INFO * pfile_info,
+           const int access_flags, const int create_options, __u16 *netfid,
+           int *pOplock, FILE_ALL_INFO *pfile_info,
            const struct nls_table *nls_codepage, int remap)
 {
        int rc = -EACCES;
@@ -1229,9 +1311,8 @@ openRetry:
        }
        if (*pOplock & REQ_OPLOCK)
                pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
-       else if (*pOplock & REQ_BATCHOPLOCK) {
+       else if (*pOplock & REQ_BATCHOPLOCK)
                pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
-       }
        pSMB->DesiredAccess = cpu_to_le32(access_flags);
        pSMB->AllocationSize = 0;
        /* set file as system file if special file such
@@ -1241,17 +1322,16 @@ openRetry:
                pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
        else
                pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
+
        /* XP does not handle ATTR_POSIX_SEMANTICS */
        /* but it helps speed up case sensitive checks for other
        servers such as Samba */
        if (tcon->ses->capabilities & CAP_UNIX)
                pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
 
-       /* if ((omode & S_IWUGO) == 0)
-               pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
-       /*  Above line causes problems due to vfs splitting create into two
-               pieces - need to set mode after file created not while it is
-               being created */
+       if (create_options & CREATE_OPTION_READONLY)
+               pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
+
        pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
        pSMB->CreateDisposition = cpu_to_le32(openDisposition);
        pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
@@ -1266,7 +1346,7 @@ openRetry:
        pSMB->ByteCount = cpu_to_le16(count);
        /* long_op set to 1 to allow for oplock break timeouts */
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, 1);
+                       (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
        cifs_stats_inc(&tcon->num_opens);
        if (rc) {
                cFYI(1, ("Error in Open = %d", rc));
@@ -1278,12 +1358,13 @@ openRetry:
                if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
                        *pOplock |= CIFS_CREATE_ACTION;
                if (pfile_info) {
-                   memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
-                       36 /* CreationTime to Attributes */);
-                   /* the file_info buf is endian converted by caller */
-                   pfile_info->AllocationSize = pSMBr->AllocationSize;
-                   pfile_info->EndOfFile = pSMBr->EndOfFile;
-                   pfile_info->NumberOfLinks = cpu_to_le32(1);
+                       memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
+                               36 /* CreationTime to Attributes */);
+                       /* the file_info buf is endian converted by caller */
+                       pfile_info->AllocationSize = pSMBr->AllocationSize;
+                       pfile_info->EndOfFile = pSMBr->EndOfFile;
+                       pfile_info->NumberOfLinks = cpu_to_le32(1);
+                       pfile_info->DeletePending = 0;
                }
        }
 
@@ -1309,8 +1390,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
        cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
        if (tcon->ses->capabilities & CAP_LARGE_FILES)
                wct = 12;
-       else
+       else {
                wct = 10; /* old style read */
+               if ((lseek >> 32) > 0)  {
+                       /* can not handle this big offset for old */
+                       return -EIO;
+               }
+       }
 
        *nbytes = 0;
        rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
@@ -1326,8 +1412,6 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
        pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
        if (wct == 12)
                pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
-       else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
-               return -EIO;
 
        pSMB->Remaining = 0;
        pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
@@ -1343,9 +1427,8 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
 
        iov[0].iov_base = (char *)pSMB;
        iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
-       rc = SendReceive2(xid, tcon->ses, iov,
-                         1 /* num iovecs */,
-                         &resp_buf_type, 0);
+       rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
+                        &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
        cifs_stats_inc(&tcon->num_reads);
        pSMBr = (READ_RSP *)iov[0].iov_base;
        if (rc) {
@@ -1365,11 +1448,11 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
                        *nbytes = 0;
                } else {
                        pReadData = (char *) (&pSMBr->hdr.Protocol) +
-                           le16_to_cpu(pSMBr->DataOffset);
-/*                      if (rc = copy_to_user(buf, pReadData, data_length)) {
+                                       le16_to_cpu(pSMBr->DataOffset);
+/*                     if (rc = copy_to_user(buf, pReadData, data_length)) {
                                cERROR(1,("Faulting on read rc = %d",rc));
                                rc = -EFAULT;
-                        }*/ /* can not use copy_to_user when using page cache*/
+                       }*/ /* can not use copy_to_user when using page cache*/
                        if (*buf)
                                memcpy(*buf, pReadData, data_length);
                }
@@ -1409,14 +1492,19 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        __u32 bytes_sent;
        __u16 byte_count;
 
-       /* cFYI(1,("write at %lld %d bytes",offset,count));*/
+       /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
        if (tcon->ses == NULL)
                return -ECONNABORTED;
 
        if (tcon->ses->capabilities & CAP_LARGE_FILES)
                wct = 14;
-       else
+       else {
                wct = 12;
+               if ((offset >> 32) > 0) {
+                       /* can not handle big offset for old srv */
+                       return -EIO;
+               }
+       }
 
        rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
                      (void **) &pSMBr);
@@ -1431,8 +1519,6 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
        if (wct == 14)
                pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
-       else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
-               return -EIO;
 
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
@@ -1454,7 +1540,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        pSMB->DataOffset =
                cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
        if (buf)
-           memcpy(pSMB->Data, buf, bytes_sent);
+               memcpy(pSMB->Data, buf, bytes_sent);
        else if (ubuf) {
                if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
                        cifs_buf_release(pSMB);
@@ -1467,9 +1553,9 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        } /* else setting file size with write of zero bytes */
        if (wct == 14)
                byte_count = bytes_sent + 1; /* pad */
-       else /* wct == 12 */ {
+       else /* wct == 12 */
                byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
-       }
+
        pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
        pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
        pSMB->hdr.smb_buf_length += byte_count;
@@ -1515,12 +1601,19 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        int smb_hdr_len;
        int resp_buf_type = 0;
 
+       *nbytes = 0;
+
        cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
 
-       if (tcon->ses->capabilities & CAP_LARGE_FILES)
+       if (tcon->ses->capabilities & CAP_LARGE_FILES) {
                wct = 14;
-       else
+       } else {
                wct = 12;
+               if ((offset >> 32) > 0) {
+                       /* can not handle big offset for old srv */
+                       return -EIO;
+               }
+       }
        rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
        if (rc)
                return rc;
@@ -1533,8 +1626,6 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
        if (wct == 14)
                pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
-       else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
-               return -EIO;
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
        pSMB->Remaining = 0;
@@ -1568,13 +1659,11 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        cifs_stats_inc(&tcon->num_writes);
        if (rc) {
                cFYI(1, ("Send error Write2 = %d", rc));
-               *nbytes = 0;
        } else if (resp_buf_type == 0) {
                /* presumably this can not happen, but best to be safe */
                rc = -EIO;
-               *nbytes = 0;
        } else {
-               WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
+               WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
                *nbytes = le16_to_cpu(pSMBr->CountHigh);
                *nbytes = (*nbytes) << 16;
                *nbytes += le16_to_cpu(pSMBr->Count);
@@ -1597,28 +1686,26 @@ int
 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
            const __u16 smb_file_id, const __u64 len,
            const __u64 offset, const __u32 numUnlock,
-           const __u32 numLock, const __u8 lockType, const int waitFlag)
+           const __u32 numLock, const __u8 lockType, const bool waitFlag)
 {
        int rc = 0;
        LOCK_REQ *pSMB = NULL;
-       LOCK_RSP *pSMBr = NULL;
+/*     LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
        int bytes_returned;
        int timeout = 0;
        __u16 count;
 
-       cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
+       cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
        rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
 
        if (rc)
                return rc;
 
-       pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
-
        if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
-               timeout = -1; /* no response expected */
+               timeout = CIFS_ASYNC_OP; /* no response expected */
                pSMB->Timeout = 0;
-       } else if (waitFlag == TRUE) {
-               timeout = 3;  /* blocking operation, no timeout */
+       } else if (waitFlag) {
+               timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
                pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
        } else {
                pSMB->Timeout = 0;
@@ -1647,16 +1734,16 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
 
        if (waitFlag) {
                rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
-                       (struct smb_hdr *) pSMBr, &bytes_returned);
+                       (struct smb_hdr *) pSMB, &bytes_returned);
+               cifs_small_buf_release(pSMB);
        } else {
-               rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
+               rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
+                                     timeout);
+               /* SMB buffer freed by function above */
        }
        cifs_stats_inc(&tcon->num_locks);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Send error in Lock = %d", rc));
-       }
-       cifs_small_buf_release(pSMB);
 
        /* Note: On -EAGAIN error only caller can retry on handle based calls
        since file handle passed in no longer valid */
@@ -1667,21 +1754,22 @@ int
 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                const __u16 smb_file_id, const int get_flag, const __u64 len,
                struct file_lock *pLockData, const __u16 lock_type,
-               const int waitFlag)
+               const bool waitFlag)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
-       char *data_offset;
        struct cifs_posix_lock *parm_data;
        int rc = 0;
        int timeout = 0;
        int bytes_returned = 0;
+       int resp_buf_type = 0;
        __u16 params, param_offset, offset, byte_count, count;
+       struct kvec iov[1];
 
        cFYI(1, ("Posix Lock"));
 
        if (pLockData == NULL)
-               return EINVAL;
+               return -EINVAL;
 
        rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
 
@@ -1698,11 +1786,9 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
        offset = param_offset + params;
 
-       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
-
        count = sizeof(struct cifs_posix_lock);
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        if (get_flag)
@@ -1720,7 +1806,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
 
        parm_data->lock_type = cpu_to_le16(lock_type);
        if (waitFlag) {
-               timeout = 3;  /* blocking operation, no timeout */
+               timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
                parm_data->lock_flags = cpu_to_le16(1);
                pSMB->Timeout = cpu_to_le32(-1);
        } else
@@ -1740,8 +1826,13 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
                        (struct smb_hdr *) pSMBr, &bytes_returned);
        } else {
-               rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                       (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
+               iov[0].iov_base = (char *)pSMB;
+               iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
+               rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
+                               &resp_buf_type, timeout);
+               pSMB = NULL; /* request buf already freed by SendReceive2. Do
+                               not try to free it twice below on exit */
+               pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
        }
 
        if (rc) {
@@ -1756,10 +1847,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                        rc = -EIO;      /* bad smb */
                        goto plk_err_exit;
                }
-               if (pLockData == NULL) {
-                       rc = -EINVAL;
-                       goto plk_err_exit;
-               }
                data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
                data_count  = le16_to_cpu(pSMBr->t2.DataCount);
                if (data_count < sizeof(struct cifs_posix_lock)) {
@@ -1776,6 +1863,11 @@ plk_err_exit:
        if (pSMB)
                cifs_small_buf_release(pSMB);
 
+       if (resp_buf_type == CIFS_SMALL_BUFFER)
+               cifs_small_buf_release(iov[0].iov_base);
+       else if (resp_buf_type == CIFS_LARGE_BUFFER)
+               cifs_buf_release(iov[0].iov_base);
+
        /* Note: On -EAGAIN error only caller can retry on handle based calls
           since file handle passed in no longer valid */
 
@@ -1788,8 +1880,6 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 {
        int rc = 0;
        CLOSE_REQ *pSMB = NULL;
-       CLOSE_RSP *pSMBr = NULL;
-       int bytes_returned;
        cFYI(1, ("In CIFSSMBClose"));
 
 /* do not retry on dead session on close */
@@ -1799,13 +1889,10 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
        if (rc)
                return rc;
 
-       pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
-
        pSMB->FileID = (__u16) smb_file_id;
        pSMB->LastWriteTime = 0xFFFFFFFF;
        pSMB->ByteCount = 0;
-       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
        cifs_stats_inc(&tcon->num_closes);
        if (rc) {
                if (rc != -EINTR) {
@@ -1814,8 +1901,6 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
                }
        }
 
-       cifs_small_buf_release(pSMB);
-
        /* Since session is dead, file will be closed on server already */
        if (rc == -EAGAIN)
                rc = 0;
@@ -1824,6 +1909,27 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 }
 
 int
+CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
+{
+       int rc = 0;
+       FLUSH_REQ *pSMB = NULL;
+       cFYI(1, ("In CIFSSMBFlush"));
+
+       rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
+       if (rc)
+               return rc;
+
+       pSMB->FileID = (__u16) smb_file_id;
+       pSMB->ByteCount = 0;
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       cifs_stats_inc(&tcon->num_flushes);
+       if (rc)
+               cERROR(1, ("Send error in Flush = %d", rc));
+
+       return rc;
+}
+
+int
 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
              const char *fromName, const char *toName,
              const struct nls_table *nls_codepage, int remap)
@@ -1857,7 +1963,7 @@ renameRetry:
        /* protocol requires ASCII signature byte on Unicode string */
                pSMB->OldFileName[name_len + 1] = 0x00;
                name_len2 =
-                   cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
+                   cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
                                     toName, PATH_MAX, nls_codepage, remap);
                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
                name_len2 *= 2; /* convert to bytes */
@@ -1880,9 +1986,8 @@ renameRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_renames);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Send error in rename = %d", rc));
-       }
 
        cifs_buf_release(pSMB);
 
@@ -1893,7 +1998,7 @@ renameRetry:
 }
 
 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
-               int netfid, char *target_name,
+               int netfid, const char *target_name,
                const struct nls_table *nls_codepage, int remap)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
@@ -1924,7 +2029,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
        rename_info = (struct set_file_rename *) data_offset;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
@@ -1947,7 +2052,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
                                        remap);
        }
        rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
-       count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
+       count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
        byte_count += count;
        pSMB->DataCount = cpu_to_le16(count);
        pSMB->TotalDataCount = pSMB->DataCount;
@@ -1960,9 +2065,8 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
        rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&pTcon->num_t2renames);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
-       }
 
        cifs_buf_release(pSMB);
 
@@ -2032,8 +2136,7 @@ copyRetry:
                cFYI(1, ("Send error in copy = %d with %d files copied",
                        rc, le16_to_cpu(pSMBr->CopyCount)));
        }
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
 
        if (rc == -EAGAIN)
                goto copyRetry;
@@ -2119,14 +2222,10 @@ createSymLinkRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_symlinks);
-       if (rc) {
-               cFYI(1,
-                    ("Send error in SetPathInfo (create symlink) = %d",
-                     rc));
-       }
+       if (rc)
+               cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
 
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
 
        if (rc == -EAGAIN)
                goto createSymLinkRetry;
@@ -2209,9 +2308,8 @@ createHardLinkRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_hardlinks);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
-       }
 
        cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
@@ -2254,8 +2352,10 @@ winCreateHardLinkRetry:
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-               pSMB->OldFileName[name_len] = 0;        /* pad */
-               pSMB->OldFileName[name_len + 1] = 0x04;
+
+               /* protocol specifies ASCII buffer format (0x04) for unicode */
+               pSMB->OldFileName[name_len] = 0x04;
+               pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
                name_len2 =
                    cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
                                     toName, PATH_MAX, nls_codepage, remap);
@@ -2280,9 +2380,9 @@ winCreateHardLinkRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_hardlinks);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
-       }
+
        cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
                goto winCreateHardLinkRetry;
@@ -2292,8 +2392,7 @@ winCreateHardLinkRetry:
 
 int
 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
-                       const unsigned char *searchName,
-                       char *symlinkinfo, const int buflen,
+                       const unsigned char *searchName, char **symlinkinfo,
                        const struct nls_table *nls_codepage)
 {
 /* SMB_QUERY_FILE_UNIX_LINK */
@@ -2303,6 +2402,7 @@ CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
        int bytes_returned;
        int name_len;
        __u16 params, byte_count;
+       char *data_start;
 
        cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
 
@@ -2357,30 +2457,26 @@ querySymLinkRetry:
                /* decode response */
 
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-               if (rc || (pSMBr->ByteCount < 2))
                /* BB also check enough total bytes returned */
-                       rc = -EIO;      /* bad smb */
+               if (rc || (pSMBr->ByteCount < 2))
+                       rc = -EIO;
                else {
-                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+                       bool is_unicode;
+                       u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+
+                       data_start = ((char *) &pSMBr->hdr.Protocol) +
+                                          le16_to_cpu(pSMBr->t2.DataOffset);
+
+                       if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+                               is_unicode = true;
+                       else
+                               is_unicode = false;
 
-                       if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-                               name_len = UniStrnlen((wchar_t *) ((char *)
-                                       &pSMBr->hdr.Protocol + data_offset),
-                                       min_t(const int, buflen, count) / 2);
                        /* BB FIXME investigate remapping reserved chars here */
-                               cifs_strfromUCS_le(symlinkinfo,
-                                       (__le16 *) ((char *)&pSMBr->hdr.Protocol
-                                                       + data_offset),
-                                       name_len, nls_codepage);
-                       } else {
-                               strncpy(symlinkinfo,
-                                       (char *) &pSMBr->hdr.Protocol +
-                                               data_offset,
-                                       min_t(const int, buflen, count));
-                       }
-                       symlinkinfo[buflen] = 0;
-       /* just in case so calling code does not go off the end of buffer */
+                       *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
+                                                   is_unicode, nls_codepage);
+                       if (!symlinkinfo)
+                               rc = -ENOMEM;
                }
        }
        cifs_buf_release(pSMB);
@@ -2389,6 +2485,7 @@ querySymLinkRetry:
        return rc;
 }
 
+#ifdef CONFIG_CIFS_EXPERIMENTAL
 /* Initialize NT TRANSACT SMB into small smb request buffer.
    This assumes that all NT TRANSACTS that we init here have
    total parm and data under about 400 bytes (to fit in small cifs
@@ -2397,7 +2494,7 @@ querySymLinkRetry:
        MaxSetupCount (size of returned setup area) and
        MaxParameterCount (returned parms size) must be set by caller */
 static int
-smb_init_ntransact(const __u16 sub_command, const int setup_count,
+smb_init_nttransact(const __u16 sub_command, const int setup_count,
                   const int parm_len, struct cifsTconInfo *tcon,
                   void **ret_buf)
 {
@@ -2428,12 +2525,15 @@ smb_init_ntransact(const __u16 sub_command, const int setup_count,
 
 static int
 validate_ntransact(char *buf, char **ppparm, char **ppdata,
-                  int *pdatalen, int *pparmlen)
+                  __u32 *pparmlen, __u32 *pdatalen)
 {
        char *end_of_smb;
        __u32 data_count, data_offset, parm_count, parm_offset;
        struct smb_com_ntransact_rsp *pSMBr;
 
+       *pdatalen = 0;
+       *pparmlen = 0;
+
        if (buf == NULL)
                return -EINVAL;
 
@@ -2462,7 +2562,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
                cFYI(1, ("data starts after end of smb"));
                return -EINVAL;
        } else if (data_count + *ppdata > end_of_smb) {
-               cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
+               cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
                        *ppdata, data_count, (data_count + *ppdata),
                        end_of_smb, pSMBr));
                return -EINVAL;
@@ -2470,6 +2570,8 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
                cFYI(1, ("parm count and data count larger than SMB"));
                return -EINVAL;
        }
+       *pdatalen = data_count;
+       *pparmlen = parm_count;
        return 0;
 }
 
@@ -2481,7 +2583,6 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
 {
        int rc = 0;
        int bytes_returned;
-       int name_len;
        struct smb_com_transaction_ioctl_req *pSMB;
        struct smb_com_transaction_ioctl_rsp *pSMBr;
 
@@ -2518,58 +2619,55 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
        } else {                /* decode response */
                __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
                __u32 data_count = le32_to_cpu(pSMBr->DataCount);
-               if ((pSMBr->ByteCount < 2) || (data_offset > 512))
+               if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
                /* BB also check enough total bytes returned */
                        rc = -EIO;      /* bad smb */
-               else {
-                       if (data_count && (data_count < 2048)) {
-                               char *end_of_smb = 2 /* sizeof byte count */ +
-                                               pSMBr->ByteCount +
-                                               (char *)&pSMBr->ByteCount;
+                       goto qreparse_out;
+               }
+               if (data_count && (data_count < 2048)) {
+                       char *end_of_smb = 2 /* sizeof byte count */ +
+                               pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
 
-                               struct reparse_data *reparse_buf =
+                       struct reparse_data *reparse_buf =
                                                (struct reparse_data *)
                                                ((char *)&pSMBr->hdr.Protocol
                                                                 + data_offset);
-                               if ((char *)reparse_buf >= end_of_smb) {
-                                       rc = -EIO;
-                                       goto qreparse_out;
-                               }
-                               if ((reparse_buf->LinkNamesBuf +
-                                       reparse_buf->TargetNameOffset +
-                                       reparse_buf->TargetNameLen) >
-                                               end_of_smb) {
-                                       cFYI(1,("reparse buf extended beyond SMB"));
-                                       rc = -EIO;
-                                       goto qreparse_out;
-                               }
+                       if ((char *)reparse_buf >= end_of_smb) {
+                               rc = -EIO;
+                               goto qreparse_out;
+                       }
+                       if ((reparse_buf->LinkNamesBuf +
+                               reparse_buf->TargetNameOffset +
+                               reparse_buf->TargetNameLen) > end_of_smb) {
+                               cFYI(1, ("reparse buf beyond SMB"));
+                               rc = -EIO;
+                               goto qreparse_out;
+                       }
 
-                               if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-                                       name_len = UniStrnlen((wchar_t *)
+                       if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+                               cifs_from_ucs2(symlinkinfo, (__le16 *)
                                                (reparse_buf->LinkNamesBuf +
                                                reparse_buf->TargetNameOffset),
-                                               min(buflen/2,
-                                               reparse_buf->TargetNameLen / 2));
-                                       cifs_strfromUCS_le(symlinkinfo,
-                                               (__le16 *) (reparse_buf->LinkNamesBuf +
-                                               reparse_buf->TargetNameOffset),
-                                               name_len, nls_codepage);
-                               } else { /* ASCII names */
-                                       strncpy(symlinkinfo,
-                                               reparse_buf->LinkNamesBuf +
-                                               reparse_buf->TargetNameOffset,
-                                               min_t(const int, buflen,
-                                                  reparse_buf->TargetNameLen));
-                               }
-                       } else {
-                               rc = -EIO;
-                               cFYI(1,("Invalid return data count on get reparse info ioctl"));
+                                               buflen,
+                                               reparse_buf->TargetNameLen,
+                                               nls_codepage, 0);
+                       } else { /* ASCII names */
+                               strncpy(symlinkinfo,
+                                       reparse_buf->LinkNamesBuf +
+                                       reparse_buf->TargetNameOffset,
+                                       min_t(const int, buflen,
+                                          reparse_buf->TargetNameLen));
                        }
-                       symlinkinfo[buflen] = 0; /* just in case so the caller
-                                       does not go off the end of the buffer */
-                       cFYI(1, ("readlink result - %s", symlinkinfo));
+               } else {
+                       rc = -EIO;
+                       cFYI(1, ("Invalid return data count on "
+                                "get reparse info ioctl"));
                }
+               symlinkinfo[buflen] = 0; /* just in case so the caller
+                                       does not go off the end of the buffer */
+               cFYI(1, ("readlink result - %s", symlinkinfo));
        }
+
 qreparse_out:
        cifs_buf_release(pSMB);
 
@@ -2578,6 +2676,7 @@ qreparse_out:
 
        return rc;
 }
+#endif /* CIFS_EXPERIMENTAL */
 
 #ifdef CONFIG_CIFS_POSIX
 
@@ -2681,7 +2780,8 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
                return 0;
 
        count = posix_acl_xattr_count((size_t)buflen);
-       cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
+       cFYI(1, ("setting acl with %d entries from buf of length %d and "
+               "version of %d",
                count, buflen, le32_to_cpu(local_acl->a_version)));
        if (le32_to_cpu(local_acl->a_version) != 2) {
                cFYI(1, ("unknown POSIX ACL version %d",
@@ -2835,7 +2935,8 @@ setAclRetry:
        }
        params = 6 + name_len;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
+       /* BB find max SMB size from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -2869,9 +2970,8 @@ setAclRetry:
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Set POSIX ACL returned %d", rc));
-       }
 
 setACLerrorExit:
        cifs_buf_release(pSMB);
@@ -2883,7 +2983,7 @@ setACLerrorExit:
 /* BB fix tabs in this function FIXME BB */
 int
 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
-              const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
+              const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
 {
        int rc = 0;
        struct smb_t2_qfi_req *pSMB = NULL;
@@ -2901,7 +3001,7 @@ GetExtAttrRetry:
        if (rc)
                return rc;
 
-       params = 2 /* level */ +2 /* fid */;
+       params = 2 /* level */ + 2 /* fid */;
        pSMB->t2.TotalDataCount = 0;
        pSMB->t2.MaxParameterCount = cpu_to_le16(4);
        /* BB find exact max data count below from sess structure BB */
@@ -2964,34 +3064,23 @@ GetExtAttrOut:
 
 #endif /* CONFIG_POSIX */
 
-
-/* security id for everyone */
-static const struct cifs_sid sid_everyone =
-               {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
-/* group users */
-static const struct cifs_sid sid_user =
-               {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
-
-/* Convert CIFS ACL to POSIX form */
-static int parse_sec_desc(struct cifs_sid *psec_desc, int acl_len)
-{
-       return 0;
-}
-
+#ifdef CONFIG_CIFS_EXPERIMENTAL
 /* Get Security Descriptor (by handle) from remote server for a file or dir */
 int
 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
-               /* BB fix up return info */ char *acl_inf, const int buflen,
-                 const int acl_type /* ACCESS/DEFAULT not sure implication */)
+                 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
 {
        int rc = 0;
        int buf_type = 0;
-       QUERY_SEC_DESC_REQ * pSMB;
+       QUERY_SEC_DESC_REQ *pSMB;
        struct kvec iov[1];
 
        cFYI(1, ("GetCifsACL"));
 
-       rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
+       *pbuflen = 0;
+       *acl_inf = NULL;
+
+       rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
                        8 /* parm len */, tcon, (void **) &pSMB);
        if (rc)
                return rc;
@@ -3007,40 +3096,58 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
        iov[0].iov_base = (char *)pSMB;
        iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
 
-       rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
+       rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
+                        CIFS_STD_OP);
        cifs_stats_inc(&tcon->num_acl_get);
        if (rc) {
                cFYI(1, ("Send error in QuerySecDesc = %d", rc));
        } else {                /* decode response */
-               struct cifs_sid *psec_desc;
-               __le32 * parm;
-               int parm_len;
-               int data_len;
-               int acl_len;
+               __le32 *parm;
+               __u32 parm_len;
+               __u32 acl_len;
                struct smb_com_ntransact_rsp *pSMBr;
+               char *pdata;
 
 /* validate_nttransact */
                rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
-                                       (char **)&psec_desc,
-                                       &parm_len, &data_len);
+                                       &pdata, &parm_len, pbuflen);
                if (rc)
                        goto qsec_out;
                pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
 
-               cERROR(1, ("smb %p parm %p data %p",
-                         pSMBr, parm, psec_desc));  /* BB removeme BB */
+               cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
 
                if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
                        rc = -EIO;      /* bad smb */
+                       *pbuflen = 0;
                        goto qsec_out;
                }
 
 /* BB check that data area is minimum length and as big as acl_len */
 
-               acl_len = le32_to_cpu(*(__le32 *)parm);
-               /* BB check if (acl_len > bufsize) */
+               acl_len = le32_to_cpu(*parm);
+               if (acl_len != *pbuflen) {
+                       cERROR(1, ("acl length %d does not match %d",
+                                  acl_len, *pbuflen));
+                       if (*pbuflen > acl_len)
+                               *pbuflen = acl_len;
+               }
 
-               parse_sec_desc(psec_desc, acl_len);
+               /* check if buffer is big enough for the acl
+                  header followed by the smallest SID */
+               if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
+                   (*pbuflen >= 64 * 1024)) {
+                       cERROR(1, ("bad acl length %d", *pbuflen));
+                       rc = -EINVAL;
+                       *pbuflen = 0;
+               } else {
+                       *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
+                       if (*acl_inf == NULL) {
+                               *pbuflen = 0;
+                               rc = -ENOMEM;
+                       }
+                       memcpy(*acl_inf, pdata, *pbuflen);
+               }
        }
 qsec_out:
        if (buf_type == CIFS_SMALL_BUFFER)
@@ -3051,6 +3158,72 @@ qsec_out:
        return rc;
 }
 
+int
+CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
+                       struct cifs_ntsd *pntsd, __u32 acllen)
+{
+       __u16 byte_count, param_count, data_count, param_offset, data_offset;
+       int rc = 0;
+       int bytes_returned = 0;
+       SET_SEC_DESC_REQ *pSMB = NULL;
+       NTRANSACT_RSP *pSMBr = NULL;
+
+setCifsAclRetry:
+       rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
+                       (void **) &pSMBr);
+       if (rc)
+                       return (rc);
+
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+
+       param_count = 8;
+       param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
+       data_count = acllen;
+       data_offset = param_offset + param_count;
+       byte_count = 3 /* pad */  + param_count;
+
+       pSMB->DataCount = cpu_to_le32(data_count);
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->MaxParameterCount = cpu_to_le32(4);
+       pSMB->MaxDataCount = cpu_to_le32(16384);
+       pSMB->ParameterCount = cpu_to_le32(param_count);
+       pSMB->ParameterOffset = cpu_to_le32(param_offset);
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->DataOffset = cpu_to_le32(data_offset);
+       pSMB->SetupCount = 0;
+       pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
+       pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
+
+       pSMB->Fid = fid; /* file handle always le */
+       pSMB->Reserved2 = 0;
+       pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
+
+       if (pntsd && acllen) {
+               memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
+                       (char *) pntsd,
+                       acllen);
+               pSMB->hdr.smb_buf_length += (byte_count + data_count);
+
+       } else
+               pSMB->hdr.smb_buf_length += byte_count;
+
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+               (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+       cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
+       if (rc)
+               cFYI(1, ("Set CIFS ACL returned %d", rc));
+       cifs_buf_release(pSMB);
+
+       if (rc == -EAGAIN)
+               goto setCifsAclRetry;
+
+       return (rc);
+}
+
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
+
 /* Legacy Query Path Information call for lookup to old servers such
    as Win9x/WinME */
 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
@@ -3058,8 +3231,8 @@ int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
                        FILE_ALL_INFO *pFinfo,
                        const struct nls_table *nls_codepage, int remap)
 {
-       QUERY_INFORMATION_REQ * pSMB;
-       QUERY_INFORMATION_RSP * pSMBr;
+       QUERY_INFORMATION_REQ *pSMB;
+       QUERY_INFORMATION_RSP *pSMBr;
        int rc = 0;
        int bytes_returned;
        int name_len;
@@ -3091,9 +3264,11 @@ QInfRetry:
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
                cFYI(1, ("Send error in QueryInfo = %d", rc));
-       } else if (pFinfo) {            /* decode response */
+       } else if (pFinfo) {
                struct timespec ts;
                __u32 time = le32_to_cpu(pSMBr->last_write_time);
+
+               /* decode response */
                /* BB FIXME - add time zone adjustment BB */
                memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
                ts.tv_nsec = 0;
@@ -3124,7 +3299,7 @@ QInfRetry:
 int
 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
                 const unsigned char *searchName,
-                FILE_ALL_INFO * pFindData,
+                FILE_ALL_INFO *pFindData,
                 int legacy /* old style infolevel */,
                 const struct nls_table *nls_codepage, int remap)
 {
@@ -3158,7 +3333,8 @@ QPathInfoRetry:
        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(4000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -3199,10 +3375,12 @@ QPathInfoRetry:
                else if (pFindData) {
                        int size;
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       if (legacy) /* we do not read the last field, EAsize,
-                                      fortunately since it varies by subdialect
-                                      and on Set vs. Get, is two bytes or 4
-                                      bytes depending but we don't care here */
+
+                       /* On legacy responses we do not read the last field,
+                       EAsize, fortunately since it varies by subdialect and
+                       also note it differs on Set vs. Get, ie two bytes or 4
+                       bytes depending but we don't care here */
+                       if (legacy)
                                size = sizeof(FILE_INFO_STANDARD);
                        else
                                size = sizeof(FILE_ALL_INFO);
@@ -3222,7 +3400,7 @@ QPathInfoRetry:
 int
 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
                     const unsigned char *searchName,
-                    FILE_UNIX_BASIC_INFO * pFindData,
+                    FILE_UNIX_BASIC_INFO *pFindData,
                     const struct nls_table *nls_codepage, int remap)
 {
 /* SMB_QUERY_FILE_UNIX_BASIC */
@@ -3285,13 +3463,16 @@ UnixQPathInfoRetry:
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
                if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
+                       cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
+                                  "Unix Extensions can be disabled on mount "
+                                  "by specifying the nosfu mount option."));
                        rc = -EIO;      /* bad smb */
                } else {
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
                        memcpy((char *) pFindData,
                               (char *) &pSMBr->hdr.Protocol +
                               data_offset,
-                              sizeof (FILE_UNIX_BASIC_INFO));
+                              sizeof(FILE_UNIX_BASIC_INFO));
                }
        }
        cifs_buf_release(pSMB);
@@ -3301,85 +3482,6 @@ UnixQPathInfoRetry:
        return rc;
 }
 
-#if 0  /* function unused at present */
-int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
-              const char *searchName, FILE_ALL_INFO * findData,
-              const struct nls_table *nls_codepage)
-{
-/* level 257 SMB_ */
-       TRANSACTION2_FFIRST_REQ *pSMB = NULL;
-       TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
-       int rc = 0;
-       int bytes_returned;
-       int name_len;
-       __u16 params, byte_count;
-
-       cFYI(1, ("In FindUnique"));
-findUniqueRetry:
-       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-                     (void **) &pSMBr);
-       if (rc)
-               return rc;
-
-       if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-               name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
-                                    PATH_MAX, nls_codepage);
-               name_len++;     /* trailing null */
-               name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(searchName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, searchName, name_len);
-       }
-
-       params = 12 + name_len /* includes null */ ;
-       pSMB->TotalDataCount = 0;       /* no EAs */
-       pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
-       pSMB->MaxSetupCount = 0;
-       pSMB->Reserved = 0;
-       pSMB->Flags = 0;
-       pSMB->Timeout = 0;
-       pSMB->Reserved2 = 0;
-       pSMB->ParameterOffset = cpu_to_le16(
-        offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
-       pSMB->DataCount = 0;
-       pSMB->DataOffset = 0;
-       pSMB->SetupCount = 1;   /* one byte, no need to le convert */
-       pSMB->Reserved3 = 0;
-       pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
-       byte_count = params + 1 /* pad */ ;
-       pSMB->TotalParameterCount = cpu_to_le16(params);
-       pSMB->ParameterCount = pSMB->TotalParameterCount;
-       pSMB->SearchAttributes =
-           cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
-                       ATTR_DIRECTORY);
-       pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
-       pSMB->SearchFlags = cpu_to_le16(1);
-       pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
-       pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
-       pSMB->hdr.smb_buf_length += byte_count;
-       pSMB->ByteCount = cpu_to_le16(byte_count);
-
-       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-
-       if (rc) {
-               cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
-       } else {                /* decode response */
-               cifs_stats_inc(&tcon->num_ffirst);
-               /* BB fill in */
-       }
-
-       cifs_buf_release(pSMB);
-       if (rc == -EAGAIN)
-               goto findUniqueRetry;
-
-       return rc;
-}
-#endif /* end unused (temporarily) function */
-
 /* xid, tcon, searchName and codepage are input parms, rest are returned */
 int
 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
@@ -3391,7 +3493,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
 /* level 257 SMB_ */
        TRANSACTION2_FFIRST_REQ *pSMB = NULL;
        TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
-       T2_FFIRST_RSP_PARMS * parms;
+       T2_FFIRST_RSP_PARMS *parms;
        int rc = 0;
        int bytes_returned = 0;
        int name_len;
@@ -3486,10 +3588,12 @@ findFirstRetry:
                /* BB remember to free buffer if error BB */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
                if (rc == 0) {
+                       unsigned int lnoff;
+
                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
-                               psrch_inf->unicode = TRUE;
+                               psrch_inf->unicode = true;
                        else
-                               psrch_inf->unicode = FALSE;
+                               psrch_inf->unicode = false;
 
                        psrch_inf->ntwrk_buf_start = (char *)pSMBr;
                        psrch_inf->smallBuf = 0;
@@ -3500,14 +3604,25 @@ findFirstRetry:
                               le16_to_cpu(pSMBr->t2.ParameterOffset));
 
                        if (parms->EndofSearch)
-                               psrch_inf->endOfSearch = TRUE;
+                               psrch_inf->endOfSearch = true;
                        else
-                               psrch_inf->endOfSearch = FALSE;
+                               psrch_inf->endOfSearch = false;
 
                        psrch_inf->entries_in_buffer =
                                        le16_to_cpu(parms->SearchCount);
                        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) {
+                               cERROR(1, ("ignoring corrupt resume name"));
+                               psrch_inf->last_entry = NULL;
+                               return rc;
+                       }
+
+                       psrch_inf->last_entry = psrch_inf->srch_entries_start +
+                                                       lnoff;
+
                        *pnetfid = parms->SearchHandle;
                } else {
                        cifs_buf_release(pSMB);
@@ -3522,7 +3637,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 {
        TRANSACTION2_FNEXT_REQ *pSMB = NULL;
        TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
-       T2_FNEXT_RSP_PARMS * parms;
+       T2_FNEXT_RSP_PARMS *parms;
        char *response_data;
        int rc = 0;
        int bytes_returned, name_len;
@@ -3530,7 +3645,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 
        cFYI(1, ("In FindNext"));
 
-       if (psrch_inf->endOfSearch == TRUE)
+       if (psrch_inf->endOfSearch)
                return -ENOENT;
 
        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
@@ -3559,16 +3674,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
        pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
        pSMB->SearchHandle = searchHandle;      /* always kept as le */
        pSMB->SearchCount =
-               cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
-       /* test for Unix extensions */
-/*     if (tcon->ses->capabilities & CAP_UNIX) {
-               pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
-               psrch_inf->info_level = SMB_FIND_FILE_UNIX;
-       } else {
-               pSMB->InformationLevel =
-                  cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
-               psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
-       } */
+               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 =
@@ -3597,7 +3703,8 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
        cifs_stats_inc(&tcon->num_fnext);
        if (rc) {
                if (rc == -EBADF) {
-                       psrch_inf->endOfSearch = TRUE;
+                       psrch_inf->endOfSearch = true;
+                       cifs_buf_release(pSMB);
                        rc = 0; /* search probably was closed at end of search*/
                } else
                        cFYI(1, ("FindNext returned = %d", rc));
@@ -3605,11 +3712,13 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
                if (rc == 0) {
+                       unsigned int lnoff;
+
                        /* BB fixme add lock for file (srch_info) struct here */
                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
-                               psrch_inf->unicode = TRUE;
+                               psrch_inf->unicode = true;
                        else
-                               psrch_inf->unicode = FALSE;
+                               psrch_inf->unicode = false;
                        response_data = (char *) &pSMBr->hdr.Protocol +
                               le16_to_cpu(pSMBr->t2.ParameterOffset);
                        parms = (T2_FNEXT_RSP_PARMS *)response_data;
@@ -3624,13 +3733,23 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                        psrch_inf->ntwrk_buf_start = (char *)pSMB;
                        psrch_inf->smallBuf = 0;
                        if (parms->EndofSearch)
-                               psrch_inf->endOfSearch = TRUE;
+                               psrch_inf->endOfSearch = true;
                        else
-                               psrch_inf->endOfSearch = FALSE;
+                               psrch_inf->endOfSearch = false;
                        psrch_inf->entries_in_buffer =
                                                le16_to_cpu(parms->SearchCount);
                        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) {
+                               cERROR(1, ("ignoring corrupt resume name"));
+                               psrch_inf->last_entry = NULL;
+                               return rc;
+                       } else
+                               psrch_inf->last_entry =
+                                       psrch_inf->srch_entries_start + lnoff;
+
 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
            psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
 
@@ -3656,8 +3775,6 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
 {
        int rc = 0;
        FINDCLOSE_REQ *pSMB = NULL;
-       CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
-       int bytes_returned;
 
        cFYI(1, ("In CIFSSMBFindClose"));
        rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
@@ -3669,16 +3786,13 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
        if (rc)
                return rc;
 
-       pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
        pSMB->FileID = searchHandle;
        pSMB->ByteCount = 0;
-       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc) {
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       if (rc)
                cERROR(1, ("Send error in FindClose = %d", rc));
-       }
+
        cifs_stats_inc(&tcon->num_fclose);
-       cifs_small_buf_release(pSMB);
 
        /* Since session is dead, search handle closed on server already */
        if (rc == -EAGAIN)
@@ -3690,7 +3804,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
 int
 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
                      const unsigned char *searchName,
-                     __u64 * inode_number,
+                     __u64 *inode_number,
                      const struct nls_table *nls_codepage, int remap)
 {
        int rc = 0;
@@ -3770,7 +3884,7 @@ GetInodeNumberRetry:
                        }
                        pfinfo = (struct file_internal_info *)
                                (data_offset + (char *) &pSMBr->hdr.Protocol);
-                       *inode_number = pfinfo->UniqueId;
+                       *inode_number = le64_to_cpu(pfinfo->UniqueId);
                }
        }
 GetInodeNumOut:
@@ -3780,25 +3894,127 @@ GetInodeNumOut:
        return rc;
 }
 
+/* parses DFS refferal V3 structure
+ * caller is responsible for freeing target_nodes
+ * returns:
+ *     on success - 0
+ *     on failure - errno
+ */
+static int
+parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
+               unsigned int *num_of_nodes,
+               struct dfs_info3_param **target_nodes,
+               const struct nls_table *nls_codepage, int remap,
+               const char *searchName)
+{
+       int i, rc = 0;
+       char *data_end;
+       bool is_unicode;
+       struct dfs_referral_level_3 *ref;
+
+       if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+               is_unicode = true;
+       else
+               is_unicode = false;
+       *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
+
+       if (*num_of_nodes < 1) {
+               cERROR(1, ("num_referrals: must be at least > 0,"
+                       "but we get num_referrals = %d\n", *num_of_nodes));
+               rc = -EINVAL;
+               goto parse_DFS_referrals_exit;
+       }
+
+       ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
+       if (ref->VersionNumber != cpu_to_le16(3)) {
+               cERROR(1, ("Referrals of V%d version are not supported,"
+                       "should be V3", le16_to_cpu(ref->VersionNumber)));
+               rc = -EINVAL;
+               goto parse_DFS_referrals_exit;
+       }
+
+       /* get the upper boundary of the resp buffer */
+       data_end = (char *)(&(pSMBr->PathConsumed)) +
+                               le16_to_cpu(pSMBr->t2.DataCount);
+
+       cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
+                       *num_of_nodes,
+                       le32_to_cpu(pSMBr->DFSFlags)));
+
+       *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
+                       *num_of_nodes, GFP_KERNEL);
+       if (*target_nodes == NULL) {
+               cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
+               rc = -ENOMEM;
+               goto parse_DFS_referrals_exit;
+       }
+
+       /* collect neccessary data from referrals */
+       for (i = 0; i < *num_of_nodes; i++) {
+               char *temp;
+               int max_len;
+               struct dfs_info3_param *node = (*target_nodes)+i;
+
+               node->flags = le32_to_cpu(pSMBr->DFSFlags);
+               if (is_unicode) {
+                       __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
+                                               GFP_KERNEL);
+                       cifsConvertToUCS((__le16 *) tmp, searchName,
+                                       PATH_MAX, nls_codepage, remap);
+                       node->path_consumed = cifs_ucs2_bytes(tmp,
+                                       le16_to_cpu(pSMBr->PathConsumed),
+                                       nls_codepage);
+                       kfree(tmp);
+               } else
+                       node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
+
+               node->server_type = le16_to_cpu(ref->ServerType);
+               node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
+
+               /* copy DfsPath */
+               temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
+               max_len = data_end - temp;
+               node->path_name = cifs_strndup_from_ucs(temp, max_len,
+                                                     is_unicode, nls_codepage);
+               if (!node->path_name) {
+                       rc = -ENOMEM;
+                       goto parse_DFS_referrals_exit;
+               }
+
+               /* copy link target UNC */
+               temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
+               max_len = data_end - temp;
+               node->node_name = cifs_strndup_from_ucs(temp, max_len,
+                                                     is_unicode, nls_codepage);
+               if (!node->node_name)
+                       rc = -ENOMEM;
+       }
+
+parse_DFS_referrals_exit:
+       if (rc) {
+               free_dfs_info_array(*target_nodes, *num_of_nodes);
+               *target_nodes = NULL;
+               *num_of_nodes = 0;
+       }
+       return rc;
+}
+
 int
 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
                const unsigned char *searchName,
-               unsigned char **targetUNCs,
-               unsigned int *number_of_UNC_in_array,
+               struct dfs_info3_param **target_nodes,
+               unsigned int *num_of_nodes,
                const struct nls_table *nls_codepage, int remap)
 {
 /* TRANS2_GET_DFS_REFERRAL */
        TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
        TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
-       struct dfs_referral_level_3 *referrals = NULL;
        int rc = 0;
        int bytes_returned;
        int name_len;
-       unsigned int i;
-       char *temp;
        __u16 params, byte_count;
-       *number_of_UNC_in_array = 0;
-       *targetUNCs = NULL;
+       *num_of_nodes = 0;
+       *target_nodes = NULL;
 
        cFYI(1, ("In GetDFSRefer the path %s", searchName));
        if (ses == NULL)
@@ -3814,12 +4030,10 @@ getDFSRetry:
        pSMB->hdr.Mid = GetNextMid(ses->server);
        pSMB->hdr.Tid = ses->ipc_tid;
        pSMB->hdr.Uid = ses->Suid;
-       if (ses->capabilities & CAP_STATUS32) {
+       if (ses->capabilities & CAP_STATUS32)
                pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
-       }
-       if (ses->capabilities & CAP_DFS) {
+       if (ses->capabilities & CAP_DFS)
                pSMB->hdr.Flags2 |= SMBFLG2_DFS;
-       }
 
        if (ses->capabilities & CAP_UNICODE) {
                pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
@@ -3847,7 +4061,8 @@ getDFSRetry:
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->MaxParameterCount = 0;
-       pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(4000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -3869,101 +4084,27 @@ getDFSRetry:
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
                cFYI(1, ("Send error in GetDFSRefer = %d", rc));
-       } else {                /* decode response */
-/* BB Add logic to parse referrals here */
-               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+               goto GetDFSRefExit;
+       }
+       rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-               /* BB Also check if enough total bytes returned? */
-               if (rc || (pSMBr->ByteCount < 17))
-                       rc = -EIO;      /* bad smb */
-               else {
-                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
+       /* BB Also check if enough total bytes returned? */
+       if (rc || (pSMBr->ByteCount < 17)) {
+               rc = -EIO;      /* bad smb */
+               goto GetDFSRefExit;
+       }
 
-                       cFYI(1,
-                           ("Decoding GetDFSRefer response BCC: %d  Offset %d",
-                             pSMBr->ByteCount, data_offset));
-                       referrals =
-                           (struct dfs_referral_level_3 *)
-                                       (8 /* sizeof start of data block */ +
-                                       data_offset +
-                                       (char *) &pSMBr->hdr.Protocol);
-                       cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",
-                               le16_to_cpu(pSMBr->NumberOfReferrals),
-                               le16_to_cpu(pSMBr->DFSFlags),
-                               le16_to_cpu(referrals->ReferralSize),
-                               le16_to_cpu(referrals->ServerType),
-                               le16_to_cpu(referrals->ReferralFlags),
-                               le16_to_cpu(referrals->TimeToLive)));
-                       /* BB This field is actually two bytes in from start of
-                          data block so we could do safety check that DataBlock
-                          begins at address of pSMBr->NumberOfReferrals */
-                       *number_of_UNC_in_array =
-                                       le16_to_cpu(pSMBr->NumberOfReferrals);
-
-                       /* BB Fix below so can return more than one referral */
-                       if (*number_of_UNC_in_array > 1)
-                               *number_of_UNC_in_array = 1;
-
-                       /* get the length of the strings describing refs */
-                       name_len = 0;
-                       for (i = 0; i < *number_of_UNC_in_array; i++) {
-                               /* make sure that DfsPathOffset not past end */
-                               __u16 offset =
-                                       le16_to_cpu(referrals->DfsPathOffset);
-                               if (offset > data_count) {
-                                       /* if invalid referral, stop here and do
-                                       not try to copy any more */
-                                       *number_of_UNC_in_array = i;
-                                       break;
-                               }
-                               temp = ((char *)referrals) + offset;
+       cFYI(1, ("Decoding GetDFSRefer response BCC: %d  Offset %d",
+                               pSMBr->ByteCount,
+                               le16_to_cpu(pSMBr->t2.DataOffset)));
 
-                               if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-                                       name_len += UniStrnlen((wchar_t *)temp,
-                                                               data_count);
-                               } else {
-                                       name_len += strnlen(temp, data_count);
-                               }
-                               referrals++;
-                               /* BB add check that referral pointer does
-                                  not fall off end PDU */
-                       }
-                       /* BB add check for name_len bigger than bcc */
-                       *targetUNCs =
-                               kmalloc(name_len+1+(*number_of_UNC_in_array),
-                                       GFP_KERNEL);
-                       if (*targetUNCs == NULL) {
-                               rc = -ENOMEM;
-                               goto GetDFSRefExit;
-                       }
-                       /* copy the ref strings */
-                       referrals = (struct dfs_referral_level_3 *)
-                                       (8 /* sizeof data hdr */ + data_offset +
-                                       (char *) &pSMBr->hdr.Protocol);
-
-                       for (i = 0; i < *number_of_UNC_in_array; i++) {
-                               temp = ((char *)referrals) +
-                                         le16_to_cpu(referrals->DfsPathOffset);
-                               if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-                                       cifs_strfromUCS_le(*targetUNCs,
-                                                         (__le16 *) temp,
-                                                         name_len,
-                                                         nls_codepage);
-                               } else {
-                                       strncpy(*targetUNCs, temp, name_len);
-                               }
-                               /*  BB update target_uncs pointers */
-                               referrals++;
-                       }
-                       temp = *targetUNCs;
-                       temp[name_len] = 0;
-               }
+       /* parse returned result into more usable form */
+       rc = parse_DFS_referrals(pSMBr, num_of_nodes,
+                                target_nodes, nls_codepage, remap,
+                                searchName);
 
-       }
 GetDFSRefExit:
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
 
        if (rc == -EAGAIN)
                goto getDFSRetry;
@@ -3989,10 +4130,6 @@ oldQFSInfoRetry:
                (void **) &pSMBr);
        if (rc)
                return rc;
-       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-                     (void **) &pSMBr);
-       if (rc)
-               return rc;
 
        params = 2;     /* level */
        pSMB->TotalDataCount = 0;
@@ -4157,7 +4294,8 @@ QFSAttributeRetry:
        params = 2;     /* level */
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -4194,7 +4332,7 @@ QFSAttributeRetry:
                             *) (((char *) &pSMBr->hdr.Protocol) +
                                 data_offset);
                        memcpy(&tcon->fsAttrInfo, response_data,
-                              sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
+                              sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
                }
        }
        cifs_buf_release(pSMB);
@@ -4226,7 +4364,8 @@ QFSDeviceRetry:
        params = 2;     /* level */
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -4254,7 +4393,7 @@ QFSDeviceRetry:
        } else {                /* decode response */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-               if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
+               if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
                        rc = -EIO;      /* bad smb */
                else {
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
@@ -4263,7 +4402,7 @@ QFSDeviceRetry:
                                (((char *) &pSMBr->hdr.Protocol) +
                                 data_offset);
                        memcpy(&tcon->fsDevInfo, response_data,
-                              sizeof (FILE_SYSTEM_DEVICE_INFO));
+                              sizeof(FILE_SYSTEM_DEVICE_INFO));
                }
        }
        cifs_buf_release(pSMB);
@@ -4297,7 +4436,8 @@ QFSUnixRetry:
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(100);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -4331,7 +4471,7 @@ QFSUnixRetry:
                             *) (((char *) &pSMBr->hdr.Protocol) +
                                 data_offset);
                        memcpy(&tcon->fsUnixInfo, response_data,
-                              sizeof (FILE_SYSTEM_UNIX_INFO));
+                              sizeof(FILE_SYSTEM_UNIX_INFO));
                }
        }
        cifs_buf_release(pSMB);
@@ -4372,7 +4512,8 @@ SETFSUnixRetry:
        offset = param_offset + params;
 
        pSMB->MaxParameterCount = cpu_to_le16(4);
-       pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(100);
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
@@ -4403,9 +4544,8 @@ SETFSUnixRetry:
                cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
        } else {                /* decode response */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-               if (rc) {
+               if (rc)
                        rc = -EIO;      /* bad smb */
-               }
        }
        cifs_buf_release(pSMB);
 
@@ -4441,7 +4581,8 @@ QFSPosixRetry:
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(100);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -4511,7 +4652,7 @@ QFSPosixRetry:
 
 int
 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-             __u64 size, int SetAllocation,
+             __u64 size, bool SetAllocation,
              const struct nls_table *nls_codepage, int remap)
 {
        struct smb_com_transaction2_spi_req *pSMB = NULL;
@@ -4541,7 +4682,7 @@ SetEOFRetry:
                strncpy(pSMB->FileName, fileName, name_len);
        }
        params = 6 + name_len;
-       data_count = sizeof (struct file_end_of_file_info);
+       data_count = sizeof(struct file_end_of_file_info);
        pSMB->MaxParameterCount = cpu_to_le16(2);
        pSMB->MaxDataCount = cpu_to_le16(4100);
        pSMB->MaxSetupCount = 0;
@@ -4587,9 +4728,8 @@ SetEOFRetry:
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc) {
+       if (rc)
                cFYI(1, ("SetPathInfo (file size) returned %d", rc));
-       }
 
        cifs_buf_release(pSMB);
 
@@ -4601,14 +4741,12 @@ SetEOFRetry:
 
 int
 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
-                  __u16 fid, __u32 pid_of_opener, int SetAllocation)
+                  __u16 fid, __u32 pid_of_opener, bool SetAllocation)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
-       struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
        char *data_offset;
        struct file_end_of_file_info *parm_data;
        int rc = 0;
-       int bytes_returned = 0;
        __u16 params, param_offset, offset, byte_count, count;
 
        cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
@@ -4618,8 +4756,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
        if (rc)
                return rc;
 
-       pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
-
        pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
        pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
 
@@ -4636,7 +4772,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
 
        count = sizeof(struct file_end_of_file_info);
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
@@ -4670,17 +4807,13 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
        pSMB->Reserved4 = 0;
        pSMB->hdr.smb_buf_length += byte_count;
        pSMB->ByteCount = cpu_to_le16(byte_count);
-       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
        if (rc) {
                cFYI(1,
                     ("Send error in SetFileInfo (SetFileSize) = %d",
                      rc));
        }
 
-       if (pSMB)
-               cifs_small_buf_release(pSMB);
-
        /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
 
@@ -4694,14 +4827,12 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
    time and resort to the original setpathinfo level which takes the ancient
    DOS time format with 2 second granularity */
 int
-CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
-                   const FILE_BASIC_INFO *data, __u16 fid)
+CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+                   const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
-       struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
        char *data_offset;
        int rc = 0;
-       int bytes_returned = 0;
        __u16 params, param_offset, offset, byte_count, count;
 
        cFYI(1, ("Set Times (via SetFileInfo)"));
@@ -4710,13 +4841,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
        if (rc)
                return rc;
 
-       pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
-
-       /* At this point there is no need to override the current pid
-       with the pid of the opener, but that could change if we someday
-       use an existing handle (rather than opening one on the fly) */
-       /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
-       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
+       pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
 
        params = 6;
        pSMB->MaxSetupCount = 0;
@@ -4729,9 +4855,10 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
 
        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
 
-       count = sizeof (FILE_BASIC_INFO);
+       count = sizeof(FILE_BASIC_INFO);
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+       /* BB find max SMB PDU from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
@@ -4751,13 +4878,9 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
        pSMB->hdr.smb_buf_length += byte_count;
        pSMB->ByteCount = cpu_to_le16(byte_count);
        memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
-       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc) {
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       if (rc)
                cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
-       }
-
-       cifs_small_buf_release(pSMB);
 
        /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
@@ -4765,11 +4888,66 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
        return rc;
 }
 
+int
+CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
+                         bool delete_file, __u16 fid, __u32 pid_of_opener)
+{
+       struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+       char *data_offset;
+       int rc = 0;
+       __u16 params, param_offset, offset, byte_count, count;
+
+       cFYI(1, ("Set File Disposition (via SetFileInfo)"));
+       rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+       if (rc)
+               return rc;
+
+       pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
+
+       params = 6;
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+       offset = param_offset + params;
+
+       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+
+       count = 1;
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       /* BB find max SMB PDU from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+       byte_count = 3 /* pad */  + params + count;
+       pSMB->DataCount = cpu_to_le16(count);
+       pSMB->ParameterCount = cpu_to_le16(params);
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->ParameterOffset = cpu_to_le16(param_offset);
+       pSMB->DataOffset = cpu_to_le16(offset);
+       pSMB->Fid = fid;
+       pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
+       pSMB->Reserved4 = 0;
+       pSMB->hdr.smb_buf_length += 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);
+       if (rc)
+               cFYI(1, ("Send error in SetFileDisposition = %d", rc));
+
+       return rc;
+}
 
 int
-CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-               const FILE_BASIC_INFO *data,
-               const struct nls_table *nls_codepage, int remap)
+CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
+                  const char *fileName, const FILE_BASIC_INFO *data,
+                  const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
        TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -4800,9 +4978,10 @@ SetTimesRetry:
        }
 
        params = 6 + name_len;
-       count = sizeof (FILE_BASIC_INFO);
+       count = sizeof(FILE_BASIC_INFO);
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -4829,13 +5008,12 @@ SetTimesRetry:
                pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
        pSMB->Reserved4 = 0;
        pSMB->hdr.smb_buf_length += byte_count;
-       memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
+       memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc) {
+       if (rc)
                cFYI(1, ("SetPathInfo (times) returned %d", rc));
-       }
 
        cifs_buf_release(pSMB);
 
@@ -4885,9 +5063,8 @@ SetAttrLgcyRetry:
        pSMB->ByteCount = cpu_to_le16(name_len + 1);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Error in LegacySetAttr = %d", rc));
-       }
 
        cifs_buf_release(pSMB);
 
@@ -4899,10 +5076,9 @@ SetAttrLgcyRetry:
 #endif /* temporarily unneeded SetAttr legacy function */
 
 int
-CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
-                   char *fileName, __u64 mode, __u64 uid, __u64 gid,
-                   dev_t device, const struct nls_table *nls_codepage,
-                   int remap)
+CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
+                  const struct cifs_unix_set_info_args *args,
+                  const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
        TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -4911,6 +5087,7 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
        int bytes_returned = 0;
        FILE_UNIX_BASIC_INFO *data_offset;
        __u16 params, param_offset, offset, count, byte_count;
+       __u64 mode = args->mode;
 
        cFYI(1, ("In SetUID/GID/Mode"));
 setPermsRetry:
@@ -4932,9 +5109,10 @@ setPermsRetry:
        }
 
        params = 6 + name_len;
-       count = sizeof (FILE_UNIX_BASIC_INFO);
+       count = sizeof(FILE_UNIX_BASIC_INFO);
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -4965,16 +5143,16 @@ setPermsRetry:
        set file size and do not want to truncate file size to zero
        accidently as happened on one Samba server beta by putting
        zero instead of -1 here */
-       data_offset->EndOfFile = NO_CHANGE_64;
-       data_offset->NumOfBytes = NO_CHANGE_64;
-       data_offset->LastStatusChange = NO_CHANGE_64;
-       data_offset->LastAccessTime = NO_CHANGE_64;
-       data_offset->LastModificationTime = NO_CHANGE_64;
-       data_offset->Uid = cpu_to_le64(uid);
-       data_offset->Gid = cpu_to_le64(gid);
+       data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
+       data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
+       data_offset->LastStatusChange = cpu_to_le64(args->ctime);
+       data_offset->LastAccessTime = cpu_to_le64(args->atime);
+       data_offset->LastModificationTime = cpu_to_le64(args->mtime);
+       data_offset->Uid = cpu_to_le64(args->uid);
+       data_offset->Gid = cpu_to_le64(args->gid);
        /* better to leave device as zero when it is  */
-       data_offset->DevMajor = cpu_to_le64(MAJOR(device));
-       data_offset->DevMinor = cpu_to_le64(MINOR(device));
+       data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
+       data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
        data_offset->Permissions = cpu_to_le64(mode);
 
        if (S_ISREG(mode))
@@ -4996,12 +5174,10 @@ setPermsRetry:
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc) {
+       if (rc)
                cFYI(1, ("SetPathInfo (perms) returned %d", rc));
-       }
 
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
                goto setPermsRetry;
        return rc;
@@ -5049,7 +5225,8 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
        pSMB->ByteCount = 0;
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                       (struct smb_hdr *) pSMBr, &bytes_returned, -1);
+                        (struct smb_hdr *)pSMBr, &bytes_returned,
+                        CIFS_ASYNC_OP);
        if (rc) {
                cFYI(1, ("Error in Notify = %d", rc));
        } else {
@@ -5117,7 +5294,8 @@ QAllEAsRetry:
        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(4000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -5221,8 +5399,7 @@ QAllEAsRetry:
                        }
                }
        }
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
                goto QAllEAsRetry;
 
@@ -5265,7 +5442,8 @@ QEARetry:
        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(4000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -5370,8 +5548,7 @@ QEARetry:
                        }
                }
        }
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
                goto QEARetry;
 
@@ -5421,9 +5598,10 @@ SetEARetry:
        else
                name_len = strnlen(ea_name, 255);
 
-       count = sizeof(*parm_data) + ea_value_len + name_len + 1;
+       count = sizeof(*parm_data) + ea_value_len + name_len;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
+       /* BB find max SMB PDU from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -5472,9 +5650,8 @@ SetEARetry:
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc) {
+       if (rc)
                cFYI(1, ("SetPathInfo (EA) returned %d", rc));
-       }
 
        cifs_buf_release(pSMB);