Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / fs / cifs / cifssmb.c
index 1620991..4511b70 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifssmb.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2008
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   Contains the routines for constructing the SMB PDUs themselves
@@ -24,8 +24,8 @@
  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
  /* These are mostly routines that operate on a pathname, or on a tree id     */
  /* (mounted volume), but there are eight handle based routines which must be */
- /* treated slightly different for reconnection purposes since we never want  */
- /* to reuse a stale file handle and the caller knows the file handle */
+ /* treated slightly differently for reconnection purposes since we never     */
+ /* want to reuse a stale file handle and only the caller knows the file info */
 
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -34,6 +34,7 @@
 #include <asm/uaccess.h>
 #include "cifspdu.h"
 #include "cifsglob.h"
+#include "cifsacl.h"
 #include "cifsproto.h"
 #include "cifs_unicode.h"
 #include "cifs_debug.h"
@@ -43,8 +44,12 @@ static struct {
        int index;
        char *name;
 } protocols[] = {
-       {CIFS_PROT, "\2NT LM 0.12"}, 
-       {CIFS_PROT, "\2POSIX 2"},
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+       {LANMAN_PROT, "\2LM1.2X002"},
+       {LANMAN2_PROT, "\2LANMAN2.1"},
+#endif /* weak password hashing for legacy clients */
+       {CIFS_PROT, "\2NT LM 0.12"},
+       {POSIX_PROT, "\2POSIX 2"},
        {BAD_PROT, "\2"}
 };
 #else
@@ -52,106 +57,171 @@ static struct {
        int index;
        char *name;
 } protocols[] = {
-       {CIFS_PROT, "\2NT LM 0.12"}, 
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+       {LANMAN_PROT, "\2LM1.2X002"},
+       {LANMAN2_PROT, "\2LANMAN2.1"},
+#endif /* weak password hashing for legacy clients */
+       {CIFS_PROT, "\2NT LM 0.12"},
        {BAD_PROT, "\2"}
 };
 #endif
 
+/* define the number of elements in the cifs dialect array */
+#ifdef CONFIG_CIFS_POSIX
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define CIFS_NUM_PROT 4
+#else
+#define CIFS_NUM_PROT 2
+#endif /* CIFS_WEAK_PW_HASH */
+#else /* not posix */
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define CIFS_NUM_PROT 3
+#else
+#define CIFS_NUM_PROT 1
+#endif /* CONFIG_CIFS_WEAK_PW_HASH */
+#endif /* CIFS_POSIX */
+
+/* Allocates buffer into dst and copies smb string from src to it.
+ * caller is responsible for freeing dst if function returned 0.
+ * returns:
+ *     on success - 0
+ *     on failure - errno
+ */
+static int
+cifs_strncpy_to_host(char **dst, const char *src, const int maxlen,
+                const bool is_unicode, const struct nls_table *nls_codepage)
+{
+       int plen;
+
+       if (is_unicode) {
+               plen = UniStrnlen((wchar_t *)src, maxlen);
+               *dst = kmalloc(plen + 2, GFP_KERNEL);
+               if (!*dst)
+                       goto cifs_strncpy_to_host_ErrExit;
+               cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage);
+       } else {
+               plen = strnlen(src, maxlen);
+               *dst = kmalloc(plen + 2, GFP_KERNEL);
+               if (!*dst)
+                       goto cifs_strncpy_to_host_ErrExit;
+               strncpy(*dst, src, plen);
+       }
+       (*dst)[plen] = 0;
+       (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */
+       return 0;
+
+cifs_strncpy_to_host_ErrExit:
+       cERROR(1, ("Failed to allocate buffer for string\n"));
+       return -ENOMEM;
+}
+
 
 /* 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)
+static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
 {
        struct cifsFileInfo *open_file = NULL;
-       struct list_head * tmp;
-       struct list_head * tmp1;
+       struct list_head *tmp;
+       struct list_head *tmp1;
 
 /* list all files open on tree connection and mark them invalid */
        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 = list_entry(tmp, struct cifsFileInfo, tlist);
+               if (open_file)
+                       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;
 
        /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
           check for tcp and smb session status done differently
           for those three - in the calling routine */
-       if(tcon) {
-               if(tcon->tidStatus == CifsExiting) {
+       if (tcon) {
+               if (tcon->tidStatus == CifsExiting) {
                        /* only tree disconnect, open, and write,
                        (and ulogoff which does not have tcon)
                        are allowed as we start force umount */
-                       if((smb_command != SMB_COM_WRITE_ANDX) && 
-                          (smb_command != SMB_COM_OPEN_ANDX) && 
+                       if ((smb_command != SMB_COM_WRITE_ANDX) &&
+                          (smb_command != SMB_COM_OPEN_ANDX) &&
                           (smb_command != SMB_COM_TREE_DISCONNECT)) {
-                               cFYI(1,("can not send cmd %d while umounting",
+                               cFYI(1, ("can not send cmd %d while umounting",
                                        smb_command));
                                return -ENODEV;
                        }
                }
-               if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
-                                 (tcon->ses->server)){
+               if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
+                                 (tcon->ses->server)) {
                        struct nls_table *nls_codepage;
-                               /* Give Demultiplex thread up to 10 seconds to 
+                               /* 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"));
+                                               cFYI(1, ("gave up waiting on "
+                                                     "reconnect in smb_init"));
                                                return -EHOSTDOWN;
                                        } /* else "hard" mount - keep retrying
                                             until process is killed or server
                                             comes back on-line */
                                } else /* TCP session is reestablished now */
                                        break;
-                                
                        }
-                       
+
                        nls_codepage = load_nls_default();
                /* need to prevent multiple threads trying to
                simultaneously reconnect the same SMB session */
                        down(&tcon->ses->sesSem);
-                       if(tcon->ses->status == CifsNeedReconnect)
-                               rc = cifs_setup_session(0, tcon->ses, 
+                       if (tcon->ses->status == CifsNeedReconnect)
+                               rc = cifs_setup_session(0, tcon->ses,
                                                        nls_codepage);
-                       if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+                       if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
                                mark_open_files_invalid(tcon);
-                               rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
-                                       , nls_codepage);
+                               rc = CIFSTCon(0, tcon->ses, tcon->treeName,
+                                             tcon, nls_codepage);
                                up(&tcon->ses->sesSem);
                                /* 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 - 
-                                  it is safer (and faster) to reopen files
+                               /* Removed call to reopen open files here.
+                                  It is safer (and faster) to reopen files
                                   one at a time as needed in read and write */
 
-                               /* Check if handle based operation so we 
+                               /* Check if handle based operation so we
                                   know whether we can continue or not without
                                   returning to caller to reset file handle */
-                               switch(smb_command) {
+                               switch (smb_command) {
                                        case SMB_COM_READ_ANDX:
                                        case SMB_COM_WRITE_ANDX:
                                        case SMB_COM_CLOSE:
@@ -170,7 +240,7 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                        return -EIO;
                }
        }
-       if(rc)
+       if (rc)
                return rc;
 
        *request_buf = cifs_small_buf_get();
@@ -179,13 +249,40 @@ 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);
+
+       return rc;
+}
+
+int
+small_smb_init_no_tc(const int smb_command, const int wct,
+                    struct cifsSesInfo *ses, void **request_buf)
+{
+       int rc;
+       struct smb_hdr *buffer;
+
+       rc = small_smb_init(smb_command, wct, NULL, request_buf);
+       if (rc)
+               return rc;
+
+       buffer = (struct smb_hdr *)*request_buf;
+       buffer->Mid = GetNextMid(ses->server);
+       if (ses->capabilities & CAP_UNICODE)
+               buffer->Flags2 |= SMBFLG2_UNICODE;
+       if (ses->capabilities & CAP_STATUS32)
+               buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+
+       /* uid, tid can stay at zero as set in header assemble */
 
-        if(tcon != NULL)
-                cifs_stats_inc(&tcon->num_smbs_sent);
+       /* BB add support for turning on the signing when
+       this function is used after 1st of session setup requests */
 
        return rc;
-}  
+}
 
 /* If the return code is zero, this function must fill in request_buf pointer */
 static int
@@ -198,52 +295,53 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
        /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
           check for tcp and smb session status done differently
           for those three - in the calling routine */
-       if(tcon) {
-               if(tcon->tidStatus == CifsExiting) {
+       if (tcon) {
+               if (tcon->tidStatus == CifsExiting) {
                        /* only tree disconnect, open, and write,
                          (and ulogoff which does not have tcon)
                          are allowed as we start force umount */
-                       if((smb_command != SMB_COM_WRITE_ANDX) &&
+                       if ((smb_command != SMB_COM_WRITE_ANDX) &&
                           (smb_command != SMB_COM_OPEN_ANDX) &&
                           (smb_command != SMB_COM_TREE_DISCONNECT)) {
-                               cFYI(1,("can not send cmd %d while umounting",
+                               cFYI(1, ("can not send cmd %d while umounting",
                                        smb_command));
                                return -ENODEV;
                        }
                }
 
-               if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
-                                 (tcon->ses->server)){
+               if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
+                                 (tcon->ses->server)) {
                        struct nls_table *nls_codepage;
                                /* 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 == 
+                                       (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"));
+                                               cFYI(1, ("gave up waiting on "
+                                                     "reconnect in smb_init"));
                                                return -EHOSTDOWN;
                                        } /* else "hard" mount - keep retrying
                                             until process is killed or server
                                             comes on-line */
                                } else /* TCP session is reestablished now */
                                        break;
-                                
                        }
-                       
                        nls_codepage = load_nls_default();
                /* need to prevent multiple threads trying to
                simultaneously reconnect the same SMB session */
                        down(&tcon->ses->sesSem);
-                       if(tcon->ses->status == CifsNeedReconnect)
-                               rc = cifs_setup_session(0, tcon->ses, 
+                       if (tcon->ses->status == CifsNeedReconnect)
+                               rc = cifs_setup_session(0, tcon->ses,
                                                        nls_codepage);
-                       if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+                       if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
                                mark_open_files_invalid(tcon);
                                rc = CIFSTCon(0, tcon->ses, tcon->treeName,
                                              tcon, nls_codepage);
@@ -251,18 +349,26 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                                /* 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 - 
-                                  it is safer (and faster) to reopen files
+                               /* Removed call to reopen open files here.
+                                  It is safer (and faster) to reopen files
                                   one at a time as needed in read and write */
 
-                               /* Check if handle based operation so we 
+                               /* Check if handle based operation so we
                                   know whether we can continue or not without
                                   returning to caller to reset file handle */
-                               switch(smb_command) {
+                               switch (smb_command) {
                                        case SMB_COM_READ_ANDX:
                                        case SMB_COM_WRITE_ANDX:
                                        case SMB_COM_CLOSE:
@@ -281,7 +387,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                        return -EIO;
                }
        }
-       if(rc)
+       if (rc)
                return rc;
 
        *request_buf = cifs_buf_get();
@@ -293,47 +399,48 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
     /* potential retries of smb operations it turns out we can determine */
     /* from the mid flags when the request buffer can be resent without  */
     /* having to use a second distinct buffer for the response */
-       *response_buf = *request_buf; 
+       if (response_buf)
+               *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);
+       if (tcon != NULL)
+               cifs_stats_inc(&tcon->num_smbs_sent);
 
        return rc;
 }
 
-static int validate_t2(struct smb_t2_rsp * pSMB) 
+static int validate_t2(struct smb_t2_rsp *pSMB)
 {
        int rc = -EINVAL;
        int total_size;
-       char * pBCC;
+       char *pBCC;
 
        /* check for plausible wct, bcc and t2 data and parm sizes */
        /* check for parm and data offset going beyond end of smb */
-       if(pSMB->hdr.WordCount >= 10) {
-               if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
+       if (pSMB->hdr.WordCount >= 10) {
+               if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
                   (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
                        /* check that bcc is at least as big as parms + data */
                        /* 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);
+                       if (total_size < 512) {
+                               total_size +=
+                                       le16_to_cpu(pSMB->t2_rsp.DataCount);
                                /* BCC le converted in SendReceive */
-                               pBCC = (pSMB->hdr.WordCount * 2) + 
+                               pBCC = (pSMB->hdr.WordCount * 2) +
                                        sizeof(struct smb_hdr) +
                                        (char *)pSMB;
-                               if((total_size <= (*(u16 *)pBCC)) && 
-                                  (total_size < 
+                               if ((total_size <= (*(u16 *)pBCC)) &&
+                                  (total_size <
                                        CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
                                        return 0;
                                }
-                               
                        }
                }
        }
-       cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
+       cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
                sizeof(struct smb_t2_rsp) + 16);
        return rc;
 }
@@ -344,10 +451,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        NEGOTIATE_RSP *pSMBr;
        int rc = 0;
        int bytes_returned;
-       struct TCP_Server_Info * server;
+       int i;
+       struct TCP_Server_Info *server;
        u16 count;
+       unsigned int secFlags;
+       u16 dialect;
 
-       if(ses->server)
+       if (ses->server)
                server = ses->server;
        else {
                rc = -EIO;
@@ -357,100 +467,270 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                      (void **) &pSMB, (void **) &pSMBr);
        if (rc)
                return rc;
+
+       /* if any of auth flags (ie not sign or seal) are overriden use them */
+       if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
+               secFlags = ses->overrideSecFlg;  /* BB FIXME fix sign flags? */
+       else /* if override flags set only sign/seal OR them with global auth */
+               secFlags = extended_security | ses->overrideSecFlg;
+
+       cFYI(1, ("secFlags 0x%x", secFlags));
+
        pSMB->hdr.Mid = GetNextMid(server);
-       pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
-       if (extended_security)
-               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
+       pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
 
-       count = strlen(protocols[0].name) + 1;
-       strncpy(pSMB->DialectsArray, protocols[0].name, 30);    
-    /* null guaranteed to be at end of source and target buffers anyway */
+       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;
+       }
 
+       count = 0;
+       for (i = 0; i < CIFS_NUM_PROT; i++) {
+               strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
+               count += strlen(protocols[i].name) + 1;
+               /* null at end of source and target buffers anyway */
+       }
        pSMB->hdr.smb_buf_length += count;
        pSMB->ByteCount = cpu_to_le16(count);
 
        rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc == 0) {
-               server->secMode = pSMBr->SecurityMode;  
-               server->secType = NTLM; /* BB override default for 
-                                          NTLMv2 or kerberos v5 */
-               /* one byte - no need to convert this or EncryptionKeyLen
-                  from little endian */
-               server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
-               /* probably no need to store and check maxvcs */
-               server->maxBuf =
-                       min(le32_to_cpu(pSMBr->MaxBufferSize),
+       if (rc != 0)
+               goto neg_err_exit;
+
+       dialect = le16_to_cpu(pSMBr->DialectIndex);
+       cFYI(1, ("Dialect: %d", dialect));
+       /* Check wct = 1 error case */
+       if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
+               /* core returns wct = 1, but we do not ask for core - otherwise
+               small wct just comes when dialect index is -1 indicating we
+               could not negotiate a common dialect */
+               rc = -EOPNOTSUPP;
+               goto neg_err_exit;
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+       } else if ((pSMBr->hdr.WordCount == 13)
+                       && ((dialect == LANMAN_PROT)
+                               || (dialect == LANMAN2_PROT))) {
+               __s16 tmp;
+               struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
+
+               if ((secFlags & CIFSSEC_MAY_LANMAN) ||
+                       (secFlags & CIFSSEC_MAY_PLNTXT))
+                       server->secType = LANMAN;
+               else {
+                       cERROR(1, ("mount failed weak security disabled"
+                                  " in /proc/fs/cifs/SecurityFlags"));
+                       rc = -EOPNOTSUPP;
+                       goto neg_err_exit;
+               }
+               server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
+               server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
+               server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
+                               (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
+               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->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
+               } else {
+                       server->maxRw = 0;/* we do not need to use raw anyway */
+                       server->capabilities = CAP_MPX_MODE;
+               }
+               tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
+               if (tmp == -1) {
+                       /* OS/2 often does not set timezone therefore
+                        * we must use server time to calc time zone.
+                        * Could deviate slightly from the right zone.
+                        * Smallest defined timezone difference is 15 minutes
+                        * (i.e. Nepal).  Rounding up/down is done to match
+                        * this requirement.
+                        */
+                       int val, seconds, remain, result;
+                       struct timespec ts, utc;
+                       utc = CURRENT_TIME;
+                       ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
+                                               le16_to_cpu(rsp->SrvTime.Time));
+                       cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
+                               (int)ts.tv_sec, (int)utc.tv_sec,
+                               (int)(utc.tv_sec - ts.tv_sec)));
+                       val = (int)(utc.tv_sec - ts.tv_sec);
+                       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;
+                       server->timeAdj = result;
+               } else {
+                       server->timeAdj = (int)tmp;
+                       server->timeAdj *= 60; /* also in seconds */
+               }
+               cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
+
+
+               /* BB get server time for time conversions and add
+               code to use it and timezone since this is not UTC */
+
+               if (rsp->EncryptionKeyLength ==
+                               cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
+                       memcpy(server->cryptKey, rsp->EncryptionKey,
+                               CIFS_CRYPTO_KEY_SIZE);
+               } else if (server->secMode & SECMODE_PW_ENCRYPT) {
+                       rc = -EIO; /* need cryptkey unless plain text */
+                       goto neg_err_exit;
+               }
+
+               cFYI(1, ("LANMAN negotiated"));
+               /* we will not end up setting signing flags - as no signing
+               was in LANMAN and server did not return the flags on */
+               goto signing_check;
+#else /* weak security disabled */
+       } else if (pSMBr->hdr.WordCount == 13) {
+               cERROR(1, ("mount failed, cifs module not built "
+                         "with CIFS_WEAK_PW_HASH support"));
+                       rc = -EOPNOTSUPP;
+#endif /* WEAK_PW_HASH */
+               goto neg_err_exit;
+       } else if (pSMBr->hdr.WordCount != 17) {
+               /* unknown wct */
+               rc = -EOPNOTSUPP;
+               goto neg_err_exit;
+       }
+       /* else wct == 17 NTLM */
+       server->secMode = pSMBr->SecurityMode;
+       if ((server->secMode & SECMODE_USER) == 0)
+               cFYI(1, ("share mode security"));
+
+       if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+               if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
+#endif /* CIFS_WEAK_PW_HASH */
+                       cERROR(1, ("Server requests plain text password"
+                                 " but client support disabled"));
+
+       if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
+               server->secType = NTLMv2;
+       else if (secFlags & CIFSSEC_MAY_NTLM)
+               server->secType = NTLM;
+       else if (secFlags & CIFSSEC_MAY_NTLMV2)
+               server->secType = NTLMv2;
+       else if (secFlags & CIFSSEC_MAY_KRB5)
+               server->secType = Kerberos;
+       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 */
+       server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
+       /* 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));
-               GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
-               server->capabilities = le32_to_cpu(pSMBr->Capabilities);
-               server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
-        /* BB with UTC do we ever need to be using srvr timezone? */
-               if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
-                       memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
-                              CIFS_CRYPTO_KEY_SIZE);
-               } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
-                          && (pSMBr->EncryptionKeyLength == 0)) {
-                       /* decode security blob */
-               } else
+       server->maxRw = 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);
+       server->timeAdj *= 60;
+       if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+               memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
+                      CIFS_CRYPTO_KEY_SIZE);
+       } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
+                       && (pSMBr->EncryptionKeyLength == 0)) {
+               /* decode security blob */
+       } else if (server->secMode & SECMODE_PW_ENCRYPT) {
+               rc = -EIO; /* no crypt key only if plain text pwd */
+               goto neg_err_exit;
+       }
+
+       /* BB might be helpful to save off the domain of server here */
+
+       if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
+               (server->capabilities & CAP_EXTENDED_SECURITY)) {
+               count = pSMBr->ByteCount;
+               if (count < 16) {
                        rc = -EIO;
+                       goto neg_err_exit;
+               }
 
-               /* BB might be helpful to save off the domain of server here */
+               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
+                       memcpy(server->server_GUID,
+                              pSMBr->u.extended_response.GUID, 16);
 
-               if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
-                       (server->capabilities & CAP_EXTENDED_SECURITY)) {
-                       count = pSMBr->ByteCount;
-                       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,
-                                                    ("UID of server does not match previous connection to same ip address"));
-                                               memcpy(server->
-                                                       server_GUID,
-                                                       pSMBr->u.
-                                                       extended_response.
-                                                       GUID, 16);
-                                       }
-                               } else
-                                       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) {
+                               rc = 0;
                        } 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 {
-                                       rc = -EINVAL;
-                               }
+                               rc = -EINVAL;
                        }
-               } else
-                       server->capabilities &= ~CAP_EXTENDED_SECURITY;
-               if(sign_CIFS_PDUs == FALSE) {        
-                       if(server->secMode & SECMODE_SIGN_REQUIRED)
-                               cERROR(1,
-                                ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
-                       server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-               } else if(sign_CIFS_PDUs == 1) {
-                       if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
-                               server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
                }
-                               
+       } else
+               server->capabilities &= ~CAP_EXTENDED_SECURITY;
+
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+signing_check:
+#endif
+       if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
+               /* 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) {
+                       cERROR(1, ("Server requires "
+                                  "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) {
+               /* signing required */
+               cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
+               if ((server->secMode &
+                       (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
+                       cERROR(1,
+                               ("signing required but server lacks support"));
+                       rc = -EOPNOTSUPP;
+               } else
+                       server->secMode |= SECMODE_SIGN_REQUIRED;
+       } else {
+               /* signing optional ie CIFSSEC_MAY_SIGN */
+               if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
+                       server->secMode &=
+                               ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
        }
-       
+
+neg_err_exit:
        cifs_buf_release(pSMB);
+
+       cFYI(1, ("negprot rc %d", rc));
        return rc;
 }
 
@@ -458,16 +738,14 @@ 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 
+        *  (and inside session disconnect we should check if tcp socket needs
         *  to be freed and kernel thread woken up).
         */
        if (tcon)
@@ -481,35 +759,31 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
                return -EBUSY;
        }
 
-       /* No need to return error on this operation if tid invalidated and 
+       /* 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) {
+       if (tcon->tidStatus == CifsNeedReconnect) {
                up(&tcon->tconSem);
-               return 0;  
+               return 0;
        }
 
-       if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {    
+       if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
                up(&tcon->tconSem);
                return -EIO;
        }
-       rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 
+       rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
                            (void **)&smb_buffer);
        if (rc) {
                up(&tcon->tconSem);
                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 
+       /* No need to return error on this operation if tid invalidated and
        closed on server already e.g. due to tcp session crashing */
        if (rc == -EAGAIN)
                rc = 0;
@@ -520,10 +794,8 @@ 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)
@@ -542,12 +814,10 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
                return rc;
        }
 
-       smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
-       
-       if(ses->server) {
+       if (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;
        }
@@ -555,8 +825,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
        pSMB->hdr.Uid = ses->Suid;
 
        pSMB->AndXCommand = 0xFF;
-       rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
-                        smb_buffer_response, &length, 0);
+       rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
        if (ses->server) {
                atomic_dec(&ses->server->socketUseCount);
                if (atomic_read(&ses->server->socketUseCount) == 0) {
@@ -567,10 +836,9 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
                }
        }
        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 
+               since server closed smb session, no sense reporting
                error */
        if (rc == -EAGAIN)
                rc = 0;
@@ -578,6 +846,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)
 {
@@ -595,7 +938,7 @@ DelFileRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, 
+                   cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -612,9 +955,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)
@@ -624,7 +966,7 @@ DelFileRetry:
 }
 
 int
-CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, 
+CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
             const struct nls_table *nls_codepage, int remap)
 {
        DELETE_DIRECTORY_REQ *pSMB = NULL;
@@ -657,9 +999,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)
@@ -685,7 +1026,7 @@ MkDirRetry:
                return rc;
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-               name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, 
+               name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
                                            PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -701,9 +1042,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)
@@ -711,6 +1051,125 @@ MkDirRetry:
        return rc;
 }
 
+int
+CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
+               __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
+               __u32 *pOplock, const char *name,
+               const struct nls_table *nls_codepage, int remap)
+{
+       TRANSACTION2_SPI_REQ *pSMB = NULL;
+       TRANSACTION2_SPI_RSP *pSMBr = NULL;
+       int name_len;
+       int rc = 0;
+       int bytes_returned = 0;
+       __u16 params, param_offset, offset, byte_count, count;
+       OPEN_PSX_REQ *pdata;
+       OPEN_PSX_RSP *psx_rsp;
+
+       cFYI(1, ("In POSIX Create"));
+PsxCreat:
+       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, name,
+                                    PATH_MAX, nls_codepage, remap);
+               name_len++;     /* trailing null */
+               name_len *= 2;
+       } else {        /* BB improve the check for buffer overruns BB */
+               name_len = strnlen(name, PATH_MAX);
+               name_len++;     /* trailing null */
+               strncpy(pSMB->FileName, name, name_len);
+       }
+
+       params = 6 + name_len;
+       count = sizeof(OPEN_PSX_REQ);
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
+       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;
+       pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
+       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);
+       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 + count;
+
+       pSMB->DataCount = cpu_to_le16(count);
+       pSMB->ParameterCount = cpu_to_le16(params);
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
+       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 create returned %d", rc));
+               goto psx_create_err;
+       }
+
+       cFYI(1, ("copying inode info"));
+       rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+       if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
+               rc = -EIO;      /* bad smb */
+               goto psx_create_err;
+       }
+
+       /* copy return information to pRetData */
+       psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
+                       + le16_to_cpu(pSMBr->t2.DataOffset));
+
+       *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
+       if (netfid)
+               *netfid = psx_rsp->Fid;   /* cifs fid stays in le */
+       /* Let caller know file was created so we can set the mode. */
+       /* Do we care about the CreateAction in any other cases? */
+       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 != 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 = cpu_to_le32(-1);
+                       goto psx_create_err;
+               }
+               memcpy((char *) pRetData,
+                       (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
+                       sizeof(FILE_UNIX_BASIC_INFO));
+       }
+
+psx_create_err:
+       cifs_buf_release(pSMB);
+
+       cifs_stats_inc(&tcon->num_mkdirs);
+
+       if (rc == -EAGAIN)
+               goto PsxCreat;
+
+       return rc;
+}
+
 static __u16 convert_disposition(int disposition)
 {
        __u16 ofun = 0;
@@ -735,17 +1194,31 @@ static __u16 convert_disposition(int disposition)
                        ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
                        break;
                default:
-                       cFYI(1,("unknown disposition %d",disposition));
+                       cFYI(1, ("unknown disposition %d", disposition));
                        ofun =  SMBOPEN_OAPPEND; /* regular open */
        }
        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;
@@ -778,35 +1251,27 @@ 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
           no Unix extensions */
 
-        if(create_options & CREATE_OPTION_SPECIAL)
-                pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
-        else
-                pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
+       if (create_options & CREATE_OPTION_SPECIAL)
+               pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
+       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 & CREATE_OPTIONS_MASK); */
+/*     pSMB->CreateOptions = cpu_to_le32(create_options &
+                                                CREATE_OPTIONS_MASK); */
        /* BB FIXME END BB */
 
        pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
@@ -817,30 +1282,30 @@ 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. */
                /* Do we care about the CreateAction in any other cases? */
        /* BB FIXME BB */
-/*             if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
+/*             if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
                        *pOplock |= CIFS_CREATE_ACTION; */
        /* BB FIXME END */
 
-               if(pfile_info) {
+               if (pfile_info) {
                        pfile_info->CreationTime = 0; /* BB convert CreateTime*/
                        pfile_info->LastAccessTime = 0; /* BB fixme */
                        pfile_info->LastWriteTime = 0; /* BB fixme */
                        pfile_info->ChangeTime = 0;  /* BB fixme */
                        pfile_info->Attributes =
-                               cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); 
+                               cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
                        /* the file_info buf is endian converted by caller */
                        pfile_info->AllocationSize =
                                cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
@@ -858,8 +1323,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;
@@ -894,29 +1359,27 @@ 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
           as fifo and server expecting SFU style and
           no Unix extensions */
-       if(create_options & CREATE_OPTION_SPECIAL)
+       if (create_options & CREATE_OPTION_SPECIAL)
                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);
@@ -931,7 +1394,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));
@@ -940,10 +1403,10 @@ openRetry:
                *netfid = pSMBr->Fid;   /* cifs fid stays in le */
                /* Let caller know file was created so we can set the mode. */
                /* Do we care about the CreateAction in any other cases? */
-               if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
-                       *pOplock |= CIFS_CREATE_ACTION; 
-               if(pfile_info) {
-                   memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
+               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;
@@ -959,10 +1422,9 @@ openRetry:
 }
 
 int
-CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
-            const int netfid, const unsigned int count,
-            const __u64 lseek, unsigned int *nbytes, char **buf,
-           int * pbuf_type)
+CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
+           const unsigned int count, const __u64 lseek, unsigned int *nbytes,
+           char **buf, int *pbuf_type)
 {
        int rc = -EACCES;
        READ_REQ *pSMB = NULL;
@@ -972,8 +1434,8 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
        int resp_buf_type = 0;
        struct kvec iov[1];
 
-       cFYI(1,("Reading %d bytes on fid %d",count,netfid));
-       if(tcon->ses->capabilities & CAP_LARGE_FILES)
+       cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
+       if (tcon->ses->capabilities & CAP_LARGE_FILES)
                wct = 12;
        else
                wct = 10; /* old style read */
@@ -990,28 +1452,27 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
-       if(wct == 12)
+       if (wct == 12)
                pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
-       else if((lseek >> 32) > 0) /* can not handle this big offset for old */
+       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);
        pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
-       if(wct == 12)
+       if (wct == 12)
                pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
        else {
                /* old style read */
-               struct smb_com_readx_req * pSMBW =
+               struct smb_com_readx_req *pSMBW =
                        (struct smb_com_readx_req *)pSMB;
                pSMBW->ByteCount = 0;
        }
 
        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) {
@@ -1025,34 +1486,36 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
                /*check that DataLength would not go beyond end of SMB */
                if ((data_length > CIFSMaxBufSize)
                                || (data_length > count)) {
-                       cFYI(1,("bad length %d for count %d",data_length,count));
+                       cFYI(1, ("bad length %d for count %d",
+                                data_length, count));
                        rc = -EIO;
                        *nbytes = 0;
                } else {
                        pReadData = (char *) (&pSMBr->hdr.Protocol) +
-                           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*/
-                       if(*buf)
-                               memcpy(*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*/
+                       if (*buf)
+                               memcpy(*buf, pReadData, data_length);
                }
        }
 
-       cifs_small_buf_release(pSMB);
-       if(*buf) {
-               if(resp_buf_type == CIFS_SMALL_BUFFER)
+/*     cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
+       if (*buf) {
+               if (resp_buf_type == CIFS_SMALL_BUFFER)
                        cifs_small_buf_release(iov[0].iov_base);
-               else if(resp_buf_type == CIFS_LARGE_BUFFER)
+               else if (resp_buf_type == CIFS_LARGE_BUFFER)
                        cifs_buf_release(iov[0].iov_base);
-       } else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ {
+       } else if (resp_buf_type != CIFS_NO_BUFFER) {
+               /* return buffer to caller to free */
                *buf = iov[0].iov_base;
-               if(resp_buf_type == CIFS_SMALL_BUFFER)
+               if (resp_buf_type == CIFS_SMALL_BUFFER)
                        *pbuf_type = CIFS_SMALL_BUFFER;
-               else if(resp_buf_type == CIFS_LARGE_BUFFER)
+               else if (resp_buf_type == CIFS_LARGE_BUFFER)
                        *pbuf_type = CIFS_LARGE_BUFFER;
-       }
+       } /* else no valid buffer on return - leave as null */
 
        /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
@@ -1064,7 +1527,7 @@ int
 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
             const int netfid, const unsigned int count,
             const __u64 offset, unsigned int *nbytes, const char *buf,
-            const char __user * ubuf, const int long_op)
+            const char __user *ubuf, const int long_op)
 {
        int rc = -EACCES;
        WRITE_REQ *pSMB = NULL;
@@ -1074,10 +1537,10 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        __u16 byte_count;
 
        /* cFYI(1,("write at %lld %d bytes",offset,count));*/
-       if(tcon->ses == NULL)
+       if (tcon->ses == NULL)
                return -ECONNABORTED;
 
-       if(tcon->ses->capabilities & CAP_LARGE_FILES)
+       if (tcon->ses->capabilities & CAP_LARGE_FILES)
                wct = 14;
        else
                wct = 12;
@@ -1093,20 +1556,20 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
-       if(wct == 14) 
+       if (wct == 14)
                pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
-       else if((offset >> 32) > 0) /* can not handle this big offset for old */
+       else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
                return -EIO;
-       
+
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
        pSMB->Remaining = 0;
 
-       /* Can increase buffer size if buffer is big enough in some cases - ie we 
+       /* Can increase buffer size if buffer is big enough in some cases ie we
        can send more if LARGE_WRITE_X capability returned by the server and if
        our buffer is big enough or if we convert to iovecs on socket writes
        and eliminate the copy to the CIFS buffer */
-       if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
+       if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
                bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
        } else {
                bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
@@ -1116,11 +1579,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        if (bytes_sent > count)
                bytes_sent = count;
        pSMB->DataOffset =
-               cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
-       if(buf)
-           memcpy(pSMB->Data,buf,bytes_sent);
-       else if(ubuf) {
-               if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
+               cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
+       if (buf)
+           memcpy(pSMB->Data, buf, bytes_sent);
+       else if (ubuf) {
+               if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
                        cifs_buf_release(pSMB);
                        return -EFAULT;
                }
@@ -1129,19 +1592,20 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
                cifs_buf_release(pSMB);
                return -EINVAL;
        } /* else setting file size with write of zero bytes */
-       if(wct == 14)
+       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;
 
-       if(wct == 14)
+       if (wct == 14)
                pSMB->ByteCount = cpu_to_le16(byte_count);
-       else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
-               struct smb_com_writex_req * pSMBW = 
+       else { /* old style write has byte count 4 bytes earlier
+                 so 4 bytes pad  */
+               struct smb_com_writex_req *pSMBW =
                        (struct smb_com_writex_req *)pSMB;
                pSMBW->ByteCount = cpu_to_le16(byte_count);
        }
@@ -1160,7 +1624,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 
        cifs_buf_release(pSMB);
 
-       /* Note: On -EAGAIN error only caller can retry on handle based calls 
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
 
        return rc;
@@ -1178,9 +1642,9 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        int smb_hdr_len;
        int resp_buf_type = 0;
 
-       cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
+       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
                wct = 12;
@@ -1194,37 +1658,37 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
-       if(wct == 14)
+       if (wct == 14)
                pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
-       else if((offset >> 32) > 0) /* can not handle this big offset for old */
+       else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
                return -EIO;
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
        pSMB->Remaining = 0;
 
        pSMB->DataOffset =
-           cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
+           cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
 
        pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
        pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
        smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
-       if(wct == 14)
+       if (wct == 14)
                pSMB->hdr.smb_buf_length += count+1;
        else /* wct == 12 */
-               pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ 
-       if(wct == 14)
+               pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
+       if (wct == 14)
                pSMB->ByteCount = cpu_to_le16(count + 1);
        else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
-               struct smb_com_writex_req * pSMBW =
+               struct smb_com_writex_req *pSMBW =
                                (struct smb_com_writex_req *)pSMB;
                pSMBW->ByteCount = cpu_to_le16(count + 5);
        }
        iov[0].iov_base = pSMB;
-       if(wct == 14)
+       if (wct == 14)
                iov[0].iov_len = smb_hdr_len + 4;
        else /* wct == 12 pad bigger by four bytes */
                iov[0].iov_len = smb_hdr_len + 8;
-       
+
 
        rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
                          long_op);
@@ -1232,24 +1696,24 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        if (rc) {
                cFYI(1, ("Send error Write2 = %d", rc));
                *nbytes = 0;
-       } else if(resp_buf_type == 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);
-       } 
+       }
 
-       cifs_small_buf_release(pSMB);
-       if(resp_buf_type == CIFS_SMALL_BUFFER)
+/*     cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
+       if (resp_buf_type == CIFS_SMALL_BUFFER)
                cifs_small_buf_release(iov[0].iov_base);
-       else if(resp_buf_type == CIFS_LARGE_BUFFER)
+       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 
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
 
        return rc;
@@ -1260,28 +1724,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 */
+       if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
+               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;
@@ -1293,7 +1755,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = smb_file_id; /* netfid stays le */
 
-       if((numLock != 0) || (numUnlock != 0)) {
+       if ((numLock != 0) || (numUnlock != 0)) {
                pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
                /* BB where to store pid high? */
                pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
@@ -1308,54 +1770,181 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
        pSMB->hdr.smb_buf_length += count;
        pSMB->ByteCount = cpu_to_le16(count);
 
-       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
+       if (waitFlag) {
+               rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
+                       (struct smb_hdr *) pSMB, &bytes_returned);
+               cifs_small_buf_release(pSMB);
+       } else {
+               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 
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
        since file handle passed in no longer valid */
        return rc;
 }
 
 int
-CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
+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 bool waitFlag)
+{
+       struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+       struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+       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;
+
+       rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+       if (rc)
+               return rc;
+
+       pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
+
+       params = 6;
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Reserved2 = 0;
+       param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+       offset = param_offset + params;
+
+       count = sizeof(struct cifs_posix_lock);
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       if (get_flag)
+               pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+       else
+               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);
+       parm_data = (struct cifs_posix_lock *)
+                       (((char *) &pSMB->hdr.Protocol) + offset);
+
+       parm_data->lock_type = cpu_to_le16(lock_type);
+       if (waitFlag) {
+               timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
+               parm_data->lock_flags = cpu_to_le16(1);
+               pSMB->Timeout = cpu_to_le32(-1);
+       } else
+               pSMB->Timeout = 0;
+
+       parm_data->pid = cpu_to_le32(current->tgid);
+       parm_data->start = cpu_to_le64(pLockData->fl_start);
+       parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
+
+       pSMB->DataOffset = cpu_to_le16(offset);
+       pSMB->Fid = smb_file_id;
+       pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
+       pSMB->Reserved4 = 0;
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->ByteCount = cpu_to_le16(byte_count);
+       if (waitFlag) {
+               rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
+                       (struct smb_hdr *) pSMBr, &bytes_returned);
+       } else {
+               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) {
+               cFYI(1, ("Send error in Posix Lock = %d", rc));
+       } else if (get_flag) {
+               /* lock structure can be returned on get */
+               __u16 data_offset;
+               __u16 data_count;
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+               if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
+                       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)) {
+                       rc = -EIO;
+                       goto plk_err_exit;
+               }
+               parm_data = (struct cifs_posix_lock *)
+                       ((char *)&pSMBr->hdr.Protocol + data_offset);
+               if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
+                       pLockData->fl_type = F_UNLCK;
+       }
+
+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 */
+
+       return rc;
+}
+
+
+int
+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 */
        rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
-       if(rc == -EAGAIN)
+       if (rc == -EAGAIN)
                return 0;
        if (rc)
                return rc;
 
-       pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
-
        pSMB->FileID = (__u16) smb_file_id;
-       pSMB->LastWriteTime = 0;
+       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) {
+               if (rc != -EINTR) {
                        /* EINTR is expected when user ctl-c to kill app */
                        cERROR(1, ("Send error in Close = %d", rc));
                }
        }
 
-       cifs_small_buf_release(pSMB);
-
        /* Since session is dead, file will be closed on server already */
-       if(rc == -EAGAIN)
+       if (rc == -EAGAIN)
                rc = 0;
 
        return rc;
@@ -1387,7 +1976,7 @@ renameRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, 
+                   cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -1395,11 +1984,11 @@ 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 */
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fromName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->OldFileName, fromName, name_len);
@@ -1418,9 +2007,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);
 
@@ -1430,13 +2018,13 @@ renameRetry:
        return rc;
 }
 
-int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
-               int netfid, char * target_name, 
-               const struct nls_table * nls_codepage, int remap)
+int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
+               int netfid, char *target_name,
+               const struct nls_table *nls_codepage, int remap)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
-       struct set_file_rename * rename_info;
+       struct set_file_rename *rename_info;
        char *data_offset;
        char dummy_string[30];
        int rc = 0;
@@ -1462,7 +2050,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);
@@ -1475,13 +2063,14 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
        rename_info->overwrite = cpu_to_le32(1);
        rename_info->root_fid  = 0;
        /* unicode only call */
-       if(target_name == NULL) {
-               sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
-               len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
+       if (target_name == NULL) {
+               sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
+               len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
                                        dummy_string, 24, nls_codepage, remap);
        } else {
                len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
-                                       target_name, PATH_MAX, nls_codepage, remap);
+                                       target_name, PATH_MAX, nls_codepage,
+                                       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;
@@ -1495,11 +2084,10 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
        pSMB->hdr.smb_buf_length += byte_count;
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
-                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&pTcon->num_t2renames);
-       if (rc) {
-               cFYI(1,("Send error in Rename (by file handle) = %d", rc));
-       }
+       if (rc)
+               cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
 
        cifs_buf_release(pSMB);
 
@@ -1510,9 +2098,9 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
 }
 
 int
-CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
-            const __u16 target_tid, const char *toName, const int flags,
-            const struct nls_table *nls_codepage, int remap)
+CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
+           const __u16 target_tid, const char *toName, const int flags,
+           const struct nls_table *nls_codepage, int remap)
 {
        int rc = 0;
        COPY_REQ *pSMB = NULL;
@@ -1534,7 +2122,7 @@ copyRetry:
        pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-               name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, 
+               name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
                                            fromName, PATH_MAX, nls_codepage,
                                            remap);
                name_len++;     /* trailing null */
@@ -1542,11 +2130,12 @@ copyRetry:
                pSMB->OldFileName[name_len] = 0x04;     /* pad */
                /* protocol requires ASCII signature byte on Unicode string */
                pSMB->OldFileName[name_len + 1] = 0x00;
-               name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
+               name_len2 =
+                   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 */
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fromName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->OldFileName, fromName, name_len);
@@ -1568,8 +2157,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;
@@ -1606,7 +2194,7 @@ createSymLinkRetry:
                name_len++;     /* trailing null */
                name_len *= 2;
 
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fromName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, fromName, name_len);
@@ -1618,7 +2206,7 @@ createSymLinkRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
 
        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
@@ -1629,7 +2217,7 @@ createSymLinkRetry:
                                  , nls_codepage);
                name_len_target++;      /* trailing null */
                name_len_target *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len_target = strnlen(toName, PATH_MAX);
                name_len_target++;      /* trailing null */
                strncpy(data_offset, toName, name_len_target);
@@ -1655,14 +2243,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;
@@ -1697,7 +2281,7 @@ createHardLinkRetry:
                name_len++;     /* trailing null */
                name_len *= 2;
 
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(toName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, toName, name_len);
@@ -1709,7 +2293,7 @@ createHardLinkRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
 
        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
@@ -1719,7 +2303,7 @@ createHardLinkRetry:
                                     nls_codepage, remap);
                name_len_target++;      /* trailing null */
                name_len_target *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len_target = strnlen(fromName, PATH_MAX);
                name_len_target++;      /* trailing null */
                strncpy(data_offset, fromName, name_len_target);
@@ -1745,9 +2329,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)
@@ -1791,13 +2374,13 @@ winCreateHardLinkRetry:
                name_len++;     /* trailing null */
                name_len *= 2;
                pSMB->OldFileName[name_len] = 0;        /* pad */
-               pSMB->OldFileName[name_len + 1] = 0x04; 
+               pSMB->OldFileName[name_len + 1] = 0x04;
                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 */
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fromName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->OldFileName, fromName, name_len);
@@ -1816,9 +2399,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;
@@ -1850,12 +2433,11 @@ querySymLinkRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
-                                 /* find define for this maxpathcomponent */
-                                 , nls_codepage);
+                   cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
+                                 PATH_MAX, nls_codepage);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } 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);
@@ -1872,7 +2454,7 @@ querySymLinkRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+       struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -1903,16 +2485,16 @@ querySymLinkRetry:
 
                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
                                name_len = UniStrnlen((wchar_t *) ((char *)
-                                       &pSMBr->hdr.Protocol +data_offset),
-                                       min_t(const int, buflen,count) / 2);
+                                       &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),
+                                       (__le16 *) ((char *)&pSMBr->hdr.Protocol
+                                                       + data_offset),
                                        name_len, nls_codepage);
                        } else {
                                strncpy(symlinkinfo,
-                                       (char *) &pSMBr->hdr.Protocol + 
+                                       (char *) &pSMBr->hdr.Protocol +
                                                data_offset,
                                        min_t(const int, buflen, count));
                        }
@@ -1926,17 +2508,108 @@ 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
+   buffer size), which is the case so far, it easily fits. NB:
+       Setup words themselves and ByteCount
+       MaxSetupCount (size of returned setup area) and
+       MaxParameterCount (returned parms size) must be set by caller */
+static int
+smb_init_nttransact(const __u16 sub_command, const int setup_count,
+                  const int parm_len, struct cifsTconInfo *tcon,
+                  void **ret_buf)
+{
+       int rc;
+       __u32 temp_offset;
+       struct smb_com_ntransact_req *pSMB;
+
+       rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
+                               (void **)&pSMB);
+       if (rc)
+               return rc;
+       *ret_buf = (void *)pSMB;
+       pSMB->Reserved = 0;
+       pSMB->TotalParameterCount = cpu_to_le32(parm_len);
+       pSMB->TotalDataCount  = 0;
+       pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
+                                         MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+       pSMB->ParameterCount = pSMB->TotalParameterCount;
+       pSMB->DataCount  = pSMB->TotalDataCount;
+       temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
+                       (setup_count * 2) - 4 /* for rfc1001 length itself */;
+       pSMB->ParameterOffset = cpu_to_le32(temp_offset);
+       pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
+       pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
+       pSMB->SubCommand = cpu_to_le16(sub_command);
+       return 0;
+}
+
+static int
+validate_ntransact(char *buf, char **ppparm, char **ppdata,
+                  __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;
+
+       pSMBr = (struct smb_com_ntransact_rsp *)buf;
+
+       /* ByteCount was converted from little endian in SendReceive */
+       end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
+                       (char *)&pSMBr->ByteCount;
+
+       data_offset = le32_to_cpu(pSMBr->DataOffset);
+       data_count = le32_to_cpu(pSMBr->DataCount);
+       parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
+       parm_count = le32_to_cpu(pSMBr->ParameterCount);
+
+       *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
+       *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
+
+       /* should we also check that parm and data areas do not overlap? */
+       if (*ppparm > end_of_smb) {
+               cFYI(1, ("parms start after end of smb"));
+               return -EINVAL;
+       } else if (parm_count + *ppparm > end_of_smb) {
+               cFYI(1, ("parm end after end of smb"));
+               return -EINVAL;
+       } else if (*ppdata > end_of_smb) {
+               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",
+                       *ppdata, data_count, (data_count + *ppdata),
+                       end_of_smb, pSMBr));
+               return -EINVAL;
+       } else if (parm_count + data_count > pSMBr->ByteCount) {
+               cFYI(1, ("parm count and data count larger than SMB"));
+               return -EINVAL;
+       }
+       *pdatalen = data_count;
+       *pparmlen = parm_count;
+       return 0;
+}
+#endif /* CIFS_EXPERIMENTAL */
+
 int
 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
                        const unsigned char *searchName,
-                       char *symlinkinfo, const int buflen,__u16 fid,
+                       char *symlinkinfo, const int buflen, __u16 fid,
                        const struct nls_table *nls_codepage)
 {
        int rc = 0;
        int bytes_returned;
        int name_len;
-       struct smb_com_transaction_ioctl_req * pSMB;
-       struct smb_com_transaction_ioctl_rsp * pSMBr;
+       struct smb_com_transaction_ioctl_req *pSMB;
+       struct smb_com_transaction_ioctl_rsp *pSMBr;
 
        cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
        rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
@@ -1948,7 +2621,8 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le32(2);
        /* BB find exact data count max from sess structure BB */
-       pSMB->MaxDataCount = cpu_to_le32(4000);
+       pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
+                                         MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
        pSMB->MaxSetupCount = 4;
        pSMB->Reserved = 0;
        pSMB->ParameterOffset = 0;
@@ -1974,45 +2648,53 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
                /* BB also check enough total bytes returned */
                        rc = -EIO;      /* bad smb */
                else {
-                       if(data_count && (data_count < 2048)) {
-                               char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
-
-                               struct reparse_data * reparse_buf = (struct reparse_data *)
-                                       ((char *)&pSMBr->hdr.Protocol + data_offset);
-                               if((char*)reparse_buf >= end_of_smb) {
+                       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 *)
+                                               ((char *)&pSMBr->hdr.Protocol
+                                                                + data_offset);
+                               if ((char *)reparse_buf >= end_of_smb) {
                                        rc = -EIO;
                                        goto qreparse_out;
                                }
-                               if((reparse_buf->LinkNamesBuf + 
+                               if ((reparse_buf->LinkNamesBuf +
                                        reparse_buf->TargetNameOffset +
                                        reparse_buf->TargetNameLen) >
                                                end_of_smb) {
-                                       cFYI(1,("reparse buf extended beyond SMB"));
+                                       cFYI(1, ("reparse buf beyond SMB"));
                                        rc = -EIO;
                                        goto qreparse_out;
                                }
-                               
+
                                if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
                                        name_len = UniStrnlen((wchar_t *)
-                                                       (reparse_buf->LinkNamesBuf + 
-                                                       reparse_buf->TargetNameOffset),
-                                                       min(buflen/2, reparse_buf->TargetNameLen / 2)); 
+                                               (reparse_buf->LinkNamesBuf +
+                                               reparse_buf->TargetNameOffset),
+                                               min(buflen/2,
+                                               reparse_buf->TargetNameLen / 2));
                                        cifs_strfromUCS_le(symlinkinfo,
-                                               (__le16 *) (reparse_buf->LinkNamesBuf + 
+                                               (__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));
+                                       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"));
+                               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));
+                       cFYI(1, ("readlink result - %s", symlinkinfo));
                }
        }
 qreparse_out:
@@ -2027,7 +2709,8 @@ qreparse_out:
 #ifdef CONFIG_CIFS_POSIX
 
 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
-static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
+static void cifs_convert_ace(posix_acl_xattr_entry *ace,
+                            struct cifs_posix_ace *cifs_ace)
 {
        /* u8 cifs fields do not need le conversion */
        ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
@@ -2039,30 +2722,31 @@ static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace
 }
 
 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
-static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
-                               const int acl_type,const int size_of_data_area)
+static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
+                              const int acl_type, const int size_of_data_area)
 {
        int size =  0;
        int i;
        __u16 count;
-       struct cifs_posix_ace * pACE;
-       struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
-       posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
+       struct cifs_posix_ace *pACE;
+       struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
+       posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
 
        if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
                return -EOPNOTSUPP;
 
-       if(acl_type & ACL_TYPE_ACCESS) {
+       if (acl_type & ACL_TYPE_ACCESS) {
                count = le16_to_cpu(cifs_acl->access_entry_count);
                pACE = &cifs_acl->ace_array[0];
                size = sizeof(struct cifs_posix_acl);
                size += sizeof(struct cifs_posix_ace) * count;
                /* check if we would go beyond end of SMB */
-               if(size_of_data_area < size) {
-                       cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
+               if (size_of_data_area < size) {
+                       cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
+                               size_of_data_area, size));
                        return -EINVAL;
                }
-       } else if(acl_type & ACL_TYPE_DEFAULT) {
+       } else if (acl_type & ACL_TYPE_DEFAULT) {
                count = le16_to_cpu(cifs_acl->access_entry_count);
                size = sizeof(struct cifs_posix_acl);
                size += sizeof(struct cifs_posix_ace) * count;
@@ -2071,7 +2755,7 @@ static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
                count = le16_to_cpu(cifs_acl->default_entry_count);
                size += sizeof(struct cifs_posix_ace) * count;
                /* check if we would go beyond end of SMB */
-               if(size_of_data_area < size)
+               if (size_of_data_area < size)
                        return -EINVAL;
        } else {
                /* illegal type */
@@ -2079,76 +2763,77 @@ static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
        }
 
        size = posix_acl_xattr_size(count);
-       if((buflen == 0) || (local_acl == NULL)) {
-               /* used to query ACL EA size */                         
-       } else if(size > buflen) {
+       if ((buflen == 0) || (local_acl == NULL)) {
+               /* used to query ACL EA size */
+       } else if (size > buflen) {
                return -ERANGE;
        } else /* buffer big enough */ {
                local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
-               for(i = 0;i < count ;i++) {
-                       cifs_convert_ace(&local_acl->a_entries[i],pACE);
-                       pACE ++;
+               for (i = 0; i < count ; i++) {
+                       cifs_convert_ace(&local_acl->a_entries[i], pACE);
+                       pACE++;
                }
        }
        return size;
 }
 
-static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
-                       const posix_acl_xattr_entry * local_ace)
+static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
+                                    const posix_acl_xattr_entry *local_ace)
 {
        __u16 rc = 0; /* 0 = ACL converted ok */
 
        cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
        cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
        /* BB is there a better way to handle the large uid? */
-       if(local_ace->e_id == cpu_to_le32(-1)) {
+       if (local_ace->e_id == cpu_to_le32(-1)) {
        /* Probably no need to le convert -1 on any arch but can not hurt */
                cifs_ace->cifs_uid = cpu_to_le64(-1);
-       } else 
+       } else
                cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
-        /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
+       /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
        return rc;
 }
 
 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
-static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
-               const int acl_type)
+static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
+                              const int buflen, const int acl_type)
 {
        __u16 rc = 0;
-        struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
-        posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
+       struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
+       posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
        int count;
        int i;
 
-       if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
+       if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
                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",
+       if (le32_to_cpu(local_acl->a_version) != 2) {
+               cFYI(1, ("unknown POSIX ACL version %d",
                     le32_to_cpu(local_acl->a_version)));
                return 0;
        }
        cifs_acl->version = cpu_to_le16(1);
-       if(acl_type == ACL_TYPE_ACCESS) 
+       if (acl_type == ACL_TYPE_ACCESS)
                cifs_acl->access_entry_count = cpu_to_le16(count);
-       else if(acl_type == ACL_TYPE_DEFAULT)
+       else if (acl_type == ACL_TYPE_DEFAULT)
                cifs_acl->default_entry_count = cpu_to_le16(count);
        else {
-               cFYI(1,("unknown ACL type %d",acl_type));
+               cFYI(1, ("unknown ACL type %d", acl_type));
                return 0;
        }
-       for(i=0;i<count;i++) {
+       for (i = 0; i < count; i++) {
                rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
                                        &local_acl->a_entries[i]);
-               if(rc != 0) {
+               if (rc != 0) {
                        /* ACE not converted */
                        break;
                }
        }
-       if(rc == 0) {
+       if (rc == 0) {
                rc = (__u16)(count * sizeof(struct cifs_posix_ace));
                rc += sizeof(struct cifs_posix_acl);
                /* BB add check to make sure ACL does not overflow SMB */
@@ -2158,9 +2843,9 @@ static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int bufl
 
 int
 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
-                        const unsigned char *searchName,
-                        char *acl_inf, const int buflen, const int acl_type,
-                        const struct nls_table *nls_codepage, int remap)
+                  const unsigned char *searchName,
+                  char *acl_inf, const int buflen, const int acl_type,
+                  const struct nls_table *nls_codepage, int remap)
 {
 /* SMB_QUERY_POSIX_ACL */
        TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -2169,7 +2854,7 @@ CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
        int bytes_returned;
        int name_len;
        __u16 params, byte_count;
-                                                                                                                                             
+
        cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
 
 queryAclRetry:
@@ -2177,16 +2862,16 @@ queryAclRetry:
                (void **) &pSMBr);
        if (rc)
                return rc;
-                                                                                                                                             
+
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                       cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+                       cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
                                         PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
                pSMB->FileName[name_len] = 0;
                pSMB->FileName[name_len+1] = 0;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } 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);
@@ -2195,7 +2880,7 @@ queryAclRetry:
        params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-        /* BB find exact max data count below from sess structure BB */
+       /* BB find exact max data count below from sess structure BB */
        pSMB->MaxDataCount = cpu_to_le16(4000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
@@ -2203,7 +2888,8 @@ queryAclRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(
-               offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+               offsetof(struct smb_com_transaction2_qpi_req,
+                        InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -2219,11 +2905,12 @@ queryAclRetry:
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&tcon->num_acl_get);
        if (rc) {
                cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
        } else {
                /* decode response */
+
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
                if (rc || (pSMBr->ByteCount < 2))
                /* BB also check enough total bytes returned */
@@ -2233,7 +2920,7 @@ queryAclRetry:
                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
                        rc = cifs_copy_posix_acl(acl_inf,
                                (char *)&pSMBr->hdr.Protocol+data_offset,
-                               buflen,acl_type,count);
+                               buflen, acl_type, count);
                }
        }
        cifs_buf_release(pSMB);
@@ -2244,10 +2931,10 @@ queryAclRetry:
 
 int
 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
-                        const unsigned char *fileName,
-                        const char *local_acl, const int buflen, 
-                       const int acl_type,
-                        const struct nls_table *nls_codepage, int remap)
+                  const unsigned char *fileName,
+                  const char *local_acl, const int buflen,
+                  const int acl_type,
+                  const struct nls_table *nls_codepage, int remap)
 {
        struct smb_com_transaction2_spi_req *pSMB = NULL;
        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -2260,38 +2947,39 @@ CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
        cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
 setAclRetry:
        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-                      (void **) &pSMBr);
+                     (void **) &pSMBr);
        if (rc)
                return rc;
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                       cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
+                       cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
                                      PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                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 = 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;
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
        parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
        pSMB->ParameterOffset = cpu_to_le16(param_offset);
 
        /* convert to on the wire format for POSIX ACL */
-       data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
+       data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
 
-       if(data_count == 0) {
+       if (data_count == 0) {
                rc = -EOPNOTSUPP;
                goto setACLerrorExit;
        }
@@ -2309,10 +2997,9 @@ setAclRetry:
        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) {
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc)
                cFYI(1, ("Set POSIX ACL returned %d", rc));
-       }
 
 setACLerrorExit:
        cifs_buf_release(pSMB);
@@ -2324,130 +3011,300 @@ 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;
-        struct smb_t2_qfi_rsp *pSMBr = NULL;
-        int bytes_returned;
-        __u16 params, byte_count;
+       int rc = 0;
+       struct smb_t2_qfi_req *pSMB = NULL;
+       struct smb_t2_qfi_rsp *pSMBr = NULL;
+       int bytes_returned;
+       __u16 params, byte_count;
 
-        cFYI(1,("In GetExtAttr"));
-        if(tcon == NULL)
-                return -ENODEV;
+       cFYI(1, ("In GetExtAttr"));
+       if (tcon == NULL)
+               return -ENODEV;
 
 GetExtAttrRetry:
-        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-                      (void **) &pSMBr);
-        if (rc)
-                return rc;
-
-        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 */
-        pSMB->t2.MaxDataCount = cpu_to_le16(4000);
-        pSMB->t2.MaxSetupCount = 0;
-        pSMB->t2.Reserved = 0;
-        pSMB->t2.Flags = 0;
-        pSMB->t2.Timeout = 0;
-        pSMB->t2.Reserved2 = 0;
-        pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
-                       Fid) - 4);
-        pSMB->t2.DataCount = 0;
-        pSMB->t2.DataOffset = 0;
-        pSMB->t2.SetupCount = 1;
-        pSMB->t2.Reserved3 = 0;
-        pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
-        byte_count = params + 1 /* pad */ ;
-        pSMB->t2.TotalParameterCount = cpu_to_le16(params);
-        pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
-        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
-        pSMB->Pad = 0;
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                       (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       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 */
+       pSMB->t2.MaxDataCount = cpu_to_le16(4000);
+       pSMB->t2.MaxSetupCount = 0;
+       pSMB->t2.Reserved = 0;
+       pSMB->t2.Flags = 0;
+       pSMB->t2.Timeout = 0;
+       pSMB->t2.Reserved2 = 0;
+       pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
+                                              Fid) - 4);
+       pSMB->t2.DataCount = 0;
+       pSMB->t2.DataOffset = 0;
+       pSMB->t2.SetupCount = 1;
+       pSMB->t2.Reserved3 = 0;
+       pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+       byte_count = params + 1 /* pad */ ;
+       pSMB->t2.TotalParameterCount = cpu_to_le16(params);
+       pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
+       pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
+       pSMB->Pad = 0;
        pSMB->Fid = netfid;
-        pSMB->hdr.smb_buf_length += byte_count;
-        pSMB->t2.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, ("error %d in GetExtAttr", rc));
-        } else {
-                /* decode response */
-                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-                if (rc || (pSMBr->ByteCount < 2))
-                /* BB also check enough total bytes returned */
-                        /* If rc should we check for EOPNOSUPP and
-                        disable the srvino flag? or in caller? */
-                        rc = -EIO;      /* bad smb */
-                else {
-                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
-                        struct file_chattr_info * pfinfo;
-                        /* BB Do we need a cast or hash here ? */
-                        if(count != 16) {
-                                cFYI(1, ("Illegal size ret in GetExtAttr"));
-                                rc = -EIO;
-                                goto GetExtAttrOut;
-                        }
-                        pfinfo = (struct file_chattr_info *)
-                                (data_offset + (char *) &pSMBr->hdr.Protocol);
-                        *pExtAttrBits = le64_to_cpu(pfinfo->mode);
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->t2.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, ("error %d in GetExtAttr", rc));
+       } else {
+               /* decode response */
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+               if (rc || (pSMBr->ByteCount < 2))
+               /* BB also check enough total bytes returned */
+                       /* If rc should we check for EOPNOSUPP and
+                          disable the srvino flag? or in caller? */
+                       rc = -EIO;      /* bad smb */
+               else {
+                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+                       __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+                       struct file_chattr_info *pfinfo;
+                       /* BB Do we need a cast or hash here ? */
+                       if (count != 16) {
+                               cFYI(1, ("Illegal size ret in GetExtAttr"));
+                               rc = -EIO;
+                               goto GetExtAttrOut;
+                       }
+                       pfinfo = (struct file_chattr_info *)
+                                (data_offset + (char *) &pSMBr->hdr.Protocol);
+                       *pExtAttrBits = le64_to_cpu(pfinfo->mode);
                        *pMask = le64_to_cpu(pfinfo->mask);
-                }
-        }
+               }
+       }
 GetExtAttrOut:
-        cifs_buf_release(pSMB);
-        if (rc == -EAGAIN)
-                goto GetExtAttrRetry;
-        return rc;
+       cifs_buf_release(pSMB);
+       if (rc == -EAGAIN)
+               goto GetExtAttrRetry;
+       return rc;
 }
 
+#endif /* CONFIG_POSIX */
+
+#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,
+                 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
+{
+       int rc = 0;
+       int buf_type = 0;
+       QUERY_SEC_DESC_REQ *pSMB;
+       struct kvec iov[1];
+
+       cFYI(1, ("GetCifsACL"));
+
+       *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;
+
+       pSMB->MaxParameterCount = cpu_to_le32(4);
+       /* BB TEST with big acls that might need to be e.g. larger than 16K */
+       pSMB->MaxSetupCount = 0;
+       pSMB->Fid = fid; /* file handle always le */
+       pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
+                                    CIFS_ACL_DACL);
+       pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
+       pSMB->hdr.smb_buf_length += 11;
+       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,
+                        CIFS_STD_OP);
+       cifs_stats_inc(&tcon->num_acl_get);
+       if (rc) {
+               cFYI(1, ("Send error in QuerySecDesc = %d", rc));
+       } else {                /* decode response */
+               __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,
+                                       &pdata, &parm_len, pbuflen);
+               if (rc)
+                       goto qsec_out;
+               pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
+
+               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(*parm);
+               if (acl_len != *pbuflen) {
+                       cERROR(1, ("acl length %d does not match %d",
+                                  acl_len, *pbuflen));
+                       if (*pbuflen > acl_len)
+                               *pbuflen = 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)
+               cifs_small_buf_release(iov[0].iov_base);
+       else if (buf_type == CIFS_LARGE_BUFFER)
+               cifs_buf_release(iov[0].iov_base);
+/*     cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
+       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;
 
-#endif /* CONFIG_POSIX */
+       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,
-                 const unsigned char *searchName,
-                 FILE_ALL_INFO * pFinfo,
-                 const struct nls_table *nls_codepage, int remap)
+                       const unsigned char *searchName,
+                       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;
 
-       cFYI(1, ("In SMBQPath path %s", searchName)); 
+       cFYI(1, ("In SMBQPath path %s", searchName));
 QInfRetry:
        rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
-                      (void **) &pSMBr);
+                     (void **) &pSMBr);
        if (rc)
                return rc;
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
-                                     PATH_MAX, nls_codepage, remap);
+                       cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+                                       PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {               
+       } else {
                name_len = strnlen(searchName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, searchName, name_len);
        }
        pSMB->BufferFormat = 0x04;
-       name_len++; /* account for buffer type byte */  
+       name_len++; /* account for buffer type byte */
        pSMB->hdr.smb_buf_length += (__u16) name_len;
        pSMB->ByteCount = cpu_to_le16(name_len);
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+                        (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;
+               ts.tv_sec = time;
+               /* decode time fields */
+               pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
+               pFinfo->LastWriteTime = pFinfo->ChangeTime;
+               pFinfo->LastAccessTime = 0;
                pFinfo->AllocationSize =
                        cpu_to_le64(le32_to_cpu(pSMBr->size));
                pFinfo->EndOfFile = pFinfo->AllocationSize;
@@ -2470,7 +3327,8 @@ 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)
 {
 /* level 263 SMB_QUERY_FILE_ALL_INFO */
@@ -2490,27 +3348,28 @@ QPathInfoRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } 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 = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+       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;
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+       struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -2519,7 +3378,10 @@ QPathInfoRetry:
        byte_count = params + 1 /* pad */ ;
        pSMB->TotalParameterCount = cpu_to_le16(params);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
-       pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
+       if (legacy)
+               pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
+       else
+               pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
        pSMB->Reserved4 = 0;
        pSMB->hdr.smb_buf_length += byte_count;
        pSMB->ByteCount = cpu_to_le16(byte_count);
@@ -2531,13 +3393,28 @@ QPathInfoRetry:
        } else {                /* decode response */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-               if (rc || (pSMBr->ByteCount < 40)) 
+               if (rc) /* BB add auto retry on EOPNOTSUPP? */
+                       rc = -EIO;
+               else if (!legacy && (pSMBr->ByteCount < 40))
                        rc = -EIO;      /* bad smb */
-               else if (pFindData){
+               else if (legacy && (pSMBr->ByteCount < 24))
+                       rc = -EIO;  /* 24 or 26 expected but we do not read
+                                       last field */
+               else if (pFindData) {
+                       int size;
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+
+                       /* 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);
                        memcpy((char *) pFindData,
                               (char *) &pSMBr->hdr.Protocol +
-                              data_offset, sizeof (FILE_ALL_INFO));
+                              data_offset, size);
                } else
                    rc = -ENOMEM;
        }
@@ -2551,7 +3428,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 */
@@ -2575,24 +3452,24 @@ UnixQPathInfoRetry:
                                  PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } 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 = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+       params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
        /* BB find exact max SMB PDU from sess structure BB */
-       pSMB->MaxDataCount = cpu_to_le16(4000); 
+       pSMB->MaxDataCount = cpu_to_le16(4000);
        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_qpi_req ,InformationLevel) - 4);
+       struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -2614,13 +3491,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);
@@ -2630,104 +3510,24 @@ 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
-                                 /* find define for this maxpathcomponent */
-                                 , 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,
-             const char *searchName, 
+             const char *searchName,
              const struct nls_table *nls_codepage,
-             __u16 *   pnetfid,
-             struct cifs_search_info * psrch_inf, int remap, const char dirsep)
+             __u16 *pnetfid,
+             struct cifs_search_info *psrch_inf, int remap, const char dirsep)
 {
 /* 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;
        __u16 params, byte_count;
 
-       cFYI(1, ("In FindFirst for %s",searchName));
+       cFYI(1, ("In FindFirst for %s", searchName));
 
 findFirstRetry:
        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
@@ -2737,7 +3537,7 @@ findFirstRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
                                 PATH_MAX, nls_codepage, remap);
                /* We can not add the asterik earlier in case
                it got remapped to 0xF03A as if it were part of the
@@ -2754,7 +3554,7 @@ findFirstRetry:
        } else {        /* BB add check for overrun of SMB buf BB */
                name_len = strnlen(searchName, PATH_MAX);
 /* BB fix here and in unicode clause above ie
-               if(name_len > buffersize-header)
+               if (name_len > buffersize-header)
                        free buffer exit; BB */
                strncpy(pSMB->FileName, searchName, name_len);
                pSMB->FileName[name_len] = dirsep;
@@ -2777,7 +3577,8 @@ findFirstRetry:
        pSMB->TotalParameterCount = cpu_to_le16(params);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
        pSMB->ParameterOffset = cpu_to_le16(
-         offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
+             offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
+               - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
@@ -2786,8 +3587,8 @@ findFirstRetry:
        pSMB->SearchAttributes =
            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
                        ATTR_DIRECTORY);
-       pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
-       pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
+       pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
+       pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
                CIFS_SEARCH_RETURN_RESUME);
        pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
 
@@ -2800,12 +3601,12 @@ findFirstRetry:
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&tcon->num_ffirst);
 
-       if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
+       if (rc) {/* BB add logic to retry regular search if Unix search
+                       rejected unexpectedly by server */
                /* BB Add code to handle unsupported level rc */
                cFYI(1, ("Error in FindFirst = %d", rc));
 
-               if (pSMB)
-                       cifs_buf_release(pSMB);
+               cifs_buf_release(pSMB);
 
                /* BB eventually could optimize out free and realloc of buf */
                /*    for this case */
@@ -2814,26 +3615,28 @@ findFirstRetry:
        } else { /* decode response */
                /* BB remember to free buffer if error BB */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-               if(rc == 0) {
+               if (rc == 0) {
                        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->srch_entries_start = 
-                               (char *) &pSMBr->hdr.Protocol + 
+                       psrch_inf->smallBuf = 0;
+                       psrch_inf->srch_entries_start =
+                               (char *) &pSMBr->hdr.Protocol +
                                        le16_to_cpu(pSMBr->t2.DataOffset);
                        parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
                               le16_to_cpu(pSMBr->t2.ParameterOffset));
 
-                       if(parms->EndofSearch)
-                               psrch_inf->endOfSearch = TRUE;
+                       if (parms->EndofSearch)
+                               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 =
+                                       le16_to_cpu(parms->SearchCount);
+                       psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
                                psrch_inf->entries_in_buffer;
                        *pnetfid = parms->SearchHandle;
                } else {
@@ -2845,11 +3648,11 @@ findFirstRetry:
 }
 
 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
-            __u16 searchHandle, struct cifs_search_info * psrch_inf)
+                __u16 searchHandle, struct cifs_search_info *psrch_inf)
 {
        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;
@@ -2857,7 +3660,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,
@@ -2865,12 +3668,13 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
        if (rc)
                return rc;
 
-       params = 14;    /* includes 2 bytes of null string, converted to LE below */
+       params = 14; /* includes 2 bytes of null string, converted to LE below*/
        byte_count = 0;
        pSMB->TotalDataCount = 0;       /* no EAs */
        pSMB->MaxParameterCount = cpu_to_le16(8);
        pSMB->MaxDataCount =
-            cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+               cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
+                               0xFFFFFF00);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -2885,16 +3689,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 =
@@ -2902,7 +3697,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 
        name_len = psrch_inf->resume_name_len;
        params += name_len;
-       if(name_len < PATH_MAX) {
+       if (name_len < PATH_MAX) {
                memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
                byte_count += name_len;
                /* 14 byte parm len above enough for 2 byte null terminator */
@@ -2917,42 +3712,49 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
        pSMB->ParameterCount = pSMB->TotalParameterCount;
        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);
        cifs_stats_inc(&tcon->num_fnext);
        if (rc) {
                if (rc == -EBADF) {
-                       psrch_inf->endOfSearch = TRUE;
-                       rc = 0; /* search probably was closed at end of search above */
+                       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));
        } else {                /* decode response */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-               
-               if(rc == 0) {
+
+               if (rc == 0) {
                        /* 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;
                        response_data = (char *)&pSMBr->hdr.Protocol +
                                le16_to_cpu(pSMBr->t2.DataOffset);
-                       cifs_buf_release(psrch_inf->ntwrk_buf_start);
+                       if (psrch_inf->smallBuf)
+                               cifs_small_buf_release(
+                                       psrch_inf->ntwrk_buf_start);
+                       else
+                               cifs_buf_release(psrch_inf->ntwrk_buf_start);
                        psrch_inf->srch_entries_start = response_data;
                        psrch_inf->ntwrk_buf_start = (char *)pSMB;
-                       if(parms->EndofSearch)
-                               psrch_inf->endOfSearch = TRUE;
+                       psrch_inf->smallBuf = 0;
+                       if (parms->EndofSearch)
+                               psrch_inf->endOfSearch = true;
                        else
-                               psrch_inf->endOfSearch = FALSE;
-                                                                                              
-                       psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
+                               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;
-/*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
+/*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
+           psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
 
                        /* BB fixme add unlock here */
                }
@@ -2967,38 +3769,33 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 FNext2_err_exit:
        if (rc != 0)
                cifs_buf_release(pSMB);
-                                                                                              
        return rc;
 }
 
 int
-CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
+CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
+             const __u16 searchHandle)
 {
        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);
 
        /* no sense returning error if session restarted
                as file handle has been closed */
-       if(rc == -EAGAIN)
+       if (rc == -EAGAIN)
                return 0;
        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)
@@ -3009,9 +3806,9 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
 
 int
 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
-                const unsigned char *searchName,
-                __u64 * inode_number,
-                const struct nls_table *nls_codepage, int remap)
+                     const unsigned char *searchName,
+                     __u64 *inode_number,
+                     const struct nls_table *nls_codepage, int remap)
 {
        int rc = 0;
        TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -3019,24 +3816,23 @@ CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
        int name_len, bytes_returned;
        __u16 params, byte_count;
 
-       cFYI(1,("In GetSrvInodeNum for %s",searchName));
-       if(tcon == NULL)
-               return -ENODEV; 
+       cFYI(1, ("In GetSrvInodeNum for %s", searchName));
+       if (tcon == NULL)
+               return -ENODEV;
 
 GetInodeNumberRetry:
        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-                      (void **) &pSMBr);
+                     (void **) &pSMBr);
        if (rc)
                return rc;
 
-
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
                        cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
-                               PATH_MAX,nls_codepage, remap);
+                                        PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } 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);
@@ -3053,7 +3849,7 @@ GetInodeNumberRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-               struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+               struct smb_com_transaction2_qpi_reqInformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -3079,12 +3875,12 @@ GetInodeNumberRetry:
                        /* If rc should we check for EOPNOSUPP and
                        disable the srvino flag? or in caller? */
                        rc = -EIO;      /* bad smb */
-                else {
+               else {
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
-                       struct file_internal_info * pfinfo;
+                       struct file_internal_info *pfinfo;
                        /* BB Do we need a cast or hash here ? */
-                       if(count < 8) {
+                       if (count < 8) {
                                cFYI(1, ("Illegal size ret in QryIntrnlInf"));
                                rc = -EIO;
                                goto GetInodeNumOut;
@@ -3101,25 +3897,112 @@ 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 i, rc = 0;
+       char *data_end;
+       bool is_unicode;
+       struct dfs_referral_level_3 *ref;
+
+       is_unicode = pSMBr->hdr.Flags2 & SMBFLG2_UNICODE;
+       *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,
+                       le16_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 = le16_to_cpu(pSMBr->DFSFlags);
+               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;
+               rc = cifs_strncpy_to_host(&(node->path_name), temp,
+                                       max_len, is_unicode, nls_codepage);
+               if (rc)
+                       goto parse_DFS_referrals_exit;
+
+               /* copy link target UNC */
+               temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
+               max_len = data_end - temp;
+               rc = cifs_strncpy_to_host(&(node->node_name), temp,
+                                       max_len, is_unicode, nls_codepage);
+               if (rc)
+                       goto parse_DFS_referrals_exit;
+
+               ref += le16_to_cpu(ref->Size);
+       }
+
+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)
@@ -3129,18 +4012,16 @@ getDFSRetry:
                      (void **) &pSMBr);
        if (rc)
                return rc;
-       
-       /* server pointer checked in called function, 
+
+       /* server pointer checked in called function,
        but should never be null here anyway */
        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;
@@ -3149,25 +4030,34 @@ getDFSRetry:
                                     searchName, PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(searchName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->RequestFileName, searchName, name_len);
        }
 
+       if (ses->server) {
+               if (ses->server->secMode &
+                  (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+                       pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+       }
+
+       pSMB->hdr.Uid = ses->Suid;
+
        params = 2 /* level */  + name_len /*includes null */ ;
        pSMB->TotalDataCount = 0;
        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;
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
+         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
@@ -3182,90 +4072,26 @@ 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);
 
-               if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
-                       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);
 
-       }
 GetDFSRefExit:
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
 
        if (rc == -EAGAIN)
                goto getDFSRetry;
@@ -3291,10 +4117,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;
@@ -3330,18 +4152,17 @@ oldQFSInfoRetry:
                        rc = -EIO;      /* bad smb */
                else {
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       cFYI(1,("qfsinf resp BCC: %d  Offset %d",
+                       cFYI(1, ("qfsinf resp BCC: %d  Offset %d",
                                 pSMBr->ByteCount, data_offset));
 
-                       response_data =
-                               (FILE_SYSTEM_ALLOC_INFO *) 
+                       response_data = (FILE_SYSTEM_ALLOC_INFO *)
                                (((char *) &pSMBr->hdr.Protocol) + data_offset);
                        FSData->f_bsize =
                                le16_to_cpu(response_data->BytesPerSector) *
                                le32_to_cpu(response_data->
                                        SectorsPerAllocationUnit);
                        FSData->f_blocks =
-                               le32_to_cpu(response_data->TotalAllocationUnits);
+                              le32_to_cpu(response_data->TotalAllocationUnits);
                        FSData->f_bfree = FSData->f_bavail =
                                le32_to_cpu(response_data->FreeAllocationUnits);
                        cFYI(1,
@@ -3390,7 +4211,7 @@ QFSInfoRetry:
        pSMB->TotalParameterCount = cpu_to_le16(params);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+               struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -3405,7 +4226,7 @@ QFSInfoRetry:
        if (rc) {
                cFYI(1, ("Send error in QFSInfo = %d", rc));
        } else {                /* decode response */
-                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
                if (rc || (pSMBr->ByteCount < 24))
                        rc = -EIO;      /* bad smb */
@@ -3460,7 +4281,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;
@@ -3470,7 +4292,7 @@ QFSAttributeRetry:
        pSMB->TotalParameterCount = cpu_to_le16(params);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+               struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -3487,7 +4309,8 @@ QFSAttributeRetry:
        } else {                /* decode response */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-               if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
+               if (rc || (pSMBr->ByteCount < 13)) {
+                       /* BB also check if enough bytes returned */
                        rc = -EIO;      /* bad smb */
                } else {
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
@@ -3496,7 +4319,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);
@@ -3528,7 +4351,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;
@@ -3538,7 +4362,7 @@ QFSDeviceRetry:
        pSMB->TotalParameterCount = cpu_to_le16(params);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+               struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
 
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
@@ -3556,7 +4380,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);
@@ -3565,7 +4389,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);
@@ -3599,7 +4423,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;
@@ -3608,8 +4433,8 @@ QFSUnixRetry:
        byte_count = params + 1 /* pad */ ;
        pSMB->ParameterCount = cpu_to_le16(params);
        pSMB->TotalParameterCount = pSMB->ParameterCount;
-       pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
-        smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+       pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
+                       smb_com_transaction2_qfsi_req, InformationLevel) - 4);
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
@@ -3633,7 +4458,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);
@@ -3657,6 +4482,7 @@ CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
 
        cFYI(1, ("In SETFSUnixInfo"));
 SETFSUnixRetry:
+       /* BB switch to small buf init to save memory */
        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
                      (void **) &pSMBr);
        if (rc)
@@ -3668,11 +4494,13 @@ SETFSUnixRetry:
        pSMB->Flags = 0;
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
-       param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
+       param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
+                               - 4;
        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);
@@ -3703,9 +4531,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);
 
@@ -3741,7 +4568,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;
@@ -3750,8 +4578,8 @@ QFSPosixRetry:
        byte_count = params + 1 /* pad */ ;
        pSMB->ParameterCount = cpu_to_le16(params);
        pSMB->TotalParameterCount = pSMB->ParameterCount;
-       pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
-        smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+       pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
+                       smb_com_transaction2_qfsi_req, InformationLevel) - 4);
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
@@ -3780,18 +4608,18 @@ QFSPosixRetry:
                                        le64_to_cpu(response_data->TotalBlocks);
                        FSData->f_bfree =
                            le64_to_cpu(response_data->BlocksAvail);
-                       if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
+                       if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
                                FSData->f_bavail = FSData->f_bfree;
                        } else {
                                FSData->f_bavail =
-                                       le64_to_cpu(response_data->UserBlocksAvail);
+                                   le64_to_cpu(response_data->UserBlocksAvail);
                        }
-                       if(response_data->TotalFileNodes != cpu_to_le64(-1))
+                       if (response_data->TotalFileNodes != cpu_to_le64(-1))
                                FSData->f_files =
-                                       le64_to_cpu(response_data->TotalFileNodes);
-                       if(response_data->FreeFileNodes != cpu_to_le64(-1))
+                                    le64_to_cpu(response_data->TotalFileNodes);
+                       if (response_data->FreeFileNodes != cpu_to_le64(-1))
                                FSData->f_ffree =
-                                       le64_to_cpu(response_data->FreeFileNodes);
+                                     le64_to_cpu(response_data->FreeFileNodes);
                }
        }
        cifs_buf_release(pSMB);
@@ -3803,15 +4631,15 @@ QFSPosixRetry:
 }
 
 
-/* We can not use write of zero bytes trick to 
-   set file size due to need for large file support.  Also note that 
-   this SetPathInfo is preferred to SetFileInfo based method in next 
+/* We can not use write of zero bytes trick to
+   set file size due to need for large file support.  Also note that
+   this SetPathInfo is preferred to SetFileInfo based method in next
    routine which is only needed to work around a sharing violation bug
    in Samba which this routine can run into */
 
 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;
@@ -3841,7 +4669,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;
@@ -3850,22 +4678,22 @@ SetEOFRetry:
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
-       if(SetAllocation) {
-               if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
-                   pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
-               else
-                   pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
-       } else /* Set File Size */  {    
+       if (SetAllocation) {
+               if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+                       pSMB->InformationLevel =
+                               cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
+               else
+                       pSMB->InformationLevel =
+                               cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
+       } else /* Set File Size */  {
            if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
                    pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+                               cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
            else
                    pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+                               cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
        }
 
        parm_data =
@@ -3887,9 +4715,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);
 
@@ -3900,15 +4727,13 @@ SetEOFRetry:
 }
 
 int
-CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
-                   __u16 fid, __u32 pid_of_opener, int SetAllocation)
+CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
+                  __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",
@@ -3918,11 +4743,9 @@ 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));
-    
+
        params = 6;
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
@@ -3932,11 +4755,12 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
        offset = param_offset + params;
 
-       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
+       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
 
        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);
@@ -3947,61 +4771,55 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
        pSMB->TotalParameterCount = pSMB->ParameterCount;
        pSMB->ParameterOffset = cpu_to_le16(param_offset);
        parm_data =
-               (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
-                       offset);
+               (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
+                               + offset);
        pSMB->DataOffset = cpu_to_le16(offset);
        parm_data->FileSize = cpu_to_le64(size);
        pSMB->Fid = fid;
-       if(SetAllocation) {
+       if (SetAllocation) {
                if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
                        pSMB->InformationLevel =
                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
                else
                        pSMB->InformationLevel =
                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
-       } else /* Set File Size */  {    
+       } else /* Set File Size */  {
            if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
                    pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+                               cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
            else
                    pSMB->InformationLevel =
-                       cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+                               cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
        }
        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 
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
 
        return rc;
 }
 
-/* Some legacy servers such as NT4 require that the file times be set on 
+/* Some legacy servers such as NT4 require that the file times be set on
    an open handle, rather than by pathname - this is awkward due to
    potential access conflicts on the open, but it is unavoidable for these
    old servers since the only other choice is to go from 100 nanosecond DCE
    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)
+CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
+                   const FILE_BASIC_INFO *data, __u16 fid)
 {
        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)"));
@@ -4010,14 +4828,12 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
        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));*/
-    
+
        params = 6;
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
@@ -4027,11 +4843,12 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
        offset = param_offset + params;
 
-       data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
+       data_offset = (char *) (&pSMB->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);
@@ -4050,16 +4867,12 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
        pSMB->Reserved4 = 0;
        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) {
-               cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
-       }
-
-       cifs_small_buf_release(pSMB);
+       memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       if (rc)
+               cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
 
-       /* Note: On -EAGAIN error only caller can retry on handle based calls 
+       /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
 
        return rc;
@@ -4068,7 +4881,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
 
 int
 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-               const FILE_BASIC_INFO * data, 
+               const FILE_BASIC_INFO *data,
                const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
@@ -4093,23 +4906,24 @@ SetTimesRetry:
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fileName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, fileName, name_len);
        }
 
        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;
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
        pSMB->ParameterOffset = cpu_to_le16(param_offset);
@@ -4129,13 +4943,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);
 
@@ -4170,11 +4983,11 @@ SetAttrLgcyRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                       ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
+                       ConvertToUCS((__le16 *) pSMB->fileName, fileName,
                                PATH_MAX, nls_codepage);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fileName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->fileName, fileName, name_len);
@@ -4185,9 +4998,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);
 
@@ -4200,8 +5012,8 @@ SetAttrLgcyRetry:
 
 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, 
+                   char *fileName, __u64 mode, __u64 uid, __u64 gid,
+                   dev_t device, const struct nls_table *nls_codepage,
                    int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
@@ -4221,7 +5033,7 @@ setPermsRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -4232,16 +5044,17 @@ 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;
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
        data_offset =
            (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
@@ -4260,57 +5073,65 @@ setPermsRetry:
        pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
        pSMB->Reserved4 = 0;
        pSMB->hdr.smb_buf_length += byte_count;
+       /* Samba server ignores set of file size to zero due to bugs in some
+       older clients, but we should be precise - we use SetFileSize to
+       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);
        /* 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->Permissions = cpu_to_le64(mode);
-    
-       if(S_ISREG(mode))
+
+       if (S_ISREG(mode))
                data_offset->Type = cpu_to_le32(UNIX_FILE);
-       else if(S_ISDIR(mode))
+       else if (S_ISDIR(mode))
                data_offset->Type = cpu_to_le32(UNIX_DIR);
-       else if(S_ISLNK(mode))
+       else if (S_ISLNK(mode))
                data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
-       else if(S_ISCHR(mode))
+       else if (S_ISCHR(mode))
                data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
-       else if(S_ISBLK(mode))
+       else if (S_ISBLK(mode))
                data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
-       else if(S_ISFIFO(mode))
+       else if (S_ISFIFO(mode))
                data_offset->Type = cpu_to_le32(UNIX_FIFO);
-       else if(S_ISSOCK(mode))
+       else if (S_ISSOCK(mode))
                data_offset->Type = cpu_to_le32(UNIX_SOCKET);
 
 
        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;
 }
 
-int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
+int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
                  const int notify_subdirs, const __u16 netfid,
-                 __u32 filter, struct file * pfile, int multishot, 
+                 __u32 filter, struct file *pfile, int multishot,
                  const struct nls_table *nls_codepage)
 {
        int rc = 0;
-       struct smb_com_transaction_change_notify_req * pSMB = NULL;
-       struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
+       struct smb_com_transaction_change_notify_req *pSMB = NULL;
+       struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
        struct dir_notify_req *dnotify_req;
        int bytes_returned;
 
-       cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
+       cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
        rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
-                      (void **) &pSMBr);
+                     (void **) &pSMBr);
        if (rc)
                return rc;
 
@@ -4319,6 +5140,10 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
        pSMB->MaxParameterCount = cpu_to_le32(2);
        /* BB find exact data count max from sess structure BB */
        pSMB->MaxDataCount = 0; /* same in little endian or be */
+/* BB VERIFY verify which is correct for above BB */
+       pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
+                                            MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+
        pSMB->MaxSetupCount = 4;
        pSMB->Reserved = 0;
        pSMB->ParameterOffset = 0;
@@ -4327,7 +5152,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
        pSMB->SetupCount = 4; /* single byte does not need le conversion */
        pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
        pSMB->ParameterCount = pSMB->TotalParameterCount;
-       if(notify_subdirs)
+       if (notify_subdirs)
                pSMB->WatchTree = 1; /* one byte - no le conversion needed */
        pSMB->Reserved2 = 0;
        pSMB->CompletionFilter = cpu_to_le32(filter);
@@ -4335,16 +5160,17 @@ 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 {
                /* Add file to outstanding requests */
-               /* BB change to kmem cache alloc */     
-               dnotify_req = (struct dir_notify_req *) kmalloc(
+               /* BB change to kmem cache alloc */
+               dnotify_req = kmalloc(
                                                sizeof(struct dir_notify_req),
                                                 GFP_KERNEL);
-               if(dnotify_req) {
+               if (dnotify_req) {
                        dnotify_req->Pid = pSMB->hdr.Pid;
                        dnotify_req->PidHigh = pSMB->hdr.PidHigh;
                        dnotify_req->Mid = pSMB->hdr.Mid;
@@ -4355,20 +5181,20 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
                        dnotify_req->filter = filter;
                        dnotify_req->multishot = multishot;
                        spin_lock(&GlobalMid_Lock);
-                       list_add_tail(&dnotify_req->lhead, 
+                       list_add_tail(&dnotify_req->lhead,
                                        &GlobalDnotifyReqList);
                        spin_unlock(&GlobalMid_Lock);
-               } else 
+               } else
                        rc = -ENOMEM;
        }
        cifs_buf_release(pSMB);
-       return rc;      
+       return rc;
 }
 #ifdef CONFIG_CIFS_XATTR
 ssize_t
 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
                 const unsigned char *searchName,
-                char * EAData, size_t buf_size,
+                char *EAData, size_t buf_size,
                 const struct nls_table *nls_codepage, int remap)
 {
                /* BB assumes one setup word */
@@ -4377,8 +5203,8 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
        int rc = 0;
        int bytes_returned;
        int name_len;
-       struct fea * temp_fea;
-       char * temp_ptr;
+       struct fea *temp_fea;
+       char *temp_ptr;
        __u16 params, byte_count;
 
        cFYI(1, ("In Query All EAs path %s", searchName));
@@ -4390,7 +5216,7 @@ QAllEAsRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -4400,17 +5226,18 @@ QAllEAsRetry:
                strncpy(pSMB->FileName, searchName, name_len);
        }
 
-       params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+       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;
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+       struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -4434,7 +5261,7 @@ QAllEAsRetry:
                /* BB also check enough total bytes returned */
                /* BB we need to improve the validity checking
                of these trans2 responses */
-               if (rc || (pSMBr->ByteCount < 4)) 
+               if (rc || (pSMBr->ByteCount < 4))
                        rc = -EIO;      /* bad smb */
           /* else if (pFindData){
                        memcpy((char *) pFindData,
@@ -4447,39 +5274,40 @@ QAllEAsRetry:
                        /* check that each element of each entry does not
                           go beyond end of list */
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       struct fealist * ea_response_data;
+                       struct fealist *ea_response_data;
                        rc = 0;
                        /* validate_trans2_offsets() */
-                       /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
+                       /* BB check if start of smb + data_offset > &bcc+ bcc */
                        ea_response_data = (struct fealist *)
                                (((char *) &pSMBr->hdr.Protocol) +
                                data_offset);
                        name_len = le32_to_cpu(ea_response_data->list_len);
-                       cFYI(1,("ea length %d", name_len));
-                       if(name_len <= 8) {
+                       cFYI(1, ("ea length %d", name_len));
+                       if (name_len <= 8) {
                        /* returned EA size zeroed at top of function */
-                               cFYI(1,("empty EA list returned from server"));
+                               cFYI(1, ("empty EA list returned from server"));
                        } else {
                                /* account for ea list len */
                                name_len -= 4;
                                temp_fea = ea_response_data->list;
                                temp_ptr = (char *)temp_fea;
-                               while(name_len > 0) {
+                               while (name_len > 0) {
                                        __u16 value_len;
                                        name_len -= 4;
                                        temp_ptr += 4;
                                        rc += temp_fea->name_len;
                                /* account for prefix user. and trailing null */
-                                       rc = rc + 5 + 1; 
-                                       if(rc<(int)buf_size) {
-                                               memcpy(EAData,"user.",5);
-                                               EAData+=5;
-                                               memcpy(EAData,temp_ptr,temp_fea->name_len);
-                                               EAData+=temp_fea->name_len;
+                                       rc = rc + 5 + 1;
+                                       if (rc < (int)buf_size) {
+                                               memcpy(EAData, "user.", 5);
+                                               EAData += 5;
+                                               memcpy(EAData, temp_ptr,
+                                                      temp_fea->name_len);
+                                               EAData += temp_fea->name_len;
                                                /* null terminate name */
                                                *EAData = 0;
                                                EAData = EAData + 1;
-                                       } else if(buf_size == 0) {
+                                       } else if (buf_size == 0) {
                                                /* skip copy - calc size only */
                                        } else {
                                                /* stop before overrun buffer */
@@ -4491,28 +5319,31 @@ QAllEAsRetry:
                                        /* account for trailing null */
                                        name_len--;
                                        temp_ptr++;
-                                       value_len = le16_to_cpu(temp_fea->value_len);
+                                       value_len =
+                                             le16_to_cpu(temp_fea->value_len);
                                        name_len -= value_len;
                                        temp_ptr += value_len;
-                                       /* BB check that temp_ptr is still within smb BB*/
-                               /* no trailing null to account for in value len */
+                                       /* BB check that temp_ptr is still
+                                             within the SMB BB*/
+
+                                       /* no trailing null to account for
+                                          in value len */
                                        /* go on to next EA */
                                        temp_fea = (struct fea *)temp_ptr;
                                }
                        }
                }
        }
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
                goto QAllEAsRetry;
 
        return (ssize_t)rc;
 }
 
-ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
-               const unsigned char * searchName,const unsigned char * ea_name,
-               unsigned char * ea_value, size_t buf_size, 
+ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
+               const unsigned char *searchName, const unsigned char *ea_name,
+               unsigned char *ea_value, size_t buf_size,
                const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -4520,8 +5351,8 @@ ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
        int rc = 0;
        int bytes_returned;
        int name_len;
-       struct fea * temp_fea;
-       char * temp_ptr;
+       struct fea *temp_fea;
+       char *temp_ptr;
        __u16 params, byte_count;
 
        cFYI(1, ("In Query EA path %s", searchName));
@@ -4533,7 +5364,7 @@ QEARetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
@@ -4543,17 +5374,18 @@ QEARetry:
                strncpy(pSMB->FileName, searchName, name_len);
        }
 
-       params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+       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;
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        pSMB->ParameterOffset = cpu_to_le16(offsetof(
-        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+               struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->SetupCount = 1;
@@ -4577,7 +5409,7 @@ QEARetry:
                /* BB also check enough total bytes returned */
                /* BB we need to improve the validity checking
                of these trans2 responses */
-               if (rc || (pSMBr->ByteCount < 4)) 
+               if (rc || (pSMBr->ByteCount < 4))
                        rc = -EIO;      /* bad smb */
           /* else if (pFindData){
                        memcpy((char *) pFindData,
@@ -4590,18 +5422,18 @@ QEARetry:
                        /* check that each element of each entry does not
                           go beyond end of list */
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       struct fealist * ea_response_data;
+                       struct fealist *ea_response_data;
                        rc = -ENODATA;
                        /* validate_trans2_offsets() */
-                       /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
+                       /* BB check if start of smb + data_offset > &bcc+ bcc*/
                        ea_response_data = (struct fealist *)
                                (((char *) &pSMBr->hdr.Protocol) +
                                data_offset);
                        name_len = le32_to_cpu(ea_response_data->list_len);
-                       cFYI(1,("ea length %d", name_len));
-                       if(name_len <= 8) {
+                       cFYI(1, ("ea length %d", name_len));
+                       if (name_len <= 8) {
                        /* returned EA size zeroed at top of function */
-                               cFYI(1,("empty EA list returned from server"));
+                               cFYI(1, ("empty EA list returned from server"));
                        } else {
                                /* account for ea list len */
                                name_len -= 4;
@@ -4609,28 +5441,30 @@ QEARetry:
                                temp_ptr = (char *)temp_fea;
                                /* loop through checking if we have a matching
                                name and then return the associated value */
-                               while(name_len > 0) {
+                               while (name_len > 0) {
                                        __u16 value_len;
                                        name_len -= 4;
                                        temp_ptr += 4;
-                                       value_len = le16_to_cpu(temp_fea->value_len);
-                               /* BB validate that value_len falls within SMB, 
-                               even though maximum for name_len is 255 */ 
-                                       if(memcmp(temp_fea->name,ea_name,
+                                       value_len =
+                                             le16_to_cpu(temp_fea->value_len);
+                               /* BB validate that value_len falls within SMB,
+                               even though maximum for name_len is 255 */
+                                       if (memcmp(temp_fea->name, ea_name,
                                                  temp_fea->name_len) == 0) {
                                                /* found a match */
                                                rc = value_len;
                                /* account for prefix user. and trailing null */
-                                               if(rc<=(int)buf_size) {
+                                               if (rc <= (int)buf_size) {
                                                        memcpy(ea_value,
                                                                temp_fea->name+temp_fea->name_len+1,
                                                                rc);
-                                                       /* ea values, unlike ea names,
-                                                       are not null terminated */
-                                               } else if(buf_size == 0) {
+                                                       /* ea values, unlike ea
+                                                          names, are not null
+                                                          terminated */
+                                               } else if (buf_size == 0) {
                                                /* skip copy - calc size only */
                                                } else {
-                                                       /* stop before overrun buffer */
+                                               /* stop before overrun buffer */
                                                        rc = -ERANGE;
                                                }
                                                break;
@@ -4642,15 +5476,14 @@ QEARetry:
                                        temp_ptr++;
                                        name_len -= value_len;
                                        temp_ptr += value_len;
-                               /* no trailing null to account for in value len */
-                                       /* go on to next EA */
+                                       /* No trailing null to account for in
+                                          value_len.  Go on to next EA */
                                        temp_fea = (struct fea *)temp_ptr;
                                }
-                       } 
+                       }
                }
        }
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
                goto QEARetry;
 
@@ -4659,9 +5492,9 @@ QEARetry:
 
 int
 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-               const char * ea_name, const void * ea_value, 
-               const __u16 ea_value_len, const struct nls_table *nls_codepage,
-               int remap)
+            const char *ea_name, const void *ea_value,
+            const __u16 ea_value_len, const struct nls_table *nls_codepage,
+            int remap)
 {
        struct smb_com_transaction2_spi_req *pSMB = NULL;
        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -4680,11 +5513,11 @@ SetEARetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
+                   cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-       } else {                /* BB improve the check for buffer overruns BB */
+       } else {        /* BB improve the check for buffer overruns BB */
                name_len = strnlen(fileName, PATH_MAX);
                name_len++;     /* trailing null */
                strncpy(pSMB->FileName, fileName, name_len);
@@ -4695,21 +5528,22 @@ SetEARetry:
        /* done calculating parms using name_len of file name,
        now use name_len to calculate length of ea name
        we are going to create in the inode xattrs */
-       if(ea_name == NULL)
+       if (ea_name == NULL)
                name_len = 0;
        else
-               name_len = strnlen(ea_name,255);
+               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;
        pSMB->Timeout = 0;
        pSMB->Reserved2 = 0;
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
-                                     InformationLevel) - 4;
+                               InformationLevel) - 4;
        offset = param_offset + params;
        pSMB->InformationLevel =
                cpu_to_le16(SMB_SET_FILE_EA);
@@ -4727,19 +5561,21 @@ SetEARetry:
        parm_data->list_len = cpu_to_le32(count);
        parm_data->list[0].EA_flags = 0;
        /* we checked above that name len is less than 255 */
-       parm_data->list[0].name_len = (__u8)name_len;;
+       parm_data->list[0].name_len = (__u8)name_len;
        /* EA names are always ASCII */
-       if(ea_name)
-               strncpy(parm_data->list[0].name,ea_name,name_len);
+       if (ea_name)
+               strncpy(parm_data->list[0].name, ea_name, name_len);
        parm_data->list[0].name[name_len] = 0;
        parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
        /* caller ensures that ea_value_len is less than 64K but
        we need to ensure that it fits within the smb */
 
-       /*BB add length check that it would fit in negotiated SMB buffer size BB */
-       /* if(ea_value_len > buffer_size - 512 (enough for header)) */
-       if(ea_value_len)
-               memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
+       /*BB add length check to see if it would fit in
+            negotiated SMB buffer size BB */
+       /* if (ea_value_len > buffer_size - 512 (enough for header)) */
+       if (ea_value_len)
+               memcpy(parm_data->list[0].name+name_len+1,
+                      ea_value, ea_value_len);
 
        pSMB->TotalDataCount = pSMB->DataCount;
        pSMB->ParameterCount = cpu_to_le16(params);
@@ -4749,9 +5585,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);