Commit 9b2a48c5 authored by Steve French's avatar Steve French Committed by Steve French

Fix spinlock usage for SMP safety

parent ee6fd424
......@@ -2,6 +2,7 @@ Version 0.92
------------
Active smb transactions should never go negative (fix double FreeXid). Fix
list processing in file routines. Check return code on kmalloc in open.
Fix spinlock usage for SMP.
Version 0.91
------------
......
/*
* fs/cifs_debug.c
*
* Copyright (c) International Business Machines Corp., 2000,2002
* Copyright (C) International Business Machines Corp., 2000,2003
*
* Modified by Steve French (sfrench@us.ibm.com)
*
......@@ -84,12 +84,12 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
length =
sprintf(buf,
"\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s ServerNOS: %s\n\tCapabilities: 0x%x",
"\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x",
i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse),
ses->serverOS, ses->serverNOS, ses->capabilities);
buf += length;
if(ses->server)
buf += sprintf(buf, "\tLocal Users To Same Server: %d SecMode: 0x%x",
buf += sprintf(buf, "\n\tLocal Users To Same Server: %d SecMode: 0x%x",
atomic_read(&ses->server->socketUseCount),ses->server->secMode);
}
read_unlock(&GlobalSMBSeslock);
......@@ -123,6 +123,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
sprintf(buf, " type: %d ",
tcon->fsDevInfo.DeviceType);
buf += length;
if(tcon->tidStatus == CifsNeedReconnect)
buf += sprintf(buf, "\tDISCONNECTED ");
}
read_unlock(&GlobalSMBSeslock);
length = sprintf(buf, "\n");
......
/*
* fs/cifs/cifsencrypt.c
*
* Copyright (c) International Business Machines Corp., 2003
* Copyright (C) International Business Machines Corp., 2003
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
......@@ -64,13 +64,13 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
if((le32_to_cpu(cifs_pdu->Flags2) & SMBFLG2_SECURITY_SIGNATURE) == 0)
return rc;
write_lock(&GlobalMid_Lock);
spin_lock(&GlobalMid_Lock);
cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0;
*pexpected_response_sequence_number = ses->sequence_number++;
ses->sequence_number++;
write_unlock(&GlobalMid_Lock);
spin_unlock(&GlobalMid_Lock);
rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature);
if(rc)
......
/*
* fs/cifs/cifsfs.c
*
* Copyright (c) International Business Machines Corp., 2002
* Copyright (C) International Business Machines Corp., 2002,2003
* Author(s): Steve French (sfrench@us.ibm.com)
*
* Common Internet FileSystem (CIFS) client
......@@ -571,8 +571,6 @@ cifs_destroy_mids(void)
static int cifs_oplock_thread(void * dummyarg)
{
struct list_head * tmp;
struct list_head * tmp1;
struct oplock_q_entry * oplock_item;
struct cifsTconInfo *pTcon;
struct inode * inode;
......@@ -585,19 +583,22 @@ static int cifs_oplock_thread(void * dummyarg)
oplockThread = current;
do {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(100*HZ);
/* BB add missing code */
write_lock(&GlobalMid_Lock);
list_for_each_safe(tmp, tmp1, &GlobalOplock_Q) {
oplock_item = list_entry(tmp, struct oplock_q_entry,
qhead);
schedule_timeout(39*HZ);
spin_lock(&GlobalMid_Lock);
if(list_empty(&GlobalOplock_Q)) {
spin_unlock(&GlobalMid_Lock);
schedule_timeout(39*HZ);
} else {
oplock_item = list_entry(GlobalOplock_Q.next,
struct oplock_q_entry, qhead);
if(oplock_item) {
pTcon = oplock_item->tcon;
inode = oplock_item->pinode;
netfid = oplock_item->netfid;
DeleteOplockQEntry(oplock_item);
write_unlock(&GlobalMid_Lock);
if (S_ISREG(inode->i_mode))
spin_unlock(&GlobalMid_Lock);
if (S_ISREG(inode->i_mode))
rc = filemap_fdatawrite(inode->i_mapping);
else
rc = 0;
......@@ -609,11 +610,9 @@ static int cifs_oplock_thread(void * dummyarg)
0, LOCKING_ANDX_OPLOCK_RELEASE,
0 /* wait flag */);
cFYI(1,("Oplock release rc = %d ",rc));
write_lock(&GlobalMid_Lock);
} else
break;
spin_unlock(&GlobalMid_Lock);
}
write_unlock(&GlobalMid_Lock);
} while(!signal_pending(current));
complete_and_exit (&cifs_oplock_exited, 0);
}
......@@ -640,7 +639,7 @@ init_cifs(void)
GlobalTotalActiveXid = 0;
GlobalMaxActiveXid = 0;
GlobalSMBSeslock = RW_LOCK_UNLOCKED;
GlobalMid_Lock = RW_LOCK_UNLOCKED;
GlobalMid_Lock = SPIN_LOCK_UNLOCKED;
rc = cifs_init_inodecache();
if (!rc) {
......
/*
* fs/cifs/cifsglob.h
*
* Copyright (c) International Business Machines Corp., 2002
* Copyright (C) International Business Machines Corp., 2002,2003
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
......@@ -212,6 +212,7 @@ struct cifsFileInfo {
int endOfSearch:1; /* we have reached end of search */
int closePend:1; /* file is marked to close */
int emptyDir:1;
int invalidHandle:1; /* file closed via session abend */
char * search_resume_name;
unsigned int resume_name_length;
__u32 resume_key;
......@@ -294,7 +295,27 @@ struct servers_not_supported { /* @z4a */
* following to be declared.
*/
/* BB Every global should have an associated mutex for safe update BB */
/****************************************************************************
* Locking notes. All updates to global variables and lists should be
* protected by spinlocks or semaphores.
*
* Spinlocks
* ---------
* GlobalMid_Lock protects:
* list operations on pending_mid_q and oplockQ
* updates to XID counters, multiplex id and SMB sequence numbers
* GlobalSMBSesLock protects:
* list operations on tcp and SMB session lists and tCon lists
* f_owner.lock protects certain per file struct operations
* mapping->page_lock protects certain per page operations
*
* Semaphores
* ----------
* sesSem operations on smb session
* tconSem operations on tree connection
* i_sem inode operations
*
****************************************************************************/
#ifdef DECLARE_GLOBALS_HERE
#define GLOBAL_EXTERN
......@@ -327,7 +348,7 @@ GLOBAL_EXTERN struct list_head GlobalOplock_Q;
GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */
GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */
GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */
GLOBAL_EXTERN rwlock_t GlobalMid_Lock; /* protects above and list operations */
GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */
/* on midQ entries */
GLOBAL_EXTERN char Local_System_Name[15];
......
/*
* fs/cifs/connect.c
*
* Copyright (c) International Business Machines Corp., 2002
* Copyright (C) International Business Machines Corp., 2002,2003
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
......@@ -272,7 +272,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
}
task_to_wake = NULL;
read_lock(&GlobalMid_Lock);
spin_lock(&GlobalMid_Lock);
list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct
mid_q_entry,
......@@ -288,7 +288,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
MID_RESPONSE_RECEIVED;
}
}
read_unlock(&GlobalMid_Lock);
spin_unlock(&GlobalMid_Lock);
if (task_to_wake) {
smb_buffer = NULL; /* will be freed by users thread after he is done */
wake_up_process(task_to_wake);
......
......@@ -218,6 +218,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
pCifsFile->netfid = fileHandle;
pCifsFile->pid = current->tgid;
pCifsFile->pInode = newinode;
pCifsFile->invalidHandle = FALSE;
/* pCifsFile->pfile = file; */ /* put in at open time */
write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist,&pTcon->openFileList);
......
......@@ -144,6 +144,7 @@ cifs_open(struct inode *inode, struct file *file)
pCifsFile->pid = current->pid;
pCifsFile->pfile = file; /* needed for writepage */
pCifsFile->pInode = inode;
pCifsFile->invalidHandle = FALSE;
write_lock(&file->f_owner.lock);
write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist,&pTcon->openFileList);
......@@ -215,33 +216,51 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo)
struct list_head *tmp;
struct list_head *tmp1;
/* list all files open on tree connection */
write_lock(&GlobalSMBSeslock); /* BB change to semaphore */
/* list all files open on tree connection and mark them invalid */
write_lock(&GlobalSMBSeslock);
list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
open_file = list_entry(tmp,struct cifsFileInfo, tlist);
if(open_file) {
if(open_file->search_resume_name) {
kfree(open_file->search_resume_name);
}
file = open_file->pfile;
list_del(&open_file->flist);
list_del(&open_file->tlist);
kfree(open_file);
if(file) {
file->private_data = NULL;
if(file->f_dentry == 0) {
cFYI(1,("Null dentry for file %p",file));
} else {
rc = cifs_open(file->f_dentry->d_inode,file);
if(rc) {
cFYI(1,("reconnecting file %s failed with %d",
file->f_dentry->d_name.name,rc));
open_file->invalidHandle = TRUE;
}
}
/* reopen files */
for(;;) {
/* BB need to fix above to check list end and skip entries we do not need to reopen */
if(list_empty(&pTcon->openFileList)) {
break;
} else {
open_file = list_entry(tmp,struct cifsFileInfo, tlist);
if(open_file) {
if(open_file->invalidHandle == FALSE)
continue;
if(open_file->search_resume_name) {
kfree(open_file->search_resume_name);
}
file = open_file->pfile;
list_del(&open_file->flist);
list_del(&open_file->tlist);
kfree(open_file);
if(file) {
file->private_data = NULL;
if(file->f_dentry == 0) {
cFYI(1,("Null dentry for file %p",file));
} else {
cFYI(1,("reconnection of %s succeeded",
write_unlock(&GlobalSMBSeslock);
rc = cifs_open(file->f_dentry->d_inode,file);
write_lock(&GlobalSMBSeslock);
if(rc) {
cFYI(1,("reconnecting file %s failed with %d",
file->f_dentry->d_name.name,rc));
} else {
cFYI(1,("reconnection of %s succeeded",
file->f_dentry->d_name.name));
}
}
}
}
}
}
}
write_unlock(&GlobalSMBSeslock);
......@@ -264,6 +283,7 @@ cifs_close(struct inode *inode, struct file *file)
pTcon = cifs_sb->tcon;
if (pSMBFile) {
write_lock(&file->f_owner.lock);
pSMBFile->invalidHandle = TRUE;
list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist);
write_unlock(&file->f_owner.lock);
......@@ -1242,8 +1262,10 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
rc = 0;
break;
}
} else
} else {
cifsFile->invalidHandle = TRUE;
CIFSFindClose(xid, pTcon, cifsFile->netfid);
}
if(cifsFile->search_resume_name) {
kfree(cifsFile->search_resume_name);
cifsFile->search_resume_name = NULL;
......@@ -1267,6 +1289,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
cifsFile =
(struct cifsFileInfo *) file->private_data;
cifsFile->netfid = searchHandle;
cifsFile->invalidHandle = FALSE;
} else {
rc = -ENOMEM;
break;
......
/*
* fs/cifs/misc.c
*
* Copyright (c) International Business Machines Corp., 2002,2003
* Copyright (C) International Business Machines Corp., 2002,2003
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
......@@ -42,23 +42,23 @@ _GetXid(void)
{
unsigned int xid;
write_lock(&GlobalMid_Lock);
spin_lock(&GlobalMid_Lock);
GlobalTotalActiveXid++;
if (GlobalTotalActiveXid > GlobalMaxActiveXid)
GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */
xid = GlobalCurrentXid++;
write_unlock(&GlobalMid_Lock);
spin_unlock(&GlobalMid_Lock);
return xid;
}
void
_FreeXid(unsigned int xid)
{
write_lock(&GlobalMid_Lock);
spin_lock(&GlobalMid_Lock);
/* if(GlobalTotalActiveXid == 0)
BUG(); */
GlobalTotalActiveXid--;
write_unlock(&GlobalMid_Lock);
spin_unlock(&GlobalMid_Lock);
}
struct cifsSesInfo *
......@@ -217,10 +217,10 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
buffer->Pid = tmp & 0xFFFF;
tmp >>= 16;
buffer->PidHigh = tmp & 0xFFFF;
write_lock(&GlobalMid_Lock);
spin_lock(&GlobalMid_Lock);
GlobalMid++;
buffer->Mid = GlobalMid;
write_unlock(&GlobalMid_Lock);
spin_unlock(&GlobalMid_Lock);
if (treeCon) {
buffer->Tid = treeCon->tid;
if (treeCon->ses) {
......
/*
* fs/cifs/transport.c
*
* Copyright (c) International Business Machines Corp., 2002
* Copyright (C) International Business Machines Corp., 2002,2003
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
......@@ -39,7 +39,6 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
struct mid_q_entry *temp;
int timeout = 10 * HZ;
/* BB add spinlock to protect midq for each session BB */
if (ses == NULL) {
cERROR(1, ("Null session passed in to AllocMidQEntry "));
return NULL;
......@@ -72,11 +71,11 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
}
if (ses->server->tcpStatus == CifsGood) {
write_lock(&GlobalMid_Lock);
spin_lock(&GlobalMid_Lock);
list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
atomic_inc(&midCount);
temp->midState = MID_REQUEST_ALLOCATED;
write_unlock(&GlobalMid_Lock);
spin_unlock(&GlobalMid_Lock);
} else {
cERROR(1,("Need to reconnect after session died to server"));
if (temp)
......@@ -89,12 +88,11 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
void
DeleteMidQEntry(struct mid_q_entry *midEntry)
{
/* BB add spinlock to protect midq for each session BB */
write_lock(&GlobalMid_Lock);
spin_lock(&GlobalMid_Lock);
midEntry->midState = MID_FREE;
list_del(&midEntry->qhead);
atomic_dec(&midCount);
write_unlock(&GlobalMid_Lock);
spin_unlock(&GlobalMid_Lock);
buf_release(midEntry->resp_buf);
kmem_cache_free(cifs_mid_cachep, midEntry);
}
......@@ -115,9 +113,9 @@ AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
temp->pinode = pinode;
temp->tcon = tcon;
temp->netfid = fid;
write_lock(&GlobalMid_Lock);
spin_lock(&GlobalMid_Lock);
list_add_tail(&temp->qhead, &GlobalOplock_Q);
write_unlock(&GlobalMid_Lock);
spin_unlock(&GlobalMid_Lock);
}
return temp;
......@@ -125,11 +123,10 @@ AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
{
/* BB add spinlock to protect midq for each session BB */
write_lock(&GlobalMid_Lock);
spin_lock(&GlobalMid_Lock);
/* should we check if list empty first? */
list_del(&oplockEntry->qhead);
write_unlock(&GlobalMid_Lock);
spin_unlock(&GlobalMid_Lock);
kmem_cache_free(cifs_oplock_cachep, oplockEntry);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment