Skip to content

Commit

Permalink
cifs: disable sharing session and tcon and add new TCP sharing code
Browse files Browse the repository at this point in the history
The code that allows these structs to be shared is extremely racy.
Disable the sharing of SMB and tcon structs for now until we can
come up with a way to do this that's race free.

We want to continue to share TCP sessions, however since they are
required for multiuser mounts. For that, implement a new (hopefully
race-free) scheme. Add a new global list of TCP sessions, and take
care to get a reference to it whenever we're dealing with one.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
  • Loading branch information
Jeff Layton authored and Steve French committed Nov 14, 2008
1 parent 3ec332e commit e7ddee9
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 150 deletions.
2 changes: 1 addition & 1 deletion fs/cifs/cifs_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
seq_printf(m, "TCP status: %d\n\tLocal Users To "
"Server: %d SecMode: 0x%x Req On Wire: %d",
ses->server->tcpStatus,
atomic_read(&ses->server->socketUseCount),
ses->server->srv_count,
ses->server->secMode,
atomic_read(&ses->server->inFlight));

Expand Down
3 changes: 2 additions & 1 deletion fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,7 @@ init_cifs(void)
{
int rc = 0;
cifs_proc_init();
INIT_LIST_HEAD(&global_cifs_sock_list);
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);
Expand Down Expand Up @@ -1089,6 +1089,7 @@ init_cifs(void)
GlobalMaxActiveXid = 0;
memset(Local_System_Name, 0, 15);
rwlock_init(&GlobalSMBSeslock);
rwlock_init(&cifs_tcp_ses_lock);
spin_lock_init(&GlobalMid_Lock);

if (cifs_max_pending < 2) {
Expand Down
17 changes: 11 additions & 6 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ struct cifs_cred {
struct TCP_Server_Info {
struct list_head tcp_ses_list;
struct list_head smb_ses_list;
int srv_count; /* reference counter */
/* 15 character server name + 0x20 16th byte indicating type = srv */
char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
Expand All @@ -144,7 +145,6 @@ struct TCP_Server_Info {
bool svlocal:1; /* local server or remote */
bool noblocksnd; /* use blocking sendmsg */
bool noautotune; /* do not autotune send buf sizes */
atomic_t socketUseCount; /* number of open cifs sessions on socket */
atomic_t inFlight; /* number of requests on the wire to server */
#ifdef CONFIG_CIFS_STATS2
atomic_t inSend; /* requests trying to send */
Expand Down Expand Up @@ -591,13 +591,18 @@ require use of the stronger protocol */
#define GLOBAL_EXTERN extern
#endif


/* the list of TCP_Server_Info structures, ie each of the sockets
/*
* the list of TCP_Server_Info structures, ie each of the sockets
* connecting our client to a distinct server (ip address), is
* chained together by global_cifs_sock_list. The list of all our SMB
* chained together by cifs_tcp_ses_list. The list of all our SMB
* sessions (and from that the tree connections) can be found
* by iterating over global_cifs_sock_list */
GLOBAL_EXTERN struct list_head global_cifs_sock_list;
* by iterating over cifs_tcp_ses_list
*/
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 */
Expand Down
1 change: 1 addition & 0 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ 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 *);
Expand Down
18 changes: 9 additions & 9 deletions fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -664,8 +664,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
rc = -EIO;
goto neg_err_exit;
}

if (server->socketUseCount.counter > 1) {
read_lock(&cifs_tcp_ses_lock);
if (server->srv_count > 1) {
read_unlock(&cifs_tcp_ses_lock);
if (memcmp(server->server_GUID,
pSMBr->u.extended_response.
GUID, 16) != 0) {
Expand All @@ -674,9 +675,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
pSMBr->u.extended_response.GUID,
16);
}
} else
} else {
read_unlock(&cifs_tcp_ses_lock);
memcpy(server->server_GUID,
pSMBr->u.extended_response.GUID, 16);
}

if (count == 16) {
server->secType = RawNTLMSSP;
Expand Down Expand Up @@ -830,12 +833,9 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
pSMB->AndXCommand = 0xFF;
rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
session_already_dead:
atomic_dec(&ses->server->socketUseCount);
if (atomic_read(&ses->server->socketUseCount) == 0) {
spin_lock(&GlobalMid_Lock);
ses->server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock);
rc = -ESHUTDOWN;
if (ses->server) {
cifs_put_tcp_session(ses->server);
rc = 0;
}
up(&ses->sesSem);

Expand Down
Loading

0 comments on commit e7ddee9

Please sign in to comment.