Commit 2aa60962 authored by Steve French's avatar Steve French

Fix locking of global smb list. Add missing rc checks.

parent ecf2c214
...@@ -79,18 +79,20 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -79,18 +79,20 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
buf += length; buf += length;
i = 0; i = 0;
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalSMBSessionList) { list_for_each(tmp, &GlobalSMBSessionList) {
i++; i++;
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
length = length =
sprintf(buf, sprintf(buf,
"\n%d) Name: %s Domain: %s HowManyMounts: %d LocalUsersToSameServer: %d\n\t ServerOS: %s ServerNOS: %s Capabilities: 0x%x ", "\n%d) Name: %s Domain: %s HowManyMounts: %d ServerOS: %s ServerNOS: %s Capabilities: 0x%x\n",
i, ses->serverName, ses->serverDomain, i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse),
atomic_read(&ses->inUse), ses->serverOS, ses->serverNOS, ses->capabilities);
atomic_read(&ses->server->socketUseCount),
ses->serverOS, ses->serverNOS, ses->capabilities);
buf += length; buf += length;
if(ses->server)
buf += sprintf(buf, "\tLocal Users To Same Server: %d ",atomic_read(&ses->server->socketUseCount));
} }
read_unlock(&GlobalSMBSeslock);
sprintf(buf, "\n"); sprintf(buf, "\n");
buf++; buf++;
printk("\nTotal Buffer so far: %s\n", buf_start); printk("\nTotal Buffer so far: %s\n", buf_start);
...@@ -99,6 +101,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -99,6 +101,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
buf += length; buf += length;
i = 0; i = 0;
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalTreeConnectionList) { list_for_each(tmp, &GlobalTreeConnectionList) {
i++; i++;
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
...@@ -122,6 +125,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -122,6 +125,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
tcon->fsDevInfo.DeviceType); tcon->fsDevInfo.DeviceType);
buf += length; buf += length;
} }
read_unlock(&GlobalSMBSeslock);
length = sprintf(buf, "\n"); length = sprintf(buf, "\n");
buf += length; buf += length;
*eof = 1; *eof = 1;
...@@ -156,22 +160,22 @@ int ...@@ -156,22 +160,22 @@ int
cifs_stats_read(char *buf, char **beginBuffer, off_t offset, cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
int length, int *eof, void *data) int length, int *eof, void *data)
{ {
int item_length; int item_length;
length = length =
sprintf(buf, sprintf(buf,
"Currently Allocated structures\nCIFS Sessions: %d\n",sesInfoAllocCount.counter); "Currently Allocated structures\nCIFS Sessions: %d\n",sesInfoAllocCount.counter);
buf += length; buf += length;
item_length = item_length =
sprintf(buf,"Shares (unique mount targets): %d\n",tconInfoAllocCount.counter); sprintf(buf,"Shares (unique mount targets): %d\n",tconInfoAllocCount.counter);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
item_length = item_length =
sprintf(buf,"Allocated SMB Request and Response Buffers: %d\n",bufAllocCount.counter); sprintf(buf,"Allocated SMB Request and Response Buffers: %d\n",bufAllocCount.counter);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
item_length = item_length =
sprintf(buf,"Active Operations (MIDs in use): %d\n",midCount.counter); sprintf(buf,"Active Operations (MIDs in use): %d\n",midCount.counter);
length += item_length; length += item_length;
return length; return length;
} }
...@@ -262,10 +266,13 @@ cifs_proc_clean(void) ...@@ -262,10 +266,13 @@ cifs_proc_clean(void)
remove_proc_entry("DebugData", proc_fs_cifs); remove_proc_entry("DebugData", proc_fs_cifs);
remove_proc_entry("cifsFYI", proc_fs_cifs); remove_proc_entry("cifsFYI", proc_fs_cifs);
remove_proc_entry("TraceSMB", proc_fs_cifs); remove_proc_entry("TraceSMB", proc_fs_cifs);
remove_proc_entry("MaxSimultaneousOps", proc_fs_cifs); remove_proc_entry("SimultaneousOps", proc_fs_cifs);
remove_proc_entry("TotalOps", proc_fs_cifs); remove_proc_entry("TotalOps", proc_fs_cifs);
remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("MultiuserMount", proc_fs_cifs);
remove_proc_entry("oplockEnabled", proc_fs_cifs); remove_proc_entry("oplockEnabled", proc_fs_cifs);
remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
remove_proc_entry("cifs", proc_root_fs); remove_proc_entry("cifs", proc_root_fs);
} }
......
...@@ -64,8 +64,10 @@ cifs_read_super(struct super_block *sb, void *data, char *devname, int silent) ...@@ -64,8 +64,10 @@ cifs_read_super(struct super_block *sb, void *data, char *devname, int silent)
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
int rc = 0; int rc = 0;
sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL); sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
cifs_sb = CIFS_SB(sb); cifs_sb = CIFS_SB(sb);
if(cifs_sb == NULL)
return -ENOMEM;
cifs_sb->local_nls = load_nls_default(); /* needed for ASCII cp to Unicode converts */ cifs_sb->local_nls = load_nls_default(); /* needed for ASCII cp to Unicode converts */
rc = cifs_mount(sb, cifs_sb, data, devname); rc = cifs_mount(sb, cifs_sb, data, devname);
...@@ -97,13 +99,12 @@ cifs_read_super(struct super_block *sb, void *data, char *devname, int silent) ...@@ -97,13 +99,12 @@ cifs_read_super(struct super_block *sb, void *data, char *devname, int silent)
if (inode) if (inode)
iput(inode); iput(inode);
/* rc = cifs_umount(sb); BB is CIFS unmount routine needed? */
if (rc) { if (rc) {
cERROR(1, ("cifs_umount failed with return code %d\n", rc)); cERROR(1, ("cifs_mount failed with no root inode"));
} }
out_mount_failed: out_mount_failed:
if(cifs_sb) if(cifs_sb)
kfree(cifs_sb); kfree(cifs_sb);
return -EINVAL; return -EINVAL;
} }
...@@ -114,15 +115,18 @@ cifs_put_super(struct super_block *sb) ...@@ -114,15 +115,18 @@ cifs_put_super(struct super_block *sb)
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
cFYI(1, ("In cifs_put_super\n")); cFYI(1, ("In cifs_put_super\n"));
schedule_timeout(HZ*4);
cifs_sb = CIFS_SB(sb); cifs_sb = CIFS_SB(sb);
rc = cifs_umount(sb, cifs_sb); if(cifs_sb == NULL) {
cFYI(1,("\nEmpty cifs superblock info passed to unmount"));
return;
}
rc = cifs_umount(sb, cifs_sb);
if (rc) { if (rc) {
cERROR(1, ("cifs_umount failed with return code %d\n", rc)); cERROR(1, ("cifs_umount failed with return code %d\n", rc));
} }
if(cifs_sb) { unload_nls(cifs_sb->local_nls);
unload_nls(cifs_sb->local_nls); kfree(cifs_sb);
kfree(cifs_sb);
}
return; return;
} }
...@@ -387,8 +391,11 @@ init_cifs(void) ...@@ -387,8 +391,11 @@ init_cifs(void)
atomic_set(&tconInfoAllocCount, 0); atomic_set(&tconInfoAllocCount, 0);
atomic_set(&bufAllocCount, 0); atomic_set(&bufAllocCount, 0);
atomic_set(&midCount, 0); atomic_set(&midCount, 0);
GlobalCurrentXid = 0;
GlobalTotalActiveXid = 0; GlobalTotalActiveXid = 0;
GlobalMaxActiveXid = 0; GlobalMaxActiveXid = 0;
GlobalSMBSeslock = RW_LOCK_UNLOCKED;
GlobalMid_Lock = RW_LOCK_UNLOCKED;
rc = cifs_init_inodecache(); rc = cifs_init_inodecache();
if (!rc) { if (!rc) {
......
...@@ -292,13 +292,10 @@ GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */ ...@@ -292,13 +292,10 @@ GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */
*/ */
GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH]; GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH];
GLOBAL_EXTERN struct list_head GlobalServerList; /* BB this one is not implemented yet */ GLOBAL_EXTERN struct list_head GlobalServerList; /* BB not implemented yet */
GLOBAL_EXTERN struct list_head GlobalSMBSessionList; GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
/* GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
* Global list of free SMB structures
*/
GLOBAL_EXTERN void *GlobalFreeSMB;
/* /*
* Global transaction id (XID) information * Global transaction id (XID) information
...@@ -306,7 +303,8 @@ GLOBAL_EXTERN void *GlobalFreeSMB; ...@@ -306,7 +303,8 @@ GLOBAL_EXTERN void *GlobalFreeSMB;
GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */
GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */
GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */
GLOBAL_EXTERN rwlock_t GlobalMid_Lock; /* protects above and list operations */
/* on midQ entries */
GLOBAL_EXTERN char Local_System_Name[15]; GLOBAL_EXTERN char Local_System_Name[15];
/* /*
...@@ -321,13 +319,12 @@ GLOBAL_EXTERN atomic_t midCount; ...@@ -321,13 +319,12 @@ GLOBAL_EXTERN atomic_t midCount;
/* Misc globals */ /* Misc globals */
GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
to be established on existing mount if we to be established on existing mount if we
have the uid/password or Kerberos credential have the uid/password or Kerberos credential
or equivalent for current user */ or equivalent for current user */
GLOBAL_EXTERN unsigned int oplockEnabled; GLOBAL_EXTERN unsigned int oplockEnabled;
GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */ with more secure ntlmssp2 challenge/resp */
GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */
GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
...@@ -505,7 +505,8 @@ CIFSSMBRead(const int xid, const struct cifsTconInfo *tcon, ...@@ -505,7 +505,8 @@ CIFSSMBRead(const int xid, const struct cifsTconInfo *tcon,
pReadData = pReadData =
(char *) (&pSMBr->hdr.Protocol) + (char *) (&pSMBr->hdr.Protocol) +
le16_to_cpu(pSMBr->DataOffset); le16_to_cpu(pSMBr->DataOffset);
copy_to_user(buf, pReadData, pSMBr->DataLength); if(copy_to_user(buf, pReadData, pSMBr->DataLength))
rc = -EFAULT;
} }
} }
...@@ -544,7 +545,13 @@ CIFSSMBWrite(const int xid, const struct cifsTconInfo *tcon, ...@@ -544,7 +545,13 @@ CIFSSMBWrite(const int xid, const struct cifsTconInfo *tcon,
pSMB->DataLengthHigh = 0; pSMB->DataLengthHigh = 0;
pSMB->DataOffset = pSMB->DataOffset =
cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
copy_from_user(pSMB->Data, buf, pSMB->DataLengthLow);
if(copy_from_user(pSMB->Data, buf, pSMB->DataLengthLow)) {
buf_release(pSMB);
return -EFAULT;
}
pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ; pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ;
pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow); pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow);
......
...@@ -219,6 +219,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -219,6 +219,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
task_to_wake = NULL; task_to_wake = NULL;
read_lock(&GlobalMid_Lock);
list_for_each(tmp, &server->pending_mid_q) { list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_entry = list_entry(tmp, struct
mid_q_entry, mid_q_entry,
...@@ -234,7 +235,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -234,7 +235,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
MID_RESPONSE_RECEIVED; MID_RESPONSE_RECEIVED;
} }
} }
read_unlock(&GlobalMid_Lock);
if (task_to_wake) { if (task_to_wake) {
smb_buffer = NULL; /* will be freed by users thread after he is done */ smb_buffer = NULL; /* will be freed by users thread after he is done */
wake_up_process(task_to_wake); wake_up_process(task_to_wake);
...@@ -256,12 +257,14 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -256,12 +257,14 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
/* BB add code to lock SMB sessions while releasing */ /* BB add code to lock SMB sessions while releasing */
if(server->ssocket) { if(server->ssocket) {
sock_release(csocket); sock_release(csocket);
server->ssocket = NULL; server->ssocket = NULL;
} }
set_fs(temp_fs); set_fs(temp_fs);
if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
buf_release(smb_buffer); buf_release(smb_buffer);
read_lock(&GlobalSMBSeslock);
if (list_empty(&server->pending_mid_q)) { if (list_empty(&server->pending_mid_q)) {
/* loop through server session structures attached to this and mark them dead */ /* loop through server session structures attached to this and mark them dead */
list_for_each(tmp, &GlobalSMBSessionList) { list_for_each(tmp, &GlobalSMBSessionList) {
...@@ -275,10 +278,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -275,10 +278,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
kfree(server); kfree(server);
} else /* BB need to more gracefully handle the rare negative session } else /* BB need to more gracefully handle the rare negative session
response case because response will be still outstanding */ response case because response will be still outstanding */
cERROR(1, ("\nThere are still active MIDs in queue and we are exiting but we can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!\n ")); /* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */ cERROR(1, ("\nThere are still active MIDs in queue and we are exiting but we can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!\n ")); /* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */
/* BB Need to fix bug in error path above - perhaps wait until smb requests /* BB Need to fix bug in error path above - perhaps wait until smb requests
time out and then free the tcp per server struct BB */ time out and then free the tcp per server struct BB */
read_unlock(&GlobalSMBSeslock);
cFYI(1, ("\nAbout to exit from demultiplex thread\n")); cFYI(1, ("\nAbout to exit from demultiplex thread\n"));
return 0; return 0;
...@@ -421,7 +426,7 @@ find_tcp_session(__u32 new_target_ip_addr, ...@@ -421,7 +426,7 @@ find_tcp_session(__u32 new_target_ip_addr,
struct cifsSesInfo *ses; struct cifsSesInfo *ses;
*psrvTcp = NULL; *psrvTcp = NULL;
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalSMBSessionList) { list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
if (ses->server) { if (ses->server) {
...@@ -432,12 +437,15 @@ find_tcp_session(__u32 new_target_ip_addr, ...@@ -432,12 +437,15 @@ find_tcp_session(__u32 new_target_ip_addr,
/* BB check if reconnection needed */ /* BB check if reconnection needed */
if (strncmp if (strncmp
(ses->userName, userName, (ses->userName, userName,
MAX_USERNAME_SIZE) == 0) MAX_USERNAME_SIZE) == 0){
read_unlock(&GlobalSMBSeslock);
return ses; /* found exact match on both tcp and SMB sessions */ return ses; /* found exact match on both tcp and SMB sessions */
}
} }
} }
/* else tcp and smb sessions need reconnection */ /* else tcp and smb sessions need reconnection */
} }
read_unlock(&GlobalSMBSeslock);
return NULL; return NULL;
} }
...@@ -447,6 +455,7 @@ find_unc(__u32 new_target_ip_addr, char *uncName, char *userName) ...@@ -447,6 +455,7 @@ find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
struct list_head *tmp; struct list_head *tmp;
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalTreeConnectionList) { list_for_each(tmp, &GlobalTreeConnectionList) {
cFYI(1, ("\nNext tcon - ")); cFYI(1, ("\nNext tcon - "));
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
...@@ -473,13 +482,16 @@ find_unc(__u32 new_target_ip_addr, char *uncName, char *userName) ...@@ -473,13 +482,16 @@ find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
if (strncmp if (strncmp
(tcon->ses->userName, (tcon->ses->userName,
userName, userName,
MAX_USERNAME_SIZE) == 0) MAX_USERNAME_SIZE) == 0) {
read_unlock(&GlobalSMBSeslock);
return tcon;/* also matched user (smb session)*/ return tcon;/* also matched user (smb session)*/
}
} }
} }
} }
} }
} }
read_unlock(&GlobalSMBSeslock);
return NULL; return NULL;
} }
...@@ -599,7 +611,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -599,7 +611,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
{ {
int rc = 0; int rc = 0;
int xid; int xid;
int ntlmv2_flag = FALSE; int ntlmv2_flag = FALSE;
struct socket *csocket; struct socket *csocket;
struct sockaddr_in sin_server; struct sockaddr_in sin_server;
/* struct sockaddr_in6 sin_server6; */ /* struct sockaddr_in6 sin_server6; */
...@@ -616,7 +628,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -616,7 +628,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
xid = GetXid(); xid = GetXid();
cFYI(0, ("\nEntering cifs_mount. Xid: %d with: %s\n", xid, mount_data)); cFYI(0, ("\nEntering cifs_mount. Xid: %d with: %s\n", xid, mount_data));
parse_mount_options(mount_data, devname, &volume_info); if(parse_mount_options(mount_data, devname, &volume_info)) {
FreeXid(xid);
return -EINVAL;
}
if (volume_info.username) { if (volume_info.username) {
cFYI(1, ("\nUsername: %s ", volume_info.username)); cFYI(1, ("\nUsername: %s ", volume_info.username));
...@@ -634,7 +650,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -634,7 +650,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cERROR(1, cERROR(1,
("\nCIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); ("\nCIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
FreeXid(xid); FreeXid(xid);
return -ENODEV; return -EINVAL;
} }
/* BB add support to use the multiuser_mount flag BB */ /* BB add support to use the multiuser_mount flag BB */
existingCifsSes = existingCifsSes =
...@@ -2202,6 +2218,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) ...@@ -2202,6 +2218,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
struct cifsSesInfo *ses = NULL; struct cifsSesInfo *ses = NULL;
xid = GetXid(); xid = GetXid();
if (cifs_sb->tcon) { if (cifs_sb->tcon) {
ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/ ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
rc = CIFSSMBTDis(xid, cifs_sb->tcon); rc = CIFSSMBTDis(xid, cifs_sb->tcon);
...@@ -2218,16 +2235,11 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) ...@@ -2218,16 +2235,11 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
FreeXid(xid); FreeXid(xid);
return 0; return 0;
} }
/* wake_up_process(ses->server->tsk);*/ /* was worth a try */
schedule_timeout(HZ / 4); /* give captive thread time to exit */ schedule_timeout(HZ / 4); /* give captive thread time to exit */
if((ses->server) && (ses->server->ssocket)) { if((ses->server) && (ses->server->ssocket)) {
cFYI(1,("\nWaking up socket by sending it signal ")); cFYI(1,("\nWaking up socket by sending it signal "));
send_sig(SIGINT,ses->server->tsk,1); send_sig(SIGINT,ses->server->tsk,1);
/* No luck figuring out a better way to_close socket */ }
/*ses->server->ssocket->sk->prot->close(ses->server->ssocket->sk,0);*/
/* ses->server->ssocket = NULL; */ /* serialize better */
/* sock_wake_async(ses->server->ssocket,3,POLL_HUP); */
}
} else } else
cFYI(1, ("\nNo session or bad tcon")); cFYI(1, ("\nNo session or bad tcon"));
} }
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
extern kmem_cache_t *cifs_req_cachep; extern kmem_cache_t *cifs_req_cachep;
static DECLARE_MUTEX(GlobalMid_Sem); /* also protects XID globals */
__u16 GlobalMid; /* multiplex id - rotating counter */ __u16 GlobalMid; /* multiplex id - rotating counter */
/* The xid serves as a useful identifier for each incoming vfs request, /* The xid serves as a useful identifier for each incoming vfs request,
...@@ -42,21 +41,21 @@ _GetXid(void) ...@@ -42,21 +41,21 @@ _GetXid(void)
{ {
unsigned int xid; unsigned int xid;
down(&GlobalMid_Sem); write_lock(&GlobalMid_Lock);
GlobalTotalActiveXid++; GlobalTotalActiveXid++;
if (GlobalTotalActiveXid > GlobalMaxActiveXid) if (GlobalTotalActiveXid > GlobalMaxActiveXid)
GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */
xid = GlobalCurrentXid++; xid = GlobalCurrentXid++;
up(&GlobalMid_Sem); write_unlock(&GlobalMid_Lock);
return xid; return xid;
} }
void void
_FreeXid(unsigned int xid) _FreeXid(unsigned int xid)
{ {
down(&GlobalMid_Sem); write_lock(&GlobalMid_Lock);
GlobalTotalActiveXid--; GlobalTotalActiveXid--;
up(&GlobalMid_Sem); write_unlock(&GlobalMid_Lock);
} }
struct cifsSesInfo * struct cifsSesInfo *
...@@ -69,9 +68,11 @@ sesInfoAlloc(void) ...@@ -69,9 +68,11 @@ sesInfoAlloc(void)
GFP_KERNEL); GFP_KERNEL);
if (ret_buf) { if (ret_buf) {
memset(ret_buf, 0, sizeof (struct cifsSesInfo)); memset(ret_buf, 0, sizeof (struct cifsSesInfo));
write_lock(&GlobalSMBSeslock);
atomic_inc(&sesInfoAllocCount); atomic_inc(&sesInfoAllocCount);
list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList); list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList);
init_MUTEX(&ret_buf->sesSem); init_MUTEX(&ret_buf->sesSem);
write_unlock(&GlobalSMBSeslock);
} }
return ret_buf; return ret_buf;
} }
...@@ -84,8 +85,10 @@ sesInfoFree(struct cifsSesInfo *buf_to_free) ...@@ -84,8 +85,10 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
return; return;
} }
write_lock(&GlobalSMBSeslock);
atomic_dec(&sesInfoAllocCount); atomic_dec(&sesInfoAllocCount);
list_del(&buf_to_free->cifsSessionList); list_del(&buf_to_free->cifsSessionList);
write_unlock(&GlobalSMBSeslock);
if (buf_to_free->serverOS) if (buf_to_free->serverOS)
kfree(buf_to_free->serverOS); kfree(buf_to_free->serverOS);
if (buf_to_free->serverDomain) if (buf_to_free->serverDomain)
...@@ -104,11 +107,13 @@ tconInfoAlloc(void) ...@@ -104,11 +107,13 @@ tconInfoAlloc(void)
GFP_KERNEL); GFP_KERNEL);
if (ret_buf) { if (ret_buf) {
memset(ret_buf, 0, sizeof (struct cifsTconInfo)); memset(ret_buf, 0, sizeof (struct cifsTconInfo));
write_lock(&GlobalSMBSeslock);
atomic_inc(&tconInfoAllocCount); atomic_inc(&tconInfoAllocCount);
list_add(&ret_buf->cifsConnectionList, list_add(&ret_buf->cifsConnectionList,
&GlobalTreeConnectionList); &GlobalTreeConnectionList);
INIT_LIST_HEAD(&ret_buf->openFileList); INIT_LIST_HEAD(&ret_buf->openFileList);
init_MUTEX(&ret_buf->tconSem); init_MUTEX(&ret_buf->tconSem);
write_unlock(&GlobalSMBSeslock);
} }
return ret_buf; return ret_buf;
} }
...@@ -120,9 +125,10 @@ tconInfoFree(struct cifsTconInfo *buf_to_free) ...@@ -120,9 +125,10 @@ tconInfoFree(struct cifsTconInfo *buf_to_free)
cFYI(1, ("\nNull buffer passed to tconInfoFree")); cFYI(1, ("\nNull buffer passed to tconInfoFree"));
return; return;
} }
write_lock(&GlobalSMBSeslock);
atomic_dec(&tconInfoAllocCount); atomic_dec(&tconInfoAllocCount);
list_del(&buf_to_free->cifsConnectionList); list_del(&buf_to_free->cifsConnectionList);
write_unlock(&GlobalSMBSeslock);
if (buf_to_free->nativeFileSystem) if (buf_to_free->nativeFileSystem)
kfree(buf_to_free->nativeFileSystem); kfree(buf_to_free->nativeFileSystem);
kfree(buf_to_free); kfree(buf_to_free);
...@@ -203,9 +209,10 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -203,9 +209,10 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
buffer->Pid = tmp & 0xFFFF; buffer->Pid = tmp & 0xFFFF;
tmp >>= 16; tmp >>= 16;
buffer->PidHigh = tmp & 0xFFFF; buffer->PidHigh = tmp & 0xFFFF;
down(&GlobalMid_Sem); write_lock(&GlobalMid_Lock);
GlobalMid++; GlobalMid++;
buffer->Mid = GlobalMid; buffer->Mid = GlobalMid;
write_unlock(&GlobalMid_Lock);
if (treeCon) { if (treeCon) {
buffer->Tid = treeCon->tid; buffer->Tid = treeCon->tid;
if (treeCon->ses) { if (treeCon->ses) {
...@@ -218,13 +225,11 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -218,13 +225,11 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
} }
if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
buffer->Flags2 |= SMBFLG2_DFS; buffer->Flags2 |= SMBFLG2_DFS;
if(treeCon->ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) if(treeCon->ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
} }
/* endian conversion of flags is now done just before sending */ /* endian conversion of flags is now done just before sending */
up(&GlobalMid_Sem);
buffer->WordCount = (char) word_count; buffer->WordCount = (char) word_count;
return; return;
} }
...@@ -233,17 +238,18 @@ int ...@@ -233,17 +238,18 @@ int
checkSMBhdr(struct smb_hdr *smb, __u16 mid) checkSMBhdr(struct smb_hdr *smb, __u16 mid)
{ {
/* Make sure that this really is an SMB, that it is a response, /* Make sure that this really is an SMB, that it is a response,
and that the message ids match */ and that the message ids match */
if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) && (mid == smb->Mid)) { if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
if(smb->Flags & SMBFLG_RESPONSE) (mid == smb->Mid)) {
return 0; if(smb->Flags & SMBFLG_RESPONSE)
else { return 0;
/* only one valid case where server sends us request */ else {
if(smb->Command == SMB_COM_LOCKING_ANDX) /* only one valid case where server sends us request */
return 0; if(smb->Command == SMB_COM_LOCKING_ANDX)
else return 0;
cERROR(1, ("\n Rcvd Request not response ")); else
} cERROR(1, ("\n Rcvd Request not response "));
}
} else { /* bad signature or mid */ } else { /* bad signature or mid */
if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff)) if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff))
cERROR(1, cERROR(1,
...@@ -252,8 +258,8 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) ...@@ -252,8 +258,8 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
if (mid != smb->Mid) if (mid != smb->Mid)
cERROR(1, ("\n Mids do not match \n")); cERROR(1, ("\n Mids do not match \n"));
} }
cERROR(1, ("\nCIFS: bad smb detected. The Mid=%d\n", smb->Mid)); cERROR(1, ("\nCIFS: bad smb detected. The Mid=%d\n", smb->Mid));
return 1; return 1;
} }
int int
...@@ -269,7 +275,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) ...@@ -269,7 +275,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
cERROR(1, ("\n Length less than 2 + sizeof smb_hdr ")); cERROR(1, ("\n Length less than 2 + sizeof smb_hdr "));
if ((length >= sizeof (struct smb_hdr) - 1) if ((length >= sizeof (struct smb_hdr) - 1)
&& (smb->Status.CifsError != 0)) && (smb->Status.CifsError != 0))
return 0; /* this is ok - some error cases do not return wct and bcc */ return 0; /* some error cases do not return wct and bcc */
} }
if (4 + ntohl(smb->smb_buf_length) > if (4 + ntohl(smb->smb_buf_length) >
...@@ -298,30 +304,42 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) ...@@ -298,30 +304,42 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
int int
is_valid_oplock_break(struct smb_hdr *buf) is_valid_oplock_break(struct smb_hdr *buf)
{ {
struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf; struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf;
struct list_head *tmp;
/* could add check for smb response flag 0x80 */ struct cifsTconInfo *tcon;
cFYI(1,("\nChecking for oplock break"));
if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) /* could add check for smb response flag 0x80 */
return FALSE; cFYI(1,("\nChecking for oplock break"));
if(pSMB->hdr.Flags & SMBFLG_RESPONSE) if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
return FALSE; /* server sends us "request" here */ return FALSE;
if(pSMB->hdr.WordCount != 8) if(pSMB->hdr.Flags & SMBFLG_RESPONSE)
return FALSE; return FALSE; /* server sends us "request" here */
if(pSMB->hdr.WordCount != 8)
cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel)); return FALSE;
if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
return FALSE; cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel));
if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
/* BB Add following logic: return FALSE;
1) look up tcon based on tid & uid
2) look up inode from tcon->openFileList->file->f_dentry->d_inode /* look up tcon based on tid & uid */
3) flush dirty pages and cached byte range locks and mark inode read_lock(&GlobalSMBSeslock);
4) depending on break type change to r/o caching or no caching list_for_each(tmp, &GlobalTreeConnectionList) {
5) send oplock break response to server */ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
cFYI(1,("\nNeed to process oplock break ")); if (tcon->tid == buf->Tid)
if(tcon->ses->Suid == buf->Uid) {
return TRUE; /* BB Add following logic:
2) look up inode from tcon->openFileList->file->f_dentry->d_inode
3) flush dirty pages and cached byte range locks and mark inode
4) depending on break type change to r/o caching or no caching
5) send oplock break response to server */
read_unlock(&GlobalSMBSeslock);
cFYI(1,("\nFound matching connection, process oplock break"));
return TRUE;
}
}
read_unlock(&GlobalSMBSeslock);
cFYI(1,("\nProcessing oplock break for non-existent connection"));
return TRUE;
} }
void void
......
...@@ -59,9 +59,11 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) ...@@ -59,9 +59,11 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
temp->tsk = current; temp->tsk = current;
} }
if (ses->status == CifsGood) { if (ses->status == CifsGood) {
write_lock(&GlobalMid_Lock);
list_add_tail(&temp->qhead, &ses->server->pending_mid_q); list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
atomic_inc(&midCount); atomic_inc(&midCount);
temp->midState = MID_REQUEST_ALLOCATED; temp->midState = MID_REQUEST_ALLOCATED;
write_unlock(&GlobalMid_Lock);
} else { /* BB add reconnect code here BB */ } else { /* BB add reconnect code here BB */
cERROR(1, cERROR(1,
...@@ -77,11 +79,13 @@ void ...@@ -77,11 +79,13 @@ void
DeleteMidQEntry(struct mid_q_entry *midEntry) DeleteMidQEntry(struct mid_q_entry *midEntry)
{ {
/* BB add spinlock to protect midq for each session BB */ /* BB add spinlock to protect midq for each session BB */
write_lock(&GlobalMid_Lock);
midEntry->midState = MID_FREE; midEntry->midState = MID_FREE;
buf_release(midEntry->resp_buf);
list_del(&midEntry->qhead); list_del(&midEntry->qhead);
kmem_cache_free(cifs_mid_cachep, midEntry);
atomic_dec(&midCount); atomic_dec(&midCount);
write_unlock(&GlobalMid_Lock);
buf_release(midEntry->resp_buf);
kmem_cache_free(cifs_mid_cachep, midEntry);
} }
int int
......
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