Merge branch 'kvm-updates-2.6.27' of git://git.kernel.org/pub/scm/linux/kernel/git...
[safe/jmp/linux-2.6] / fs / cifs / connect.c
index 58c509e..e8fa46c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/connect.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2007
+ *   Copyright (C) International Business Machines  Corp., 2002,2008
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -49,8 +49,6 @@
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
 
-static DECLARE_COMPLETION(cifsd_complete);
-
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
                         unsigned char *p24);
 
@@ -62,7 +60,7 @@ struct smb_vol {
        char *domainname;
        char *UNC;
        char *UNCip;
-       char *in6_addr;  /* ipv6 address as human readable form of in6_addr */
+       char *in6_addr;   /* ipv6 address as human readable form of in6_addr */
        char *iocharset;  /* local code page for mapping to and from Unicode */
        char source_rfc1001_name[16]; /* netbios name of client */
        char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
@@ -71,25 +69,27 @@ struct smb_vol {
        mode_t file_mode;
        mode_t dir_mode;
        unsigned secFlg;
-       unsigned rw:1;
-       unsigned retry:1;
-       unsigned intr:1;
-       unsigned setuids:1;
-       unsigned override_uid:1;
-       unsigned override_gid:1;
-       unsigned noperm:1;
-       unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
-       unsigned cifs_acl:1;
-       unsigned no_xattr:1;   /* set if xattr (EA) support should be disabled*/
-       unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
-       unsigned direct_io:1;
-       unsigned remap:1;   /* set to remap seven reserved chars in filenames */
-       unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */
-       unsigned no_linux_ext:1;
-       unsigned sfu_emul:1;
-       unsigned nullauth:1; /* attempt to authenticate with null user */
-       unsigned nocase;     /* request case insensitive filenames */
-       unsigned nobrl;      /* disable sending byte range locks to srv */
+       bool rw:1;
+       bool retry:1;
+       bool intr:1;
+       bool setuids:1;
+       bool override_uid:1;
+       bool override_gid:1;
+       bool dynperm:1;
+       bool noperm:1;
+       bool no_psx_acl:1; /* set if posix acl support should be disabled */
+       bool cifs_acl:1;
+       bool no_xattr:1;   /* set if xattr (EA) support should be disabled*/
+       bool server_ino:1; /* use inode numbers from server ie UniqueId */
+       bool direct_io:1;
+       bool remap:1;      /* set to remap seven reserved chars in filenames */
+       bool posix_paths:1; /* unset to not ask for posix pathnames. */
+       bool no_linux_ext:1;
+       bool sfu_emul:1;
+       bool nullauth:1;   /* attempt to authenticate with null user */
+       bool nocase:1;     /* request case insensitive filenames */
+       bool nobrl:1;      /* disable sending byte range locks to srv */
+       bool seal:1;       /* request transport encryption on share */
        unsigned int rsize;
        unsigned int wsize;
        unsigned int sockopt;
@@ -345,18 +345,16 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        struct task_struct *task_to_wake = NULL;
        struct mid_q_entry *mid_entry;
        char temp;
-       int isLargeBuf = FALSE;
-       int isMultiRsp;
+       bool isLargeBuf = false;
+       bool isMultiRsp;
        int reconnect;
 
        current->flags |= PF_MEMALLOC;
-       server->tsk = current;  /* save process info to wake at shutdown */
        cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
        write_lock(&GlobalSMBSeslock);
        atomic_inc(&tcpSesAllocCount);
        length = tcpSesAllocCount.counter;
        write_unlock(&GlobalSMBSeslock);
-       complete(&cifsd_complete);
        if (length  > 1)
                mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
                                GFP_KERNEL);
@@ -390,8 +388,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                } else /* if existing small buf clear beginning */
                        memset(smallbuf, 0, sizeof(struct smb_hdr));
 
-               isLargeBuf = FALSE;
-               isMultiRsp = FALSE;
+               isLargeBuf = false;
+               isMultiRsp = false;
                smb_buffer = smallbuf;
                iov.iov_base = smb_buffer;
                iov.iov_len = 4;
@@ -438,9 +436,9 @@ incomplete_rcv:
                        csocket = server->ssocket;
                        wake_up(&server->response_q);
                        continue;
-               } else if (length < 4) {
-                       cFYI(1, ("less than four bytes received (%d bytes)",
-                             length));
+               } else if (length < pdu_length) {
+                       cFYI(1, ("requested %d bytes but only got %d bytes",
+                                 pdu_length, length));
                        pdu_length -= length;
                        msleep(1);
                        goto incomplete_rcv;
@@ -517,7 +515,7 @@ incomplete_rcv:
                reconnect = 0;
 
                if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
-                       isLargeBuf = TRUE;
+                       isLargeBuf = true;
                        memcpy(bigbuf, smallbuf, 4);
                        smb_buffer = bigbuf;
                }
@@ -582,16 +580,18 @@ incomplete_rcv:
                            (mid_entry->command == smb_buffer->Command)) {
                                if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
                                        /* We have a multipart transact2 resp */
-                                       isMultiRsp = TRUE;
+                                       isMultiRsp = true;
                                        if (mid_entry->resp_buf) {
                                                /* merge response - fix up 1st*/
                                                if (coalesce_t2(smb_buffer,
                                                        mid_entry->resp_buf)) {
-                                                       mid_entry->multiRsp = 1;
+                                                       mid_entry->multiRsp =
+                                                                true;
                                                        break;
                                                } else {
                                                        /* all parts received */
-                                                       mid_entry->multiEnd = 1;
+                                                       mid_entry->multiEnd =
+                                                                true;
                                                        goto multi_t2_fnd;
                                                }
                                        } else {
@@ -603,17 +603,15 @@ incomplete_rcv:
                                                        /* Have first buffer */
                                                        mid_entry->resp_buf =
                                                                 smb_buffer;
-                                                       mid_entry->largeBuf = 1;
+                                                       mid_entry->largeBuf =
+                                                                true;
                                                        bigbuf = NULL;
                                                }
                                        }
                                        break;
                                }
                                mid_entry->resp_buf = smb_buffer;
-                               if (isLargeBuf)
-                                       mid_entry->largeBuf = 1;
-                               else
-                                       mid_entry->largeBuf = 0;
+                               mid_entry->largeBuf = isLargeBuf;
 multi_t2_fnd:
                                task_to_wake = mid_entry->tsk;
                                mid_entry->midState = MID_RESPONSE_RECEIVED;
@@ -638,8 +636,8 @@ multi_t2_fnd:
                                        smallbuf = NULL;
                        }
                        wake_up_process(task_to_wake);
-               } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
-                   && (isMultiRsp == FALSE)) {
+               } else if (!is_valid_oplock_break(smb_buffer, server) &&
+                          !isMultiRsp) {
                        cERROR(1, ("No task to wake, unknown frame received! "
                                   "NumMids %d", midCount.counter));
                        cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
@@ -654,10 +652,21 @@ multi_t2_fnd:
 
        spin_lock(&GlobalMid_Lock);
        server->tcpStatus = CifsExiting;
-       server->tsk = NULL;
+       spin_unlock(&GlobalMid_Lock);
+       wake_up_all(&server->response_q);
+
+       /* don't exit until kthread_stop is called */
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       while (!kthread_should_stop()) {
+               schedule();
+               set_current_state(TASK_UNINTERRUPTIBLE);
+       }
+       set_current_state(TASK_RUNNING);
+
        /* check if we have blocked requests that need to free */
        /* Note that cifs_max_pending is normally 50, but
        can be set at module install time to as little as two */
+       spin_lock(&GlobalMid_Lock);
        if (atomic_read(&server->inFlight) >= cifs_max_pending)
                atomic_set(&server->inFlight, cifs_max_pending - 1);
        /* We do not want to set the max_pending too low or we
@@ -752,6 +761,7 @@ multi_t2_fnd:
        }
        write_unlock(&GlobalSMBSeslock);
 
+       kfree(server->hostname);
        kfree(server);
        if (length  > 0)
                mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
@@ -760,6 +770,34 @@ multi_t2_fnd:
        return 0;
 }
 
+/* extract the host portion of the UNC string */
+static char *
+extract_hostname(const char *unc)
+{
+       const char *src;
+       char *dst, *delim;
+       unsigned int len;
+
+       /* skip double chars at beginning of string */
+       /* BB: check validity of these bytes? */
+       src = unc + 2;
+
+       /* delimiter between hostname and sharename is always '\\' now */
+       delim = strchr(src, '\\');
+       if (!delim)
+               return ERR_PTR(-EINVAL);
+
+       len = delim - src;
+       dst = kmalloc((len + 1), GFP_KERNEL);
+       if (dst == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       memcpy(dst, src, len);
+       dst[len] = '\0';
+
+       return dst;
+}
+
 static int
 cifs_parse_mount_options(char *options, const char *devname,
                         struct smb_vol *vol)
@@ -796,7 +834,7 @@ cifs_parse_mount_options(char *options, const char *devname,
        vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
 
        /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
-       vol->rw = TRUE;
+       vol->rw = true;
        /* default is always to request posix paths. */
        vol->posix_paths = 1;
 
@@ -1152,7 +1190,7 @@ cifs_parse_mount_options(char *options, const char *devname,
                } else if (strnicmp(data, "guest", 5) == 0) {
                        /* ignore */
                } else if (strnicmp(data, "rw", 2) == 0) {
-                       vol->rw = TRUE;
+                       vol->rw = true;
                } else if ((strnicmp(data, "suid", 4) == 0) ||
                                   (strnicmp(data, "nosuid", 6) == 0) ||
                                   (strnicmp(data, "exec", 4) == 0) ||
@@ -1168,7 +1206,7 @@ cifs_parse_mount_options(char *options, const char *devname,
                            is ok to just ignore them */
                        continue;
                } else if (strnicmp(data, "ro", 2) == 0) {
-                       vol->rw = FALSE;
+                       vol->rw = false;
                } else if (strnicmp(data, "hard", 4) == 0) {
                        vol->retry = 1;
                } else if (strnicmp(data, "soft", 4) == 0) {
@@ -1211,6 +1249,10 @@ cifs_parse_mount_options(char *options, const char *devname,
                        vol->setuids = 1;
                } else if (strnicmp(data, "nosetuids", 9) == 0) {
                        vol->setuids = 0;
+               } else if (strnicmp(data, "dynperm", 7) == 0) {
+                       vol->dynperm = true;
+               } else if (strnicmp(data, "nodynperm", 9) == 0) {
+                       vol->dynperm = false;
                } else if (strnicmp(data, "nohard", 6) == 0) {
                        vol->retry = 0;
                } else if (strnicmp(data, "nosoft", 6) == 0) {
@@ -1233,8 +1275,12 @@ cifs_parse_mount_options(char *options, const char *devname,
                        vol->no_psx_acl = 1;
                } else if (strnicmp(data, "sign", 4) == 0) {
                        vol->secFlg |= CIFSSEC_MUST_SIGN;
-/*             } else if (strnicmp(data, "seal",4) == 0) {
-                       vol->secFlg |= CIFSSEC_MUST_SEAL; */
+               } else if (strnicmp(data, "seal", 4) == 0) {
+                       /* we do not do the following in secFlags because seal
+                          is a per tree connection (mount) not a per socket
+                          or per-smb connection option in the protocol */
+                       /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
+                       vol->seal = 1;
                } else if (strnicmp(data, "direct", 6) == 0) {
                        vol->direct_io = 1;
                } else if (strnicmp(data, "forcedirectio", 13) == 0) {
@@ -1276,6 +1322,9 @@ cifs_parse_mount_options(char *options, const char *devname,
                                                    "begin with // or \\\\ \n");
                                return 1;
                        }
+                       value = strpbrk(vol->UNC+2, "/\\");
+                       if (value)
+                               *value = '\\';
                } else {
                        printk(KERN_WARNING "CIFS: UNC name too long\n");
                        return 1;
@@ -1289,42 +1338,43 @@ cifs_parse_mount_options(char *options, const char *devname,
 
 static struct cifsSesInfo *
 cifs_find_tcp_session(struct in_addr *target_ip_addr,
-               struct in6_addr *target_ip6_addr,
-                char *userName, struct TCP_Server_Info **psrvTcp)
+                     struct in6_addr *target_ip6_addr,
+                     char *userName, struct TCP_Server_Info **psrvTcp)
 {
        struct list_head *tmp;
        struct cifsSesInfo *ses;
+
        *psrvTcp = NULL;
-       read_lock(&GlobalSMBSeslock);
 
+       read_lock(&GlobalSMBSeslock);
        list_for_each(tmp, &GlobalSMBSessionList) {
                ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
-               if (ses->server) {
-                       if ((target_ip_addr &&
-                               (ses->server->addr.sockAddr.sin_addr.s_addr
-                                 == target_ip_addr->s_addr)) || (target_ip6_addr
-                               && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
-                                       target_ip6_addr, sizeof(*target_ip6_addr)))) {
-                               /* BB lock server and tcp session and increment
-                                     use count here?? */
-
-                               /* found a match on the TCP session */
-                               *psrvTcp = ses->server;
-
-                               /* BB check if reconnection needed */
-                               if (strncmp
-                                   (ses->userName, userName,
-                                    MAX_USERNAME_SIZE) == 0){
-                                       read_unlock(&GlobalSMBSeslock);
-                                       /* Found exact match on both TCP and
-                                          SMB sessions */
-                                       return ses;
-                               }
-                       }
+               if (!ses->server)
+                       continue;
+
+               if (target_ip_addr &&
+                   ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr)
+                               continue;
+               else if (target_ip6_addr &&
+                        memcmp(&ses->server->addr.sockAddr6.sin6_addr,
+                               target_ip6_addr, sizeof(*target_ip6_addr)))
+                               continue;
+               /* BB lock server and tcp session; increment use count here?? */
+
+               /* found a match on the TCP session */
+               *psrvTcp = ses->server;
+
+               /* BB check if reconnection needed */
+               if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) {
+                       read_unlock(&GlobalSMBSeslock);
+                       /* Found exact match on both TCP and
+                          SMB sessions */
+                       return ses;
                }
                /* else tcp and smb sessions need reconnection */
        }
        read_unlock(&GlobalSMBSeslock);
+
        return NULL;
 }
 
@@ -1333,79 +1383,57 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
 {
        struct list_head *tmp;
        struct cifsTconInfo *tcon;
+       __be32 old_ip;
 
        read_lock(&GlobalSMBSeslock);
+
        list_for_each(tmp, &GlobalTreeConnectionList) {
                cFYI(1, ("Next tcon"));
                tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
-               if (tcon->ses) {
-                       if (tcon->ses->server) {
-                               cFYI(1,
-                                    ("old ip addr: %x == new ip %x ?",
-                                     tcon->ses->server->addr.sockAddr.sin_addr.
-                                     s_addr, new_target_ip_addr));
-                               if (tcon->ses->server->addr.sockAddr.sin_addr.
-                                   s_addr == new_target_ip_addr) {
-       /* BB lock tcon, server and tcp session and increment use count here? */
-                                       /* found a match on the TCP session */
-                                       /* BB check if reconnection needed */
-                                       cFYI(1,
-                                             ("IP match, old UNC: %s new: %s",
-                                             tcon->treeName, uncName));
-                                       if (strncmp
-                                           (tcon->treeName, uncName,
-                                            MAX_TREE_SIZE) == 0) {
-                                               cFYI(1,
-                                                    ("and old usr: %s new: %s",
-                                                     tcon->treeName, uncName));
-                                               if (strncmp
-                                                   (tcon->ses->userName,
-                                                    userName,
-                                                    MAX_USERNAME_SIZE) == 0) {
-                                                       read_unlock(&GlobalSMBSeslock);
-                                                       /* matched smb session
-                                                       (user name */
-                                                       return tcon;
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-       read_unlock(&GlobalSMBSeslock);
-       return NULL;
-}
+               if (!tcon->ses || !tcon->ses->server)
+                       continue;
 
-int
-connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
-                   const char *old_path, const struct nls_table *nls_codepage,
-                   int remap)
-{
-       unsigned char *referrals = NULL;
-       unsigned int num_referrals;
-       int rc = 0;
+               old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr;
+               cFYI(1, ("old ip addr: %x == new ip %x ?",
+                       old_ip, new_target_ip_addr));
 
-       rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
-                       &num_referrals, &referrals, remap);
+               if (old_ip != new_target_ip_addr)
+                       continue;
 
-       /* BB Add in code to: if valid refrl, if not ip address contact
-               the helper that resolves tcp names, mount to it, try to
-               tcon to it unmount it if fail */
+               /* BB lock tcon, server, tcp session and increment use count? */
+               /* found a match on the TCP session */
+               /* BB check if reconnection needed */
+               cFYI(1, ("IP match, old UNC: %s new: %s",
+                       tcon->treeName, uncName));
 
-       kfree(referrals);
+               if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE))
+                       continue;
 
-       return rc;
+               cFYI(1, ("and old usr: %s new: %s",
+                       tcon->treeName, uncName));
+
+               if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE))
+                       continue;
+
+               /* matched smb session (user name) */
+               read_unlock(&GlobalSMBSeslock);
+               return tcon;
+       }
+
+       read_unlock(&GlobalSMBSeslock);
+       return NULL;
 }
 
 int
 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
             const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
-            unsigned char **preferrals, int remap)
+            struct dfs_info3_param **preferrals, int remap)
 {
        char *temp_unc;
        int rc = 0;
 
        *pnum_referrals = 0;
+       *preferrals = NULL;
 
        if (pSesInfo->ipc_tid == 0) {
                temp_unc = kmalloc(2 /* for slashes */ +
@@ -1427,6 +1455,8 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
        if (rc == 0)
                rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
                                     pnum_referrals, nls_codepage, remap);
+       /* BB map targetUNCs to dfs_info3 structures, here or
+               in CIFSGetDFSRefer BB */
 
        return rc;
 }
@@ -1689,8 +1719,15 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
                           originally at mount time */
                        if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
                                cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
-                       if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
+                       if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
+                               if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
+                                       cERROR(1, ("POSIXPATH support change"));
                                cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
+                       } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
+                               cERROR(1, ("possible reconnect error"));
+                               cERROR(1,
+                                       ("server disabled POSIX path support"));
+                       }
                }
 
                cap &= CIFS_UNIX_CAP_MASK;
@@ -1720,9 +1757,8 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
                if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
                        if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
                                CIFS_SB(sb)->rsize = 127 * 1024;
-#ifdef CONFIG_CIFS_DEBUG2
-                               cFYI(1, ("larger reads not supported by srv"));
-#endif
+                               cFYI(DBG2,
+                                       ("larger reads not supported by srv"));
                        }
                }
 
@@ -1759,6 +1795,26 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
        }
 }
 
+static void
+convert_delimiter(char *path, char delim)
+{
+       int i;
+       char old_delim;
+
+       if (path == NULL)
+               return;
+
+       if (delim == '/')
+               old_delim = '\\';
+       else
+               old_delim = '/';
+
+       for (i = 0; path[i] != '\0'; i++) {
+               if (path[i] == old_delim)
+                       path[i] = delim;
+       }
+}
+
 int
 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
           char *mount_data, const char *devname)
@@ -1900,6 +1956,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        /* BB Add code for ipv6 case too */
                        srvTcp->ssocket = csocket;
                        srvTcp->protocolType = IPV4;
+                       srvTcp->hostname = extract_hostname(volume_info.UNC);
+                       if (IS_ERR(srvTcp->hostname)) {
+                               rc = PTR_ERR(srvTcp->hostname);
+                               sock_release(csocket);
+                               goto out;
+                       }
                        init_waitqueue_head(&srvTcp->response_q);
                        init_waitqueue_head(&srvTcp->request_q);
                        INIT_LIST_HEAD(&srvTcp->pending_mid_q);
@@ -1909,14 +1971,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        srvTcp->tcpStatus = CifsNew;
                        init_MUTEX(&srvTcp->tcpSem);
                        srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
-                       if ( IS_ERR(srvTcp->tsk) ) {
+                       if (IS_ERR(srvTcp->tsk)) {
                                rc = PTR_ERR(srvTcp->tsk);
                                cERROR(1, ("error %d create cifsd thread", rc));
                                srvTcp->tsk = NULL;
                                sock_release(csocket);
+                               kfree(srvTcp->hostname);
                                goto out;
                        }
-                       wait_for_completion(&cifsd_complete);
                        rc = 0;
                        memcpy(srvTcp->workstation_RFC1001_name,
                                volume_info.source_rfc1001_name, 16);
@@ -1928,7 +1990,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 
        if (existingCifsSes) {
                pSesInfo = existingCifsSes;
-               cFYI(1, ("Existing smb sess found"));
+               cFYI(1, ("Existing smb sess found (status=%d)",
+                       pSesInfo->status));
+               down(&pSesInfo->sesSem);
+               if (pSesInfo->status == CifsNeedReconnect) {
+                       cFYI(1, ("Session needs reconnect"));
+                       rc = cifs_setup_session(xid, pSesInfo,
+                                               cifs_sb->local_nls);
+               }
+               up(&pSesInfo->sesSem);
        } else if (!rc) {
                cFYI(1, ("Existing smb sess not found"));
                pSesInfo = sesInfoAlloc();
@@ -2009,7 +2079,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                cifs_sb->prepath = volume_info.prepath;
                if (cifs_sb->prepath) {
                        cifs_sb->prepathlen = strlen(cifs_sb->prepath);
-                       cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
+                       /* we can not convert the / to \ in the path
+                       separators in the prefixpath yet because we do not
+                       know (until reset_cifs_unix_caps is called later)
+                       whether POSIX PATH CAP is available. We normalize
+                       the / to \ after reset_cifs_unix_caps is called */
                        volume_info.prepath = NULL;
                } else
                        cifs_sb->prepathlen = 0;
@@ -2040,11 +2114,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
                if (volume_info.override_gid)
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
+               if (volume_info.dynperm)
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
                if (volume_info.direct_io) {
                        cFYI(1, ("mounting share using direct i/o"));
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
                }
 
+               if ((volume_info.cifs_acl) && (volume_info.dynperm))
+                       cERROR(1, ("mount option dynperm ignored if cifsacl "
+                                  "mount option supported"));
+
                tcon =
                    find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
                             volume_info.username);
@@ -2056,6 +2136,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                           for the retry flag is used */
                        tcon->retry = volume_info.retry;
                        tcon->nocase = volume_info.nocase;
+                       if (tcon->seal != volume_info.seal)
+                               cERROR(1, ("transport encryption setting "
+                                          "conflicts with existing tid"));
                } else {
                        tcon = tconInfoAlloc();
                        if (tcon == NULL)
@@ -2069,10 +2152,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                if ((strchr(volume_info.UNC + 3, '\\') == NULL)
                                    && (strchr(volume_info.UNC + 3, '/') ==
                                        NULL)) {
-                                       rc = connect_to_dfs_path(xid, pSesInfo,
+/*                                     rc = connect_to_dfs_path(xid, pSesInfo,
                                                "", cifs_sb->local_nls,
                                                cifs_sb->mnt_cifs_flags &
-                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
+                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);*/
+                                       cFYI(1, ("DFS root not supported"));
                                        rc = -ENODEV;
                                        goto out;
                                } else {
@@ -2088,6 +2172,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                        atomic_inc(&pSesInfo->inUse);
                                        tcon->retry = volume_info.retry;
                                        tcon->nocase = volume_info.nocase;
+                                       tcon->seal = volume_info.seal;
                                }
                        }
                }
@@ -2111,15 +2196,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        srvTcp->tcpStatus = CifsExiting;
                        spin_unlock(&GlobalMid_Lock);
                        if (srvTcp->tsk) {
-                               struct task_struct *tsk;
                                /* If we could verify that kthread_stop would
                                   always wake up processes blocked in
                                   tcp in recv_mesg then we could remove the
                                   send_sig call */
                                force_sig(SIGKILL, srvTcp->tsk);
-                               tsk = srvTcp->tsk;
-                               if (tsk)
-                                       kthread_stop(tsk);
+                               kthread_stop(srvTcp->tsk);
                        }
                }
                 /* If find_unc succeeded then rc == 0 so we can not end */
@@ -2135,23 +2217,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                        if ((temp_rc == -ESHUTDOWN) &&
                                            (pSesInfo->server) &&
                                            (pSesInfo->server->tsk)) {
-                                               struct task_struct *tsk;
                                                force_sig(SIGKILL,
                                                        pSesInfo->server->tsk);
-                                               tsk = pSesInfo->server->tsk;
-                                               if (tsk)
-                                                       kthread_stop(tsk);
+                                               kthread_stop(pSesInfo->server->tsk);
                                        }
                                } else {
                                        cFYI(1, ("No session or bad tcon"));
                                        if ((pSesInfo->server) &&
                                            (pSesInfo->server->tsk)) {
-                                               struct task_struct *tsk;
                                                force_sig(SIGKILL,
                                                        pSesInfo->server->tsk);
-                                               tsk = pSesInfo->server->tsk;
-                                               if (tsk)
-                                                       kthread_stop(tsk);
+                                               kthread_stop(pSesInfo->server->tsk);
                                        }
                                }
                                sesInfoFree(pSesInfo);
@@ -2177,11 +2253,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                else
                        tcon->unix_ext = 0; /* server does not support them */
 
+               /* convert forward to back slashes in prepath here if needed */
+               if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
+                       convert_delimiter(cifs_sb->prepath,
+                                         CIFS_DIR_SEP(cifs_sb));
+
                if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
                        cifs_sb->rsize = 1024 * 127;
-#ifdef CONFIG_CIFS_DEBUG2
-                       cFYI(1, ("no very large read support, rsize now 127K"));
-#endif
+                       cFYI(DBG2,
+                               ("no very large read support, rsize now 127K"));
                }
                if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
                        cifs_sb->wsize = min(cifs_sb->wsize,
@@ -2234,9 +2314,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        user = ses->userName;
        domain = ses->domainName;
        smb_buffer = cifs_buf_get();
-       if (smb_buffer == NULL) {
+
+       if (smb_buffer == NULL)
                return -ENOMEM;
-       }
+
        smb_buffer_response = smb_buffer;
        pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
 
@@ -2520,7 +2601,7 @@ sesssetup_nomem:  /* do not return an error on nomem for the info strings,
 
 static int
 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
-                             struct cifsSesInfo *ses, int *pNTLMv2_flag,
+                             struct cifsSesInfo *ses, bool *pNTLMv2_flag,
                              const struct nls_table *nls_codepage)
 {
        struct smb_hdr *smb_buffer;
@@ -2543,7 +2624,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        if (ses == NULL)
                return -EINVAL;
        domain = ses->domainName;
-       *pNTLMv2_flag = FALSE;
+       *pNTLMv2_flag = false;
        smb_buffer = cifs_buf_get();
        if (smb_buffer == NULL) {
                return -ENOMEM;
@@ -2696,7 +2777,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                       CIFS_CRYPTO_KEY_SIZE);
                                if (SecurityBlob2->NegotiateFlags &
                                        cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
-                                       *pNTLMv2_flag = TRUE;
+                                       *pNTLMv2_flag = true;
 
                                if ((SecurityBlob2->NegotiateFlags &
                                        cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
@@ -2857,7 +2938,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 }
 static int
 CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
-                       char *ntlm_session_key, int ntlmv2_flag,
+                       char *ntlm_session_key, bool ntlmv2_flag,
                        const struct nls_table *nls_codepage)
 {
        struct smb_hdr *smb_buffer;
@@ -3445,6 +3526,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
                        FreeXid(xid);
                        return 0;
                }
+               DeleteTconOplockQEntries(cifs_sb->tcon);
                tconInfoFree(cifs_sb->tcon);
                if ((ses) && (ses->server)) {
                        /* save off task so we do not refer to ses later */
@@ -3473,12 +3555,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
        cifs_sb->prepath = NULL;
        kfree(tmp);
        if (ses)
-               schedule_timeout_interruptible(msecs_to_jiffies(500));
-       if (ses)
                sesInfoFree(ses);
 
        FreeXid(xid);
-       return rc;      /* BB check if we should always return zero here */
+       return rc;
 }
 
 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
@@ -3486,7 +3566,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
 {
        int rc = 0;
        char ntlm_session_key[CIFS_SESS_KEY_SIZE];
-       int ntlmv2_flag = FALSE;
+       bool ntlmv2_flag = false;
        int first_time = 0;
 
        /* what if server changes its buffer size after dropping the session? */