[XFS] Remove vn_from_inode()
[safe/jmp/linux-2.6] / fs / cifs / connect.c
index 6b520aa..0711db6 100644 (file)
@@ -60,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 */
@@ -75,19 +75,21 @@ struct smb_vol {
        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 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 */
-       unsigned nocase;     /* request case insensitive filenames */
-       unsigned nobrl;      /* disable sending byte range locks to srv */
+       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;
@@ -149,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);
@@ -171,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);
@@ -348,13 +348,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        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);
-       if (length  > 1)
+
+       length = atomic_inc_return(&tcpSesAllocCount);
+       if (length > 1)
                mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
                                GFP_KERNEL);
 
@@ -454,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));
@@ -651,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
@@ -733,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);
@@ -751,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);
@@ -1237,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) {
@@ -1259,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) {
@@ -1339,7 +1354,7 @@ cifs_find_tcp_session(struct in_addr *target_ip_addr,
                         memcmp(&ses->server->addr.sockAddr6.sin6_addr,
                                target_ip6_addr, sizeof(*target_ip6_addr)))
                                continue;
-               /* BB lock server and tcp session and increment use count here?? */
+               /* BB lock server and tcp session; increment use count here?? */
 
                /* found a match on the TCP session */
                *psrvTcp = ses->server;
@@ -1405,34 +1420,12 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
 }
 
 int
-connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
-                   const char *old_path, const struct nls_table *nls_codepage,
-                   int remap)
-{
-       struct dfs_info3_param *referrals = NULL;
-       unsigned int num_referrals;
-       int rc = 0;
-
-       rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
-                       &num_referrals, &referrals, remap);
-
-       /* 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 */
-
-       kfree(referrals);
-
-       return rc;
-}
-
-int
 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
             const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
             struct dfs_info3_param **preferrals, int remap)
 {
        char *temp_unc;
        int rc = 0;
-       unsigned char *targetUNCs;
 
        *pnum_referrals = 0;
        *preferrals = NULL;
@@ -1455,7 +1448,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
                kfree(temp_unc);
        }
        if (rc == 0)
-               rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs,
+               rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
                                     pnum_referrals, nls_codepage, remap);
        /* BB map targetUNCs to dfs_info3 structures, here or
                in CIFSGetDFSRefer BB */
@@ -1463,6 +1456,39 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
        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)
 {
@@ -1497,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);
                }
        }
 
@@ -1629,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);
                }
        }
 
@@ -1806,7 +1834,7 @@ convert_delimiter(char *path, char delim)
        if (path == NULL)
                return;
 
-       if (delim == '/') 
+       if (delim == '/')
                old_delim = '\\';
        else
                old_delim = '/';
@@ -2116,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);
@@ -2132,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)
@@ -2145,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 {
@@ -2164,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;
                                }
                        }
                }
@@ -2187,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 */
@@ -2211,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);
@@ -2314,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;
 
@@ -3587,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;
 }