cifs: reinstate sharing of SMB sessions sans races
authorJeff Layton <jlayton@redhat.com>
Fri, 14 Nov 2008 18:53:46 +0000 (13:53 -0500)
committerSteve French <sfrench@us.ibm.com>
Fri, 14 Nov 2008 23:56:55 +0000 (23:56 +0000)
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>
fs/cifs/cifs_debug.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/misc.c

index 40b5108fb4f9d463144ff167c59cd5cbef58839c..59841a68b0b672eb61f46a886046b2d012699d8f 100644 (file)
@@ -107,9 +107,9 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
 #ifdef CONFIG_PROC_FS
 static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 {
-       struct list_head *tmp;
-       struct list_head *tmp1;
+       struct list_head *tmp, *tmp2, *tmp3;
        struct mid_q_entry *mid_entry;
+       struct TCP_Server_Info *server;
        struct cifsSesInfo *ses;
        struct cifsTconInfo *tcon;
        int i;
@@ -122,43 +122,45 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
        seq_printf(m, "Servers:");
 
        i = 0;
-       read_lock(&GlobalSMBSeslock);
-       list_for_each(tmp, &GlobalSMBSessionList) {
+       read_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &cifs_tcp_ses_list) {
+               server = list_entry(tmp, struct TCP_Server_Info,
+                                   tcp_ses_list);
                i++;
-               ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
-               if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
-                  (ses->serverNOS == NULL)) {
-                       seq_printf(m, "\nentry for %s not fully "
-                                       "displayed\n\t", ses->serverName);
-               } else {
-                       seq_printf(m,
+               list_for_each(tmp2, &server->smb_ses_list) {
+                       ses = list_entry(tmp2, struct cifsSesInfo,
+                                        smb_ses_list);
+                       if ((ses->serverDomain == NULL) ||
+                               (ses->serverOS == NULL) ||
+                               (ses->serverNOS == NULL)) {
+                               seq_printf(m, "\nentry for %s not fully "
+                                          "displayed\n\t", ses->serverName);
+                       } else {
+                               seq_printf(m,
                                    "\n%d) Name: %s  Domain: %s Mounts: %d OS:"
                                    " %s  \n\tNOS: %s\tCapability: 0x%x\n\tSMB"
                                    " session status: %d\t",
                                i, ses->serverName, ses->serverDomain,
-                               atomic_read(&ses->inUse),
-                               ses->serverOS, ses->serverNOS,
+                               ses->ses_count, ses->serverOS, ses->serverNOS,
                                ses->capabilities, ses->status);
-               }
-               if (ses->server) {
+                       }
                        seq_printf(m, "TCP status: %d\n\tLocal Users To "
-                                   "Server: %d SecMode: 0x%x Req On Wire: %d",
-                               ses->server->tcpStatus,
-                               ses->server->srv_count,
-                               ses->server->secMode,
-                               atomic_read(&ses->server->inFlight));
+                                  "Server: %d SecMode: 0x%x Req On Wire: %d",
+                                  server->tcpStatus, server->srv_count,
+                                  server->secMode,
+                                  atomic_read(&server->inFlight));
 
 #ifdef CONFIG_CIFS_STATS2
                        seq_printf(m, " In Send: %d In MaxReq Wait: %d",
-                               atomic_read(&ses->server->inSend),
-                               atomic_read(&ses->server->num_waiters));
+                               atomic_read(&server->inSend),
+                               atomic_read(&server->num_waiters));
 #endif
 
                        seq_puts(m, "\nMIDs:\n");
 
                        spin_lock(&GlobalMid_Lock);
-                       list_for_each(tmp1, &ses->server->pending_mid_q) {
-                               mid_entry = list_entry(tmp1, struct
+                       list_for_each(tmp3, &server->pending_mid_q) {
+                               mid_entry = list_entry(tmp3, struct
                                        mid_q_entry,
                                        qhead);
                                seq_printf(m, "State: %d com: %d pid:"
@@ -171,9 +173,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                        }
                        spin_unlock(&GlobalMid_Lock);
                }
-
        }
-       read_unlock(&GlobalSMBSeslock);
+       read_unlock(&cifs_tcp_ses_lock);
        seq_putc(m, '\n');
 
        seq_puts(m, "Shares:");
index 2946dab0718f8b4f6d0375fee1cdd463f123bdc3..a1e96620b097cce3d9a2b793b328db9e0aa226b9 100644 (file)
@@ -1031,24 +1031,24 @@ static int cifs_oplock_thread(void *dummyarg)
 static int cifs_dnotify_thread(void *dummyarg)
 {
        struct list_head *tmp;
-       struct cifsSesInfo *ses;
+       struct TCP_Server_Info *server;
 
        do {
                if (try_to_freeze())
                        continue;
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(15*HZ);
-               read_lock(&GlobalSMBSeslock);
                /* check if any stuck requests that need
                   to be woken up and wakeq so the
                   thread can wake up and error out */
-               list_for_each(tmp, &GlobalSMBSessionList) {
-                       ses = list_entry(tmp, struct cifsSesInfo,
-                               cifsSessionList);
-                       if (ses->server && atomic_read(&ses->server->inFlight))
-                               wake_up_all(&ses->server->response_q);
+               read_lock(&cifs_tcp_ses_lock);
+               list_for_each(tmp, &cifs_tcp_ses_list) {
+                       server = list_entry(tmp, struct TCP_Server_Info,
+                                        tcp_ses_list);
+                       if (atomic_read(&server->inFlight))
+                               wake_up_all(&server->response_q);
                }
-               read_unlock(&GlobalSMBSeslock);
+               read_unlock(&cifs_tcp_ses_lock);
        } while (!kthread_should_stop());
 
        return 0;
@@ -1060,7 +1060,6 @@ init_cifs(void)
        int rc = 0;
        cifs_proc_init();
        INIT_LIST_HEAD(&cifs_tcp_ses_list);
-       INIT_LIST_HEAD(&GlobalSMBSessionList); /* BB to be removed by jl */
        INIT_LIST_HEAD(&GlobalTreeConnectionList); /* BB to be removed by jl */
        INIT_LIST_HEAD(&GlobalOplock_Q);
 #ifdef CONFIG_CIFS_EXPERIMENTAL
index 313f7bfedec7e76dfe1ea1d3cbb5bf16f1dee462..631a99f72f22b6534b73d87c2e9c5471201de766 100644 (file)
@@ -195,14 +195,14 @@ struct cifsUidInfo {
  * Session structure.  One of these for each uid session with a particular host
  */
 struct cifsSesInfo {
-       struct list_head cifsSessionList;
+       struct list_head smb_ses_list;
        struct list_head tcon_list;
        struct semaphore sesSem;
 #if 0
        struct cifsUidInfo *uidInfo;    /* pointer to user info */
 #endif
        struct TCP_Server_Info *server; /* pointer to server info */
-       atomic_t inUse; /* # of mounts (tree connections) on this ses */
+       int ses_count;          /* reference counter */
        enum statusEnum status;
        unsigned overrideSecFlg;  /* if non-zero override global sec flags */
        __u16 ipc_tid;          /* special tid for connection to IPC share */
@@ -602,8 +602,6 @@ GLOBAL_EXTERN struct list_head              cifs_tcp_ses_list;
 
 /* protects cifs_tcp_ses_list and srv_count for each tcp session */
 GLOBAL_EXTERN rwlock_t         cifs_tcp_ses_lock;
-
-GLOBAL_EXTERN struct list_head GlobalSMBSessionList; /* BB to be removed by jl*/
 GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; /* BB to be removed */
 GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;  /* protects list inserts on 3 above */
 
index 0250a994c6e6672aad10bde1e239a858fecc2ba7..6f21ecb85ce517b07d36d973cfb030d478e08ebf 100644 (file)
@@ -102,7 +102,6 @@ extern void acl_to_uid_mode(struct inode *inode, const char *path,
                            const __u16 *pfid);
 extern int mode_to_acl(struct inode *inode, const char *path, __u64);
 
-extern void cifs_put_tcp_session(struct TCP_Server_Info *server);
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
                        const char *);
 extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
index cd9e9a145e4d85fefdb6a1c963f16cee8ca90661..9c95617baa4dbc13638ad98582163a35aacd993e 100644 (file)
@@ -799,20 +799,16 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
        int rc = 0;
 
        cFYI(1, ("In SMBLogoff for session disconnect"));
-       if (ses)
-               down(&ses->sesSem);
-       else
-               return -EIO;
-
-       atomic_dec(&ses->inUse);
-       if (atomic_read(&ses->inUse) > 0) {
-               up(&ses->sesSem);
-               return -EBUSY;
-       }
 
-       if (ses->server == NULL)
+       /*
+        * BB: do we need to check validity of ses and server? They should
+        * always be valid since we have an active reference. If not, that
+        * should probably be a BUG()
+        */
+       if (!ses || !ses->server)
                return -EIO;
 
+       down(&ses->sesSem);
        if (ses->need_reconnect)
                goto session_already_dead; /* no need to send SMBlogoff if uid
                                              already closed due to reconnect */
@@ -833,10 +829,6 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
        pSMB->AndXCommand = 0xFF;
        rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
 session_already_dead:
-       if (ses->server) {
-               cifs_put_tcp_session(ses->server);
-               rc = 0;
-       }
        up(&ses->sesSem);
 
        /* if session dead then we do not need to do ulogoff,
index a0314259f94de548681197e58b2b5fab0bae16f1..44130e052e0bdaf73836d5b6e8b8d8cacf788305 100644 (file)
@@ -144,23 +144,18 @@ cifs_reconnect(struct TCP_Server_Info *server)
 
        /* before reconnecting the tcp session, mark the smb session (uid)
                and the tid bad so they are not used until reconnected */
-       read_lock(&GlobalSMBSeslock);
-       list_for_each(tmp, &GlobalSMBSessionList) {
-               ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
-               if (ses->server) {
-                       if (ses->server == server) {
-                               ses->need_reconnect = true;
-                               ses->ipc_tid = 0;
-                       }
-               }
-               /* else tcp and smb sessions need reconnection */
+       read_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &server->smb_ses_list) {
+               ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
+               ses->need_reconnect = true;
+               ses->ipc_tid = 0;
        }
+       read_unlock(&cifs_tcp_ses_lock);
        list_for_each(tmp, &GlobalTreeConnectionList) {
                tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
                if ((tcon->ses) && (tcon->ses->server == server))
                        tcon->need_reconnect = true;
        }
-       read_unlock(&GlobalSMBSeslock);
        /* do not want to be sending data on a socket we are freeing */
        down(&server->tcpSem);
        if (server->ssocket) {
@@ -696,29 +691,29 @@ multi_t2_fnd:
        if (smallbuf) /* no sense logging a debug message if NULL */
                cifs_small_buf_release(smallbuf);
 
-       read_lock(&GlobalSMBSeslock);
+       /*
+        * BB: we shouldn't have to do any of this. It shouldn't be
+        * possible to exit from the thread with active SMB sessions
+        */
+       read_lock(&cifs_tcp_ses_lock);
        if (list_empty(&server->pending_mid_q)) {
                /* loop through server session structures attached to this and
                    mark them dead */
-               list_for_each(tmp, &GlobalSMBSessionList) {
-                       ses =
-                           list_entry(tmp, struct cifsSesInfo,
-                                      cifsSessionList);
-                       if (ses->server == server) {
-                               ses->status = CifsExiting;
-                               ses->server = NULL;
-                       }
+               list_for_each(tmp, &server->smb_ses_list) {
+                       ses = list_entry(tmp, struct cifsSesInfo,
+                                        smb_ses_list);
+                       ses->status = CifsExiting;
+                       ses->server = NULL;
                }
-               read_unlock(&GlobalSMBSeslock);
+               read_unlock(&cifs_tcp_ses_lock);
        } else {
                /* although we can not zero the server struct pointer yet,
                since there are active requests which may depnd on them,
                mark the corresponding SMB sessions as exiting too */
-               list_for_each(tmp, &GlobalSMBSessionList) {
+               list_for_each(tmp, &server->smb_ses_list) {
                        ses = list_entry(tmp, struct cifsSesInfo,
-                                        cifsSessionList);
-                       if (ses->server == server)
-                               ses->status = CifsExiting;
+                                        smb_ses_list);
+                       ses->status = CifsExiting;
                }
 
                spin_lock(&GlobalMid_Lock);
@@ -733,7 +728,7 @@ multi_t2_fnd:
                        }
                }
                spin_unlock(&GlobalMid_Lock);
-               read_unlock(&GlobalSMBSeslock);
+               read_unlock(&cifs_tcp_ses_lock);
                /* 1/8th of sec is more than enough time for them to exit */
                msleep(125);
        }
@@ -755,14 +750,13 @@ multi_t2_fnd:
        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);
-               if (ses->server == server)
-                       ses->server = NULL;
+       /* BB: This shouldn't be necessary, see above */
+       read_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &server->smb_ses_list) {
+               ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
+               ses->server = NULL;
        }
-       write_unlock(&GlobalSMBSeslock);
+       read_unlock(&cifs_tcp_ses_lock);
 
        kfree(server->hostname);
        task_to_wake = xchg(&server->tsk, NULL);
@@ -1401,7 +1395,7 @@ cifs_find_tcp_session(struct sockaddr *addr)
        return NULL;
 }
 
-void
+static void
 cifs_put_tcp_session(struct TCP_Server_Info *server)
 {
        struct task_struct *task;
@@ -1424,6 +1418,50 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
                force_sig(SIGKILL, task);
 }
 
+static struct cifsSesInfo *
+cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
+{
+       struct list_head *tmp;
+       struct cifsSesInfo *ses;
+
+       write_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &server->smb_ses_list) {
+               ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
+               if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
+                       continue;
+
+               ++ses->ses_count;
+               write_unlock(&cifs_tcp_ses_lock);
+               return ses;
+       }
+       write_unlock(&cifs_tcp_ses_lock);
+       return NULL;
+}
+
+static void
+cifs_put_smb_ses(struct cifsSesInfo *ses)
+{
+       int xid;
+       struct TCP_Server_Info *server = ses->server;
+
+       write_lock(&cifs_tcp_ses_lock);
+       if (--ses->ses_count > 0) {
+               write_unlock(&cifs_tcp_ses_lock);
+               return;
+       }
+
+       list_del_init(&ses->smb_ses_list);
+       write_unlock(&cifs_tcp_ses_lock);
+
+       if (ses->status == CifsGood) {
+               xid = GetXid();
+               CIFSSMBLogoff(xid, ses);
+               _FreeXid(xid);
+       }
+       sesInfoFree(ses);
+       cifs_put_tcp_session(server);
+}
+
 int
 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
             const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
@@ -1958,7 +1996,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
        struct smb_vol volume_info;
        struct cifsSesInfo *pSesInfo = NULL;
-       struct cifsSesInfo *existingCifsSes = NULL;
        struct cifsTconInfo *tcon = NULL;
        struct TCP_Server_Info *srvTcp = NULL;
 
@@ -2112,6 +2149,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                volume_info.target_rfc1001_name, 16);
                        srvTcp->sequence_number = 0;
                        INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
+                       INIT_LIST_HEAD(&srvTcp->smb_ses_list);
                        ++srvTcp->srv_count;
                        write_lock(&cifs_tcp_ses_lock);
                        list_add(&srvTcp->tcp_ses_list,
@@ -2120,10 +2158,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                }
        }
 
-       if (existingCifsSes) {
-               pSesInfo = existingCifsSes;
+       pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
+       if (pSesInfo) {
                cFYI(1, ("Existing smb sess found (status=%d)",
                        pSesInfo->status));
+               /*
+                * The existing SMB session already has a reference to srvTcp,
+                * so we can put back the extra one we got before
+                */
+               cifs_put_tcp_session(srvTcp);
+
                down(&pSesInfo->sesSem);
                if (pSesInfo->need_reconnect) {
                        cFYI(1, ("Session needs reconnect"));
@@ -2134,41 +2178,44 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        } else if (!rc) {
                cFYI(1, ("Existing smb sess not found"));
                pSesInfo = sesInfoAlloc();
-               if (pSesInfo == NULL)
+               if (pSesInfo == NULL) {
                        rc = -ENOMEM;
-               else {
-                       pSesInfo->server = srvTcp;
-                       sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
-                               NIPQUAD(sin_server->sin_addr.s_addr));
+                       goto mount_fail_check;
                }
 
-               if (!rc) {
-                       /* volume_info.password freed at unmount */
-                       if (volume_info.password) {
-                               pSesInfo->password = volume_info.password;
-                               /* set to NULL to prevent freeing on exit */
-                               volume_info.password = NULL;
-                       }
-                       if (volume_info.username)
-                               strncpy(pSesInfo->userName,
-                                       volume_info.username,
-                                       MAX_USERNAME_SIZE);
-                       if (volume_info.domainname) {
-                               int len = strlen(volume_info.domainname);
-                               pSesInfo->domainName =
-                                       kmalloc(len + 1, GFP_KERNEL);
-                               if (pSesInfo->domainName)
-                                       strcpy(pSesInfo->domainName,
-                                               volume_info.domainname);
-                       }
-                       pSesInfo->linux_uid = volume_info.linux_uid;
-                       pSesInfo->overrideSecFlg = volume_info.secFlg;
-                       down(&pSesInfo->sesSem);
-                       /* BB FIXME need to pass vol->secFlgs BB */
-                       rc = cifs_setup_session(xid, pSesInfo,
-                                               cifs_sb->local_nls);
-                       up(&pSesInfo->sesSem);
-               }
+               /* new SMB session uses our srvTcp ref */
+               pSesInfo->server = srvTcp;
+               sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
+                       NIPQUAD(sin_server->sin_addr.s_addr));
+
+               write_lock(&cifs_tcp_ses_lock);
+               list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
+               write_unlock(&cifs_tcp_ses_lock);
+
+               /* volume_info.password freed at unmount */
+               if (volume_info.password) {
+                       pSesInfo->password = volume_info.password;
+                       /* set to NULL to prevent freeing on exit */
+                       volume_info.password = NULL;
+               }
+               if (volume_info.username)
+                       strncpy(pSesInfo->userName, volume_info.username,
+                               MAX_USERNAME_SIZE);
+               if (volume_info.domainname) {
+                       int len = strlen(volume_info.domainname);
+                       pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
+                       if (pSesInfo->domainName)
+                               strcpy(pSesInfo->domainName,
+                                       volume_info.domainname);
+               }
+               pSesInfo->linux_uid = volume_info.linux_uid;
+               pSesInfo->overrideSecFlg = volume_info.secFlg;
+               down(&pSesInfo->sesSem);
+
+               /* BB FIXME need to pass vol->secFlgs BB */
+               rc = cifs_setup_session(xid, pSesInfo,
+                                       cifs_sb->local_nls);
+               up(&pSesInfo->sesSem);
        }
 
        /* search for existing tcon to this server share */
@@ -2209,11 +2256,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                                tcon->Flags));
                                }
                        }
-                       if (!rc) {
-                               atomic_inc(&pSesInfo->inUse);
-                               tcon->seal = volume_info.seal;
-                       } else
+                       if (rc)
                                goto mount_fail_check;
+                       tcon->seal = volume_info.seal;
                }
 
                /* we can have only one retry value for a connection
@@ -2234,29 +2279,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        /* BB FIXME fix time_gran to be larger for LANMAN sessions */
        sb->s_time_gran = 100;
 
-/* on error free sesinfo and tcon struct if needed */
 mount_fail_check:
+       /* on error free sesinfo and tcon struct if needed */
        if (rc) {
                /* If find_unc succeeded then rc == 0 so we can not end */
                /* up accidently freeing someone elses tcon struct */
                if (tcon)
                        tconInfoFree(tcon);
 
-               if (existingCifsSes == NULL) {
-                       if (pSesInfo) {
-                               if ((pSesInfo->server) &&
-                                   (pSesInfo->status == CifsGood))
-                                       CIFSSMBLogoff(xid, pSesInfo);
-                               else {
-                                       cFYI(1, ("No session or bad tcon"));
-                                       if (pSesInfo->server)
-                                               cifs_put_tcp_session(
-                                                       pSesInfo->server);
-                               }
-                               sesInfoFree(pSesInfo);
-                               /* pSesInfo = NULL; */
-                       }
-               }
+               /* should also end up putting our tcp session ref if needed */
+               if (pSesInfo)
+                       cifs_put_smb_ses(pSesInfo);
+               else
+                       cifs_put_tcp_session(srvTcp);
        } else {
                atomic_inc(&tcon->useCount);
                cifs_sb->tcon = tcon;
@@ -3551,16 +3586,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
                }
                DeleteTconOplockQEntries(cifs_sb->tcon);
                tconInfoFree(cifs_sb->tcon);
-               if ((ses) && (ses->server)) {
-                       /* save off task so we do not refer to ses later */
-                       cFYI(1, ("About to do SMBLogoff "));
-                       rc = CIFSSMBLogoff(xid, ses);
-                       if (rc == -EBUSY) {
-                               FreeXid(xid);
-                               return 0;
-                       }
-               } else
-                       cFYI(1, ("No session or bad tcon"));
+               cifs_put_smb_ses(ses);
        }
 
        cifs_sb->tcon = NULL;
@@ -3568,8 +3594,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
        cifs_sb->prepathlen = 0;
        cifs_sb->prepath = NULL;
        kfree(tmp);
-       if (ses)
-               sesInfoFree(ses);
 
        FreeXid(xid);
        return rc;
index 88786ba02d277fac25923893c29bb96206e42827..46c8c7baccbae1b1fc0629460babaabbe254f49b 100644 (file)
@@ -75,12 +75,11 @@ sesInfoAlloc(void)
 
        ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL);
        if (ret_buf) {
-               write_lock(&GlobalSMBSeslock);
                atomic_inc(&sesInfoAllocCount);
                ret_buf->status = CifsNew;
-               list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList);
+               ++ret_buf->ses_count;
+               INIT_LIST_HEAD(&ret_buf->smb_ses_list);
                init_MUTEX(&ret_buf->sesSem);
-               write_unlock(&GlobalSMBSeslock);
        }
        return ret_buf;
 }
@@ -93,10 +92,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
                return;
        }
 
-       write_lock(&GlobalSMBSeslock);
        atomic_dec(&sesInfoAllocCount);
-       list_del(&buf_to_free->cifsSessionList);
-       write_unlock(&GlobalSMBSeslock);
        kfree(buf_to_free->serverOS);
        kfree(buf_to_free->serverDomain);
        kfree(buf_to_free->serverNOS);
@@ -350,9 +346,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                                if (current->fsuid != treeCon->ses->linux_uid) {
                                        cFYI(1, ("Multiuser mode and UID "
                                                 "did not match tcon uid"));
-                                       read_lock(&GlobalSMBSeslock);
-                                       list_for_each(temp_item, &GlobalSMBSessionList) {
-                                               ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
+                                       read_lock(&cifs_tcp_ses_lock);
+                                       list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
+                                               ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
                                                if (ses->linux_uid == current->fsuid) {
                                                        if (ses->server == treeCon->ses->server) {
                                                                cFYI(1, ("found matching uid substitute right smb_uid"));
@@ -364,7 +360,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                                                        }
                                                }
                                        }
-                                       read_unlock(&GlobalSMBSeslock);
+                                       read_unlock(&cifs_tcp_ses_lock);
                                }
                        }
                }