af_key: fix netns ops ordering on module load/unload
[safe/jmp/linux-2.6] / fs / cifs / cifssmb.c
index 9e8a6be..941441d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifssmb.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2007
+ *   Copyright (C) International Business Machines  Corp., 2002,2009
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   Contains the routines for constructing the SMB PDUs themselves
@@ -81,7 +81,6 @@ static struct {
 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
 #endif /* CIFS_POSIX */
 
-
 /* Mark as invalid, all open files on tree connections since they
    were closed when session to server was lost */
 static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
@@ -94,114 +93,146 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
        write_lock(&GlobalSMBSeslock);
        list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
                open_file = list_entry(tmp, struct cifsFileInfo, tlist);
-               if (open_file)
-                       open_file->invalidHandle = TRUE;
+               open_file->invalidHandle = true;
+               open_file->oplock_break_cancelled = 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 */
+/* reconnect the socket, tcon, and smb session if needed */
 static int
-small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
-        void **request_buf /* returned */)
+cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
 {
        int rc = 0;
+       struct cifsSesInfo *ses;
+       struct TCP_Server_Info *server;
+       struct nls_table *nls_codepage;
 
-       /* 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) {
-                       /* 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) &&
-                          (smb_command != SMB_COM_TREE_DISCONNECT)) {
-                               cFYI(1, ("can not send cmd %d while umounting",
-                                       smb_command));
-                               return -ENODEV;
-                       }
+       /*
+        * 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)
+               return 0;
+
+       ses = tcon->ses;
+       server = ses->server;
+
+       /*
+        * only tree disconnect, open, and write, (and ulogoff which does not
+        * have tcon) are allowed as we start force umount
+        */
+       if (tcon->tidStatus == CifsExiting) {
+               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",
+                               smb_command));
+                       return -ENODEV;
                }
-               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) {
-                               wait_event_interruptible_timeout(tcon->ses->server->response_q,
-                                       (tcon->ses->server->tcpStatus ==
-                                                       CifsGood), 10 * HZ);
-                               if (tcon->ses->server->tcpStatus ==
-                                                       CifsNeedReconnect) {
-                                       /* on "soft" mounts we wait once */
-                                       if ((tcon->retry == FALSE) ||
-                                          (tcon->ses->status == CifsExiting)) {
-                                               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,
-                                                       nls_codepage);
-                       if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
-                               mark_open_files_invalid(tcon);
-                               rc = CIFSTCon(0, tcon->ses, tcon->treeName,
-                                             tcon, nls_codepage);
-                               up(&tcon->ses->sesSem);
-                               /* tell server which Unix caps we support */
-                               if (tcon->ses->capabilities & CAP_UNIX)
-                                       reset_cifs_unix_caps(0 /* no xid */,
-                                               tcon,
-                                               NULL /* we do not know sb */,
-                                               NULL /* no vol info */);
-                               /* BB FIXME add code to check if wsize needs
-                                  update due to negotiated smb buffer size
-                                  shrinking */
-                               if (rc == 0)
-                                       atomic_inc(&tconInfoReconnectCount);
-
-                               cFYI(1, ("reconnect tcon rc = %d", rc));
-                               /* 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
-                                  know whether we can continue or not without
-                                  returning to caller to reset file handle */
-                               switch (smb_command) {
-                                       case SMB_COM_READ_ANDX:
-                                       case SMB_COM_WRITE_ANDX:
-                                       case SMB_COM_CLOSE:
-                                       case SMB_COM_FIND_CLOSE2:
-                                       case SMB_COM_LOCKING_ANDX: {
-                                               unload_nls(nls_codepage);
-                                               return -EAGAIN;
-                                       }
-                               }
-                       } else {
-                               up(&tcon->ses->sesSem);
-                       }
-                       unload_nls(nls_codepage);
+       if (ses->status == CifsExiting)
+               return -EIO;
 
-               } else {
-                       return -EIO;
+       /*
+        * Give demultiplex thread up to 10 seconds to reconnect, should be
+        * greater than cifs socket timeout which is 7 seconds
+        */
+       while (server->tcpStatus == CifsNeedReconnect) {
+               wait_event_interruptible_timeout(server->response_q,
+                       (server->tcpStatus == CifsGood), 10 * HZ);
+
+               /* is TCP session is reestablished now ?*/
+               if (server->tcpStatus != CifsNeedReconnect)
+                       break;
+
+               /*
+                * on "soft" mounts we wait once. Hard mounts keep
+                * retrying until process is killed or server comes
+                * back on-line
+                */
+               if (!tcon->retry || ses->status == CifsExiting) {
+                       cFYI(1, ("gave up waiting on reconnect in smb_init"));
+                       return -EHOSTDOWN;
                }
        }
+
+       if (!ses->need_reconnect && !tcon->need_reconnect)
+               return 0;
+
+       nls_codepage = load_nls_default();
+
+       /*
+        * need to prevent multiple threads trying to simultaneously
+        * reconnect the same SMB session
+        */
+       down(&ses->sesSem);
+       if (ses->need_reconnect)
+               rc = cifs_setup_session(0, ses, nls_codepage);
+
+       /* do we need to reconnect tcon? */
+       if (rc || !tcon->need_reconnect) {
+               up(&ses->sesSem);
+               goto out;
+       }
+
+       mark_open_files_invalid(tcon);
+       rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
+       up(&ses->sesSem);
+       cFYI(1, ("reconnect tcon rc = %d", rc));
+
+       if (rc)
+               goto out;
+
+       /*
+        * FIXME: check if wsize needs updated due to negotiated smb buffer
+        *        size shrinking
+        */
+       atomic_inc(&tconInfoReconnectCount);
+
+       /* tell server Unix caps we support */
+       if (ses->capabilities & CAP_UNIX)
+               reset_cifs_unix_caps(0, tcon, NULL, NULL);
+
+       /*
+        * 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.
+        *
+        * FIXME: what about file locks? don't we need to reclaim them ASAP?
+        */
+
+out:
+       /*
+        * 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) {
+       case SMB_COM_READ_ANDX:
+       case SMB_COM_WRITE_ANDX:
+       case SMB_COM_CLOSE:
+       case SMB_COM_FIND_CLOSE2:
+       case SMB_COM_LOCKING_ANDX:
+               rc = -EAGAIN;
+       }
+
+       unload_nls(nls_codepage);
+       return rc;
+}
+
+/* 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)
+{
+       int rc = 0;
+
+       rc = cifs_reconnect_tcon(tcon, smb_command);
        if (rc)
                return rc;
 
@@ -254,99 +285,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 {
        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) {
-                       /* 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) &&
-                          (smb_command != SMB_COM_TREE_DISCONNECT)) {
-                               cFYI(1, ("can not send cmd %d while umounting",
-                                       smb_command));
-                               return -ENODEV;
-                       }
-               }
-
-               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) {
-                               wait_event_interruptible_timeout(tcon->ses->server->response_q,
-                                       (tcon->ses->server->tcpStatus ==
-                                                       CifsGood), 10 * HZ);
-                               if (tcon->ses->server->tcpStatus ==
-                                               CifsNeedReconnect) {
-                                       /* on "soft" mounts we wait once */
-                                       if ((tcon->retry == FALSE) ||
-                                          (tcon->ses->status == CifsExiting)) {
-                                               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,
-                                                       nls_codepage);
-                       if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
-                               mark_open_files_invalid(tcon);
-                               rc = CIFSTCon(0, tcon->ses, tcon->treeName,
-                                             tcon, nls_codepage);
-                               up(&tcon->ses->sesSem);
-                               /* tell server which Unix caps we support */
-                               if (tcon->ses->capabilities & CAP_UNIX)
-                                       reset_cifs_unix_caps(0 /* no xid */,
-                                               tcon,
-                                               NULL /* do not know sb */,
-                                               NULL /* no vol info */);
-                               /* BB FIXME add code to check if wsize needs
-                               update due to negotiated smb buffer size
-                               shrinking */
-                               if (rc == 0)
-                                       atomic_inc(&tconInfoReconnectCount);
-
-                               cFYI(1, ("reconnect tcon rc = %d", rc));
-                               /* 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
-                                  know whether we can continue or not without
-                                  returning to caller to reset file handle */
-                               switch (smb_command) {
-                                       case SMB_COM_READ_ANDX:
-                                       case SMB_COM_WRITE_ANDX:
-                                       case SMB_COM_CLOSE:
-                                       case SMB_COM_FIND_CLOSE2:
-                                       case SMB_COM_LOCKING_ANDX: {
-                                               unload_nls(nls_codepage);
-                                               return -EAGAIN;
-                                       }
-                               }
-                       } else {
-                               up(&tcon->ses->sesSem);
-                       }
-                       unload_nls(nls_codepage);
-
-               } else {
-                       return -EIO;
-               }
-       }
+       rc = cifs_reconnect_tcon(tcon, smb_command);
        if (rc)
                return rc;
 
@@ -363,7 +302,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                *response_buf = *request_buf;
 
        header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
-                       wct /*wct */ );
+                       wct);
 
        if (tcon != NULL)
                cifs_stats_inc(&tcon->num_smbs_sent);
@@ -445,6 +384,14 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                cFYI(1, ("Kerberos only mechanism, enable extended security"));
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
        }
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+       else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
+               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
+       else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
+               cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
+               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
+       }
+#endif
 
        count = 0;
        for (i = 0; i < CIFS_NUM_PROT; i++) {
@@ -489,14 +436,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
                server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
                                (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
+               server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
                GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
                /* even though we do not use raw we might as well set this
                accurately, in case we ever find a need for it */
                if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
-                       server->maxRw = 0xFF00;
+                       server->max_rw = 0xFF00;
                        server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
                } else {
-                       server->maxRw = 0;/* we do not need to use raw anyway */
+                       server->max_rw = 0;/* do not need to use raw anyway */
                        server->capabilities = CAP_MPX_MODE;
                }
                tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
@@ -511,8 +459,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        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));
+                       ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
+                                           rsp->SrvTime.Time, 0);
                        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)));
@@ -523,7 +471,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        if (remain >= (MIN_TZ_ADJ / 2))
                                result += MIN_TZ_ADJ;
                        if (val < 0)
-                               result = - result;
+                               result = -result;
                        server->timeAdj = result;
                } else {
                        server->timeAdj = (int)tmp;
@@ -580,6 +528,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                server->secType = NTLMv2;
        else if (secFlags & CIFSSEC_MAY_KRB5)
                server->secType = Kerberos;
+       else if (secFlags & CIFSSEC_MAY_NTLMSSP)
+               server->secType = RawNTLMSSP;
        else if (secFlags & CIFSSEC_MAY_LANMAN)
                server->secType = LANMAN;
 /* #ifdef CONFIG_CIFS_EXPERIMENTAL
@@ -599,8 +549,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        /* probably no need to store and check maxvcs */
        server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
                        (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
-       server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
-       cFYI(0, ("Max buf = %d", ses->server->maxBuf));
+       server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
+       cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
        GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
        server->capabilities = le32_to_cpu(pSMBr->Capabilities);
        server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
@@ -625,8 +575,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                        rc = -EIO;
                        goto neg_err_exit;
                }
-
-               if (server->socketUseCount.counter > 1) {
+               read_lock(&cifs_tcp_ses_lock);
+               if (server->srv_count > 1) {
+                       read_unlock(&cifs_tcp_ses_lock);
                        if (memcmp(server->server_GUID,
                                   pSMBr->u.extended_response.
                                   GUID, 16) != 0) {
@@ -635,9 +586,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                                        pSMBr->u.extended_response.GUID,
                                        16);
                        }
-               } else
+               } else {
+                       read_unlock(&cifs_tcp_ses_lock);
                        memcpy(server->server_GUID,
                               pSMBr->u.extended_response.GUID, 16);
+               }
 
                if (count == 16) {
                        server->secType = RawNTLMSSP;
@@ -646,11 +599,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                                                 SecurityBlob,
                                                 count - 16,
                                                 &server->secType);
-                       if (rc == 1) {
+                       if (rc == 1)
                                rc = 0;
-                       } else {
+                       else
                                rc = -EINVAL;
-                       }
                }
        } else
                server->capabilities &= ~CAP_EXTENDED_SECURITY;
@@ -701,50 +653,31 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
        int rc = 0;
 
        cFYI(1, ("In tree disconnect"));
-       /*
-        *  If last user of the connection and
-        *  connection alive - disconnect it
-        *  If this is the last connection on the server session disconnect it
-        *  (and inside session disconnect we should check if tcp socket needs
-        *  to be freed and kernel thread woken up).
-        */
-       if (tcon)
-               down(&tcon->tconSem);
-       else
-               return -EIO;
 
-       atomic_dec(&tcon->useCount);
-       if (atomic_read(&tcon->useCount) > 0) {
-               up(&tcon->tconSem);
-               return -EBUSY;
-       }
+       /* BB: do we need to check this? These should never be NULL. */
+       if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
+               return -EIO;
 
-       /* No need to return error on this operation if tid invalidated and
-       closed on server already e.g. due to tcp session crashing */
-       if (tcon->tidStatus == CifsNeedReconnect) {
-               up(&tcon->tconSem);
+       /*
+        * No need to return error on this operation if tid invalidated and
+        * closed on server already e.g. due to tcp session crashing. Also,
+        * the tcon is no longer on the list, so no need to take lock before
+        * checking this.
+        */
+       if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
                return 0;
-       }
 
-       if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
-               up(&tcon->tconSem);
-               return -EIO;
-       }
        rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
                            (void **)&smb_buffer);
-       if (rc) {
-               up(&tcon->tconSem);
+       if (rc)
                return rc;
-       }
 
        rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
        if (rc)
                cFYI(1, ("Tree disconnect failed %d", rc));
 
-       up(&tcon->tconSem);
-
        /* No need to return error on this operation if tid invalidated and
-       closed on server already e.g. due to tcp session crashing */
+          closed on server already e.g. due to tcp session crashing */
        if (rc == -EAGAIN)
                rc = 0;
 
@@ -758,43 +691,36 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
        int rc = 0;
 
        cFYI(1, ("In SMBLogoff for session disconnect"));
-       if (ses)
-               down(&ses->sesSem);
-       else
+
+       /*
+        * BB: do we need to check validity of ses and server? They should
+        * always be valid since we have an active reference. If not, that
+        * should probably be a BUG()
+        */
+       if (!ses || !ses->server)
                return -EIO;
 
-       atomic_dec(&ses->inUse);
-       if (atomic_read(&ses->inUse) > 0) {
-               up(&ses->sesSem);
-               return -EBUSY;
-       }
+       down(&ses->sesSem);
+       if (ses->need_reconnect)
+               goto session_already_dead; /* no need to send SMBlogoff if uid
+                                             already closed due to reconnect */
        rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
        if (rc) {
                up(&ses->sesSem);
                return rc;
        }
 
-       if (ses->server) {
-               pSMB->hdr.Mid = GetNextMid(ses->server);
+       pSMB->hdr.Mid = GetNextMid(ses->server);
 
-               if (ses->server->secMode &
+       if (ses->server->secMode &
                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-       }
 
        pSMB->hdr.Uid = ses->Suid;
 
        pSMB->AndXCommand = 0xFF;
        rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
-       if (ses->server) {
-               atomic_dec(&ses->server->socketUseCount);
-               if (atomic_read(&ses->server->socketUseCount) == 0) {
-                       spin_lock(&GlobalMid_Lock);
-                       ses->server->tcpStatus = CifsExiting;
-                       spin_unlock(&GlobalMid_Lock);
-                       rc = -ESHUTDOWN;
-               }
-       }
+session_already_dead:
        up(&ses->sesSem);
 
        /* if session dead then we do not need to do ulogoff,
@@ -868,9 +794,8 @@ PsxDelete:
        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, ("Posix delete returned %d", rc));
-       }
        cifs_buf_release(pSMB);
 
        cifs_stats_inc(&tcon->num_deletes);
@@ -916,9 +841,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)
@@ -961,9 +885,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)
@@ -1005,9 +928,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)
@@ -1017,7 +939,7 @@ MkDirRetry:
 
 int
 CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
-               __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
+               __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
                __u32 *pOplock, const char *name,
                const struct nls_table *nls_codepage, int remap)
 {
@@ -1027,8 +949,8 @@ CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
        int rc = 0;
        int bytes_returned = 0;
        __u16 params, param_offset, offset, byte_count, count;
-       OPEN_PSX_REQ * pdata;
-       OPEN_PSX_RSP * psx_rsp;
+       OPEN_PSX_REQ *pdata;
+       OPEN_PSX_RSP *psx_rsp;
 
        cFYI(1, ("In POSIX Create"));
 PsxCreat:
@@ -1110,9 +1032,7 @@ PsxCreat:
        /* 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 */
-#ifdef CONFIG_CIFS_DEBUG2
-               cFYI(1, ("unknown type"));
-#endif
+               cFYI(DBG2, ("unknown type"));
        } else {
                if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
                                        + sizeof(FILE_UNIX_BASIC_INFO)) {
@@ -1128,7 +1048,10 @@ PsxCreat:
 psx_create_err:
        cifs_buf_release(pSMB);
 
-       cifs_stats_inc(&tcon->num_mkdirs);
+       if (posix_flags & SMB_O_DIRECTORY)
+               cifs_stats_inc(&tcon->num_posixmkdirs);
+       else
+               cifs_stats_inc(&tcon->num_posixopens);
 
        if (rc == -EAGAIN)
                goto PsxCreat;
@@ -1166,11 +1089,25 @@ static __u16 convert_disposition(int disposition)
        return ofun;
 }
 
+static int
+access_flags_to_smbopen_mode(const int access_flags)
+{
+       int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
+
+       if (masked_flags == GENERIC_READ)
+               return SMBOPEN_READ;
+       else if (masked_flags == GENERIC_WRITE)
+               return SMBOPEN_WRITE;
+
+       /* just go for read/write */
+       return SMBOPEN_READWRITE;
+}
+
 int
 SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
            const char *fileName, const int openDisposition,
-           const int access_flags, const int create_options, __u16 * netfid,
-           int *pOplock, FILE_ALL_INFO * pfile_info,
+           const int access_flags, const int create_options, __u16 *netfid,
+           int *pOplock, FILE_ALL_INFO *pfile_info,
            const struct nls_table *nls_codepage, int remap)
 {
        int rc = -EACCES;
@@ -1207,13 +1144,7 @@ OldOpenRetry:
                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
@@ -1221,14 +1152,11 @@ OldOpenRetry:
 
        if (create_options & CREATE_OPTION_SPECIAL)
                pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
-       else
-                pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
+       else /* BB FIXME BB */
+               pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
 
-       /* if ((omode & S_IWUGO) == 0)
-               pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
-       /*  Above line causes problems due to vfs splitting create into two
-           pieces - need to set mode after file created not while it is
-           being created */
+       if (create_options & CREATE_OPTION_READONLY)
+               pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
 
        /* BB FIXME BB */
 /*     pSMB->CreateOptions = cpu_to_le32(create_options &
@@ -1250,7 +1178,7 @@ OldOpenRetry:
        } 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. */
@@ -1272,6 +1200,7 @@ OldOpenRetry:
                                cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
                        pfile_info->EndOfFile = pfile_info->AllocationSize;
                        pfile_info->NumberOfLinks = cpu_to_le32(1);
+                       pfile_info->DeletePending = 0;
                }
        }
 
@@ -1284,8 +1213,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;
@@ -1331,17 +1260,16 @@ openRetry:
                pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
        else
                pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
+
        /* XP does not handle ATTR_POSIX_SEMANTICS */
        /* but it helps speed up case sensitive checks for other
        servers such as Samba */
        if (tcon->ses->capabilities & CAP_UNIX)
                pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
 
-       /* if ((omode & S_IWUGO) == 0)
-               pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
-       /*  Above line causes problems due to vfs splitting create into two
-               pieces - need to set mode after file created not while it is
-               being created */
+       if (create_options & CREATE_OPTION_READONLY)
+               pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
+
        pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
        pSMB->CreateDisposition = cpu_to_le32(openDisposition);
        pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
@@ -1368,12 +1296,13 @@ openRetry:
                if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
                        *pOplock |= CIFS_CREATE_ACTION;
                if (pfile_info) {
-                   memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
-                       36 /* CreationTime to Attributes */);
-                   /* the file_info buf is endian converted by caller */
-                   pfile_info->AllocationSize = pSMBr->AllocationSize;
-                   pfile_info->EndOfFile = pSMBr->EndOfFile;
-                   pfile_info->NumberOfLinks = cpu_to_le32(1);
+                       memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
+                               36 /* CreationTime to Attributes */);
+                       /* the file_info buf is endian converted by caller */
+                       pfile_info->AllocationSize = pSMBr->AllocationSize;
+                       pfile_info->EndOfFile = pSMBr->EndOfFile;
+                       pfile_info->NumberOfLinks = cpu_to_le32(1);
+                       pfile_info->DeletePending = 0;
                }
        }
 
@@ -1399,8 +1328,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
        cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
        if (tcon->ses->capabilities & CAP_LARGE_FILES)
                wct = 12;
-       else
+       else {
                wct = 10; /* old style read */
+               if ((lseek >> 32) > 0)  {
+                       /* can not handle this big offset for old */
+                       return -EIO;
+               }
+       }
 
        *nbytes = 0;
        rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
@@ -1416,8 +1350,6 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
        pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
        if (wct == 12)
                pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
-       else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
-               return -EIO;
 
        pSMB->Remaining = 0;
        pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
@@ -1498,14 +1430,19 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        __u32 bytes_sent;
        __u16 byte_count;
 
-       /* cFYI(1,("write at %lld %d bytes",offset,count));*/
+       /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
        if (tcon->ses == NULL)
                return -ECONNABORTED;
 
        if (tcon->ses->capabilities & CAP_LARGE_FILES)
                wct = 14;
-       else
+       else {
                wct = 12;
+               if ((offset >> 32) > 0) {
+                       /* can not handle big offset for old srv */
+                       return -EIO;
+               }
+       }
 
        rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
                      (void **) &pSMBr);
@@ -1520,8 +1457,6 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
        if (wct == 14)
                pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
-       else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
-               return -EIO;
 
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
@@ -1543,7 +1478,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        pSMB->DataOffset =
                cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
        if (buf)
-           memcpy(pSMB->Data, buf, bytes_sent);
+               memcpy(pSMB->Data, buf, bytes_sent);
        else if (ubuf) {
                if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
                        cifs_buf_release(pSMB);
@@ -1556,9 +1491,9 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        } /* else setting file size with write of zero bytes */
        if (wct == 14)
                byte_count = bytes_sent + 1; /* pad */
-       else /* wct == 12 */ {
+       else /* wct == 12 */
                byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
-       }
+
        pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
        pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
        pSMB->hdr.smb_buf_length += byte_count;
@@ -1604,12 +1539,19 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        int smb_hdr_len;
        int resp_buf_type = 0;
 
+       *nbytes = 0;
+
        cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
 
-       if (tcon->ses->capabilities & CAP_LARGE_FILES)
+       if (tcon->ses->capabilities & CAP_LARGE_FILES) {
                wct = 14;
-       else
+       } else {
                wct = 12;
+               if ((offset >> 32) > 0) {
+                       /* can not handle big offset for old srv */
+                       return -EIO;
+               }
+       }
        rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
        if (rc)
                return rc;
@@ -1622,8 +1564,6 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
        if (wct == 14)
                pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
-       else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
-               return -EIO;
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
        pSMB->Remaining = 0;
@@ -1657,13 +1597,11 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
        cifs_stats_inc(&tcon->num_writes);
        if (rc) {
                cFYI(1, ("Send error Write2 = %d", rc));
-               *nbytes = 0;
        } else if (resp_buf_type == 0) {
                /* presumably this can not happen, but best to be safe */
                rc = -EIO;
-               *nbytes = 0;
        } else {
-               WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
+               WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
                *nbytes = le16_to_cpu(pSMBr->CountHigh);
                *nbytes = (*nbytes) << 16;
                *nbytes += le16_to_cpu(pSMBr->Count);
@@ -1686,27 +1624,25 @@ 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, ("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 = CIFS_ASYNC_OP; /* no response expected */
                pSMB->Timeout = 0;
-       } else if (waitFlag == TRUE) {
+       } else if (waitFlag) {
                timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
                pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
        } else {
@@ -1736,7 +1672,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
 
        if (waitFlag) {
                rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
-                       (struct smb_hdr *) pSMBr, &bytes_returned);
+                       (struct smb_hdr *) pSMB, &bytes_returned);
                cifs_small_buf_release(pSMB);
        } else {
                rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
@@ -1744,9 +1680,8 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
                /* SMB buffer freed by function above */
        }
        cifs_stats_inc(&tcon->num_locks);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Send error in Lock = %d", rc));
-       }
 
        /* Note: On -EAGAIN error only caller can retry on handle based calls
        since file handle passed in no longer valid */
@@ -1757,7 +1692,7 @@ int
 CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                const __u16 smb_file_id, const int get_flag, const __u64 len,
                struct file_lock *pLockData, const __u16 lock_type,
-               const int waitFlag)
+               const bool waitFlag)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
@@ -1772,7 +1707,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
        cFYI(1, ("Posix Lock"));
 
        if (pLockData == NULL)
-               return EINVAL;
+               return -EINVAL;
 
        rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
 
@@ -1791,7 +1726,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
 
        count = sizeof(struct cifs_posix_lock);
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        if (get_flag)
@@ -1850,10 +1785,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                        rc = -EIO;      /* bad smb */
                        goto plk_err_exit;
                }
-               if (pLockData == NULL) {
-                       rc = -EINVAL;
-                       goto plk_err_exit;
-               }
                data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
                data_count  = le16_to_cpu(pSMBr->t2.DataCount);
                if (data_count < sizeof(struct cifs_posix_lock)) {
@@ -1916,6 +1847,27 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 }
 
 int
+CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
+{
+       int rc = 0;
+       FLUSH_REQ *pSMB = NULL;
+       cFYI(1, ("In CIFSSMBFlush"));
+
+       rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
+       if (rc)
+               return rc;
+
+       pSMB->FileID = (__u16) smb_file_id;
+       pSMB->ByteCount = 0;
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       cifs_stats_inc(&tcon->num_flushes);
+       if (rc)
+               cERROR(1, ("Send error in Flush = %d", rc));
+
+       return rc;
+}
+
+int
 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
              const char *fromName, const char *toName,
              const struct nls_table *nls_codepage, int remap)
@@ -1949,7 +1901,7 @@ renameRetry:
        /* protocol requires ASCII signature byte on Unicode string */
                pSMB->OldFileName[name_len + 1] = 0x00;
                name_len2 =
-                   cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
+                   cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
                                     toName, PATH_MAX, nls_codepage, remap);
                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
                name_len2 *= 2; /* convert to bytes */
@@ -1972,9 +1924,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);
 
@@ -1985,7 +1936,7 @@ renameRetry:
 }
 
 int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
-               int netfid, char *target_name,
+               int netfid, const char *target_name,
                const struct nls_table *nls_codepage, int remap)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
@@ -2016,7 +1967,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);
@@ -2039,7 +1990,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
                                        remap);
        }
        rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
-       count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
+       count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
        byte_count += count;
        pSMB->DataCount = cpu_to_le16(count);
        pSMB->TotalDataCount = pSMB->DataCount;
@@ -2052,9 +2003,8 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
        rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        cifs_stats_inc(&pTcon->num_t2renames);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
-       }
 
        cifs_buf_release(pSMB);
 
@@ -2124,8 +2074,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;
@@ -2211,12 +2160,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) {
+       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;
@@ -2299,9 +2246,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)
@@ -2344,8 +2290,10 @@ winCreateHardLinkRetry:
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-               pSMB->OldFileName[name_len] = 0;        /* pad */
-               pSMB->OldFileName[name_len + 1] = 0x04;
+
+               /* protocol specifies ASCII buffer format (0x04) for unicode */
+               pSMB->OldFileName[name_len] = 0x04;
+               pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
                name_len2 =
                    cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
                                     toName, PATH_MAX, nls_codepage, remap);
@@ -2370,9 +2318,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;
@@ -2382,8 +2330,7 @@ winCreateHardLinkRetry:
 
 int
 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
-                       const unsigned char *searchName,
-                       char *symlinkinfo, const int buflen,
+                       const unsigned char *searchName, char **symlinkinfo,
                        const struct nls_table *nls_codepage)
 {
 /* SMB_QUERY_FILE_UNIX_LINK */
@@ -2393,6 +2340,7 @@ CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
        int bytes_returned;
        int name_len;
        __u16 params, byte_count;
+       char *data_start;
 
        cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
 
@@ -2417,8 +2365,7 @@ querySymLinkRetry:
        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 */
-       pSMB->MaxDataCount = cpu_to_le16(4000);
+       pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -2447,30 +2394,26 @@ querySymLinkRetry:
                /* decode response */
 
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-               if (rc || (pSMBr->ByteCount < 2))
                /* BB also check enough total bytes returned */
-                       rc = -EIO;      /* bad smb */
+               if (rc || (pSMBr->ByteCount < 2))
+                       rc = -EIO;
                else {
-                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+                       bool is_unicode;
+                       u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+
+                       data_start = ((char *) &pSMBr->hdr.Protocol) +
+                                          le16_to_cpu(pSMBr->t2.DataOffset);
+
+                       if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+                               is_unicode = true;
+                       else
+                               is_unicode = false;
 
-                       if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-                               name_len = UniStrnlen((wchar_t *) ((char *)
-                                       &pSMBr->hdr.Protocol + data_offset),
-                                       min_t(const int, buflen, count) / 2);
                        /* BB FIXME investigate remapping reserved chars here */
-                               cifs_strfromUCS_le(symlinkinfo,
-                                       (__le16 *) ((char *)&pSMBr->hdr.Protocol
-                                                       + data_offset),
-                                       name_len, nls_codepage);
-                       } else {
-                               strncpy(symlinkinfo,
-                                       (char *) &pSMBr->hdr.Protocol +
-                                               data_offset,
-                                       min_t(const int, buflen, count));
-                       }
-                       symlinkinfo[buflen] = 0;
-       /* just in case so calling code does not go off the end of buffer */
+                       *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
+                                                   is_unicode, nls_codepage);
+                       if (!*symlinkinfo)
+                               rc = -ENOMEM;
                }
        }
        cifs_buf_release(pSMB);
@@ -2568,7 +2511,6 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata,
        *pparmlen = parm_count;
        return 0;
 }
-#endif /* CIFS_EXPERIMENTAL */
 
 int
 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
@@ -2578,7 +2520,6 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
 {
        int rc = 0;
        int bytes_returned;
-       int name_len;
        struct smb_com_transaction_ioctl_req *pSMB;
        struct smb_com_transaction_ioctl_rsp *pSMBr;
 
@@ -2615,59 +2556,55 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
        } else {                /* decode response */
                __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
                __u32 data_count = le32_to_cpu(pSMBr->DataCount);
-               if ((pSMBr->ByteCount < 2) || (data_offset > 512))
+               if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
                /* BB also check enough total bytes returned */
                        rc = -EIO;      /* bad smb */
-               else {
-                       if (data_count && (data_count < 2048)) {
-                               char *end_of_smb = 2 /* sizeof byte count */ +
-                                               pSMBr->ByteCount +
-                                               (char *)&pSMBr->ByteCount;
+                       goto qreparse_out;
+               }
+               if (data_count && (data_count < 2048)) {
+                       char *end_of_smb = 2 /* sizeof byte count */ +
+                               pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
 
-                               struct reparse_data *reparse_buf =
+                       struct reparse_data *reparse_buf =
                                                (struct reparse_data *)
                                                ((char *)&pSMBr->hdr.Protocol
                                                                 + data_offset);
-                               if ((char *)reparse_buf >= end_of_smb) {
-                                       rc = -EIO;
-                                       goto qreparse_out;
-                               }
-                               if ((reparse_buf->LinkNamesBuf +
-                                       reparse_buf->TargetNameOffset +
-                                       reparse_buf->TargetNameLen) >
-                                               end_of_smb) {
-                                       cFYI(1, ("reparse buf beyond SMB"));
-                                       rc = -EIO;
-                                       goto qreparse_out;
-                               }
+                       if ((char *)reparse_buf >= end_of_smb) {
+                               rc = -EIO;
+                               goto qreparse_out;
+                       }
+                       if ((reparse_buf->LinkNamesBuf +
+                               reparse_buf->TargetNameOffset +
+                               reparse_buf->TargetNameLen) > end_of_smb) {
+                               cFYI(1, ("reparse buf beyond SMB"));
+                               rc = -EIO;
+                               goto qreparse_out;
+                       }
 
-                               if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-                                       name_len = UniStrnlen((wchar_t *)
+                       if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+                               cifs_from_ucs2(symlinkinfo, (__le16 *)
                                                (reparse_buf->LinkNamesBuf +
                                                reparse_buf->TargetNameOffset),
-                                               min(buflen/2,
-                                               reparse_buf->TargetNameLen / 2));
-                                       cifs_strfromUCS_le(symlinkinfo,
-                                               (__le16 *) (reparse_buf->LinkNamesBuf +
-                                               reparse_buf->TargetNameOffset),
-                                               name_len, nls_codepage);
-                               } else { /* ASCII names */
-                                       strncpy(symlinkinfo,
-                                               reparse_buf->LinkNamesBuf +
-                                               reparse_buf->TargetNameOffset,
-                                               min_t(const int, buflen,
-                                                  reparse_buf->TargetNameLen));
-                               }
-                       } else {
-                               rc = -EIO;
-                               cFYI(1, ("Invalid return data count on "
-                                        "get reparse info ioctl"));
+                                               buflen,
+                                               reparse_buf->TargetNameLen,
+                                               nls_codepage, 0);
+                       } else { /* ASCII names */
+                               strncpy(symlinkinfo,
+                                       reparse_buf->LinkNamesBuf +
+                                       reparse_buf->TargetNameOffset,
+                                       min_t(const int, buflen,
+                                          reparse_buf->TargetNameLen));
                        }
-                       symlinkinfo[buflen] = 0; /* just in case so the caller
-                                       does not go off the end of the buffer */
-                       cFYI(1, ("readlink result - %s", symlinkinfo));
+               } else {
+                       rc = -EIO;
+                       cFYI(1, ("Invalid return data count on "
+                                "get reparse info ioctl"));
                }
+               symlinkinfo[buflen] = 0; /* just in case so the caller
+                                       does not go off the end of the buffer */
+               cFYI(1, ("readlink result - %s", symlinkinfo));
        }
+
 qreparse_out:
        cifs_buf_release(pSMB);
 
@@ -2676,6 +2613,7 @@ qreparse_out:
 
        return rc;
 }
+#endif /* CIFS_EXPERIMENTAL */
 
 #ifdef CONFIG_CIFS_POSIX
 
@@ -2934,7 +2872,8 @@ setAclRetry:
        }
        params = 6 + name_len;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
+       /* BB find max SMB size from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -2968,9 +2907,8 @@ setAclRetry:
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Set POSIX ACL returned %d", rc));
-       }
 
 setACLerrorExit:
        cifs_buf_release(pSMB);
@@ -2982,7 +2920,7 @@ setACLerrorExit:
 /* BB fix tabs in this function FIXME BB */
 int
 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
-              const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
+              const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
 {
        int rc = 0;
        struct smb_t2_qfi_req *pSMB = NULL;
@@ -3000,7 +2938,7 @@ GetExtAttrRetry:
        if (rc)
                return rc;
 
-       params = 2 /* level */ +2 /* fid */;
+       params = 2 /* level */ + 2 /* fid */;
        pSMB->t2.TotalDataCount = 0;
        pSMB->t2.MaxParameterCount = cpu_to_le16(4);
        /* BB find exact max data count below from sess structure BB */
@@ -3071,7 +3009,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
 {
        int rc = 0;
        int buf_type = 0;
-       QUERY_SEC_DESC_REQ * pSMB;
+       QUERY_SEC_DESC_REQ *pSMB;
        struct kvec iov[1];
 
        cFYI(1, ("GetCifsACL"));
@@ -3101,7 +3039,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
        if (rc) {
                cFYI(1, ("Send error in QuerySecDesc = %d", rc));
        } else {                /* decode response */
-               __le32 * parm;
+               __le32 *parm;
                __u32 parm_len;
                __u32 acl_len;
                struct smb_com_ntransact_rsp *pSMBr;
@@ -3156,6 +3094,71 @@ qsec_out:
 /*     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;
+
+       return (rc);
+}
+
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 
 /* Legacy Query Path Information call for lookup to old servers such
@@ -3165,8 +3168,8 @@ int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
                        FILE_ALL_INFO *pFinfo,
                        const struct nls_table *nls_codepage, int remap)
 {
-       QUERY_INFORMATION_REQ * pSMB;
-       QUERY_INFORMATION_RSP * pSMBr;
+       QUERY_INFORMATION_REQ *pSMB;
+       QUERY_INFORMATION_RSP *pSMBr;
        int rc = 0;
        int bytes_returned;
        int name_len;
@@ -3198,9 +3201,11 @@ QInfRetry:
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
                cFYI(1, ("Send error in QueryInfo = %d", rc));
-       } else if (pFinfo) {            /* decode response */
+       } else if (pFinfo) {
                struct timespec ts;
                __u32 time = le32_to_cpu(pSMBr->last_write_time);
+
+               /* decode response */
                /* BB FIXME - add time zone adjustment BB */
                memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
                ts.tv_nsec = 0;
@@ -3231,7 +3236,7 @@ QInfRetry:
 int
 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
                 const unsigned char *searchName,
-                FILE_ALL_INFO * pFindData,
+                FILE_ALL_INFO *pFindData,
                 int legacy /* old style infolevel */,
                 const struct nls_table *nls_codepage, int remap)
 {
@@ -3265,7 +3270,8 @@ QPathInfoRetry:
        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(4000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -3306,10 +3312,12 @@ QPathInfoRetry:
                else if (pFindData) {
                        int size;
                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       if (legacy) /* we do not read the last field, EAsize,
-                                      fortunately since it varies by subdialect
-                                      and on Set vs. Get, is two bytes or 4
-                                      bytes depending but we don't care here */
+
+                       /* On legacy responses we do not read the last field,
+                       EAsize, fortunately since it varies by subdialect and
+                       also note it differs on Set vs. Get, ie two bytes or 4
+                       bytes depending but we don't care here */
+                       if (legacy)
                                size = sizeof(FILE_INFO_STANDARD);
                        else
                                size = sizeof(FILE_ALL_INFO);
@@ -3329,7 +3337,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 */
@@ -3411,85 +3419,6 @@ UnixQPathInfoRetry:
        return rc;
 }
 
-#if 0  /* function unused at present */
-int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
-              const char *searchName, FILE_ALL_INFO * findData,
-              const struct nls_table *nls_codepage)
-{
-/* level 257 SMB_ */
-       TRANSACTION2_FFIRST_REQ *pSMB = NULL;
-       TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
-       int rc = 0;
-       int bytes_returned;
-       int name_len;
-       __u16 params, byte_count;
-
-       cFYI(1, ("In FindUnique"));
-findUniqueRetry:
-       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
-                     (void **) &pSMBr);
-       if (rc)
-               return rc;
-
-       if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-               name_len =
-                   cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
-                                    PATH_MAX, nls_codepage);
-               name_len++;     /* trailing null */
-               name_len *= 2;
-       } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(searchName, PATH_MAX);
-               name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, searchName, name_len);
-       }
-
-       params = 12 + name_len /* includes null */ ;
-       pSMB->TotalDataCount = 0;       /* no EAs */
-       pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
-       pSMB->MaxSetupCount = 0;
-       pSMB->Reserved = 0;
-       pSMB->Flags = 0;
-       pSMB->Timeout = 0;
-       pSMB->Reserved2 = 0;
-       pSMB->ParameterOffset = cpu_to_le16(
-        offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
-       pSMB->DataCount = 0;
-       pSMB->DataOffset = 0;
-       pSMB->SetupCount = 1;   /* one byte, no need to le convert */
-       pSMB->Reserved3 = 0;
-       pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
-       byte_count = params + 1 /* pad */ ;
-       pSMB->TotalParameterCount = cpu_to_le16(params);
-       pSMB->ParameterCount = pSMB->TotalParameterCount;
-       pSMB->SearchAttributes =
-           cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
-                       ATTR_DIRECTORY);
-       pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
-       pSMB->SearchFlags = cpu_to_le16(1);
-       pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
-       pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
-       pSMB->hdr.smb_buf_length += byte_count;
-       pSMB->ByteCount = cpu_to_le16(byte_count);
-
-       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-
-       if (rc) {
-               cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
-       } else {                /* decode response */
-               cifs_stats_inc(&tcon->num_ffirst);
-               /* BB fill in */
-       }
-
-       cifs_buf_release(pSMB);
-       if (rc == -EAGAIN)
-               goto findUniqueRetry;
-
-       return rc;
-}
-#endif /* end unused (temporarily) function */
-
 /* xid, tcon, searchName and codepage are input parms, rest are returned */
 int
 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
@@ -3501,7 +3430,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
 /* level 257 SMB_ */
        TRANSACTION2_FFIRST_REQ *pSMB = NULL;
        TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
-       T2_FFIRST_RSP_PARMS * parms;
+       T2_FFIRST_RSP_PARMS *parms;
        int rc = 0;
        int bytes_returned = 0;
        int name_len;
@@ -3596,10 +3525,12 @@ findFirstRetry:
                /* BB remember to free buffer if error BB */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
                if (rc == 0) {
+                       unsigned int lnoff;
+
                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
-                               psrch_inf->unicode = TRUE;
+                               psrch_inf->unicode = true;
                        else
-                               psrch_inf->unicode = FALSE;
+                               psrch_inf->unicode = false;
 
                        psrch_inf->ntwrk_buf_start = (char *)pSMBr;
                        psrch_inf->smallBuf = 0;
@@ -3610,14 +3541,25 @@ findFirstRetry:
                               le16_to_cpu(pSMBr->t2.ParameterOffset));
 
                        if (parms->EndofSearch)
-                               psrch_inf->endOfSearch = TRUE;
+                               psrch_inf->endOfSearch = true;
                        else
-                               psrch_inf->endOfSearch = FALSE;
+                               psrch_inf->endOfSearch = false;
 
                        psrch_inf->entries_in_buffer =
                                        le16_to_cpu(parms->SearchCount);
                        psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
                                psrch_inf->entries_in_buffer;
+                       lnoff = le16_to_cpu(parms->LastNameOffset);
+                       if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
+                             lnoff) {
+                               cERROR(1, ("ignoring corrupt resume name"));
+                               psrch_inf->last_entry = NULL;
+                               return rc;
+                       }
+
+                       psrch_inf->last_entry = psrch_inf->srch_entries_start +
+                                                       lnoff;
+
                        *pnetfid = parms->SearchHandle;
                } else {
                        cifs_buf_release(pSMB);
@@ -3632,7 +3574,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
 {
        TRANSACTION2_FNEXT_REQ *pSMB = NULL;
        TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
-       T2_FNEXT_RSP_PARMS * parms;
+       T2_FNEXT_RSP_PARMS *parms;
        char *response_data;
        int rc = 0;
        int bytes_returned, name_len;
@@ -3640,7 +3582,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,
@@ -3698,7 +3640,8 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
        cifs_stats_inc(&tcon->num_fnext);
        if (rc) {
                if (rc == -EBADF) {
-                       psrch_inf->endOfSearch = TRUE;
+                       psrch_inf->endOfSearch = true;
+                       cifs_buf_release(pSMB);
                        rc = 0; /* search probably was closed at end of search*/
                } else
                        cFYI(1, ("FindNext returned = %d", rc));
@@ -3706,11 +3649,13 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
                if (rc == 0) {
+                       unsigned int lnoff;
+
                        /* BB fixme add lock for file (srch_info) struct here */
                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
-                               psrch_inf->unicode = TRUE;
+                               psrch_inf->unicode = true;
                        else
-                               psrch_inf->unicode = FALSE;
+                               psrch_inf->unicode = false;
                        response_data = (char *) &pSMBr->hdr.Protocol +
                               le16_to_cpu(pSMBr->t2.ParameterOffset);
                        parms = (T2_FNEXT_RSP_PARMS *)response_data;
@@ -3725,13 +3670,23 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                        psrch_inf->ntwrk_buf_start = (char *)pSMB;
                        psrch_inf->smallBuf = 0;
                        if (parms->EndofSearch)
-                               psrch_inf->endOfSearch = TRUE;
+                               psrch_inf->endOfSearch = true;
                        else
-                               psrch_inf->endOfSearch = FALSE;
+                               psrch_inf->endOfSearch = false;
                        psrch_inf->entries_in_buffer =
                                                le16_to_cpu(parms->SearchCount);
                        psrch_inf->index_of_last_entry +=
                                psrch_inf->entries_in_buffer;
+                       lnoff = le16_to_cpu(parms->LastNameOffset);
+                       if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
+                             lnoff) {
+                               cERROR(1, ("ignoring corrupt resume name"));
+                               psrch_inf->last_entry = NULL;
+                               return rc;
+                       } else
+                               psrch_inf->last_entry =
+                                       psrch_inf->srch_entries_start + lnoff;
+
 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
            psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
 
@@ -3771,9 +3726,9 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
        pSMB->FileID = searchHandle;
        pSMB->ByteCount = 0;
        rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
-       if (rc) {
+       if (rc)
                cERROR(1, ("Send error in FindClose = %d", rc));
-       }
+
        cifs_stats_inc(&tcon->num_fclose);
 
        /* Since session is dead, search handle closed on server already */
@@ -3786,7 +3741,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
 int
 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
                      const unsigned char *searchName,
-                     __u64 * inode_number,
+                     __u64 *inode_number,
                      const struct nls_table *nls_codepage, int remap)
 {
        int rc = 0;
@@ -3866,7 +3821,7 @@ GetInodeNumberRetry:
                        }
                        pfinfo = (struct file_internal_info *)
                                (data_offset + (char *) &pSMBr->hdr.Protocol);
-                       *inode_number = pfinfo->UniqueId;
+                       *inode_number = le64_to_cpu(pfinfo->UniqueId);
                }
        }
 GetInodeNumOut:
@@ -3876,25 +3831,131 @@ GetInodeNumOut:
        return rc;
 }
 
+/* parses DFS refferal V3 structure
+ * caller is responsible for freeing target_nodes
+ * returns:
+ *     on success - 0
+ *     on failure - errno
+ */
+static int
+parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
+               unsigned int *num_of_nodes,
+               struct dfs_info3_param **target_nodes,
+               const struct nls_table *nls_codepage, int remap,
+               const char *searchName)
+{
+       int i, rc = 0;
+       char *data_end;
+       bool is_unicode;
+       struct dfs_referral_level_3 *ref;
+
+       if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+               is_unicode = true;
+       else
+               is_unicode = false;
+       *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
+
+       if (*num_of_nodes < 1) {
+               cERROR(1, ("num_referrals: must be at least > 0,"
+                       "but we get num_referrals = %d\n", *num_of_nodes));
+               rc = -EINVAL;
+               goto parse_DFS_referrals_exit;
+       }
+
+       ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
+       if (ref->VersionNumber != cpu_to_le16(3)) {
+               cERROR(1, ("Referrals of V%d version are not supported,"
+                       "should be V3", le16_to_cpu(ref->VersionNumber)));
+               rc = -EINVAL;
+               goto parse_DFS_referrals_exit;
+       }
+
+       /* get the upper boundary of the resp buffer */
+       data_end = (char *)(&(pSMBr->PathConsumed)) +
+                               le16_to_cpu(pSMBr->t2.DataCount);
+
+       cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
+                       *num_of_nodes,
+                       le32_to_cpu(pSMBr->DFSFlags)));
+
+       *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
+                       *num_of_nodes, GFP_KERNEL);
+       if (*target_nodes == NULL) {
+               cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
+               rc = -ENOMEM;
+               goto parse_DFS_referrals_exit;
+       }
+
+       /* collect neccessary data from referrals */
+       for (i = 0; i < *num_of_nodes; i++) {
+               char *temp;
+               int max_len;
+               struct dfs_info3_param *node = (*target_nodes)+i;
+
+               node->flags = le32_to_cpu(pSMBr->DFSFlags);
+               if (is_unicode) {
+                       __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
+                                               GFP_KERNEL);
+                       if (tmp == NULL) {
+                               rc = -ENOMEM;
+                               goto parse_DFS_referrals_exit;
+                       }
+                       cifsConvertToUCS((__le16 *) tmp, searchName,
+                                       PATH_MAX, nls_codepage, remap);
+                       node->path_consumed = cifs_ucs2_bytes(tmp,
+                                       le16_to_cpu(pSMBr->PathConsumed),
+                                       nls_codepage);
+                       kfree(tmp);
+               } else
+                       node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
+
+               node->server_type = le16_to_cpu(ref->ServerType);
+               node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
+
+               /* copy DfsPath */
+               temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
+               max_len = data_end - temp;
+               node->path_name = cifs_strndup_from_ucs(temp, max_len,
+                                                     is_unicode, nls_codepage);
+               if (!node->path_name) {
+                       rc = -ENOMEM;
+                       goto parse_DFS_referrals_exit;
+               }
+
+               /* copy link target UNC */
+               temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
+               max_len = data_end - temp;
+               node->node_name = cifs_strndup_from_ucs(temp, max_len,
+                                                     is_unicode, nls_codepage);
+               if (!node->node_name)
+                       rc = -ENOMEM;
+       }
+
+parse_DFS_referrals_exit:
+       if (rc) {
+               free_dfs_info_array(*target_nodes, *num_of_nodes);
+               *target_nodes = NULL;
+               *num_of_nodes = 0;
+       }
+       return rc;
+}
+
 int
 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
                const unsigned char *searchName,
-               unsigned char **targetUNCs,
-               unsigned int *number_of_UNC_in_array,
+               struct dfs_info3_param **target_nodes,
+               unsigned int *num_of_nodes,
                const struct nls_table *nls_codepage, int remap)
 {
 /* TRANS2_GET_DFS_REFERRAL */
        TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
        TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
-       struct dfs_referral_level_3 *referrals = NULL;
        int rc = 0;
        int bytes_returned;
        int name_len;
-       unsigned int i;
-       char *temp;
        __u16 params, byte_count;
-       *number_of_UNC_in_array = 0;
-       *targetUNCs = NULL;
+       *num_of_nodes = 0;
+       *target_nodes = NULL;
 
        cFYI(1, ("In GetDFSRefer the path %s", searchName));
        if (ses == NULL)
@@ -3941,7 +4002,8 @@ getDFSRetry:
        pSMB->DataCount = 0;
        pSMB->DataOffset = 0;
        pSMB->MaxParameterCount = 0;
-       pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(4000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -3963,103 +4025,27 @@ getDFSRetry:
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
                cFYI(1, ("Send error in GetDFSRefer = %d", rc));
-       } else {                /* decode response */
-/* BB Add logic to parse referrals here */
-               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+               goto GetDFSRefExit;
+       }
+       rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-               /* BB Also check if enough total bytes returned? */
-               if (rc || (pSMBr->ByteCount < 17))
-                       rc = -EIO;      /* bad smb */
-               else {
-                       __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-                       __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
+       /* BB Also check if enough total bytes returned? */
+       if (rc || (pSMBr->ByteCount < 17)) {
+               rc = -EIO;      /* bad smb */
+               goto GetDFSRefExit;
+       }
 
-                       cFYI(1,
-                           ("Decoding GetDFSRefer response BCC: %d  Offset %d",
-                             pSMBr->ByteCount, data_offset));
-                       referrals =
-                           (struct dfs_referral_level_3 *)
-                                       (8 /* sizeof start of data block */ +
-                                       data_offset +
-                                       (char *) &pSMBr->hdr.Protocol);
-                       cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
-                               "for referral one refer size: 0x%x srv "
-                               "type: 0x%x refer flags: 0x%x ttl: 0x%x",
-                               le16_to_cpu(pSMBr->NumberOfReferrals),
-                               le16_to_cpu(pSMBr->DFSFlags),
-                               le16_to_cpu(referrals->ReferralSize),
-                               le16_to_cpu(referrals->ServerType),
-                               le16_to_cpu(referrals->ReferralFlags),
-                               le16_to_cpu(referrals->TimeToLive)));
-                       /* BB This field is actually two bytes in from start of
-                          data block so we could do safety check that DataBlock
-                          begins at address of pSMBr->NumberOfReferrals */
-                       *number_of_UNC_in_array =
-                                       le16_to_cpu(pSMBr->NumberOfReferrals);
-
-                       /* BB Fix below so can return more than one referral */
-                       if (*number_of_UNC_in_array > 1)
-                               *number_of_UNC_in_array = 1;
-
-                       /* get the length of the strings describing refs */
-                       name_len = 0;
-                       for (i = 0; i < *number_of_UNC_in_array; i++) {
-                               /* make sure that DfsPathOffset not past end */
-                               __u16 offset =
-                                       le16_to_cpu(referrals->DfsPathOffset);
-                               if (offset > data_count) {
-                                       /* if invalid referral, stop here and do
-                                       not try to copy any more */
-                                       *number_of_UNC_in_array = i;
-                                       break;
-                               }
-                               temp = ((char *)referrals) + offset;
+       cFYI(1, ("Decoding GetDFSRefer response BCC: %d  Offset %d",
+                               pSMBr->ByteCount,
+                               le16_to_cpu(pSMBr->t2.DataOffset)));
 
-                               if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-                                       name_len += UniStrnlen((wchar_t *)temp,
-                                                               data_count);
-                               } else {
-                                       name_len += strnlen(temp, data_count);
-                               }
-                               referrals++;
-                               /* BB add check that referral pointer does
-                                  not fall off end PDU */
-                       }
-                       /* BB add check for name_len bigger than bcc */
-                       *targetUNCs =
-                               kmalloc(name_len+1+(*number_of_UNC_in_array),
-                                       GFP_KERNEL);
-                       if (*targetUNCs == NULL) {
-                               rc = -ENOMEM;
-                               goto GetDFSRefExit;
-                       }
-                       /* copy the ref strings */
-                       referrals = (struct dfs_referral_level_3 *)
-                                       (8 /* sizeof data hdr */ + data_offset +
-                                       (char *) &pSMBr->hdr.Protocol);
-
-                       for (i = 0; i < *number_of_UNC_in_array; i++) {
-                               temp = ((char *)referrals) +
-                                         le16_to_cpu(referrals->DfsPathOffset);
-                               if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-                                       cifs_strfromUCS_le(*targetUNCs,
-                                                         (__le16 *) temp,
-                                                         name_len,
-                                                         nls_codepage);
-                               } else {
-                                       strncpy(*targetUNCs, temp, name_len);
-                               }
-                               /*  BB update target_uncs pointers */
-                               referrals++;
-                       }
-                       temp = *targetUNCs;
-                       temp[name_len] = 0;
-               }
+       /* parse returned result into more usable form */
+       rc = parse_DFS_referrals(pSMBr, num_of_nodes,
+                                target_nodes, nls_codepage, remap,
+                                searchName);
 
-       }
 GetDFSRefExit:
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
 
        if (rc == -EAGAIN)
                goto getDFSRetry;
@@ -4249,7 +4235,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;
@@ -4318,7 +4305,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;
@@ -4389,7 +4377,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;
@@ -4464,7 +4453,8 @@ SETFSUnixRetry:
        offset = param_offset + params;
 
        pSMB->MaxParameterCount = cpu_to_le16(4);
-       pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(100);
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
@@ -4495,9 +4485,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);
 
@@ -4533,7 +4522,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;
@@ -4603,7 +4593,7 @@ QFSPosixRetry:
 
 int
 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-             __u64 size, int SetAllocation,
+             __u64 size, bool SetAllocation,
              const struct nls_table *nls_codepage, int remap)
 {
        struct smb_com_transaction2_spi_req *pSMB = NULL;
@@ -4679,9 +4669,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);
 
@@ -4693,7 +4682,7 @@ SetEOFRetry:
 
 int
 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
-                  __u16 fid, __u32 pid_of_opener, int SetAllocation)
+                  __u16 fid, __u32 pid_of_opener, bool SetAllocation)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        char *data_offset;
@@ -4724,7 +4713,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
 
        count = sizeof(struct file_end_of_file_info);
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->SetupCount = 1;
        pSMB->Reserved3 = 0;
        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
@@ -4778,8 +4768,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
    time and resort to the original setpathinfo level which takes the ancient
    DOS time format with 2 second granularity */
 int
-CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
-                   const FILE_BASIC_INFO *data, __u16 fid)
+CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+                   const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        char *data_offset;
@@ -4792,11 +4782,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
        if (rc)
                return rc;
 
-       /* At this point there is no need to override the current pid
-       with the pid of the opener, but that could change if we someday
-       use an existing handle (rather than opening one on the fly) */
-       /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
-       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
+       pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
 
        params = 6;
        pSMB->MaxSetupCount = 0;
@@ -4811,7 +4798,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
 
        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);
@@ -4832,9 +4820,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
        pSMB->ByteCount = cpu_to_le16(byte_count);
        memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
        rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
-       if (rc) {
+       if (rc)
                cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
-       }
 
        /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
@@ -4842,11 +4829,66 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
        return rc;
 }
 
+int
+CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
+                         bool delete_file, __u16 fid, __u32 pid_of_opener)
+{
+       struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+       char *data_offset;
+       int rc = 0;
+       __u16 params, param_offset, offset, byte_count, count;
+
+       cFYI(1, ("Set File Disposition (via SetFileInfo)"));
+       rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+       if (rc)
+               return rc;
+
+       pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
+
+       params = 6;
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+       offset = param_offset + params;
+
+       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+
+       count = 1;
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       /* BB find max SMB PDU from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+       byte_count = 3 /* pad */  + params + count;
+       pSMB->DataCount = cpu_to_le16(count);
+       pSMB->ParameterCount = cpu_to_le16(params);
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->ParameterOffset = cpu_to_le16(param_offset);
+       pSMB->DataOffset = cpu_to_le16(offset);
+       pSMB->Fid = fid;
+       pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
+       pSMB->Reserved4 = 0;
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->ByteCount = cpu_to_le16(byte_count);
+       *data_offset = delete_file ? 1 : 0;
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       if (rc)
+               cFYI(1, ("Send error in SetFileDisposition = %d", rc));
+
+       return rc;
+}
 
 int
-CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-               const FILE_BASIC_INFO *data,
-               const struct nls_table *nls_codepage, int remap)
+CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
+                  const char *fileName, const FILE_BASIC_INFO *data,
+                  const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
        TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -4879,7 +4921,8 @@ SetTimesRetry:
        params = 6 + name_len;
        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;
@@ -4910,9 +4953,8 @@ SetTimesRetry:
        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);
 
@@ -4962,9 +5004,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);
 
@@ -4975,11 +5016,114 @@ SetAttrLgcyRetry:
 }
 #endif /* temporarily unneeded SetAttr legacy function */
 
+static void
+cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
+                       const struct cifs_unix_set_info_args *args)
+{
+       u64 mode = args->mode;
+
+       /*
+        * 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 = cpu_to_le64(NO_CHANGE_64);
+       data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
+       data_offset->LastStatusChange = cpu_to_le64(args->ctime);
+       data_offset->LastAccessTime = cpu_to_le64(args->atime);
+       data_offset->LastModificationTime = cpu_to_le64(args->mtime);
+       data_offset->Uid = cpu_to_le64(args->uid);
+       data_offset->Gid = cpu_to_le64(args->gid);
+       /* better to leave device as zero when it is  */
+       data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
+       data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
+       data_offset->Permissions = cpu_to_le64(mode);
+
+       if (S_ISREG(mode))
+               data_offset->Type = cpu_to_le32(UNIX_FILE);
+       else if (S_ISDIR(mode))
+               data_offset->Type = cpu_to_le32(UNIX_DIR);
+       else if (S_ISLNK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
+       else if (S_ISCHR(mode))
+               data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
+       else if (S_ISBLK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
+       else if (S_ISFIFO(mode))
+               data_offset->Type = cpu_to_le32(UNIX_FIFO);
+       else if (S_ISSOCK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_SOCKET);
+}
+
+int
+CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+                      const struct cifs_unix_set_info_args *args,
+                      u16 fid, u32 pid_of_opener)
+{
+       struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+       FILE_UNIX_BASIC_INFO *data_offset;
+       int rc = 0;
+       u16 params, param_offset, offset, byte_count, count;
+
+       cFYI(1, ("Set Unix Info (via SetFileInfo)"));
+       rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+       if (rc)
+               return rc;
+
+       pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
+
+       params = 6;
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+       offset = param_offset + params;
+
+       data_offset = (FILE_UNIX_BASIC_INFO *)
+                               ((char *)(&pSMB->hdr.Protocol) + offset);
+       count = sizeof(FILE_UNIX_BASIC_INFO);
+
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       /* BB find max SMB PDU from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+       byte_count = 3 /* pad */  + params + count;
+       pSMB->DataCount = cpu_to_le16(count);
+       pSMB->ParameterCount = cpu_to_le16(params);
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->ParameterOffset = cpu_to_le16(param_offset);
+       pSMB->DataOffset = cpu_to_le16(offset);
+       pSMB->Fid = fid;
+       pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
+       pSMB->Reserved4 = 0;
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->ByteCount = cpu_to_le16(byte_count);
+
+       cifs_fill_unix_set_info(data_offset, args);
+
+       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
+               since file handle passed in no longer valid */
+
+       return rc;
+}
+
 int
-CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
-                   char *fileName, __u64 mode, __u64 uid, __u64 gid,
-                   dev_t device, const struct nls_table *nls_codepage,
-                   int remap)
+CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
+                      const struct cifs_unix_set_info_args *args,
+                      const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
        TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -5011,7 +5155,8 @@ setPermsRetry:
        params = 6 + name_len;
        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;
@@ -5037,48 +5182,16 @@ 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))
-               data_offset->Type = cpu_to_le32(UNIX_FILE);
-       else if (S_ISDIR(mode))
-               data_offset->Type = cpu_to_le32(UNIX_DIR);
-       else if (S_ISLNK(mode))
-               data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
-       else if (S_ISCHR(mode))
-               data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
-       else if (S_ISBLK(mode))
-               data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
-       else if (S_ISFIFO(mode))
-               data_offset->Type = cpu_to_le32(UNIX_FIFO);
-       else if (S_ISSOCK(mode))
-               data_offset->Type = cpu_to_le32(UNIX_SOCKET);
 
+       cifs_fill_unix_set_info(data_offset, args);
 
        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;
@@ -5195,7 +5308,8 @@ QAllEAsRetry:
        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(4000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -5299,8 +5413,7 @@ QAllEAsRetry:
                        }
                }
        }
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
                goto QAllEAsRetry;
 
@@ -5343,7 +5456,8 @@ QEARetry:
        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
        pSMB->TotalDataCount = 0;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+       /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxDataCount = cpu_to_le16(4000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -5448,8 +5562,7 @@ QEARetry:
                        }
                }
        }
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
                goto QEARetry;
 
@@ -5499,9 +5612,10 @@ SetEARetry:
        else
                name_len = strnlen(ea_name, 255);
 
-       count = sizeof(*parm_data) + ea_value_len + name_len + 1;
+       count = sizeof(*parm_data) + ea_value_len + name_len;
        pSMB->MaxParameterCount = cpu_to_le16(2);
-       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
+       /* BB find max SMB PDU from sess */
+       pSMB->MaxDataCount = cpu_to_le16(1000);
        pSMB->MaxSetupCount = 0;
        pSMB->Reserved = 0;
        pSMB->Flags = 0;
@@ -5550,9 +5664,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);