cifs: reinstate sharing of SMB sessions sans races

We do this by abandoning the global list of SMB sessions and instead
moving to a per-server list. This entails adding a new list head to the
TCP_Server_Info struct. The refcounting for the cifsSesInfo is moved to
a non-atomic variable. We have to protect it by a lock anyway, so there's
no benefit to making it an atomic. The list and refcount are protected
by the global cifs_tcp_ses_lock.

The patch also adds a new routines to find and put SMB sessions and
that properly take and put references under the lock.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>

authored by Jeff Layton and committed by Steve French 14fbf50d e7ddee90

+175 -166
+27 -26
fs/cifs/cifs_debug.c
··· 107 107 #ifdef CONFIG_PROC_FS 108 108 static int cifs_debug_data_proc_show(struct seq_file *m, void *v) 109 109 { 110 - struct list_head *tmp; 111 - struct list_head *tmp1; 110 + struct list_head *tmp, *tmp2, *tmp3; 112 111 struct mid_q_entry *mid_entry; 112 + struct TCP_Server_Info *server; 113 113 struct cifsSesInfo *ses; 114 114 struct cifsTconInfo *tcon; 115 115 int i; ··· 122 122 seq_printf(m, "Servers:"); 123 123 124 124 i = 0; 125 - read_lock(&GlobalSMBSeslock); 126 - list_for_each(tmp, &GlobalSMBSessionList) { 125 + read_lock(&cifs_tcp_ses_lock); 126 + list_for_each(tmp, &cifs_tcp_ses_list) { 127 + server = list_entry(tmp, struct TCP_Server_Info, 128 + tcp_ses_list); 127 129 i++; 128 - ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); 129 - if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) || 130 - (ses->serverNOS == NULL)) { 131 - seq_printf(m, "\nentry for %s not fully " 132 - "displayed\n\t", ses->serverName); 133 - } else { 134 - seq_printf(m, 130 + list_for_each(tmp2, &server->smb_ses_list) { 131 + ses = list_entry(tmp2, struct cifsSesInfo, 132 + smb_ses_list); 133 + if ((ses->serverDomain == NULL) || 134 + (ses->serverOS == NULL) || 135 + (ses->serverNOS == NULL)) { 136 + seq_printf(m, "\nentry for %s not fully " 137 + "displayed\n\t", ses->serverName); 138 + } else { 139 + seq_printf(m, 135 140 "\n%d) Name: %s Domain: %s Mounts: %d OS:" 136 141 " %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB" 137 142 " session status: %d\t", 138 143 i, ses->serverName, ses->serverDomain, 139 - atomic_read(&ses->inUse), 140 - ses->serverOS, ses->serverNOS, 144 + ses->ses_count, ses->serverOS, ses->serverNOS, 141 145 ses->capabilities, ses->status); 142 - } 143 - if (ses->server) { 146 + } 144 147 seq_printf(m, "TCP status: %d\n\tLocal Users To " 145 - "Server: %d SecMode: 0x%x Req On Wire: %d", 146 - ses->server->tcpStatus, 147 - ses->server->srv_count, 148 - ses->server->secMode, 149 - atomic_read(&ses->server->inFlight)); 148 + "Server: %d SecMode: 0x%x Req On Wire: %d", 149 + server->tcpStatus, server->srv_count, 150 + server->secMode, 151 + atomic_read(&server->inFlight)); 150 152 151 153 #ifdef CONFIG_CIFS_STATS2 152 154 seq_printf(m, " In Send: %d In MaxReq Wait: %d", 153 - atomic_read(&ses->server->inSend), 154 - atomic_read(&ses->server->num_waiters)); 155 + atomic_read(&server->inSend), 156 + atomic_read(&server->num_waiters)); 155 157 #endif 156 158 157 159 seq_puts(m, "\nMIDs:\n"); 158 160 159 161 spin_lock(&GlobalMid_Lock); 160 - list_for_each(tmp1, &ses->server->pending_mid_q) { 161 - mid_entry = list_entry(tmp1, struct 162 + list_for_each(tmp3, &server->pending_mid_q) { 163 + mid_entry = list_entry(tmp3, struct 162 164 mid_q_entry, 163 165 qhead); 164 166 seq_printf(m, "State: %d com: %d pid:" ··· 173 171 } 174 172 spin_unlock(&GlobalMid_Lock); 175 173 } 176 - 177 174 } 178 - read_unlock(&GlobalSMBSeslock); 175 + read_unlock(&cifs_tcp_ses_lock); 179 176 seq_putc(m, '\n'); 180 177 181 178 seq_puts(m, "Shares:");
+8 -9
fs/cifs/cifsfs.c
··· 1031 1031 static int cifs_dnotify_thread(void *dummyarg) 1032 1032 { 1033 1033 struct list_head *tmp; 1034 - struct cifsSesInfo *ses; 1034 + struct TCP_Server_Info *server; 1035 1035 1036 1036 do { 1037 1037 if (try_to_freeze()) 1038 1038 continue; 1039 1039 set_current_state(TASK_INTERRUPTIBLE); 1040 1040 schedule_timeout(15*HZ); 1041 - read_lock(&GlobalSMBSeslock); 1042 1041 /* check if any stuck requests that need 1043 1042 to be woken up and wakeq so the 1044 1043 thread can wake up and error out */ 1045 - list_for_each(tmp, &GlobalSMBSessionList) { 1046 - ses = list_entry(tmp, struct cifsSesInfo, 1047 - cifsSessionList); 1048 - if (ses->server && atomic_read(&ses->server->inFlight)) 1049 - wake_up_all(&ses->server->response_q); 1044 + read_lock(&cifs_tcp_ses_lock); 1045 + list_for_each(tmp, &cifs_tcp_ses_list) { 1046 + server = list_entry(tmp, struct TCP_Server_Info, 1047 + tcp_ses_list); 1048 + if (atomic_read(&server->inFlight)) 1049 + wake_up_all(&server->response_q); 1050 1050 } 1051 - read_unlock(&GlobalSMBSeslock); 1051 + read_unlock(&cifs_tcp_ses_lock); 1052 1052 } while (!kthread_should_stop()); 1053 1053 1054 1054 return 0; ··· 1060 1060 int rc = 0; 1061 1061 cifs_proc_init(); 1062 1062 INIT_LIST_HEAD(&cifs_tcp_ses_list); 1063 - INIT_LIST_HEAD(&GlobalSMBSessionList); /* BB to be removed by jl */ 1064 1063 INIT_LIST_HEAD(&GlobalTreeConnectionList); /* BB to be removed by jl */ 1065 1064 INIT_LIST_HEAD(&GlobalOplock_Q); 1066 1065 #ifdef CONFIG_CIFS_EXPERIMENTAL
+2 -4
fs/cifs/cifsglob.h
··· 195 195 * Session structure. One of these for each uid session with a particular host 196 196 */ 197 197 struct cifsSesInfo { 198 - struct list_head cifsSessionList; 198 + struct list_head smb_ses_list; 199 199 struct list_head tcon_list; 200 200 struct semaphore sesSem; 201 201 #if 0 202 202 struct cifsUidInfo *uidInfo; /* pointer to user info */ 203 203 #endif 204 204 struct TCP_Server_Info *server; /* pointer to server info */ 205 - atomic_t inUse; /* # of mounts (tree connections) on this ses */ 205 + int ses_count; /* reference counter */ 206 206 enum statusEnum status; 207 207 unsigned overrideSecFlg; /* if non-zero override global sec flags */ 208 208 __u16 ipc_tid; /* special tid for connection to IPC share */ ··· 602 602 603 603 /* protects cifs_tcp_ses_list and srv_count for each tcp session */ 604 604 GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; 605 - 606 - GLOBAL_EXTERN struct list_head GlobalSMBSessionList; /* BB to be removed by jl*/ 607 605 GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; /* BB to be removed */ 608 606 GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ 609 607
-1
fs/cifs/cifsproto.h
··· 102 102 const __u16 *pfid); 103 103 extern int mode_to_acl(struct inode *inode, const char *path, __u64); 104 104 105 - extern void cifs_put_tcp_session(struct TCP_Server_Info *server); 106 105 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, 107 106 const char *); 108 107 extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
+8 -16
fs/cifs/cifssmb.c
··· 799 799 int rc = 0; 800 800 801 801 cFYI(1, ("In SMBLogoff for session disconnect")); 802 - if (ses) 803 - down(&ses->sesSem); 804 - else 802 + 803 + /* 804 + * BB: do we need to check validity of ses and server? They should 805 + * always be valid since we have an active reference. If not, that 806 + * should probably be a BUG() 807 + */ 808 + if (!ses || !ses->server) 805 809 return -EIO; 806 810 807 - atomic_dec(&ses->inUse); 808 - if (atomic_read(&ses->inUse) > 0) { 809 - up(&ses->sesSem); 810 - return -EBUSY; 811 - } 812 - 813 - if (ses->server == NULL) 814 - return -EIO; 815 - 811 + down(&ses->sesSem); 816 812 if (ses->need_reconnect) 817 813 goto session_already_dead; /* no need to send SMBlogoff if uid 818 814 already closed due to reconnect */ ··· 829 833 pSMB->AndXCommand = 0xFF; 830 834 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); 831 835 session_already_dead: 832 - if (ses->server) { 833 - cifs_put_tcp_session(ses->server); 834 - rc = 0; 835 - } 836 836 up(&ses->sesSem); 837 837 838 838 /* if session dead then we do not need to do ulogoff,
+124 -100
fs/cifs/connect.c
··· 144 144 145 145 /* before reconnecting the tcp session, mark the smb session (uid) 146 146 and the tid bad so they are not used until reconnected */ 147 - read_lock(&GlobalSMBSeslock); 148 - list_for_each(tmp, &GlobalSMBSessionList) { 149 - ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); 150 - if (ses->server) { 151 - if (ses->server == server) { 152 - ses->need_reconnect = true; 153 - ses->ipc_tid = 0; 154 - } 155 - } 156 - /* else tcp and smb sessions need reconnection */ 147 + read_lock(&cifs_tcp_ses_lock); 148 + list_for_each(tmp, &server->smb_ses_list) { 149 + ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); 150 + ses->need_reconnect = true; 151 + ses->ipc_tid = 0; 157 152 } 153 + read_unlock(&cifs_tcp_ses_lock); 158 154 list_for_each(tmp, &GlobalTreeConnectionList) { 159 155 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); 160 156 if ((tcon->ses) && (tcon->ses->server == server)) 161 157 tcon->need_reconnect = true; 162 158 } 163 - read_unlock(&GlobalSMBSeslock); 164 159 /* do not want to be sending data on a socket we are freeing */ 165 160 down(&server->tcpSem); 166 161 if (server->ssocket) { ··· 691 696 if (smallbuf) /* no sense logging a debug message if NULL */ 692 697 cifs_small_buf_release(smallbuf); 693 698 694 - read_lock(&GlobalSMBSeslock); 699 + /* 700 + * BB: we shouldn't have to do any of this. It shouldn't be 701 + * possible to exit from the thread with active SMB sessions 702 + */ 703 + read_lock(&cifs_tcp_ses_lock); 695 704 if (list_empty(&server->pending_mid_q)) { 696 705 /* loop through server session structures attached to this and 697 706 mark them dead */ 698 - list_for_each(tmp, &GlobalSMBSessionList) { 699 - ses = 700 - list_entry(tmp, struct cifsSesInfo, 701 - cifsSessionList); 702 - if (ses->server == server) { 703 - ses->status = CifsExiting; 704 - ses->server = NULL; 705 - } 707 + list_for_each(tmp, &server->smb_ses_list) { 708 + ses = list_entry(tmp, struct cifsSesInfo, 709 + smb_ses_list); 710 + ses->status = CifsExiting; 711 + ses->server = NULL; 706 712 } 707 - read_unlock(&GlobalSMBSeslock); 713 + read_unlock(&cifs_tcp_ses_lock); 708 714 } else { 709 715 /* although we can not zero the server struct pointer yet, 710 716 since there are active requests which may depnd on them, 711 717 mark the corresponding SMB sessions as exiting too */ 712 - list_for_each(tmp, &GlobalSMBSessionList) { 718 + list_for_each(tmp, &server->smb_ses_list) { 713 719 ses = list_entry(tmp, struct cifsSesInfo, 714 - cifsSessionList); 715 - if (ses->server == server) 716 - ses->status = CifsExiting; 720 + smb_ses_list); 721 + ses->status = CifsExiting; 717 722 } 718 723 719 724 spin_lock(&GlobalMid_Lock); ··· 728 733 } 729 734 } 730 735 spin_unlock(&GlobalMid_Lock); 731 - read_unlock(&GlobalSMBSeslock); 736 + read_unlock(&cifs_tcp_ses_lock); 732 737 /* 1/8th of sec is more than enough time for them to exit */ 733 738 msleep(125); 734 739 } ··· 750 755 if there are any pointing to this (e.g 751 756 if a crazy root user tried to kill cifsd 752 757 kernel thread explicitly this might happen) */ 753 - write_lock(&GlobalSMBSeslock); 754 - list_for_each(tmp, &GlobalSMBSessionList) { 755 - ses = list_entry(tmp, struct cifsSesInfo, 756 - cifsSessionList); 757 - if (ses->server == server) 758 - ses->server = NULL; 758 + /* BB: This shouldn't be necessary, see above */ 759 + read_lock(&cifs_tcp_ses_lock); 760 + list_for_each(tmp, &server->smb_ses_list) { 761 + ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); 762 + ses->server = NULL; 759 763 } 760 - write_unlock(&GlobalSMBSeslock); 764 + read_unlock(&cifs_tcp_ses_lock); 761 765 762 766 kfree(server->hostname); 763 767 task_to_wake = xchg(&server->tsk, NULL); ··· 1395 1401 return NULL; 1396 1402 } 1397 1403 1398 - void 1404 + static void 1399 1405 cifs_put_tcp_session(struct TCP_Server_Info *server) 1400 1406 { 1401 1407 struct task_struct *task; ··· 1416 1422 task = xchg(&server->tsk, NULL); 1417 1423 if (task) 1418 1424 force_sig(SIGKILL, task); 1425 + } 1426 + 1427 + static struct cifsSesInfo * 1428 + cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) 1429 + { 1430 + struct list_head *tmp; 1431 + struct cifsSesInfo *ses; 1432 + 1433 + write_lock(&cifs_tcp_ses_lock); 1434 + list_for_each(tmp, &server->smb_ses_list) { 1435 + ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); 1436 + if (strncmp(ses->userName, username, MAX_USERNAME_SIZE)) 1437 + continue; 1438 + 1439 + ++ses->ses_count; 1440 + write_unlock(&cifs_tcp_ses_lock); 1441 + return ses; 1442 + } 1443 + write_unlock(&cifs_tcp_ses_lock); 1444 + return NULL; 1445 + } 1446 + 1447 + static void 1448 + cifs_put_smb_ses(struct cifsSesInfo *ses) 1449 + { 1450 + int xid; 1451 + struct TCP_Server_Info *server = ses->server; 1452 + 1453 + write_lock(&cifs_tcp_ses_lock); 1454 + if (--ses->ses_count > 0) { 1455 + write_unlock(&cifs_tcp_ses_lock); 1456 + return; 1457 + } 1458 + 1459 + list_del_init(&ses->smb_ses_list); 1460 + write_unlock(&cifs_tcp_ses_lock); 1461 + 1462 + if (ses->status == CifsGood) { 1463 + xid = GetXid(); 1464 + CIFSSMBLogoff(xid, ses); 1465 + _FreeXid(xid); 1466 + } 1467 + sesInfoFree(ses); 1468 + cifs_put_tcp_session(server); 1419 1469 } 1420 1470 1421 1471 int ··· 1996 1958 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; 1997 1959 struct smb_vol volume_info; 1998 1960 struct cifsSesInfo *pSesInfo = NULL; 1999 - struct cifsSesInfo *existingCifsSes = NULL; 2000 1961 struct cifsTconInfo *tcon = NULL; 2001 1962 struct TCP_Server_Info *srvTcp = NULL; 2002 1963 ··· 2149 2112 volume_info.target_rfc1001_name, 16); 2150 2113 srvTcp->sequence_number = 0; 2151 2114 INIT_LIST_HEAD(&srvTcp->tcp_ses_list); 2115 + INIT_LIST_HEAD(&srvTcp->smb_ses_list); 2152 2116 ++srvTcp->srv_count; 2153 2117 write_lock(&cifs_tcp_ses_lock); 2154 2118 list_add(&srvTcp->tcp_ses_list, ··· 2158 2120 } 2159 2121 } 2160 2122 2161 - if (existingCifsSes) { 2162 - pSesInfo = existingCifsSes; 2123 + pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username); 2124 + if (pSesInfo) { 2163 2125 cFYI(1, ("Existing smb sess found (status=%d)", 2164 2126 pSesInfo->status)); 2127 + /* 2128 + * The existing SMB session already has a reference to srvTcp, 2129 + * so we can put back the extra one we got before 2130 + */ 2131 + cifs_put_tcp_session(srvTcp); 2132 + 2165 2133 down(&pSesInfo->sesSem); 2166 2134 if (pSesInfo->need_reconnect) { 2167 2135 cFYI(1, ("Session needs reconnect")); ··· 2178 2134 } else if (!rc) { 2179 2135 cFYI(1, ("Existing smb sess not found")); 2180 2136 pSesInfo = sesInfoAlloc(); 2181 - if (pSesInfo == NULL) 2137 + if (pSesInfo == NULL) { 2182 2138 rc = -ENOMEM; 2183 - else { 2184 - pSesInfo->server = srvTcp; 2185 - sprintf(pSesInfo->serverName, "%u.%u.%u.%u", 2186 - NIPQUAD(sin_server->sin_addr.s_addr)); 2139 + goto mount_fail_check; 2187 2140 } 2188 2141 2189 - if (!rc) { 2190 - /* volume_info.password freed at unmount */ 2191 - if (volume_info.password) { 2192 - pSesInfo->password = volume_info.password; 2193 - /* set to NULL to prevent freeing on exit */ 2194 - volume_info.password = NULL; 2195 - } 2196 - if (volume_info.username) 2197 - strncpy(pSesInfo->userName, 2198 - volume_info.username, 2199 - MAX_USERNAME_SIZE); 2200 - if (volume_info.domainname) { 2201 - int len = strlen(volume_info.domainname); 2202 - pSesInfo->domainName = 2203 - kmalloc(len + 1, GFP_KERNEL); 2204 - if (pSesInfo->domainName) 2205 - strcpy(pSesInfo->domainName, 2206 - volume_info.domainname); 2207 - } 2208 - pSesInfo->linux_uid = volume_info.linux_uid; 2209 - pSesInfo->overrideSecFlg = volume_info.secFlg; 2210 - down(&pSesInfo->sesSem); 2211 - /* BB FIXME need to pass vol->secFlgs BB */ 2212 - rc = cifs_setup_session(xid, pSesInfo, 2213 - cifs_sb->local_nls); 2214 - up(&pSesInfo->sesSem); 2142 + /* new SMB session uses our srvTcp ref */ 2143 + pSesInfo->server = srvTcp; 2144 + sprintf(pSesInfo->serverName, "%u.%u.%u.%u", 2145 + NIPQUAD(sin_server->sin_addr.s_addr)); 2146 + 2147 + write_lock(&cifs_tcp_ses_lock); 2148 + list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list); 2149 + write_unlock(&cifs_tcp_ses_lock); 2150 + 2151 + /* volume_info.password freed at unmount */ 2152 + if (volume_info.password) { 2153 + pSesInfo->password = volume_info.password; 2154 + /* set to NULL to prevent freeing on exit */ 2155 + volume_info.password = NULL; 2215 2156 } 2157 + if (volume_info.username) 2158 + strncpy(pSesInfo->userName, volume_info.username, 2159 + MAX_USERNAME_SIZE); 2160 + if (volume_info.domainname) { 2161 + int len = strlen(volume_info.domainname); 2162 + pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL); 2163 + if (pSesInfo->domainName) 2164 + strcpy(pSesInfo->domainName, 2165 + volume_info.domainname); 2166 + } 2167 + pSesInfo->linux_uid = volume_info.linux_uid; 2168 + pSesInfo->overrideSecFlg = volume_info.secFlg; 2169 + down(&pSesInfo->sesSem); 2170 + 2171 + /* BB FIXME need to pass vol->secFlgs BB */ 2172 + rc = cifs_setup_session(xid, pSesInfo, 2173 + cifs_sb->local_nls); 2174 + up(&pSesInfo->sesSem); 2216 2175 } 2217 2176 2218 2177 /* search for existing tcon to this server share */ ··· 2256 2209 tcon->Flags)); 2257 2210 } 2258 2211 } 2259 - if (!rc) { 2260 - atomic_inc(&pSesInfo->inUse); 2261 - tcon->seal = volume_info.seal; 2262 - } else 2212 + if (rc) 2263 2213 goto mount_fail_check; 2214 + tcon->seal = volume_info.seal; 2264 2215 } 2265 2216 2266 2217 /* we can have only one retry value for a connection ··· 2279 2234 /* BB FIXME fix time_gran to be larger for LANMAN sessions */ 2280 2235 sb->s_time_gran = 100; 2281 2236 2282 - /* on error free sesinfo and tcon struct if needed */ 2283 2237 mount_fail_check: 2238 + /* on error free sesinfo and tcon struct if needed */ 2284 2239 if (rc) { 2285 2240 /* If find_unc succeeded then rc == 0 so we can not end */ 2286 2241 /* up accidently freeing someone elses tcon struct */ 2287 2242 if (tcon) 2288 2243 tconInfoFree(tcon); 2289 2244 2290 - if (existingCifsSes == NULL) { 2291 - if (pSesInfo) { 2292 - if ((pSesInfo->server) && 2293 - (pSesInfo->status == CifsGood)) 2294 - CIFSSMBLogoff(xid, pSesInfo); 2295 - else { 2296 - cFYI(1, ("No session or bad tcon")); 2297 - if (pSesInfo->server) 2298 - cifs_put_tcp_session( 2299 - pSesInfo->server); 2300 - } 2301 - sesInfoFree(pSesInfo); 2302 - /* pSesInfo = NULL; */ 2303 - } 2304 - } 2245 + /* should also end up putting our tcp session ref if needed */ 2246 + if (pSesInfo) 2247 + cifs_put_smb_ses(pSesInfo); 2248 + else 2249 + cifs_put_tcp_session(srvTcp); 2305 2250 } else { 2306 2251 atomic_inc(&tcon->useCount); 2307 2252 cifs_sb->tcon = tcon; ··· 3586 3551 } 3587 3552 DeleteTconOplockQEntries(cifs_sb->tcon); 3588 3553 tconInfoFree(cifs_sb->tcon); 3589 - if ((ses) && (ses->server)) { 3590 - /* save off task so we do not refer to ses later */ 3591 - cFYI(1, ("About to do SMBLogoff ")); 3592 - rc = CIFSSMBLogoff(xid, ses); 3593 - if (rc == -EBUSY) { 3594 - FreeXid(xid); 3595 - return 0; 3596 - } 3597 - } else 3598 - cFYI(1, ("No session or bad tcon")); 3554 + cifs_put_smb_ses(ses); 3599 3555 } 3600 3556 3601 3557 cifs_sb->tcon = NULL; ··· 3594 3568 cifs_sb->prepathlen = 0; 3595 3569 cifs_sb->prepath = NULL; 3596 3570 kfree(tmp); 3597 - if (ses) 3598 - sesInfoFree(ses); 3599 3571 3600 3572 FreeXid(xid); 3601 3573 return rc;
+6 -10
fs/cifs/misc.c
··· 75 75 76 76 ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL); 77 77 if (ret_buf) { 78 - write_lock(&GlobalSMBSeslock); 79 78 atomic_inc(&sesInfoAllocCount); 80 79 ret_buf->status = CifsNew; 81 - list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList); 80 + ++ret_buf->ses_count; 81 + INIT_LIST_HEAD(&ret_buf->smb_ses_list); 82 82 init_MUTEX(&ret_buf->sesSem); 83 - write_unlock(&GlobalSMBSeslock); 84 83 } 85 84 return ret_buf; 86 85 } ··· 92 93 return; 93 94 } 94 95 95 - write_lock(&GlobalSMBSeslock); 96 96 atomic_dec(&sesInfoAllocCount); 97 - list_del(&buf_to_free->cifsSessionList); 98 - write_unlock(&GlobalSMBSeslock); 99 97 kfree(buf_to_free->serverOS); 100 98 kfree(buf_to_free->serverDomain); 101 99 kfree(buf_to_free->serverNOS); ··· 346 350 if (current->fsuid != treeCon->ses->linux_uid) { 347 351 cFYI(1, ("Multiuser mode and UID " 348 352 "did not match tcon uid")); 349 - read_lock(&GlobalSMBSeslock); 350 - list_for_each(temp_item, &GlobalSMBSessionList) { 351 - ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); 353 + read_lock(&cifs_tcp_ses_lock); 354 + list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) { 355 + ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list); 352 356 if (ses->linux_uid == current->fsuid) { 353 357 if (ses->server == treeCon->ses->server) { 354 358 cFYI(1, ("found matching uid substitute right smb_uid")); ··· 360 364 } 361 365 } 362 366 } 363 - read_unlock(&GlobalSMBSeslock); 367 + read_unlock(&cifs_tcp_ses_lock); 364 368 } 365 369 } 366 370 }