[XFS] Remove vn_from_inode()
[safe/jmp/linux-2.6] / fs / cifs / connect.c
index 98ec57f..0711db6 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;
@@ -151,7 +151,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
        }
        list_for_each(tmp, &GlobalTreeConnectionList) {
                tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
-               if ((tcon) && (tcon->ses) && (tcon->ses->server == server))
+               if ((tcon->ses) && (tcon->ses->server == server))
                        tcon->tidStatus = CifsNeedReconnect;
        }
        read_unlock(&GlobalSMBSeslock);
@@ -173,14 +173,12 @@ cifs_reconnect(struct TCP_Server_Info *server)
                mid_entry = list_entry(tmp, struct
                                        mid_q_entry,
                                        qhead);
-               if (mid_entry) {
-                       if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
+               if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
                                /* Mark other intransit requests as needing
                                   retry so we do not immediately mark the
                                   session bad again (ie after we reconnect
                                   below) as they timeout too */
-                               mid_entry->midState = MID_RETRY_NEEDED;
-                       }
+                       mid_entry->midState = MID_RETRY_NEEDED;
                }
        }
        spin_unlock(&GlobalMid_Lock);
@@ -345,19 +343,15 @@ 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)
+
+       length = atomic_inc_return(&tcpSesAllocCount);
+       if (length > 1)
                mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
                                GFP_KERNEL);
 
@@ -390,8 +384,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 +432,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;
@@ -457,7 +451,7 @@ incomplete_rcv:
                /* Note that FC 1001 length is big endian on the wire,
                but we convert it here so it is always manipulated
                as host byte order */
-               pdu_length = ntohl(smb_buffer->smb_buf_length);
+               pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
                smb_buffer->smb_buf_length = pdu_length;
 
                cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
@@ -517,7 +511,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 +576,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 +599,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 +632,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 +648,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
@@ -736,14 +741,11 @@ multi_t2_fnd:
                coming home not much else we can do but free the memory */
        }
 
-       write_lock(&GlobalSMBSeslock);
-       atomic_dec(&tcpSesAllocCount);
-       length = tcpSesAllocCount.counter;
-
        /* last chance to mark ses pointers invalid
        if there are any pointing to this (e.g
        if a crazy root user tried to kill cifsd
        kernel thread explicitly this might happen) */
+       write_lock(&GlobalSMBSeslock);
        list_for_each(tmp, &GlobalSMBSessionList) {
                ses = list_entry(tmp, struct cifsSesInfo,
                                cifsSessionList);
@@ -754,6 +756,8 @@ multi_t2_fnd:
 
        kfree(server->hostname);
        kfree(server);
+
+       length = atomic_dec_return(&tcpSesAllocCount);
        if (length  > 0)
                mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
                                GFP_KERNEL);
@@ -825,7 +829,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;
 
@@ -1181,7 +1185,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) ||
@@ -1197,7 +1201,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) {
@@ -1240,6 +1244,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) {
@@ -1262,8 +1270,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) {
@@ -1305,6 +1317,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;
@@ -1318,42 +1333,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;
 }
 
@@ -1362,79 +1378,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));
+
+               if (old_ip != new_target_ip_addr)
+                       continue;
 
-       rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
-                       &num_referrals, &referrals, remap);
+               /* 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));
 
-       /* 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 */
+               if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE))
+                       continue;
 
-       kfree(referrals);
+               cFYI(1, ("and old usr: %s new: %s",
+                       tcon->treeName, uncName));
 
-       return rc;
+               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 */ +
@@ -1456,10 +1450,45 @@ 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;
 }
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static struct lock_class_key cifs_key[2];
+static struct lock_class_key cifs_slock_key[2];
+
+static inline void
+cifs_reclassify_socket4(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       BUG_ON(sock_owned_by_user(sk));
+       sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
+               &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
+}
+
+static inline void
+cifs_reclassify_socket6(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       BUG_ON(sock_owned_by_user(sk));
+       sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
+               &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
+}
+#else
+static inline void
+cifs_reclassify_socket4(struct socket *sock)
+{
+}
+
+static inline void
+cifs_reclassify_socket6(struct socket *sock)
+{
+}
+#endif
+
 /* See RFC1001 section 14 on representation of Netbios names */
 static void rfc1002mangle(char *target, char *source, unsigned int length)
 {
@@ -1494,6 +1523,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
                /* BB other socket options to set KEEPALIVE, NODELAY? */
                        cFYI(1, ("Socket created"));
                        (*csocket)->sk->sk_allocation = GFP_NOFS;
+                       cifs_reclassify_socket4(*csocket);
                }
        }
 
@@ -1626,6 +1656,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
                /* BB other socket options to set KEEPALIVE, NODELAY? */
                         cFYI(1, ("ipv6 Socket created"));
                        (*csocket)->sk->sk_allocation = GFP_NOFS;
+                       cifs_reclassify_socket6(*csocket);
                }
        }
 
@@ -1718,8 +1749,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;
@@ -1749,9 +1787,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"));
                        }
                }
 
@@ -1788,6 +1825,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)
@@ -1944,7 +2001,7 @@ 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;
@@ -1952,7 +2009,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                kfree(srvTcp->hostname);
                                goto out;
                        }
-                       wait_for_completion(&cifsd_complete);
                        rc = 0;
                        memcpy(srvTcp->workstation_RFC1001_name,
                                volume_info.source_rfc1001_name, 16);
@@ -1964,7 +2020,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();
@@ -2045,7 +2109,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;
@@ -2076,11 +2144,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);
@@ -2092,6 +2166,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)
@@ -2105,10 +2182,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 {
@@ -2124,6 +2202,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;
                                }
                        }
                }
@@ -2147,15 +2226,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 */
@@ -2171,23 +2247,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);
@@ -2213,11 +2283,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,
@@ -2270,9 +2344,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;
 
@@ -2556,7 +2631,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;
@@ -2579,7 +2654,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;
@@ -2732,7 +2807,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))
@@ -2893,7 +2968,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;
@@ -3481,6 +3556,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 */
@@ -3509,12 +3585,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,
@@ -3522,7 +3596,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? */
@@ -3544,97 +3618,91 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                }
                first_time = 1;
        }
-       if (!rc) {
-               pSesInfo->flags = 0;
-               pSesInfo->capabilities = pSesInfo->server->capabilities;
-               if (linuxExtEnabled == 0)
-                       pSesInfo->capabilities &= (~CAP_UNIX);
+
+       if (rc)
+               goto ss_err_exit;
+
+       pSesInfo->flags = 0;
+       pSesInfo->capabilities = pSesInfo->server->capabilities;
+       if (linuxExtEnabled == 0)
+               pSesInfo->capabilities &= (~CAP_UNIX);
        /*      pSesInfo->sequence_number = 0;*/
-               cFYI(1,
-                     ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
-                       pSesInfo->server->secMode,
-                       pSesInfo->server->capabilities,
-                       pSesInfo->server->timeAdj));
-               if (experimEnabled < 2)
-                       rc = CIFS_SessSetup(xid, pSesInfo,
-                                           first_time, nls_info);
-               else if (extended_security
-                               && (pSesInfo->capabilities
-                                       & CAP_EXTENDED_SECURITY)
-                               && (pSesInfo->server->secType == NTLMSSP)) {
-                       rc = -EOPNOTSUPP;
-               } else if (extended_security
-                          && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
-                          && (pSesInfo->server->secType == RawNTLMSSP)) {
-                       cFYI(1, ("NTLMSSP sesssetup"));
-                       rc = CIFSNTLMSSPNegotiateSessSetup(xid,
-                                               pSesInfo,
-                                               &ntlmv2_flag,
-                                               nls_info);
-                       if (!rc) {
-                               if (ntlmv2_flag) {
-                                       char *v2_response;
-                                       cFYI(1, ("more secure NTLM ver2 hash"));
-                                       if (CalcNTLMv2_partial_mac_key(pSesInfo,
-                                               nls_info)) {
-                                               rc = -ENOMEM;
-                                               goto ss_err_exit;
-                                       } else
-                                               v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
-                                       if (v2_response) {
-                                               CalcNTLMv2_response(pSesInfo,
-                                                                  v2_response);
-                               /*              if (first_time)
-                                                 cifs_calculate_ntlmv2_mac_key(
-                                                  pSesInfo->server->mac_signing_key,
-                                                  response, ntlm_session_key,*/
-                                               kfree(v2_response);
+       cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
+                pSesInfo->server->secMode,
+                pSesInfo->server->capabilities,
+                pSesInfo->server->timeAdj));
+       if (experimEnabled < 2)
+               rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
+       else if (extended_security
+                       && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+                       && (pSesInfo->server->secType == NTLMSSP)) {
+               rc = -EOPNOTSUPP;
+       } else if (extended_security
+                       && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+                       && (pSesInfo->server->secType == RawNTLMSSP)) {
+               cFYI(1, ("NTLMSSP sesssetup"));
+               rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
+                                                  nls_info);
+               if (!rc) {
+                       if (ntlmv2_flag) {
+                               char *v2_response;
+                               cFYI(1, ("more secure NTLM ver2 hash"));
+                               if (CalcNTLMv2_partial_mac_key(pSesInfo,
+                                                               nls_info)) {
+                                       rc = -ENOMEM;
+                                       goto ss_err_exit;
+                               } else
+                                       v2_response = kmalloc(16 + 64 /* blob*/,
+                                                               GFP_KERNEL);
+                               if (v2_response) {
+                                       CalcNTLMv2_response(pSesInfo,
+                                                               v2_response);
+                               /*      if (first_time)
+                                               cifs_calculate_ntlmv2_mac_key */
+                                       kfree(v2_response);
                                        /* BB Put dummy sig in SessSetup PDU? */
-                                       } else {
-                                               rc = -ENOMEM;
-                                               goto ss_err_exit;
-                                       }
-
                                } else {
-                                       SMBNTencrypt(pSesInfo->password,
-                                               pSesInfo->server->cryptKey,
-                                               ntlm_session_key);
-
-                                       if (first_time)
-                                               cifs_calculate_mac_key(
-                                                       &pSesInfo->server->mac_signing_key,
-                                                       ntlm_session_key,
-                                                       pSesInfo->password);
+                                       rc = -ENOMEM;
+                                       goto ss_err_exit;
                                }
+
+                       } else {
+                               SMBNTencrypt(pSesInfo->password,
+                                            pSesInfo->server->cryptKey,
+                                            ntlm_session_key);
+
+                               if (first_time)
+                                       cifs_calculate_mac_key(
+                                            &pSesInfo->server->mac_signing_key,
+                                            ntlm_session_key,
+                                            pSesInfo->password);
+                       }
                        /* for better security the weaker lanman hash not sent
                           in AuthSessSetup so we no longer calculate it */
 
-                               rc = CIFSNTLMSSPAuthSessSetup(xid,
-                                       pSesInfo,
-                                       ntlm_session_key,
-                                       ntlmv2_flag,
-                                       nls_info);
-                       }
-               } else { /* old style NTLM 0.12 session setup */
-                       SMBNTencrypt(pSesInfo->password,
-                               pSesInfo->server->cryptKey,
-                               ntlm_session_key);
+                       rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
+                                                     ntlm_session_key,
+                                                     ntlmv2_flag,
+                                                     nls_info);
+               }
+       } else { /* old style NTLM 0.12 session setup */
+               SMBNTencrypt(pSesInfo->password, pSesInfo->server->cryptKey,
+                            ntlm_session_key);
 
-                       if (first_time)
-                               cifs_calculate_mac_key(
+               if (first_time)
+                       cifs_calculate_mac_key(
                                        &pSesInfo->server->mac_signing_key,
                                        ntlm_session_key, pSesInfo->password);
 
-                       rc = CIFSSessSetup(xid, pSesInfo,
-                               ntlm_session_key, nls_info);
-               }
-               if (rc) {
-                       cERROR(1, ("Send error in SessSetup = %d", rc));
-               } else {
-                       cFYI(1, ("CIFS Session Established successfully"));
+               rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
+       }
+       if (rc) {
+               cERROR(1, ("Send error in SessSetup = %d", rc));
+       } else {
+               cFYI(1, ("CIFS Session Established successfully"));
                        pSesInfo->status = CifsGood;
-               }
        }
+
 ss_err_exit:
        return rc;
 }