cifs: reinstate sharing of tree connections

Use a similar approach to the SMB session sharing. Add a list of tcons
attached to each SMB session. Move the refcount to non-atomic. Protect
all of the above with the cifs_tcp_ses_lock. Add functions to
properly find and put references to the tcons.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Jeff Layton
2008-11-15 11:12:47 -05:00
committed by Steve French
parent d82c2df54e
commit f1987b44f6
6 changed files with 249 additions and 218 deletions

View File

@@ -79,6 +79,7 @@ sesInfoAlloc(void)
ret_buf->status = CifsNew;
++ret_buf->ses_count;
INIT_LIST_HEAD(&ret_buf->smb_ses_list);
INIT_LIST_HEAD(&ret_buf->tcon_list);
init_MUTEX(&ret_buf->sesSem);
}
return ret_buf;
@@ -107,17 +108,14 @@ tconInfoAlloc(void)
struct cifsTconInfo *ret_buf;
ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL);
if (ret_buf) {
write_lock(&GlobalSMBSeslock);
atomic_inc(&tconInfoAllocCount);
list_add(&ret_buf->cifsConnectionList,
&GlobalTreeConnectionList);
ret_buf->tidStatus = CifsNew;
++ret_buf->tc_count;
INIT_LIST_HEAD(&ret_buf->openFileList);
init_MUTEX(&ret_buf->tconSem);
INIT_LIST_HEAD(&ret_buf->tcon_list);
#ifdef CONFIG_CIFS_STATS
spin_lock_init(&ret_buf->stat_lock);
#endif
write_unlock(&GlobalSMBSeslock);
}
return ret_buf;
}
@@ -129,10 +127,7 @@ tconInfoFree(struct cifsTconInfo *buf_to_free)
cFYI(1, ("Null buffer passed to tconInfoFree"));
return;
}
write_lock(&GlobalSMBSeslock);
atomic_dec(&tconInfoAllocCount);
list_del(&buf_to_free->cifsConnectionList);
write_unlock(&GlobalSMBSeslock);
kfree(buf_to_free->nativeFileSystem);
kfree(buf_to_free);
}
@@ -493,9 +488,10 @@ bool
is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
{
struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
struct list_head *tmp;
struct list_head *tmp1;
struct list_head *tmp, *tmp1, *tmp2;
struct cifsSesInfo *ses;
struct cifsTconInfo *tcon;
struct cifsInodeInfo *pCifsInode;
struct cifsFileInfo *netfile;
cFYI(1, ("Checking for oplock break or dnotify response"));
@@ -550,42 +546,42 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
return false;
/* look up tcon based on tid & uid */
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalTreeConnectionList) {
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) {
read_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &srv->smb_ses_list) {
ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
list_for_each(tmp1, &ses->tcon_list) {
tcon = list_entry(tmp1, struct cifsTconInfo, tcon_list);
if (tcon->tid != buf->Tid)
continue;
cifs_stats_inc(&tcon->num_oplock_brks);
list_for_each(tmp1, &tcon->openFileList) {
netfile = list_entry(tmp1, struct cifsFileInfo,
list_for_each(tmp2, &tcon->openFileList) {
netfile = list_entry(tmp2, struct cifsFileInfo,
tlist);
if (pSMB->Fid == netfile->netfid) {
struct cifsInodeInfo *pCifsInode;
read_unlock(&GlobalSMBSeslock);
cFYI(1,
("file id match, oplock break"));
pCifsInode =
CIFS_I(netfile->pInode);
pCifsInode->clientCanCacheAll = false;
if (pSMB->OplockLevel == 0)
pCifsInode->clientCanCacheRead
= false;
pCifsInode->oplockPending = true;
AllocOplockQEntry(netfile->pInode,
netfile->netfid,
tcon);
cFYI(1,
("about to wake up oplock thread"));
if (oplockThread)
wake_up_process(oplockThread);
return true;
}
if (pSMB->Fid != netfile->netfid)
continue;
read_unlock(&cifs_tcp_ses_lock);
cFYI(1, ("file id match, oplock break"));
pCifsInode = CIFS_I(netfile->pInode);
pCifsInode->clientCanCacheAll = false;
if (pSMB->OplockLevel == 0)
pCifsInode->clientCanCacheRead = false;
pCifsInode->oplockPending = true;
AllocOplockQEntry(netfile->pInode,
netfile->netfid, tcon);
cFYI(1, ("about to wake up oplock thread"));
if (oplockThread)
wake_up_process(oplockThread);
return true;
}
read_unlock(&GlobalSMBSeslock);
read_unlock(&cifs_tcp_ses_lock);
cFYI(1, ("No matching file for oplock break"));
return true;
}
}
read_unlock(&GlobalSMBSeslock);
read_unlock(&cifs_tcp_ses_lock);
cFYI(1, ("Can not process oplock break for non-existent connection"));
return true;
}