From 24b9b06ba7ea53aa0c4d0b1c8c1e93aa1bd9fe72 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 1 Dec 2008 07:09:34 -0500 Subject: [PATCH 01/31] cifs: remove unused SMB session pointer from struct mid_q_entry Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 1 - fs/cifs/transport.c | 13 ++++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c57c0565547fa9..82e28f5515c8de 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -422,7 +422,6 @@ struct mid_q_entry { unsigned long when_sent; /* time when smb send finished */ unsigned long when_received; /* when demux complete (taken off wire) */ #endif - struct cifsSesInfo *ses; /* smb was sent to this server */ struct task_struct *tsk; /* task waiting for response */ struct smb_hdr *resp_buf; /* response buffer */ int midState; /* wish this were enum but can not pass to wait_event */ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index ff8243a8fe3e95..8e0d1c397c73c2 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -37,15 +37,11 @@ extern mempool_t *cifs_mid_poolp; extern struct kmem_cache *cifs_oplock_cachep; static struct mid_q_entry * -AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) +AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) { struct mid_q_entry *temp; - if (ses == NULL) { - cERROR(1, ("Null session passed in to AllocMidQEntry")); - return NULL; - } - if (ses->server == NULL) { + if (server == NULL) { cERROR(1, ("Null TCP session in AllocMidQEntry")); return NULL; } @@ -62,12 +58,11 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ /* when mid allocated can be before when sent */ temp->when_alloc = jiffies; - temp->ses = ses; temp->tsk = current; } spin_lock(&GlobalMid_Lock); - list_add_tail(&temp->qhead, &ses->server->pending_mid_q); + list_add_tail(&temp->qhead, &server->pending_mid_q); atomic_inc(&midCount); temp->midState = MID_REQUEST_ALLOCATED; spin_unlock(&GlobalMid_Lock); @@ -400,7 +395,7 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, return -EAGAIN; /* else ok - we are setting up session */ } - *ppmidQ = AllocMidQEntry(in_buf, ses); + *ppmidQ = AllocMidQEntry(in_buf, ses->server); if (*ppmidQ == NULL) return -ENOMEM; return 0; From 80909022ce966191e6140fcc15d8aff57a7df32e Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 1 Dec 2008 07:09:35 -0500 Subject: [PATCH 02/31] cifs: display addr and prefixpath options in /proc/mounts Have cifs_show_options display the addr and prefixpath options in /proc/mounts. Reduce struct dereferencing by adding some local variables. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d9cf467309e8cd..7f87066ce29f87 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -337,39 +337,59 @@ static int cifs_show_options(struct seq_file *s, struct vfsmount *m) { struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *tcon; + struct TCP_Server_Info *server; cifs_sb = CIFS_SB(m->mnt_sb); if (cifs_sb) { - if (cifs_sb->tcon) { + tcon = cifs_sb->tcon; + if (tcon) { /* BB add prepath to mount options displayed */ seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); - if (cifs_sb->tcon->ses) { - if (cifs_sb->tcon->ses->userName) + if (tcon->ses) { + if (tcon->ses->userName) seq_printf(s, ",username=%s", - cifs_sb->tcon->ses->userName); - if (cifs_sb->tcon->ses->domainName) + tcon->ses->userName); + if (tcon->ses->domainName) seq_printf(s, ",domain=%s", - cifs_sb->tcon->ses->domainName); + tcon->ses->domainName); + server = tcon->ses->server; + if (server) { + seq_printf(s, ",addr="); + switch (server->addr.sockAddr6. + sin6_family) { + case AF_INET6: + seq_printf(s, NIP6_FMT, + NIP6(server->addr.sockAddr6.sin6_addr)); + break; + case AF_INET: + seq_printf(s, NIPQUAD_FMT, + NIPQUAD(server->addr.sockAddr.sin_addr.s_addr)); + break; + } + } } if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) || - !(cifs_sb->tcon->unix_ext)) + !(tcon->unix_ext)) seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || - !(cifs_sb->tcon->unix_ext)) + !(tcon->unix_ext)) seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); - if (!cifs_sb->tcon->unix_ext) { + if (!tcon->unix_ext) { seq_printf(s, ",file_mode=0%o,dir_mode=0%o", cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); } - if (cifs_sb->tcon->seal) + if (tcon->seal) seq_printf(s, ",seal"); - if (cifs_sb->tcon->nocase) + if (tcon->nocase) seq_printf(s, ",nocase"); - if (cifs_sb->tcon->retry) + if (tcon->retry) seq_printf(s, ",hard"); } + if (cifs_sb->prepath) + seq_printf(s, ",prepath=%s", cifs_sb->prepath); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) seq_printf(s, ",posixpaths"); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) From 0468a2cf914e79442b8309ce62e3f861599d8cab Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 1 Dec 2008 07:09:35 -0500 Subject: [PATCH 03/31] cifs: take module reference when starting cifsd cifsd can outlive the last cifs mount. We need to hold a module reference until it exits to prevent someone from unplugging the module until we're ready. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c7d341714586fd..701daf411a4bb7 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -776,7 +776,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) set_current_state(TASK_RUNNING); } - return 0; + module_put_and_exit(0); } /* extract the host portion of the UNC string */ @@ -2176,10 +2176,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, so no need to spinlock this init of tcpStatus */ srvTcp->tcpStatus = CifsNew; init_MUTEX(&srvTcp->tcpSem); + + /* + * since we're in a cifs function already, we know that + * this will succeed. No need for try_module_get(). + */ + __module_get(THIS_MODULE); srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd"); if (IS_ERR(srvTcp->tsk)) { rc = PTR_ERR(srvTcp->tsk); cERROR(1, ("error %d create cifsd thread", rc)); + module_put(THIS_MODULE); srvTcp->tsk = NULL; sock_release(csocket); kfree(srvTcp->hostname); From 72ca545b2d83ac7de671bf66d2dbc214528b4c0c Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 1 Dec 2008 07:09:36 -0500 Subject: [PATCH 04/31] cifs: convert tcpSem to a mutex Mutexes are preferred for single-holder semaphores... Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 2 +- fs/cifs/connect.c | 6 +++--- fs/cifs/transport.c | 28 ++++++++++++++-------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 82e28f5515c8de..9b002cca6bb76a 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -151,7 +151,7 @@ struct TCP_Server_Info { atomic_t num_waiters; /* blocked waiting to get in sendrecv */ #endif enum statusEnum tcpStatus; /* what we think the status is */ - struct semaphore tcpSem; + struct mutex srv_mutex; struct task_struct *tsk; char server_GUID[16]; char secMode; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 701daf411a4bb7..61b68a0ee2ff33 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -156,7 +156,7 @@ cifs_reconnect(struct TCP_Server_Info *server) } read_unlock(&cifs_tcp_ses_lock); /* do not want to be sending data on a socket we are freeing */ - down(&server->tcpSem); + mutex_lock(&server->srv_mutex); if (server->ssocket) { cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state, server->ssocket->flags)); @@ -182,7 +182,7 @@ cifs_reconnect(struct TCP_Server_Info *server) } } spin_unlock(&GlobalMid_Lock); - up(&server->tcpSem); + mutex_unlock(&server->srv_mutex); while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) { @@ -2175,7 +2175,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, to the struct since the kernel thread not created yet so no need to spinlock this init of tcpStatus */ srvTcp->tcpStatus = CifsNew; - init_MUTEX(&srvTcp->tcpSem); + mutex_init(&srvTcp->srv_mutex); /* * since we're in a cifs function already, we know that diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 8e0d1c397c73c2..cd4ed65d6cd96f 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -516,11 +516,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, and avoid races inside tcp sendmsg code that could cause corruption of smb data */ - down(&ses->server->tcpSem); + mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { - up(&ses->server->tcpSem); + mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(in_buf); /* Update # of requests on wire to server */ atomic_dec(&ses->server->inFlight); @@ -541,7 +541,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, midQ->when_sent = jiffies; #endif - up(&ses->server->tcpSem); + mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(in_buf); if (rc < 0) @@ -698,11 +698,11 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, and avoid races inside tcp sendmsg code that could cause corruption of smb data */ - down(&ses->server->tcpSem); + mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { - up(&ses->server->tcpSem); + mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); @@ -713,7 +713,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, cERROR(1, ("Illegal length, greater than maximum frame, %d", in_buf->smb_buf_length)); DeleteMidQEntry(midQ); - up(&ses->server->tcpSem); + mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); @@ -733,7 +733,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; #endif - up(&ses->server->tcpSem); + mutex_unlock(&ses->server->srv_mutex); if (rc < 0) goto out; @@ -861,16 +861,16 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf, header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0); in_buf->Mid = mid; - down(&ses->server->tcpSem); + mutex_lock(&ses->server->srv_mutex); rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); if (rc) { - up(&ses->server->tcpSem); + mutex_unlock(&ses->server->srv_mutex); return rc; } rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, (struct sockaddr *) &(ses->server->addr.sockAddr), ses->server->noblocksnd); - up(&ses->server->tcpSem); + mutex_unlock(&ses->server->srv_mutex); return rc; } @@ -936,16 +936,16 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, and avoid races inside tcp sendmsg code that could cause corruption of smb data */ - down(&ses->server->tcpSem); + mutex_lock(&ses->server->srv_mutex); rc = allocate_mid(ses, in_buf, &midQ); if (rc) { - up(&ses->server->tcpSem); + mutex_unlock(&ses->server->srv_mutex); return rc; } if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { - up(&ses->server->tcpSem); + mutex_unlock(&ses->server->srv_mutex); cERROR(1, ("Illegal length, greater than maximum frame, %d", in_buf->smb_buf_length)); DeleteMidQEntry(midQ); @@ -965,7 +965,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; #endif - up(&ses->server->tcpSem); + mutex_unlock(&ses->server->srv_mutex); if (rc < 0) { DeleteMidQEntry(midQ); From 954d7a1cf12158fed23dd8b0f3f563d5a5c97f28 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 1 Dec 2008 15:23:50 -0500 Subject: [PATCH 05/31] cifs: make dnotify thread experimental code Now that tasks sleeping in wait_for_response will time out on their own, we're not reliant on the dnotify thread to do this. Mark it as experimental code for now. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 7f87066ce29f87..061a1dca987dc0 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -66,7 +66,9 @@ unsigned int sign_CIFS_PDUs = 1; extern struct task_struct *oplockThread; /* remove sparse warning */ struct task_struct *oplockThread = NULL; /* extern struct task_struct * dnotifyThread; remove sparse warning */ +#ifdef CONFIG_CIFS_EXPERIMENTAL static struct task_struct *dnotifyThread = NULL; +#endif static const struct super_operations cifs_super_ops; unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; module_param(CIFSMaxBufSize, int, 0); @@ -1049,6 +1051,7 @@ static int cifs_oplock_thread(void *dummyarg) return 0; } +#ifdef CONFIG_CIFS_EXPERIMENTAL static int cifs_dnotify_thread(void *dummyarg) { struct list_head *tmp; @@ -1074,6 +1077,7 @@ static int cifs_dnotify_thread(void *dummyarg) return 0; } +#endif static int __init init_cifs(void) @@ -1151,16 +1155,20 @@ init_cifs(void) goto out_unregister_dfs_key_type; } +#ifdef CONFIG_CIFS_EXPERIMENTAL dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd"); if (IS_ERR(dnotifyThread)) { rc = PTR_ERR(dnotifyThread); cERROR(1, ("error %d create dnotify thread", rc)); goto out_stop_oplock_thread; } +#endif return 0; +#ifdef CONFIG_CIFS_EXPERIMENTAL out_stop_oplock_thread: +#endif kthread_stop(oplockThread); out_unregister_dfs_key_type: #ifdef CONFIG_CIFS_DFS_UPCALL @@ -1199,8 +1207,10 @@ exit_cifs(void) cifs_destroy_inodecache(); cifs_destroy_mids(); cifs_destroy_request_bufs(); - kthread_stop(oplockThread); +#ifdef CONFIG_CIFS_EXPERIMENTAL kthread_stop(dnotifyThread); +#endif + kthread_stop(oplockThread); } MODULE_AUTHOR("Steve French "); From 8ecaf67a8ea58c8f131ff045475c74e9538d6b7a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 1 Dec 2008 15:23:50 -0500 Subject: [PATCH 06/31] cifs: account for IPv6 in ses->serverName and clean up netbios name handling The current code for setting the session serverName is IPv4-specific. Allow it to be an IPv6 address as well. Use NIP* macros to set the format. This also entails increasing the length of the serverName field, so declare a new macro for RFC1001 name length and use it in the appropriate places. Finally, drop the unicode_server_Name field from TCP_Server_Info since it's not used. We can add it back later if needed, but for now it just wastes memory. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 11 +++++++---- fs/cifs/connect.c | 38 ++++++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 9b002cca6bb76a..0fb934d3623b95 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -47,7 +47,11 @@ */ #define CIFS_MAX_REQ 50 -#define SERVER_NAME_LENGTH 15 +#define RFC1001_NAME_LEN 15 +#define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1) + +/* currently length of NIP6_FMT */ +#define SERVER_NAME_LENGTH 40 #define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) /* used to define string lengths for reversing unicode strings */ @@ -125,8 +129,7 @@ struct TCP_Server_Info { 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]; + char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; char *hostname; /* hostname portion of UNC string */ struct socket *ssocket; union { @@ -171,7 +174,7 @@ struct TCP_Server_Info { __u16 CurrentMid; /* multiplex id - rotating counter */ char cryptKey[CIFS_CRYPTO_KEY_SIZE]; /* 16th byte of RFC1001 workstation name is always null */ - char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; + char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; __u32 sequence_number; /* needed for CIFS PDU signature */ struct mac_key mac_signing_key; char ntlmv2_hash[16]; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 61b68a0ee2ff33..65c121940060be 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1690,22 +1690,30 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, if (ses_init_buf) { ses_init_buf->trailer.session_req.called_len = 32; if (target_name && (target_name[0] != 0)) { - rfc1002mangle(ses_init_buf->trailer.session_req.called_name, - target_name, 16); + rfc1002mangle(ses_init_buf->trailer. + session_req.called_name, + target_name, + RFC1001_NAME_LEN_WITH_NULL); } else { - rfc1002mangle(ses_init_buf->trailer.session_req.called_name, - DEFAULT_CIFS_CALLED_NAME, 16); + rfc1002mangle(ses_init_buf->trailer. + session_req.called_name, + DEFAULT_CIFS_CALLED_NAME, + RFC1001_NAME_LEN_WITH_NULL); } ses_init_buf->trailer.session_req.calling_len = 32; /* calling name ends in null (byte 16) from old smb convention. */ if (netbios_name && (netbios_name[0] != 0)) { - rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, - netbios_name, 16); + rfc1002mangle(ses_init_buf->trailer. + session_req.calling_name, + netbios_name, + RFC1001_NAME_LEN_WITH_NULL); } else { - rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, - "LINUX_CIFS_CLNT", 16); + rfc1002mangle(ses_init_buf->trailer. + session_req.calling_name, + "LINUX_CIFS_CLNT", + RFC1001_NAME_LEN_WITH_NULL); } ses_init_buf->trailer.session_req.scope1 = 0; ses_init_buf->trailer.session_req.scope2 = 0; @@ -2194,9 +2202,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, } rc = 0; memcpy(srvTcp->workstation_RFC1001_name, - volume_info.source_rfc1001_name, 16); + volume_info.source_rfc1001_name, + RFC1001_NAME_LEN_WITH_NULL); memcpy(srvTcp->server_RFC1001_name, - volume_info.target_rfc1001_name, 16); + volume_info.target_rfc1001_name, + RFC1001_NAME_LEN_WITH_NULL); srvTcp->sequence_number = 0; INIT_LIST_HEAD(&srvTcp->tcp_ses_list); INIT_LIST_HEAD(&srvTcp->smb_ses_list); @@ -2235,8 +2245,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, /* new SMB session uses our srvTcp ref */ pSesInfo->server = srvTcp; - sprintf(pSesInfo->serverName, "%u.%u.%u.%u", - NIPQUAD(sin_server->sin_addr.s_addr)); + if (addr.sa_family == AF_INET6) + sprintf(pSesInfo->serverName, NIP6_FMT, + NIP6(sin_server6->sin6_addr)); + else + sprintf(pSesInfo->serverName, NIPQUAD_FMT, + NIPQUAD(sin_server->sin_addr.s_addr)); write_lock(&cifs_tcp_ses_lock); list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list); From 63c038c29774476c5dae759e348c269342b4dbef Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 1 Dec 2008 18:41:46 -0500 Subject: [PATCH 07/31] cifs: move allocation of new TCP_Server_Info into separate function Clean up cifs_mount a bit by moving the code that creates new TCP sessions into a separate function. Have that function search for an existing socket and then create a new one if one isn't found. Also reorganize the initializion of TCP_Server_Info a bit to prepare for cleanup of the socket connection code. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 282 ++++++++++++++++++++++++---------------------- 1 file changed, 150 insertions(+), 132 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 65c121940060be..56095b24d5b9ec 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1417,6 +1417,148 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) force_sig(SIGKILL, task); } +static struct TCP_Server_Info * +cifs_get_tcp_session(struct smb_vol *volume_info) +{ + struct TCP_Server_Info *tcp_ses = NULL; + struct sockaddr addr; + struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; + struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; + int rc; + + memset(&addr, 0, sizeof(struct sockaddr)); + + if (volume_info->UNCip && volume_info->UNC) { + rc = cifs_inet_pton(AF_INET, volume_info->UNCip, + &sin_server->sin_addr.s_addr); + + if (rc <= 0) { + /* not ipv4 address, try ipv6 */ + rc = cifs_inet_pton(AF_INET6, volume_info->UNCip, + &sin_server6->sin6_addr.in6_u); + if (rc > 0) + addr.sa_family = AF_INET6; + } else { + addr.sa_family = AF_INET; + } + + if (rc <= 0) { + /* we failed translating address */ + rc = -EINVAL; + goto out_err; + } + + cFYI(1, ("UNC: %s ip: %s", volume_info->UNC, + volume_info->UNCip)); + } else if (volume_info->UNCip) { + /* BB using ip addr as tcp_ses name to connect to the + DFS root below */ + cERROR(1, ("Connecting to DFS root not implemented yet")); + rc = -EINVAL; + goto out_err; + } else /* which tcp_sess DFS root would we conect to */ { + cERROR(1, + ("CIFS mount error: No UNC path (e.g. -o " + "unc=//192.168.1.100/public) specified")); + rc = -EINVAL; + goto out_err; + } + + /* see if we already have a matching tcp_ses */ + tcp_ses = cifs_find_tcp_session(&addr); + if (tcp_ses) + return tcp_ses; + + tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); + if (!tcp_ses) { + rc = -ENOMEM; + goto out_err; + } + + tcp_ses->hostname = extract_hostname(volume_info->UNC); + if (IS_ERR(tcp_ses->hostname)) { + rc = PTR_ERR(tcp_ses->hostname); + goto out_err; + } + + tcp_ses->noblocksnd = volume_info->noblocksnd; + tcp_ses->noautotune = volume_info->noautotune; + atomic_set(&tcp_ses->inFlight, 0); + init_waitqueue_head(&tcp_ses->response_q); + init_waitqueue_head(&tcp_ses->request_q); + INIT_LIST_HEAD(&tcp_ses->pending_mid_q); + mutex_init(&tcp_ses->srv_mutex); + memcpy(tcp_ses->workstation_RFC1001_name, + volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); + memcpy(tcp_ses->server_RFC1001_name, + volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); + tcp_ses->sequence_number = 0; + INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); + INIT_LIST_HEAD(&tcp_ses->smb_ses_list); + + /* + * at this point we are the only ones with the pointer + * to the struct since the kernel thread not created yet + * no need to spinlock this init of tcpStatus or srv_count + */ + tcp_ses->tcpStatus = CifsNew; + ++tcp_ses->srv_count; + + if (addr.sa_family == AF_INET6) { + cFYI(1, ("attempting ipv6 connect")); + /* BB should we allow ipv6 on port 139? */ + /* other OS never observed in Wild doing 139 with v6 */ + memcpy(&tcp_ses->addr.sockAddr6, sin_server6, + sizeof(struct sockaddr_in6)); + sin_server6->sin6_port = htons(volume_info->port); + rc = ipv6_connect(sin_server6, &tcp_ses->ssocket, + volume_info->noblocksnd); + } else { + memcpy(&tcp_ses->addr.sockAddr, sin_server, + sizeof(struct sockaddr_in)); + sin_server->sin_port = htons(volume_info->port); + rc = ipv4_connect(sin_server, &tcp_ses->ssocket, + volume_info->source_rfc1001_name, + volume_info->target_rfc1001_name, + volume_info->noblocksnd, + volume_info->noautotune); + } + if (rc < 0) { + cERROR(1, ("Error connecting to socket. Aborting operation")); + goto out_err; + } + + /* + * since we're in a cifs function already, we know that + * this will succeed. No need for try_module_get(). + */ + __module_get(THIS_MODULE); + tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, + tcp_ses, "cifsd"); + if (IS_ERR(tcp_ses->tsk)) { + rc = PTR_ERR(tcp_ses->tsk); + cERROR(1, ("error %d create cifsd thread", rc)); + module_put(THIS_MODULE); + goto out_err; + } + + /* thread spawned, put it on the list */ + write_lock(&cifs_tcp_ses_lock); + list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); + write_unlock(&cifs_tcp_ses_lock); + + return tcp_ses; + +out_err: + if (tcp_ses) { + kfree(tcp_ses->hostname); + if (tcp_ses->ssocket) + sock_release(tcp_ses->ssocket); + kfree(tcp_ses); + } + return ERR_PTR(rc); +} + static struct cifsSesInfo * cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) { @@ -2043,10 +2185,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, { int rc = 0; int xid; - struct socket *csocket = NULL; - struct sockaddr addr; - struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; - struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; struct smb_vol volume_info; struct cifsSesInfo *pSesInfo = NULL; struct cifsTconInfo *tcon = NULL; @@ -2056,7 +2194,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ - memset(&addr, 0, sizeof(struct sockaddr)); memset(&volume_info, 0, sizeof(struct smb_vol)); if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { rc = -EINVAL; @@ -2077,42 +2214,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, goto out; } - if (volume_info.UNCip && volume_info.UNC) { - rc = cifs_inet_pton(AF_INET, volume_info.UNCip, - &sin_server->sin_addr.s_addr); - - if (rc <= 0) { - /* not ipv4 address, try ipv6 */ - rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, - &sin_server6->sin6_addr.in6_u); - if (rc > 0) - addr.sa_family = AF_INET6; - } else { - addr.sa_family = AF_INET; - } - - if (rc <= 0) { - /* we failed translating address */ - rc = -EINVAL; - goto out; - } - - cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); - /* success */ - rc = 0; - } else if (volume_info.UNCip) { - /* BB using ip addr as server name to connect to the - DFS root below */ - cERROR(1, ("Connecting to DFS root not implemented yet")); - rc = -EINVAL; - goto out; - } else /* which servers DFS root would we conect to */ { - cERROR(1, - ("CIFS mount error: No UNC path (e.g. -o " - "unc=//192.168.1.100/public) specified")); - rc = -EINVAL; - goto out; - } /* this is needed for ASCII cp to Unicode converts */ if (volume_info.iocharset == NULL) { @@ -2128,94 +2229,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, } } - srvTcp = cifs_find_tcp_session(&addr); - if (!srvTcp) { /* create socket */ - if (addr.sa_family == AF_INET6) { - cFYI(1, ("attempting ipv6 connect")); - /* BB should we allow ipv6 on port 139? */ - /* other OS never observed in Wild doing 139 with v6 */ - sin_server6->sin6_port = htons(volume_info.port); - rc = ipv6_connect(sin_server6, &csocket, - volume_info.noblocksnd); - } else { - sin_server->sin_port = htons(volume_info.port); - rc = ipv4_connect(sin_server, &csocket, - volume_info.source_rfc1001_name, - volume_info.target_rfc1001_name, - volume_info.noblocksnd, - volume_info.noautotune); - } - if (rc < 0) { - cERROR(1, ("Error connecting to socket. " - "Aborting operation")); - if (csocket != NULL) - sock_release(csocket); - goto out; - } - - srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); - if (!srvTcp) { - rc = -ENOMEM; - sock_release(csocket); - goto out; - } else { - srvTcp->noblocksnd = volume_info.noblocksnd; - srvTcp->noautotune = volume_info.noautotune; - if (addr.sa_family == AF_INET6) - memcpy(&srvTcp->addr.sockAddr6, sin_server6, - sizeof(struct sockaddr_in6)); - else - memcpy(&srvTcp->addr.sockAddr, sin_server, - sizeof(struct sockaddr_in)); - atomic_set(&srvTcp->inFlight, 0); - /* BB Add code for ipv6 case too */ - srvTcp->ssocket = csocket; - srvTcp->hostname = extract_hostname(volume_info.UNC); - if (IS_ERR(srvTcp->hostname)) { - rc = PTR_ERR(srvTcp->hostname); - sock_release(csocket); - goto out; - } - init_waitqueue_head(&srvTcp->response_q); - init_waitqueue_head(&srvTcp->request_q); - INIT_LIST_HEAD(&srvTcp->pending_mid_q); - /* at this point we are the only ones with the pointer - to the struct since the kernel thread not created yet - so no need to spinlock this init of tcpStatus */ - srvTcp->tcpStatus = CifsNew; - mutex_init(&srvTcp->srv_mutex); - - /* - * since we're in a cifs function already, we know that - * this will succeed. No need for try_module_get(). - */ - __module_get(THIS_MODULE); - srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd"); - if (IS_ERR(srvTcp->tsk)) { - rc = PTR_ERR(srvTcp->tsk); - cERROR(1, ("error %d create cifsd thread", rc)); - module_put(THIS_MODULE); - srvTcp->tsk = NULL; - sock_release(csocket); - kfree(srvTcp->hostname); - goto out; - } - rc = 0; - memcpy(srvTcp->workstation_RFC1001_name, - volume_info.source_rfc1001_name, - RFC1001_NAME_LEN_WITH_NULL); - memcpy(srvTcp->server_RFC1001_name, - volume_info.target_rfc1001_name, - RFC1001_NAME_LEN_WITH_NULL); - 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, - &cifs_tcp_ses_list); - write_unlock(&cifs_tcp_ses_lock); - } + /* get a reference to a tcp session */ + srvTcp = cifs_get_tcp_session(&volume_info); + if (IS_ERR(srvTcp)) { + rc = PTR_ERR(srvTcp); + goto out; } pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username); @@ -2245,12 +2263,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, /* new SMB session uses our srvTcp ref */ pSesInfo->server = srvTcp; - if (addr.sa_family == AF_INET6) + if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6) sprintf(pSesInfo->serverName, NIP6_FMT, - NIP6(sin_server6->sin6_addr)); + NIP6(srvTcp->addr.sockAddr6.sin6_addr)); else sprintf(pSesInfo->serverName, NIPQUAD_FMT, - NIPQUAD(sin_server->sin_addr.s_addr)); + NIPQUAD(srvTcp->addr.sockAddr.sin_addr.s_addr)); write_lock(&cifs_tcp_ses_lock); list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list); From 7586b76585d15db767c19255ba0ecfb164df99f7 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 1 Dec 2008 18:41:49 -0500 Subject: [PATCH 08/31] cifs: don't declare smb_vol info on the stack struct smb_vol is fairly large, it's probably best to kzalloc it... Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 91 +++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 56095b24d5b9ec..c2ed0f57a66cb9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2185,27 +2185,30 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, { int rc = 0; int xid; - struct smb_vol volume_info; + struct smb_vol *volume_info; struct cifsSesInfo *pSesInfo = NULL; struct cifsTconInfo *tcon = NULL; struct TCP_Server_Info *srvTcp = NULL; xid = GetXid(); -/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ + volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL); + if (!volume_info) { + rc = -ENOMEM; + goto out; + } - memset(&volume_info, 0, sizeof(struct smb_vol)); - if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { + if (cifs_parse_mount_options(mount_data, devname, volume_info)) { rc = -EINVAL; goto out; } - if (volume_info.nullauth) { + if (volume_info->nullauth) { cFYI(1, ("null user")); - volume_info.username = ""; - } else if (volume_info.username) { + volume_info->username = ""; + } else if (volume_info->username) { /* BB fixme parse for domain name here */ - cFYI(1, ("Username: %s", volume_info.username)); + cFYI(1, ("Username: %s", volume_info->username)); } else { cifserror("No username specified"); /* In userspace mount helper we can get user name from alternate @@ -2216,27 +2219,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, /* this is needed for ASCII cp to Unicode converts */ - if (volume_info.iocharset == NULL) { + if (volume_info->iocharset == NULL) { cifs_sb->local_nls = load_nls_default(); /* load_nls_default can not return null */ } else { - cifs_sb->local_nls = load_nls(volume_info.iocharset); + cifs_sb->local_nls = load_nls(volume_info->iocharset); if (cifs_sb->local_nls == NULL) { cERROR(1, ("CIFS mount error: iocharset %s not found", - volume_info.iocharset)); + volume_info->iocharset)); rc = -ELIBACC; goto out; } } /* get a reference to a tcp session */ - srvTcp = cifs_get_tcp_session(&volume_info); + srvTcp = cifs_get_tcp_session(volume_info); if (IS_ERR(srvTcp)) { rc = PTR_ERR(srvTcp); goto out; } - pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username); + pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username); if (pSesInfo) { cFYI(1, ("Existing smb sess found (status=%d)", pSesInfo->status)); @@ -2274,24 +2277,24 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, 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; + /* 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; + volume_info->password = NULL; } - if (volume_info.username) - strncpy(pSesInfo->userName, volume_info.username, + if (volume_info->username) + strncpy(pSesInfo->userName, volume_info->username, MAX_USERNAME_SIZE); - if (volume_info.domainname) { - int len = strlen(volume_info.domainname); + 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); + volume_info->domainname); } - pSesInfo->linux_uid = volume_info.linux_uid; - pSesInfo->overrideSecFlg = volume_info.secFlg; + pSesInfo->linux_uid = volume_info->linux_uid; + pSesInfo->overrideSecFlg = volume_info->secFlg; down(&pSesInfo->sesSem); /* BB FIXME need to pass vol->secFlgs BB */ @@ -2302,14 +2305,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, /* search for existing tcon to this server share */ if (!rc) { - setup_cifs_sb(&volume_info, cifs_sb); + setup_cifs_sb(volume_info, cifs_sb); - tcon = cifs_find_tcon(pSesInfo, volume_info.UNC); + tcon = cifs_find_tcon(pSesInfo, volume_info->UNC); if (tcon) { cFYI(1, ("Found match on UNC path")); /* existing tcon already has a reference */ cifs_put_smb_ses(pSesInfo); - if (tcon->seal != volume_info.seal) + if (tcon->seal != volume_info->seal) cERROR(1, ("transport encryption setting " "conflicts with existing tid")); } else { @@ -2321,8 +2324,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, tcon->ses = pSesInfo; /* check for null share name ie connect to dfs root */ - if ((strchr(volume_info.UNC + 3, '\\') == NULL) - && (strchr(volume_info.UNC + 3, '/') == NULL)) { + if ((strchr(volume_info->UNC + 3, '\\') == NULL) + && (strchr(volume_info->UNC + 3, '/') == NULL)) { /* rc = connect_to_dfs_path(...) */ cFYI(1, ("DFS root not supported")); rc = -ENODEV; @@ -2331,10 +2334,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, /* BB Do we need to wrap sesSem around * this TCon call and Unix SetFS as * we do on SessSetup and reconnect? */ - rc = CIFSTCon(xid, pSesInfo, volume_info.UNC, + rc = CIFSTCon(xid, pSesInfo, volume_info->UNC, tcon, cifs_sb->local_nls); cFYI(1, ("CIFS Tcon rc = %d", rc)); - if (volume_info.nodfs) { + if (volume_info->nodfs) { tcon->Flags &= ~SMB_SHARE_IS_IN_DFS; cFYI(1, ("DFS disabled (%d)", tcon->Flags)); @@ -2342,7 +2345,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, } if (rc) goto mount_fail_check; - tcon->seal = volume_info.seal; + tcon->seal = volume_info->seal; write_lock(&cifs_tcp_ses_lock); list_add(&tcon->tcon_list, &pSesInfo->tcon_list); write_unlock(&cifs_tcp_ses_lock); @@ -2352,9 +2355,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, to a share so for resources mounted more than once to the same server share the last value passed in for the retry flag is used */ - tcon->retry = volume_info.retry; - tcon->nocase = volume_info.nocase; - tcon->local_lease = volume_info.local_lease; + tcon->retry = volume_info->retry; + tcon->nocase = volume_info->nocase; + tcon->local_lease = volume_info->local_lease; } if (pSesInfo) { if (pSesInfo->capabilities & CAP_LARGE_FILES) { @@ -2391,7 +2394,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (tcon->ses->capabilities & CAP_UNIX) /* reset of caps checks mount to see if unix extensions disabled for just this mount */ - reset_cifs_unix_caps(xid, tcon, sb, &volume_info); + reset_cifs_unix_caps(xid, tcon, sb, volume_info); else tcon->unix_ext = 0; /* server does not support them */ @@ -2410,18 +2413,22 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->rsize = min(cifs_sb->rsize, (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); - /* volume_info.password is freed above when existing session found + /* volume_info->password is freed above when existing session found (in which case it is not needed anymore) but when new sesion is created the password ptr is put in the new session structure (in which case the password will be freed at unmount time) */ out: /* zero out password before freeing */ - if (volume_info.password != NULL) { - memset(volume_info.password, 0, strlen(volume_info.password)); - kfree(volume_info.password); + if (volume_info) { + if (volume_info->password != NULL) { + memset(volume_info->password, 0, + strlen(volume_info->password)); + kfree(volume_info->password); + } + kfree(volume_info->UNC); + kfree(volume_info->prepath); + kfree(volume_info); } - kfree(volume_info.UNC); - kfree(volume_info.prepath); FreeXid(xid); return rc; } From bcf4b1063db246a90b9e09e0556f635d632eef36 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 1 Dec 2008 18:42:15 -0500 Subject: [PATCH 09/31] cifs: make ipv4_connect take a TCP_Server_Info arg In order to unify the smb_send routines, we need to reorganize the routines that connect the sockets. Have ipv4_connect take a TCP_Server_Info pointer and get the necessary fields from that. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 146 ++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 77 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c2ed0f57a66cb9..a36f4bd5a764c1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -101,12 +101,7 @@ struct smb_vol { char *prepath; }; -static int ipv4_connect(struct sockaddr_in *psin_server, - struct socket **csocket, - char *netb_name, - char *server_netb_name, - bool noblocksnd, - bool nosndbuf); /* ipv6 never set sndbuf size */ +static int ipv4_connect(struct TCP_Server_Info *server); static int ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket, bool noblocksnd); @@ -187,16 +182,11 @@ cifs_reconnect(struct TCP_Server_Info *server) while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) { try_to_freeze(); - if (server->addr.sockAddr6.sin6_family == AF_INET6) { + if (server->addr.sockAddr6.sin6_family == AF_INET6) rc = ipv6_connect(&server->addr.sockAddr6, &server->ssocket, server->noautotune); - } else { - rc = ipv4_connect(&server->addr.sockAddr, - &server->ssocket, - server->workstation_RFC1001_name, - server->server_RFC1001_name, - server->noblocksnd, server->noautotune); - } + else + rc = ipv4_connect(server); if (rc) { cFYI(1, ("reconnect error %d", rc)); msleep(3000); @@ -1517,11 +1507,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) memcpy(&tcp_ses->addr.sockAddr, sin_server, sizeof(struct sockaddr_in)); sin_server->sin_port = htons(volume_info->port); - rc = ipv4_connect(sin_server, &tcp_ses->ssocket, - volume_info->source_rfc1001_name, - volume_info->target_rfc1001_name, - volume_info->noblocksnd, - volume_info->noautotune); + rc = ipv4_connect(tcp_ses); } if (rc < 0) { cERROR(1, ("Error connecting to socket. Aborting operation")); @@ -1735,93 +1721,96 @@ static void rfc1002mangle(char *target, char *source, unsigned int length) static int -ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, - char *netbios_name, char *target_name, - bool noblocksnd, bool noautotune) +ipv4_connect(struct TCP_Server_Info *server) { int rc = 0; - int connected = 0; + bool connected = false; __be16 orig_port = 0; + struct socket *socket = server->ssocket; - if (*csocket == NULL) { + if (socket == NULL) { rc = sock_create_kern(PF_INET, SOCK_STREAM, - IPPROTO_TCP, csocket); + IPPROTO_TCP, &socket); if (rc < 0) { cERROR(1, ("Error %d creating socket", rc)); - *csocket = NULL; return rc; - } else { - /* BB other socket options to set KEEPALIVE, NODELAY? */ - cFYI(1, ("Socket created")); - (*csocket)->sk->sk_allocation = GFP_NOFS; - cifs_reclassify_socket4(*csocket); } + + /* BB other socket options to set KEEPALIVE, NODELAY? */ + cFYI(1, ("Socket created")); + server->ssocket = socket; + socket->sk->sk_allocation = GFP_NOFS; + cifs_reclassify_socket4(socket); } - psin_server->sin_family = AF_INET; - if (psin_server->sin_port) { /* user overrode default port */ - rc = (*csocket)->ops->connect(*csocket, - (struct sockaddr *) psin_server, - sizeof(struct sockaddr_in), 0); + /* user overrode default port */ + if (server->addr.sockAddr.sin_port) { + rc = socket->ops->connect(socket, (struct sockaddr *) + &server->addr.sockAddr, + sizeof(struct sockaddr_in), 0); if (rc >= 0) - connected = 1; + connected = true; } if (!connected) { /* save original port so we can retry user specified port later if fall back ports fail this time */ - orig_port = psin_server->sin_port; + orig_port = server->addr.sockAddr.sin_port; /* do not retry on the same port we just failed on */ - if (psin_server->sin_port != htons(CIFS_PORT)) { - psin_server->sin_port = htons(CIFS_PORT); - - rc = (*csocket)->ops->connect(*csocket, - (struct sockaddr *) psin_server, - sizeof(struct sockaddr_in), 0); + if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) { + server->addr.sockAddr.sin_port = htons(CIFS_PORT); + rc = socket->ops->connect(socket, + (struct sockaddr *) + &server->addr.sockAddr, + sizeof(struct sockaddr_in), 0); if (rc >= 0) - connected = 1; + connected = true; } } if (!connected) { - psin_server->sin_port = htons(RFC1001_PORT); - rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) - psin_server, + server->addr.sockAddr.sin_port = htons(RFC1001_PORT); + rc = socket->ops->connect(socket, (struct sockaddr *) + &server->addr.sockAddr, sizeof(struct sockaddr_in), 0); if (rc >= 0) - connected = 1; + connected = true; } /* give up here - unless we want to retry on different protocol families some day */ if (!connected) { if (orig_port) - psin_server->sin_port = orig_port; + server->addr.sockAddr.sin_port = orig_port; cFYI(1, ("Error %d connecting to server via ipv4", rc)); - sock_release(*csocket); - *csocket = NULL; + sock_release(socket); + server->ssocket = NULL; return rc; } - /* Eventually check for other socket options to change from - the default. sock_setsockopt not used because it expects - user space buffer */ - cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx", - (*csocket)->sk->sk_sndbuf, - (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); - (*csocket)->sk->sk_rcvtimeo = 7 * HZ; - if (!noblocksnd) - (*csocket)->sk->sk_sndtimeo = 3 * HZ; + + + /* + * Eventually check for other socket options to change from + * the default. sock_setsockopt not used because it expects + * user space buffer + */ + socket->sk->sk_rcvtimeo = 7 * HZ; + socket->sk->sk_sndtimeo = 3 * HZ; /* make the bufsizes depend on wsize/rsize and max requests */ - if (noautotune) { - if ((*csocket)->sk->sk_sndbuf < (200 * 1024)) - (*csocket)->sk->sk_sndbuf = 200 * 1024; - if ((*csocket)->sk->sk_rcvbuf < (140 * 1024)) - (*csocket)->sk->sk_rcvbuf = 140 * 1024; + if (server->noautotune) { + if (socket->sk->sk_sndbuf < (200 * 1024)) + socket->sk->sk_sndbuf = 200 * 1024; + if (socket->sk->sk_rcvbuf < (140 * 1024)) + socket->sk->sk_rcvbuf = 140 * 1024; } + cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx", + socket->sk->sk_sndbuf, + socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo)); + /* send RFC1001 sessinit */ - if (psin_server->sin_port == htons(RFC1001_PORT)) { + if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) { /* some servers require RFC1001 sessinit before sending negprot - BB check reconnection in case where second sessinit is sent but no second negprot */ @@ -1831,39 +1820,42 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, GFP_KERNEL); if (ses_init_buf) { ses_init_buf->trailer.session_req.called_len = 32; - if (target_name && (target_name[0] != 0)) { + if (server->server_RFC1001_name && + server->server_RFC1001_name[0] != 0) rfc1002mangle(ses_init_buf->trailer. session_req.called_name, - target_name, + server->server_RFC1001_name, RFC1001_NAME_LEN_WITH_NULL); - } else { + else rfc1002mangle(ses_init_buf->trailer. session_req.called_name, DEFAULT_CIFS_CALLED_NAME, RFC1001_NAME_LEN_WITH_NULL); - } ses_init_buf->trailer.session_req.calling_len = 32; + /* calling name ends in null (byte 16) from old smb convention. */ - if (netbios_name && (netbios_name[0] != 0)) { + if (server->workstation_RFC1001_name && + server->workstation_RFC1001_name[0] != 0) rfc1002mangle(ses_init_buf->trailer. session_req.calling_name, - netbios_name, + server->workstation_RFC1001_name, RFC1001_NAME_LEN_WITH_NULL); - } else { + else rfc1002mangle(ses_init_buf->trailer. session_req.calling_name, "LINUX_CIFS_CLNT", RFC1001_NAME_LEN_WITH_NULL); - } + ses_init_buf->trailer.session_req.scope1 = 0; ses_init_buf->trailer.session_req.scope2 = 0; smb_buf = (struct smb_hdr *)ses_init_buf; /* sizeof RFC1002_SESSION_REQUEST with no scope */ smb_buf->smb_buf_length = 0x81000044; - rc = smb_send(*csocket, smb_buf, 0x44, - (struct sockaddr *)psin_server, noblocksnd); + rc = smb_send(socket, smb_buf, 0x44, + (struct sockaddr *) &server->addr.sockAddr, + server->noblocksnd); kfree(ses_init_buf); msleep(1); /* RFC1001 layer in at least one server requires very short break before negprot From d5c5605c27c92dac6de1a7a658af5b030847f949 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 1 Dec 2008 18:42:33 -0500 Subject: [PATCH 10/31] cifs: make ipv6_connect take a TCP_Server_Info arg Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 103 ++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 53 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index a36f4bd5a764c1..d6a3c1c8a6f8c2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -102,19 +102,16 @@ struct smb_vol { }; static int ipv4_connect(struct TCP_Server_Info *server); -static int ipv6_connect(struct sockaddr_in6 *psin_server, - struct socket **csocket, bool noblocksnd); - - - /* - * cifs tcp session reconnection - * - * mark tcp session as reconnecting so temporarily locked - * mark all smb sessions as reconnecting for tcp session - * reconnect tcp session - * wake up waiters on reconnection? - (not needed currently) - */ +static int ipv6_connect(struct TCP_Server_Info *server); +/* + * cifs tcp session reconnection + * + * mark tcp session as reconnecting so temporarily locked + * mark all smb sessions as reconnecting for tcp session + * reconnect tcp session + * wake up waiters on reconnection? - (not needed currently) + */ static int cifs_reconnect(struct TCP_Server_Info *server) { @@ -183,8 +180,7 @@ cifs_reconnect(struct TCP_Server_Info *server) (server->tcpStatus != CifsGood)) { try_to_freeze(); if (server->addr.sockAddr6.sin6_family == AF_INET6) - rc = ipv6_connect(&server->addr.sockAddr6, - &server->ssocket, server->noautotune); + rc = ipv6_connect(server); else rc = ipv4_connect(server); if (rc) { @@ -1501,8 +1497,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) memcpy(&tcp_ses->addr.sockAddr6, sin_server6, sizeof(struct sockaddr_in6)); sin_server6->sin6_port = htons(volume_info->port); - rc = ipv6_connect(sin_server6, &tcp_ses->ssocket, - volume_info->noblocksnd); + rc = ipv6_connect(tcp_ses); } else { memcpy(&tcp_ses->addr.sockAddr, sin_server, sizeof(struct sockaddr_in)); @@ -1875,79 +1870,81 @@ ipv4_connect(struct TCP_Server_Info *server) } static int -ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket, - bool noblocksnd) +ipv6_connect(struct TCP_Server_Info *server) { int rc = 0; - int connected = 0; + bool connected = false; __be16 orig_port = 0; + struct socket *socket = server->ssocket; - if (*csocket == NULL) { + if (socket == NULL) { rc = sock_create_kern(PF_INET6, SOCK_STREAM, - IPPROTO_TCP, csocket); + IPPROTO_TCP, &socket); if (rc < 0) { cERROR(1, ("Error %d creating ipv6 socket", rc)); - *csocket = NULL; + socket = NULL; return rc; - } else { - /* BB other socket options to set KEEPALIVE, NODELAY? */ - cFYI(1, ("ipv6 Socket created")); - (*csocket)->sk->sk_allocation = GFP_NOFS; - cifs_reclassify_socket6(*csocket); } - } - psin_server->sin6_family = AF_INET6; + /* BB other socket options to set KEEPALIVE, NODELAY? */ + cFYI(1, ("ipv6 Socket created")); + server->ssocket = socket; + socket->sk->sk_allocation = GFP_NOFS; + cifs_reclassify_socket6(socket); + } - if (psin_server->sin6_port) { /* user overrode default port */ - rc = (*csocket)->ops->connect(*csocket, - (struct sockaddr *) psin_server, + /* user overrode default port */ + if (server->addr.sockAddr6.sin6_port) { + rc = socket->ops->connect(socket, + (struct sockaddr *) &server->addr.sockAddr6, sizeof(struct sockaddr_in6), 0); if (rc >= 0) - connected = 1; + connected = true; } if (!connected) { /* save original port so we can retry user specified port later if fall back ports fail this time */ - orig_port = psin_server->sin6_port; + orig_port = server->addr.sockAddr6.sin6_port; /* do not retry on the same port we just failed on */ - if (psin_server->sin6_port != htons(CIFS_PORT)) { - psin_server->sin6_port = htons(CIFS_PORT); - - rc = (*csocket)->ops->connect(*csocket, - (struct sockaddr *) psin_server, + if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) { + server->addr.sockAddr6.sin6_port = htons(CIFS_PORT); + rc = socket->ops->connect(socket, (struct sockaddr *) + &server->addr.sockAddr6, sizeof(struct sockaddr_in6), 0); if (rc >= 0) - connected = 1; + connected = true; } } if (!connected) { - psin_server->sin6_port = htons(RFC1001_PORT); - rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) - psin_server, sizeof(struct sockaddr_in6), 0); + server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT); + rc = socket->ops->connect(socket, (struct sockaddr *) + &server->addr.sockAddr6, + sizeof(struct sockaddr_in6), 0); if (rc >= 0) - connected = 1; + connected = true; } /* give up here - unless we want to retry on different protocol families some day */ if (!connected) { if (orig_port) - psin_server->sin6_port = orig_port; + server->addr.sockAddr6.sin6_port = orig_port; cFYI(1, ("Error %d connecting to server via ipv6", rc)); - sock_release(*csocket); - *csocket = NULL; + sock_release(socket); + server->ssocket = NULL; return rc; } - /* Eventually check for other socket options to change from - the default. sock_setsockopt not used because it expects - user space buffer */ - (*csocket)->sk->sk_rcvtimeo = 7 * HZ; - if (!noblocksnd) - (*csocket)->sk->sk_sndtimeo = 3 * HZ; + /* + * Eventually check for other socket options to change from + * the default. sock_setsockopt not used because it expects + * user space buffer + */ + socket->sk->sk_rcvtimeo = 7 * HZ; + socket->sk->sk_sndtimeo = 3 * HZ; + server->ssocket = socket; return rc; } From 13a6e42af8d90e2e8eb7fa50adf862a525b70518 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 2 Dec 2008 17:24:33 +0000 Subject: [PATCH 11/31] [CIFS] add mount option to send mandatory rather than advisory locks Some applications/subsystems require mandatory byte range locks (as is used for Windows/DOS/OS2 etc). Sending advisory (posix style) byte range lock requests (instead of mandatory byte range locks) can lead to problems for these applications (which expect that other clients be prevented from writing to portions of the file which they have locked and are updating). This mount option allows mounting cifs with the new mount option "forcemand" (or "forcemandatorylock") in order to have the cifs client use mandatory byte range locks (ie SMB/CIFS/Windows/NTFS style locks) rather than posix byte range lock requests, even if the server would support posix byte range lock requests. This has no effect if the server does not support the CIFS Unix Extensions (since posix style locks require support for the CIFS Unix Extensions), but for mounts to Samba servers this can be helpful for Wine and applications that require mandatory byte range locks. Acked-by: Jeff Layton CC: Alexander Bokovoy Signed-off-by: Steve French --- fs/cifs/CHANGES | 6 ++++++ fs/cifs/README | 12 +++++++++++- fs/cifs/cifs_fs_sb.h | 5 +++-- fs/cifs/cifsfs.h | 2 +- fs/cifs/connect.c | 14 ++++++++++++++ fs/cifs/file.c | 25 +++++++++++++------------ 6 files changed, 48 insertions(+), 16 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index e078b7aea1431d..3d848f463c44fc 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,9 @@ +Version 1.56 +------------ +Add "forcemandatorylock" mount option to allow user to use mandatory +rather than posix (advisory) byte range locks, even though server would +support posix byte range locks. + Version 1.55 ------------ Various fixes to make delete of open files behavior more predictable diff --git a/fs/cifs/README b/fs/cifs/README index a439dc1739b3ac..da4515e3be20b7 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -463,9 +463,19 @@ A partial list of the supported mount options follows: with cifs style mandatory byte range locks (and most cifs servers do not yet support requesting advisory byte range locks). + forcemandatorylock Even if the server supports posix (advisory) byte range + locking, send only mandatory lock requests. For some + (presumably rare) applications, originally coded for + DOS/Windows, which require Windows style mandatory byte range + locking, they may be able to take advantage of this option, + forcing the cifs client to only send mandatory locks + even if the cifs server would support posix advisory locks. + "forcemand" is accepted as a shorter form of this mount + option. nodfs Disable DFS (global name space support) even if the server claims to support it. This can help work around - a problem with parsing of DFS paths with Samba 3.0.24 server. + a problem with parsing of DFS paths with Samba server + versions 3.0.24 and 3.0.25. remount remount the share (often used to change from ro to rw mounts or vice versa) cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 877c85409f1f90..5edd5cc415aa99 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -20,7 +20,7 @@ #define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */ #define CIFS_MOUNT_SET_UID 2 /* set current->euid in create etc. */ -#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */ +#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */ #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ @@ -30,7 +30,8 @@ #define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */ #define CIFS_MOUNT_OVERR_UID 0x400 /* override uid returned from server */ #define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */ -#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */ +#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */ +#define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 074de0b5064d09..fb676076946b79 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); extern const struct export_operations cifs_export_ops; #endif /* EXPERIMENTAL */ -#define CIFS_VERSION "1.55" +#define CIFS_VERSION "1.5666666" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d6a3c1c8a6f8c2..351942042833d5 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -89,6 +89,7 @@ struct smb_vol { bool nullauth:1; /* attempt to authenticate with null user */ bool nocase:1; /* request case insensitive filenames */ bool nobrl:1; /* disable sending byte range locks to srv */ + bool mand_lock:1; /* send mandatory not posix byte range lock reqs */ bool seal:1; /* request transport encryption on share */ bool nodfs:1; /* Do not request DFS, even if available */ bool local_lease:1; /* check leases only on local system, not remote */ @@ -1246,6 +1247,17 @@ cifs_parse_mount_options(char *options, const char *devname, if (vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP))) vol->file_mode = S_IALLUGO; + } else if (strnicmp(data, "forcemandatorylock", 9) == 0) { + /* will take the shorter form "forcemand" as well */ + /* This mount option will force use of mandatory + (DOS/Windows style) byte range locks, instead of + using posix advisory byte range locks, even if the + Unix extensions are available and posix locks would + be supported otherwise. If Unix extensions are not + negotiated this has no effect since mandatory locks + would be used (mandatory locks is all that those + those servers support) */ + vol->mand_lock = 1; } else if (strnicmp(data, "setuids", 7) == 0) { vol->setuids = 1; } else if (strnicmp(data, "nosetuids", 9) == 0) { @@ -2150,6 +2162,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; if (pvolume_info->nobrl) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; + if (pvolume_info->mand_lock) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL; if (pvolume_info->cifs_acl) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; if (pvolume_info->override_uid) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index f0a81e631ae60b..babd27a4699a3b 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -644,10 +644,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) __u64 length; bool wait_flag = false; struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; + struct cifsTconInfo *tcon; __u16 netfid; __u8 lockType = LOCKING_ANDX_LARGE_FILES; - bool posix_locking; + bool posix_locking = 0; length = 1 + pfLock->fl_end - pfLock->fl_start; rc = -EACCES; @@ -698,7 +698,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) cFYI(1, ("Unknown type of lock")); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - pTcon = cifs_sb->tcon; + tcon = cifs_sb->tcon; if (file->private_data == NULL) { FreeXid(xid); @@ -706,9 +706,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) } netfid = ((struct cifsFileInfo *)file->private_data)->netfid; - posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) && - (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability)); - + if ((tcon->ses->capabilities & CAP_UNIX) && + (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL == 0)) + posix_locking = 1; /* BB add code here to normalize offset and length to account for negative length which we can not accept over the wire */ @@ -719,7 +720,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) posix_lock_type = CIFS_RDLCK; else posix_lock_type = CIFS_WRLCK; - rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */, + rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */, length, pfLock, posix_lock_type, wait_flag); FreeXid(xid); @@ -727,10 +728,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) } /* BB we could chain these into one lock request BB */ - rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, + rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start, 0, 1, lockType, 0 /* wait flag */ ); if (rc == 0) { - rc = CIFSSMBLock(xid, pTcon, netfid, length, + rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start, 1 /* numUnlock */ , 0 /* numLock */ , lockType, 0 /* wait flag */ ); @@ -767,7 +768,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) if (numUnlock == 1) posix_lock_type = CIFS_UNLCK; - rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */, + rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */, length, pfLock, posix_lock_type, wait_flag); } else { @@ -775,7 +776,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) (struct cifsFileInfo *)file->private_data; if (numLock) { - rc = CIFSSMBLock(xid, pTcon, netfid, length, + rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start, 0, numLock, lockType, wait_flag); @@ -796,7 +797,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) if (pfLock->fl_start <= li->offset && (pfLock->fl_start + length) >= (li->offset + li->length)) { - stored_rc = CIFSSMBLock(xid, pTcon, + stored_rc = CIFSSMBLock(xid, tcon, netfid, li->length, li->offset, 1, 0, li->type, false); From acc18aa1e643519035abdab5e72dc75e534b5198 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 2 Dec 2008 18:53:55 +0000 Subject: [PATCH 12/31] [CIFS] remove sparse warning Signed-off-by: Steve French --- fs/cifs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index babd27a4699a3b..b1e1fc6a6e6a02 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -708,7 +708,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) if ((tcon->ses->capabilities & CAP_UNIX) && (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && - (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL == 0)) + ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) posix_locking = 1; /* BB add code here to normalize offset and length to account for negative length which we can not accept over the From 3de2091ac722e7dbc37d87d9112ab19ec6a871de Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 2 Dec 2008 20:52:28 +0000 Subject: [PATCH 13/31] [CIFS] fix typo Signed-off-by: Steve French --- fs/cifs/cifsfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index fb676076946b79..2ce04c73d74e74 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); extern const struct export_operations cifs_export_ops; #endif /* EXPERIMENTAL */ -#define CIFS_VERSION "1.5666666" +#define CIFS_VERSION "1.56" #endif /* _CIFSFS_H */ From 61e748015866e48aff91284e3d300c6e3035a87a Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 3 Dec 2008 00:57:54 +0000 Subject: [PATCH 14/31] [CIFS] various minor cleanups pointed out by checkpatch script Signed-off-by: Steve French --- fs/cifs/AUTHORS | 2 ++ fs/cifs/cifsfs.c | 19 +++++++------------ fs/cifs/cifspdu.h | 2 +- fs/cifs/cifssmb.c | 16 ++++++++-------- fs/cifs/connect.c | 18 +++++++----------- fs/cifs/dir.c | 9 ++++----- 6 files changed, 29 insertions(+), 37 deletions(-) diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS index 9c136d7803d98f..7f7fa3c302aff6 100644 --- a/fs/cifs/AUTHORS +++ b/fs/cifs/AUTHORS @@ -36,7 +36,9 @@ Miklos Szeredi Kazeon team for various fixes especially for 2.4 version. Asser Ferno (Change Notify support) Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup +Gunter Kukkukk (testing and suggestions for support of old servers) Igor Mammedov (DFS support) +Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code) Test case and Bug Report contributors ------------------------------------- diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 061a1dca987dc0..974c8f0e615eb1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -347,7 +347,6 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) if (cifs_sb) { tcon = cifs_sb->tcon; if (tcon) { -/* BB add prepath to mount options displayed */ seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); if (tcon->ses) { if (tcon->ses->userName) @@ -439,9 +438,8 @@ int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid, xid = GetXid(); if (pTcon) { cFYI(1, ("set type: 0x%x id: %d", quota_type, qid)); - } else { + } else rc = -EIO; - } FreeXid(xid); return rc; @@ -463,9 +461,8 @@ int cifs_xquota_get(struct super_block *sb, int quota_type, qid_t qid, xid = GetXid(); if (pTcon) { cFYI(1, ("set type: 0x%x id: %d", quota_type, qid)); - } else { + } else rc = -EIO; - } FreeXid(xid); return rc; @@ -486,9 +483,8 @@ int cifs_xstate_set(struct super_block *sb, unsigned int flags, int operation) xid = GetXid(); if (pTcon) { cFYI(1, ("flags: 0x%x operation: 0x%x", flags, operation)); - } else { + } else rc = -EIO; - } FreeXid(xid); return rc; @@ -501,17 +497,16 @@ int cifs_xstate_get(struct super_block *sb, struct fs_quota_stat *qstats) struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifsTconInfo *pTcon; - if (cifs_sb) { + if (cifs_sb) pTcon = cifs_sb->tcon; - } else { + else return -EIO; - } + xid = GetXid(); if (pTcon) { cFYI(1, ("pqstats %p", qstats)); - } else { + } else rc = -EIO; - } FreeXid(xid); return rc; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index d2a073edd1b887..b4e2e9f0ee3d75 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1922,7 +1922,7 @@ typedef struct smb_com_transaction2_get_dfs_refer_req { /* DFS server target type */ #define DFS_TYPE_LINK 0x0000 /* also for sysvol targets */ #define DFS_TYPE_ROOT 0x0001 - + /* Referral Entry Flags */ #define DFS_NAME_LIST_REF 0x0200 diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6d51696dc762d3..ef9786b6bea408 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1382,13 +1382,13 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) *pOplock |= CIFS_CREATE_ACTION; if (pfile_info) { - memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime, - 36 /* CreationTime to Attributes */); - /* the file_info buf is endian converted by caller */ - pfile_info->AllocationSize = pSMBr->AllocationSize; - pfile_info->EndOfFile = pSMBr->EndOfFile; - pfile_info->NumberOfLinks = cpu_to_le32(1); - pfile_info->DeletePending = 0; + memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime, + 36 /* CreationTime to Attributes */); + /* the file_info buf is endian converted by caller */ + pfile_info->AllocationSize = pSMBr->AllocationSize; + pfile_info->EndOfFile = pSMBr->EndOfFile; + pfile_info->NumberOfLinks = cpu_to_le32(1); + pfile_info->DeletePending = 0; } } @@ -1558,7 +1558,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, pSMB->DataOffset = cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); if (buf) - memcpy(pSMB->Data, buf, bytes_sent); + memcpy(pSMB->Data, buf, bytes_sent); else if (ubuf) { if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) { cifs_buf_release(pSMB); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 351942042833d5..6107ee42b09302 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2582,7 +2582,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, __u16 action = le16_to_cpu(pSMBr->resp.Action); __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); if (action & GUEST_LOGIN) - cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */ + cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (little endian) */ cFYI(1, ("UID = %d ", ses->Suid)); @@ -2728,13 +2728,11 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, len)); } } else { - cERROR(1, - (" Security Blob Length extends beyond " + cERROR(1, ("Security Blob Length extends beyond " "end of SMB")); } } else { - cERROR(1, - (" Invalid Word count %d: ", + cERROR(1, ("Invalid Word count %d: ", smb_buffer_response->WordCount)); rc = -EIO; } @@ -2892,7 +2890,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); if (action & GUEST_LOGIN) - cFYI(1, (" Guest login")); + cFYI(1, ("Guest login")); /* Do we want to set anything in SesInfo struct when guest login? */ bcc_ptr = pByteArea(smb_buffer_response); @@ -2900,8 +2898,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; if (SecurityBlob2->MessageType != NtLmChallenge) { - cFYI(1, - ("Unexpected NTLMSSP message type received %d", + cFYI(1, ("Unexpected NTLMSSP message type received %d", SecurityBlob2->MessageType)); } else if (ses) { ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ @@ -3073,8 +3070,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, cERROR(1, ("No session structure passed in.")); } } else { - cERROR(1, - (" Invalid Word count %d:", + cERROR(1, ("Invalid Word count %d:", smb_buffer_response->WordCount)); rc = -EIO; } @@ -3313,7 +3309,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, __u16 action = le16_to_cpu(pSMBr->resp.Action); __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); if (action & GUEST_LOGIN) - cFYI(1, (" Guest login")); /* BB Should we set anything + cFYI(1, ("Guest login")); /* BB Should we set anything in SesInfo struct ? */ /* if (SecurityBlob2->MessageType != NtLm??) { cFYI("Unexpected message type on auth response is %d")); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e962e75e6f7b1e..0592dbb3a6b83d 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -483,7 +483,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, xid = GetXid(); - cFYI(1, (" parent inode = 0x%p name is: %s and dentry = 0x%p", + cFYI(1, ("parent inode = 0x%p name is: %s and dentry = 0x%p", parent_dir_inode, direntry->d_name.name, direntry)); /* check whether path exists */ @@ -515,12 +515,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, } if (direntry->d_inode != NULL) { - cFYI(1, (" non-NULL inode in lookup")); + cFYI(1, ("non-NULL inode in lookup")); } else { - cFYI(1, (" NULL inode in lookup")); + cFYI(1, ("NULL inode in lookup")); } - cFYI(1, - (" Full path: %s inode = 0x%p", full_path, direntry->d_inode)); + cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); if (pTcon->unix_ext) rc = cifs_get_inode_info_unix(&newInode, full_path, From 8be0ed44c2fa4afcf2c6d2fb3102c926e9f989df Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 5 Dec 2008 19:14:12 +0000 Subject: [PATCH 15/31] [CIFS] Can not mount with prefixpath if root directory of share is inaccessible Windows allows you to deny access to the top of a share, but permit access to a directory lower in the path. With the prefixpath feature of cifs (ie mounting \\server\share\directory\subdirectory\etc.) this should have worked if the user specified a prefixpath which put the root of the mount at a directory to which he had access, but we still were doing a lookup on the root of the share (null path) when we should have been doing it on the prefixpath subdirectory. This fixes Samba bug # 5925 Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/CHANGES | 4 +++- fs/cifs/inode.c | 58 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 3d848f463c44fc..5ab6bcce880a7a 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -2,7 +2,9 @@ Version 1.56 ------------ Add "forcemandatorylock" mount option to allow user to use mandatory rather than posix (advisory) byte range locks, even though server would -support posix byte range locks. +support posix byte range locks. Fix query of root inode when prefixpath +specified and user does not have access to query information about the +top of the share. Version 1.55 ------------ diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ff8c68de4a9205..b8821b0e73de51 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1,7 +1,7 @@ /* * fs/cifs/inode.c * - * Copyright (C) International Business Machines Corp., 2002,2007 + * Copyright (C) International Business Machines Corp., 2002,2008 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -621,6 +621,47 @@ static const struct inode_operations cifs_ipc_inode_ops = { .lookup = cifs_lookup, }; +static char *build_path_to_root(struct cifs_sb_info *cifs_sb) +{ + int pplen = cifs_sb->prepathlen; + int dfsplen; + char *full_path = NULL; + + /* if no prefix path, simply set path to the root of share to "" */ + if (pplen == 0) { + full_path = kmalloc(1, GFP_KERNEL); + if (full_path) + full_path[0] = 0; + return full_path; + } + + if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS)) + dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1); + else + dfsplen = 0; + + full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL); + if (full_path == NULL) + return full_path; + + if (dfsplen) { + strncpy(full_path, cifs_sb->tcon->treeName, dfsplen); + /* switch slash direction in prepath depending on whether + * windows or posix style path names + */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { + int i; + for (i = 0; i < dfsplen; i++) { + if (full_path[i] == '\\') + full_path[i] = '/'; + } + } + } + strncpy(full_path + dfsplen, cifs_sb->prepath, pplen); + full_path[dfsplen + pplen] = 0; /* add trailing null */ + return full_path; +} + /* gets root inode */ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) { @@ -628,6 +669,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) struct cifs_sb_info *cifs_sb; struct inode *inode; long rc; + char *full_path; inode = iget_locked(sb, ino); if (!inode) @@ -636,13 +678,17 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) return inode; cifs_sb = CIFS_SB(inode->i_sb); - xid = GetXid(); + full_path = build_path_to_root(cifs_sb); + if (full_path == NULL) + return ERR_PTR(-ENOMEM); + xid = GetXid(); if (cifs_sb->tcon->unix_ext) - rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); + rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, + xid); else - rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid, - NULL); + rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb, + xid, NULL); if (rc && cifs_sb->tcon->ipc) { cFYI(1, ("ipc connection - fake read inode")); inode->i_mode |= S_IFDIR; @@ -652,6 +698,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) inode->i_uid = cifs_sb->mnt_uid; inode->i_gid = cifs_sb->mnt_gid; } else if (rc) { + kfree(full_path); _FreeXid(xid); iget_failed(inode); return ERR_PTR(rc); @@ -659,6 +706,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) unlock_new_inode(inode); + kfree(full_path); /* can not call macro FreeXid here since in a void func * TODO: This is no longer true */ From 85705524258f93a6086c3247a58f34a661b82b3d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 5 Dec 2008 20:41:21 -0500 Subject: [PATCH 16/31] cifs: fix wait_for_response to time out sleeping processes correctly cifs: fix wait_for_response to time out sleeping processes correctly The current scheme that CIFS uses to sleep and wait for a response is not quite what we want. After sending a request, wait_for_response puts the task to sleep with wait_event(). One of the conditions for wait_event is a timeout (using time_after()). The problem with this is that there is no guarantee that the process will ever be woken back up. If the server stops sending data, then cifs_demultiplex_thread will leave its response queue sleeping. I think the only thing that saves us here is the fact that cifs_dnotify_thread periodically (every 15s) wakes up sleeping processes on all response_q's that have calls in flight. This makes for unnecessary wakeups of some processes. It also means large variability in the timeouts since they're all woken up at once. Instead of this, put the tasks to sleep with wait_event_timeout. This makes them wake up on their own if they time out. With this change, cifs_dnotify_thread should no longer be needed. I've been testing this in conjunction with some other patches that I'm working on. It doesn't seem to affect performance at all with with heavy I/O. Identical iozone -ac runs complete in almost exactly the same time (<1% difference in times). Thanks to Wasrshi Nimara for initially pointing this out. Wasrshi, it would be nice to know whether this patch also helps your testcase. Signed-off-by: Jeff Layton Cc: Wasrshi Nimara Signed-off-by: Steve French --- fs/cifs/transport.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index cd4ed65d6cd96f..4d076be46d90eb 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -410,11 +410,8 @@ static int wait_for_response(struct cifsSesInfo *ses, for (;;) { curr_timeout = timeout + jiffies; - wait_event(ses->server->response_q, - (!(midQ->midState == MID_REQUEST_SUBMITTED)) || - time_after(jiffies, curr_timeout) || - ((ses->server->tcpStatus != CifsGood) && - (ses->server->tcpStatus != CifsNew))); + wait_event_timeout(ses->server->response_q, + midQ->midState != MID_REQUEST_SUBMITTED, timeout); if (time_after(jiffies, curr_timeout) && (midQ->midState == MID_REQUEST_SUBMITTED) && From 55162dec9371a6f6ac63ff546c182cc6144a649e Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 5 Dec 2008 20:41:21 -0500 Subject: [PATCH 17/31] cifs: zero out session password before freeing it cifs: zero out session password before freeing it ...just to be on the safe side. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/misc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 9ee3f689c2b0c0..7c3f4b9230d7ff 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -97,7 +97,10 @@ sesInfoFree(struct cifsSesInfo *buf_to_free) kfree(buf_to_free->serverOS); kfree(buf_to_free->serverDomain); kfree(buf_to_free->serverNOS); - kfree(buf_to_free->password); + if (buf_to_free->password) { + memset(buf_to_free->password, 0, strlen(buf_to_free->password)); + kfree(buf_to_free->password); + } kfree(buf_to_free->domainName); kfree(buf_to_free); } From 4e53a3fb98d3d5c2941d2e7199dab317a9d4ead3 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 5 Dec 2008 20:41:21 -0500 Subject: [PATCH 18/31] cifs: have calc_lanman_hash take more granular args cifs: have calc_lanman_hash take more granular args We need to use this routine to encrypt passwords associated with the tcon too. Don't assume that the password will be attached to the smb_session. Also, make some of the values in the lower encryption functions const since they aren't changed. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 30 ++++++++++++++---------------- fs/cifs/cifsencrypt.h | 3 ++- fs/cifs/cifsproto.h | 3 ++- fs/cifs/connect.c | 5 ++++- fs/cifs/sess.c | 5 ++++- fs/cifs/smbdes.c | 5 +++-- fs/cifs/smbencrypt.c | 9 +++++---- 7 files changed, 34 insertions(+), 26 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index bd5f13d38450ba..d4839cf0cb2c79 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -37,7 +37,7 @@ extern void mdfour(unsigned char *out, unsigned char *in, int n); extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); -extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, +extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, @@ -280,25 +280,22 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses, } #ifdef CONFIG_CIFS_WEAK_PW_HASH -void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key) +void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, + char *lnm_session_key) { int i; char password_with_pad[CIFS_ENCPWD_SIZE]; - if (ses->server == NULL) - return; - memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); - if (ses->password) - strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); - - if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) - if (extended_security & CIFSSEC_MAY_PLNTXT) { - memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE); - memcpy(lnm_session_key, password_with_pad, - CIFS_ENCPWD_SIZE); - return; - } + if (password) + strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE); + + if (!encrypt && extended_security & CIFSSEC_MAY_PLNTXT) { + memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE); + memcpy(lnm_session_key, password_with_pad, + CIFS_ENCPWD_SIZE); + return; + } /* calculate old style session key */ /* calling toupper is less broken than repeatedly @@ -314,7 +311,8 @@ void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key) for (i = 0; i < CIFS_ENCPWD_SIZE; i++) password_with_pad[i] = toupper(password_with_pad[i]); - SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key); + SMBencrypt(password_with_pad, cryptkey, lnm_session_key); + /* clear password before we return/free memory */ memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); } diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h index 152fa2dcfc6c70..15d2ec00647471 100644 --- a/fs/cifs/cifsencrypt.h +++ b/fs/cifs/cifsencrypt.h @@ -26,7 +26,8 @@ extern void mdfour(unsigned char *out, unsigned char *in, int n); /* smbdes.c */ extern void E_P16(unsigned char *p14, unsigned char *p16); -extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24); +extern void E_P24(unsigned char *p21, const unsigned char *c8, + unsigned char *p24); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 6f21ecb85ce517..f48616536078ed 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -330,7 +330,8 @@ extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, const struct nls_table *); #ifdef CONFIG_CIFS_WEAK_PW_HASH -extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key); +extern void calc_lanman_hash(const char *password, const char *cryptkey, + bool encrypt, char *lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ extern int CIFSSMBCopy(int xid, struct cifsTconInfo *source_tcon, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 6107ee42b09302..3a84a375cb6f4d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3533,7 +3533,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, #ifdef CONFIG_CIFS_WEAK_PW_HASH if ((extended_security & CIFSSEC_MAY_LANMAN) && (ses->server->secType == LANMAN)) - calc_lanman_hash(ses, bcc_ptr); + calc_lanman_hash(ses->password, ses->server->cryptKey, + ses->server->secMode & + SECMODE_PW_ENCRYPT ? true : false, + bcc_ptr); else #endif /* CIFS_WEAK_PW_HASH */ SMBNTencrypt(ses->password, diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 2851d5da0c8c03..5f22de7b79a900 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -417,7 +417,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* BB calculate hash with password */ /* and copy into bcc */ - calc_lanman_hash(ses, lnm_session_key); + calc_lanman_hash(ses->password, ses->server->cryptKey, + ses->server->secMode & SECMODE_PW_ENCRYPT ? + true : false, lnm_session_key); + ses->flags |= CIFS_SES_LANMAN; memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); bcc_ptr += CIFS_SESS_KEY_SIZE; diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c index 04943c976f98d1..224a1f4789666f 100644 --- a/fs/cifs/smbdes.c +++ b/fs/cifs/smbdes.c @@ -318,7 +318,8 @@ str_to_key(unsigned char *str, unsigned char *key) } static void -smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw) +smbhash(unsigned char *out, const unsigned char *in, unsigned char *key, + int forw) { int i; char *outb; /* outb[64] */ @@ -363,7 +364,7 @@ E_P16(unsigned char *p14, unsigned char *p16) } void -E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) +E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) { smbhash(p24, c8, p21, 1); smbhash(p24 + 8, c8, p21 + 7, 1); diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index ff3232fa1015b4..93fb09a99c6902 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -49,9 +49,10 @@ /*The following definitions come from libsmb/smbencrypt.c */ -void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); +void SMBencrypt(unsigned char *passwd, const unsigned char *c8, + unsigned char *p24); void E_md4hash(const unsigned char *passwd, unsigned char *p16); -static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, +static void SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8, unsigned char p24[24]); void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); @@ -61,7 +62,7 @@ void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); encrypted password into p24 */ /* Note that password must be uppercased and null terminated */ void -SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) +SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) { unsigned char p14[15], p21[21]; @@ -212,7 +213,7 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n, /* Does the des encryption from the NT or LM MD4 hash. */ static void -SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, +SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8, unsigned char p24[24]) { unsigned char p21[21]; From 00e485b0198ea4f509341373f1d9adb0a5977a2f Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 5 Dec 2008 20:41:21 -0500 Subject: [PATCH 19/31] cifs: store password in tcon cifs: store password in tcon Each tcon has its own password for share-level security. Store it in the tcon and wipe it clean and free it when freeing the tcon. When doing the tree connect with share-level security, use the tcon password instead of the session password. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 1 + fs/cifs/connect.c | 25 ++++++++++++++++++------- fs/cifs/misc.c | 4 ++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 0fb934d3623b95..94c1ca0ec9539e 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -242,6 +242,7 @@ struct cifsTconInfo { struct cifsSesInfo *ses; /* pointer to session associated with */ char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ char *nativeFileSystem; + char *password; /* for share-level security */ __u16 tid; /* The 2 byte tree id */ __u16 Flags; /* optional support bits */ enum statusEnum tidStatus; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3a84a375cb6f4d..3caadf12d76d00 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2282,9 +2282,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, /* 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; + pSesInfo->password = kstrdup(volume_info->password, + GFP_KERNEL); + if (!pSesInfo->password) { + rc = -ENOMEM; + goto mount_fail_check; + } } if (volume_info->username) strncpy(pSesInfo->userName, volume_info->username, @@ -2324,7 +2327,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, rc = -ENOMEM; goto mount_fail_check; } + tcon->ses = pSesInfo; + if (volume_info->password) { + tcon->password = kstrdup(volume_info->password, + GFP_KERNEL); + if (!tcon->password) { + rc = -ENOMEM; + goto mount_fail_check; + } + } /* check for null share name ie connect to dfs root */ if ((strchr(volume_info->UNC + 3, '\\') == NULL) @@ -3532,15 +3544,14 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, NTLMv2 password here) */ #ifdef CONFIG_CIFS_WEAK_PW_HASH if ((extended_security & CIFSSEC_MAY_LANMAN) && - (ses->server->secType == LANMAN)) - calc_lanman_hash(ses->password, ses->server->cryptKey, + (ses->server->secType == LANMAN)) + calc_lanman_hash(tcon->password, ses->server->cryptKey, ses->server->secMode & SECMODE_PW_ENCRYPT ? true : false, bcc_ptr); else #endif /* CIFS_WEAK_PW_HASH */ - SMBNTencrypt(ses->password, - ses->server->cryptKey, + SMBNTencrypt(tcon->password, ses->server->cryptKey, bcc_ptr); bcc_ptr += CIFS_SESS_KEY_SIZE; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 7c3f4b9230d7ff..a0513605d7e39c 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -132,6 +132,10 @@ tconInfoFree(struct cifsTconInfo *buf_to_free) } atomic_dec(&tconInfoAllocCount); kfree(buf_to_free->nativeFileSystem); + if (buf_to_free->password) { + memset(buf_to_free->password, 0, strlen(buf_to_free->password)); + kfree(buf_to_free->password); + } kfree(buf_to_free); } From 6d9c6d543165d1d492602c1371cb019040093584 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 8 Dec 2008 20:50:24 +0000 Subject: [PATCH 20/31] [CIFS] In SendReceive, move consistency check out of the mutexed region inbuf->smb_buf_length does not change in in wait_for_free_request() or in allocate_mid(), so we can check it early. Signed-off-by: Volker Lendecke Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/transport.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 4d076be46d90eb..e80210693ff70c 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -687,6 +687,12 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, to the same server. We may make this configurable later or use ses->maxReq */ + if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { + cERROR(1, ("Illegal length, greater than maximum frame, %d", + in_buf->smb_buf_length)); + return -EIO; + } + rc = wait_for_free_request(ses, long_op); if (rc) return rc; @@ -706,17 +712,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, return rc; } - if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { - cERROR(1, ("Illegal length, greater than maximum frame, %d", - in_buf->smb_buf_length)); - DeleteMidQEntry(midQ); - mutex_unlock(&ses->server->srv_mutex); - /* Update # of requests on wire to server */ - atomic_dec(&ses->server->inFlight); - wake_up(&ses->server->request_q); - return -EIO; - } - rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; @@ -925,6 +920,12 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, to the same server. We may make this configurable later or use ses->maxReq */ + if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { + cERROR(1, ("Illegal length, greater than maximum frame, %d", + in_buf->smb_buf_length)); + return -EIO; + } + rc = wait_for_free_request(ses, CIFS_BLOCKING_OP); if (rc) return rc; @@ -941,14 +942,6 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, return rc; } - if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { - mutex_unlock(&ses->server->srv_mutex); - cERROR(1, ("Illegal length, greater than maximum frame, %d", - in_buf->smb_buf_length)); - DeleteMidQEntry(midQ); - return -EIO; - } - rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; From 8fbbd365cc700e288fb6f9780b092c5afa4946e5 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 6 Dec 2008 13:12:34 +0100 Subject: [PATCH 21/31] Simplify allocate_mid() slightly: Remove some unnecessary "else" branches Simplify allocate_mid() slightly: Remove some unnecessary "else" branches Signed-off-by: Volker Lendecke Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/transport.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index e80210693ff70c..c98f929315f24b 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -385,10 +385,14 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, { if (ses->server->tcpStatus == CifsExiting) { return -ENOENT; - } else if (ses->server->tcpStatus == CifsNeedReconnect) { + } + + if (ses->server->tcpStatus == CifsNeedReconnect) { cFYI(1, ("tcp session dead - return to caller to retry")); return -EAGAIN; - } else if (ses->status != CifsGood) { + } + + if (ses->status != CifsGood) { /* check if SMB session is bad because we are setting it up */ if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && (in_buf->Command != SMB_COM_NEGOTIATE)) From 27a97a613b96688e59dd116cae3f0c94107b434c Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 8 Dec 2008 20:59:39 +0000 Subject: [PATCH 22/31] [CIFS] Slightly simplify wait_for_free_request(), remove an unnecessary "else" branch This is no functional change, because in the "if" branch we do an early "return 0;". Signed-off-by: Volker Lendecke Signed-off-by: Steve French --- fs/cifs/transport.c | 51 +++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index c98f929315f24b..5f224e999585e1 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -344,37 +344,38 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) if (long_op == CIFS_ASYNC_OP) { /* oplock breaks must not be held up */ atomic_inc(&ses->server->inFlight); - } else { - spin_lock(&GlobalMid_Lock); - while (1) { - if (atomic_read(&ses->server->inFlight) >= - cifs_max_pending){ - spin_unlock(&GlobalMid_Lock); + return 0; + } + + spin_lock(&GlobalMid_Lock); + while (1) { + if (atomic_read(&ses->server->inFlight) >= + cifs_max_pending){ + spin_unlock(&GlobalMid_Lock); #ifdef CONFIG_CIFS_STATS2 - atomic_inc(&ses->server->num_waiters); + atomic_inc(&ses->server->num_waiters); #endif - wait_event(ses->server->request_q, - atomic_read(&ses->server->inFlight) - < cifs_max_pending); + wait_event(ses->server->request_q, + atomic_read(&ses->server->inFlight) + < cifs_max_pending); #ifdef CONFIG_CIFS_STATS2 - atomic_dec(&ses->server->num_waiters); + atomic_dec(&ses->server->num_waiters); #endif - spin_lock(&GlobalMid_Lock); - } else { - if (ses->server->tcpStatus == CifsExiting) { - spin_unlock(&GlobalMid_Lock); - return -ENOENT; - } - - /* can not count locking commands against total - as they are allowed to block on server */ - - /* update # of requests on the wire to server */ - if (long_op != CIFS_BLOCKING_OP) - atomic_inc(&ses->server->inFlight); + spin_lock(&GlobalMid_Lock); + } else { + if (ses->server->tcpStatus == CifsExiting) { spin_unlock(&GlobalMid_Lock); - break; + return -ENOENT; } + + /* can not count locking commands against total + as they are allowed to block on server */ + + /* update # of requests on the wire to server */ + if (long_op != CIFS_BLOCKING_OP) + atomic_inc(&ses->server->inFlight); + spin_unlock(&GlobalMid_Lock); + break; } } return 0; From 4c3130efda1ef4f28d5f26819fae2e58c3945f0b Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 9 Dec 2008 00:28:16 +0000 Subject: [PATCH 23/31] [CIFS] Cleanup: Move the check for too large R/W requests This avoids an unnecessary else branch Signed-off-by: Volker Lendecke Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index ef9786b6bea408..824df142f28812 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1414,8 +1414,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, cFYI(1, ("Reading %d bytes on fid %d", count, netfid)); if (tcon->ses->capabilities & CAP_LARGE_FILES) wct = 12; - else + else { wct = 10; /* old style read */ + if ((lseek >> 32) > 0) { + /* can not handle this big offset for old */ + return -EIO; + } + } *nbytes = 0; rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB); @@ -1431,8 +1436,6 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); if (wct == 12) pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); - else if ((lseek >> 32) > 0) /* can not handle this big offset for old */ - return -EIO; pSMB->Remaining = 0; pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); @@ -1519,8 +1522,13 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, if (tcon->ses->capabilities & CAP_LARGE_FILES) wct = 14; - else + else { wct = 12; + if ((offset >> 32) > 0) { + /* can not handle big offset for old srv */ + return -EIO; + } + } rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -1535,8 +1543,6 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); if (wct == 14) pSMB->OffsetHigh = cpu_to_le32(offset >> 32); - else if ((offset >> 32) > 0) /* can not handle big offset for old srv */ - return -EIO; pSMB->Reserved = 0xFFFFFFFF; pSMB->WriteMode = 0; @@ -1621,10 +1627,15 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count)); - if (tcon->ses->capabilities & CAP_LARGE_FILES) + if (tcon->ses->capabilities & CAP_LARGE_FILES) { wct = 14; - else + } else { wct = 12; + if ((offset >> 32) > 0) { + /* can not handle big offset for old srv */ + return -EIO; + } + } rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB); if (rc) return rc; @@ -1637,8 +1648,6 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); if (wct == 14) pSMB->OffsetHigh = cpu_to_le32(offset >> 32); - else if ((offset >> 32) > 0) /* can not handle big offset for old srv */ - return -EIO; pSMB->Reserved = 0xFFFFFFFF; pSMB->WriteMode = 0; pSMB->Remaining = 0; From 829049cbb1d2ddda2be17ea008b6b3c457808d91 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 6 Dec 2008 16:00:53 +0100 Subject: [PATCH 24/31] Check the return value of cifs_sign_smb[2] Check the return value of cifs_sign_smb[2] Signed-off-by: Volker Lendecke Signed-off-by: Steve French --- fs/cifs/transport.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 5f224e999585e1..dc2d1b0bba58a3 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -530,6 +530,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, return rc; } rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); + if (rc) { + mutex_unlock(&ses->server->srv_mutex); + cifs_small_buf_release(in_buf); + goto out; + } midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 @@ -718,6 +723,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, } rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); + if (rc) { + mutex_unlock(&ses->server->srv_mutex); + goto out; + } midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 @@ -948,6 +957,11 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, } rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); + if (rc) { + DeleteMidQEntry(midQ); + mutex_unlock(&ses->server->srv_mutex); + return rc; + } midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 From 8e4f2e8a1e5cfa07c5b2731accee0e6eb4c64575 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 6 Dec 2008 16:22:15 +0100 Subject: [PATCH 25/31] Slightly streamline SendReceive[2] Slightly streamline SendReceive[2] Remove an else branch by naming the error condition what it is Signed-off-by: Volker Lendecke Signed-off-by: Steve French --- fs/cifs/transport.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index dc2d1b0bba58a3..01b3aa5f928bb2 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -583,10 +583,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, wait_for_response(ses, midQ, timeout, 10 * HZ); spin_lock(&GlobalMid_Lock); - if (midQ->resp_buf) { - spin_unlock(&GlobalMid_Lock); - receive_len = midQ->resp_buf->smb_buf_length; - } else { + + if (midQ->resp_buf == NULL) { cERROR(1, ("No response to cmd %d mid %d", midQ->command, midQ->mid)); if (midQ->midState == MID_REQUEST_SUBMITTED) { @@ -614,6 +612,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, return rc; } + spin_unlock(&GlobalMid_Lock); + receive_len = midQ->resp_buf->smb_buf_length; + if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, ("Frame too large received. Length: %d Xid: %d", receive_len, xid)); @@ -773,10 +774,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, wait_for_response(ses, midQ, timeout, 10 * HZ); spin_lock(&GlobalMid_Lock); - if (midQ->resp_buf) { - spin_unlock(&GlobalMid_Lock); - receive_len = midQ->resp_buf->smb_buf_length; - } else { + if (midQ->resp_buf == NULL) { cERROR(1, ("No response for cmd %d mid %d", midQ->command, midQ->mid)); if (midQ->midState == MID_REQUEST_SUBMITTED) { @@ -804,6 +802,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, return rc; } + spin_unlock(&GlobalMid_Lock); + receive_len = midQ->resp_buf->smb_buf_length; + if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, ("Frame too large received. Length: %d Xid: %d", receive_len, xid)); From 2b2bdfba7a3679f67b7c3aca4a4b08b24bb675a8 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 11 Dec 2008 17:26:54 +0000 Subject: [PATCH 26/31] [CIFS] Streamline SendReceive[2] by using "goto out:" in an error condition Signed-off-by: Volker Lendecke Signed-off-by: Steve French --- fs/cifs/transport.c | 139 +++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 67 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 01b3aa5f928bb2..ca015e60002ada 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -619,49 +619,52 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, cERROR(1, ("Frame too large received. Length: %d Xid: %d", receive_len, xid)); rc = -EIO; - } else { /* rcvd frame is ok */ - if (midQ->resp_buf && - (midQ->midState == MID_RESPONSE_RECEIVED)) { + goto out; + } - iov[0].iov_base = (char *)midQ->resp_buf; - if (midQ->largeBuf) - *pRespBufType = CIFS_LARGE_BUFFER; - else - *pRespBufType = CIFS_SMALL_BUFFER; - iov[0].iov_len = receive_len + 4; + /* rcvd frame is ok */ - dump_smb(midQ->resp_buf, 80); - /* convert the length into a more usable form */ - if ((receive_len > 24) && - (ses->server->secMode & (SECMODE_SIGN_REQUIRED | - SECMODE_SIGN_ENABLED))) { - rc = cifs_verify_signature(midQ->resp_buf, + if (midQ->resp_buf && + (midQ->midState == MID_RESPONSE_RECEIVED)) { + + iov[0].iov_base = (char *)midQ->resp_buf; + if (midQ->largeBuf) + *pRespBufType = CIFS_LARGE_BUFFER; + else + *pRespBufType = CIFS_SMALL_BUFFER; + iov[0].iov_len = receive_len + 4; + + dump_smb(midQ->resp_buf, 80); + /* convert the length into a more usable form */ + if ((receive_len > 24) && + (ses->server->secMode & (SECMODE_SIGN_REQUIRED | + SECMODE_SIGN_ENABLED))) { + rc = cifs_verify_signature(midQ->resp_buf, &ses->server->mac_signing_key, midQ->sequence_number+1); - if (rc) { - cERROR(1, ("Unexpected SMB signature")); - /* BB FIXME add code to kill session */ - } + if (rc) { + cERROR(1, ("Unexpected SMB signature")); + /* BB FIXME add code to kill session */ } - - /* BB special case reconnect tid and uid here? */ - rc = map_smb_to_linux_error(midQ->resp_buf, - flags & CIFS_LOG_ERROR); - - /* convert ByteCount if necessary */ - if (receive_len >= sizeof(struct smb_hdr) - 4 - /* do not count RFC1001 header */ + - (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) - BCC(midQ->resp_buf) = - le16_to_cpu(BCC_LE(midQ->resp_buf)); - if ((flags & CIFS_NO_RESP) == 0) - midQ->resp_buf = NULL; /* mark it so buf will - not be freed by - DeleteMidQEntry */ - } else { - rc = -EIO; - cFYI(1, ("Bad MID state?")); } + + /* BB special case reconnect tid and uid here? */ + rc = map_smb_to_linux_error(midQ->resp_buf, + flags & CIFS_LOG_ERROR); + + /* convert ByteCount if necessary */ + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + + (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) + BCC(midQ->resp_buf) = + le16_to_cpu(BCC_LE(midQ->resp_buf)); + if ((flags & CIFS_NO_RESP) == 0) + midQ->resp_buf = NULL; /* mark it so buf will + not be freed by + DeleteMidQEntry */ + } else { + rc = -EIO; + cFYI(1, ("Bad MID state?")); } out: @@ -809,43 +812,45 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, cERROR(1, ("Frame too large received. Length: %d Xid: %d", receive_len, xid)); rc = -EIO; - } else { /* rcvd frame is ok */ - - if (midQ->resp_buf && out_buf - && (midQ->midState == MID_RESPONSE_RECEIVED)) { - out_buf->smb_buf_length = receive_len; - memcpy((char *)out_buf + 4, - (char *)midQ->resp_buf + 4, - receive_len); + goto out; + } - dump_smb(out_buf, 92); - /* convert the length into a more usable form */ - if ((receive_len > 24) && - (ses->server->secMode & (SECMODE_SIGN_REQUIRED | - SECMODE_SIGN_ENABLED))) { - rc = cifs_verify_signature(out_buf, + /* rcvd frame is ok */ + + if (midQ->resp_buf && out_buf + && (midQ->midState == MID_RESPONSE_RECEIVED)) { + out_buf->smb_buf_length = receive_len; + memcpy((char *)out_buf + 4, + (char *)midQ->resp_buf + 4, + receive_len); + + dump_smb(out_buf, 92); + /* convert the length into a more usable form */ + if ((receive_len > 24) && + (ses->server->secMode & (SECMODE_SIGN_REQUIRED | + SECMODE_SIGN_ENABLED))) { + rc = cifs_verify_signature(out_buf, &ses->server->mac_signing_key, midQ->sequence_number+1); - if (rc) { - cERROR(1, ("Unexpected SMB signature")); - /* BB FIXME add code to kill session */ - } + if (rc) { + cERROR(1, ("Unexpected SMB signature")); + /* BB FIXME add code to kill session */ } + } - *pbytes_returned = out_buf->smb_buf_length; + *pbytes_returned = out_buf->smb_buf_length; - /* BB special case reconnect tid and uid here? */ - rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); + /* BB special case reconnect tid and uid here? */ + rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); - /* convert ByteCount if necessary */ - if (receive_len >= sizeof(struct smb_hdr) - 4 - /* do not count RFC1001 header */ + - (2 * out_buf->WordCount) + 2 /* bcc */ ) - BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); - } else { - rc = -EIO; - cERROR(1, ("Bad MID state?")); - } + /* convert ByteCount if necessary */ + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + + (2 * out_buf->WordCount) + 2 /* bcc */ ) + BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); + } else { + rc = -EIO; + cERROR(1, ("Bad MID state?")); } out: From 17c8bfed8abbbed82937a751abfc40d2866e3196 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 6 Dec 2008 16:38:19 +0100 Subject: [PATCH 27/31] Streamline SendReceiveBlockingLock: Use "goto out:" in an error condition Streamline SendReceiveBlockingLock: Use "goto out:" in an error condition Signed-off-by: Volker Lendecke Signed-off-by: Steve French --- fs/cifs/transport.c | 70 ++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index ca015e60002ada..0fe2527ce459e9 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -1062,44 +1062,48 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, cERROR(1, ("Frame too large received. Length: %d Xid: %d", receive_len, xid)); rc = -EIO; - } else { /* rcvd frame is ok */ - - if (midQ->resp_buf && out_buf - && (midQ->midState == MID_RESPONSE_RECEIVED)) { - out_buf->smb_buf_length = receive_len; - memcpy((char *)out_buf + 4, - (char *)midQ->resp_buf + 4, - receive_len); - - dump_smb(out_buf, 92); - /* convert the length into a more usable form */ - if ((receive_len > 24) && - (ses->server->secMode & (SECMODE_SIGN_REQUIRED | - SECMODE_SIGN_ENABLED))) { - rc = cifs_verify_signature(out_buf, - &ses->server->mac_signing_key, - midQ->sequence_number+1); - if (rc) { - cERROR(1, ("Unexpected SMB signature")); - /* BB FIXME add code to kill session */ - } - } + goto out; + } - *pbytes_returned = out_buf->smb_buf_length; + /* rcvd frame is ok */ - /* BB special case reconnect tid and uid here? */ - rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); + if (midQ->resp_buf && out_buf + && (midQ->midState == MID_RESPONSE_RECEIVED)) { + out_buf->smb_buf_length = receive_len; + memcpy((char *)out_buf + 4, + (char *)midQ->resp_buf + 4, + receive_len); - /* convert ByteCount if necessary */ - if (receive_len >= sizeof(struct smb_hdr) - 4 - /* do not count RFC1001 header */ + - (2 * out_buf->WordCount) + 2 /* bcc */ ) - BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); - } else { - rc = -EIO; - cERROR(1, ("Bad MID state?")); + dump_smb(out_buf, 92); + /* convert the length into a more usable form */ + if ((receive_len > 24) && + (ses->server->secMode & (SECMODE_SIGN_REQUIRED | + SECMODE_SIGN_ENABLED))) { + rc = cifs_verify_signature(out_buf, + &ses->server->mac_signing_key, + midQ->sequence_number+1); + if (rc) { + cERROR(1, ("Unexpected SMB signature")); + /* BB FIXME add code to kill session */ + } } + + *pbytes_returned = out_buf->smb_buf_length; + + /* BB special case reconnect tid and uid here? */ + rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); + + /* convert ByteCount if necessary */ + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + + (2 * out_buf->WordCount) + 2 /* bcc */ ) + BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); + } else { + rc = -EIO; + cERROR(1, ("Bad MID state?")); } + +out: DeleteMidQEntry(midQ); if (rstart && rc == -EACCES) return -ERESTARTSYS; From 698e96a826939bb24063f6a61801c174e19c32b1 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 6 Dec 2008 16:39:31 +0100 Subject: [PATCH 28/31] Streamline SendReceiveBlockingLock: Use "goto out:" in an error condition Streamline SendReceiveBlockingLock: Use "goto out:" in an error condition Signed-off-by: Volker Lendecke Signed-off-by: Steve French --- fs/cifs/transport.c | 61 +++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0fe2527ce459e9..7e10b13d130b6e 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -1067,41 +1067,42 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, /* rcvd frame is ok */ - if (midQ->resp_buf && out_buf - && (midQ->midState == MID_RESPONSE_RECEIVED)) { - out_buf->smb_buf_length = receive_len; - memcpy((char *)out_buf + 4, - (char *)midQ->resp_buf + 4, - receive_len); + if ((midQ->resp_buf == NULL) || (out_buf == NULL) + || (midQ->midState != MID_RESPONSE_RECEIVED)) { + rc = -EIO; + cERROR(1, ("Bad MID state?")); + goto out; + } - dump_smb(out_buf, 92); - /* convert the length into a more usable form */ - if ((receive_len > 24) && - (ses->server->secMode & (SECMODE_SIGN_REQUIRED | - SECMODE_SIGN_ENABLED))) { - rc = cifs_verify_signature(out_buf, - &ses->server->mac_signing_key, - midQ->sequence_number+1); - if (rc) { - cERROR(1, ("Unexpected SMB signature")); - /* BB FIXME add code to kill session */ - } + out_buf->smb_buf_length = receive_len; + memcpy((char *)out_buf + 4, + (char *)midQ->resp_buf + 4, + receive_len); + + dump_smb(out_buf, 92); + /* convert the length into a more usable form */ + if ((receive_len > 24) && + (ses->server->secMode & (SECMODE_SIGN_REQUIRED | + SECMODE_SIGN_ENABLED))) { + rc = cifs_verify_signature(out_buf, + &ses->server->mac_signing_key, + midQ->sequence_number+1); + if (rc) { + cERROR(1, ("Unexpected SMB signature")); + /* BB FIXME add code to kill session */ } + } - *pbytes_returned = out_buf->smb_buf_length; + *pbytes_returned = out_buf->smb_buf_length; - /* BB special case reconnect tid and uid here? */ - rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); + /* BB special case reconnect tid and uid here? */ + rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); - /* convert ByteCount if necessary */ - if (receive_len >= sizeof(struct smb_hdr) - 4 - /* do not count RFC1001 header */ + - (2 * out_buf->WordCount) + 2 /* bcc */ ) - BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); - } else { - rc = -EIO; - cERROR(1, ("Bad MID state?")); - } + /* convert ByteCount if necessary */ + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + + (2 * out_buf->WordCount) + 2 /* bcc */ ) + BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); out: DeleteMidQEntry(midQ); From ac6a3ef405f314c206906463ca9913a826a577ee Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 6 Dec 2008 16:40:40 +0100 Subject: [PATCH 29/31] Remove an already-checked error condition in SendReceiveBlockingLock Remove an already-checked error condition in SendReceiveBlockingLock Signed-off-by: Volker Lendecke Signed-off-by: Steve French --- fs/cifs/transport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 7e10b13d130b6e..7ebe6599ed3a07 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -1067,8 +1067,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, /* rcvd frame is ok */ - if ((midQ->resp_buf == NULL) || (out_buf == NULL) - || (midQ->midState != MID_RESPONSE_RECEIVED)) { + if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) { rc = -EIO; cERROR(1, ("Bad MID state?")); goto out; From c6fbba0546d3ead18d4a623e76e28bcbaa66a325 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 18 Dec 2008 01:41:20 +0000 Subject: [PATCH 30/31] [CIFS] make sure that DFS pathnames are properly formed The paths in a DFS request are supposed to only have a single preceding backslash, but we are sending them with a double backslash. This is exposing a bug in Windows where it also sends a path in the response that has a double backslash. The existing code that builds the mount option string however expects a double backslash prefix in a couple of places when it tries to use the path returned by build_path_from_dentry. Fix compose_mount_options to expect properly formed DFS paths (single backslash at front). Also clean up error handling in that function. There was a possible NULL pointer dereference and situations where a partially built option string would be returned. Tested against Samba 3.0.28-ish server and Samba 3.3 and Win2k8. CC: Stable Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/CHANGES | 3 ++- fs/cifs/cifs_dfs_ref.c | 48 +++++++++++++++++++++++++++++++----------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 5ab6bcce880a7a..080703a15f44cf 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -4,7 +4,8 @@ Add "forcemandatorylock" mount option to allow user to use mandatory rather than posix (advisory) byte range locks, even though server would support posix byte range locks. Fix query of root inode when prefixpath specified and user does not have access to query information about the -top of the share. +top of the share. Fix problem in 2.6.28 resolving DFS paths to +Samba servers (worked to Windows). Version 1.55 ------------ diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index e1c18362ba466c..85c0a74d034d0c 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -122,7 +122,7 @@ static char *compose_mount_options(const char *sb_mountdata, char **devname) { int rc; - char *mountdata; + char *mountdata = NULL; int md_len; char *tkn_e; char *srvIP = NULL; @@ -136,10 +136,9 @@ static char *compose_mount_options(const char *sb_mountdata, *devname = cifs_get_share_name(ref->node_name); rc = dns_resolve_server_name_to_ip(*devname, &srvIP); if (rc != 0) { - cERROR(1, ("%s: Failed to resolve server part of %s to IP", - __func__, *devname)); - mountdata = ERR_PTR(rc); - goto compose_mount_options_out; + cERROR(1, ("%s: Failed to resolve server part of %s to IP: %d", + __func__, *devname, rc));; + goto compose_mount_options_err; } /* md_len = strlen(...) + 12 for 'sep+prefixpath=' * assuming that we have 'unc=' and 'ip=' in @@ -149,8 +148,8 @@ static char *compose_mount_options(const char *sb_mountdata, strlen(ref->node_name) + 12; mountdata = kzalloc(md_len+1, GFP_KERNEL); if (mountdata == NULL) { - mountdata = ERR_PTR(-ENOMEM); - goto compose_mount_options_out; + rc = -ENOMEM; + goto compose_mount_options_err; } /* copy all options except of unc,ip,prefixpath */ @@ -197,18 +196,32 @@ static char *compose_mount_options(const char *sb_mountdata, /* find & copy prefixpath */ tkn_e = strchr(ref->node_name + 2, '\\'); - if (tkn_e == NULL) /* invalid unc, missing share name*/ - goto compose_mount_options_out; + if (tkn_e == NULL) { + /* invalid unc, missing share name*/ + rc = -EINVAL; + goto compose_mount_options_err; + } + /* + * this function gives us a path with a double backslash prefix. We + * require a single backslash for DFS. Temporarily increment fullpath + * to put it in the proper form and decrement before freeing it. + */ fullpath = build_path_from_dentry(dentry); + if (!fullpath) { + rc = -ENOMEM; + goto compose_mount_options_err; + } + ++fullpath; tkn_e = strchr(tkn_e + 1, '\\'); - if (tkn_e || strlen(fullpath) - (ref->path_consumed)) { + if (tkn_e || (strlen(fullpath) - ref->path_consumed)) { strncat(mountdata, &sep, 1); strcat(mountdata, "prefixpath="); if (tkn_e) strcat(mountdata, tkn_e + 1); - strcat(mountdata, fullpath + (ref->path_consumed)); + strcat(mountdata, fullpath + ref->path_consumed); } + --fullpath; kfree(fullpath); /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/ @@ -217,6 +230,11 @@ static char *compose_mount_options(const char *sb_mountdata, compose_mount_options_out: kfree(srvIP); return mountdata; + +compose_mount_options_err: + kfree(mountdata); + mountdata = ERR_PTR(rc); + goto compose_mount_options_out; } @@ -309,13 +327,19 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) goto out_err; } + /* + * The MSDFS spec states that paths in DFS referral requests and + * responses must be prefixed by a single '\' character instead of + * the double backslashes usually used in the UNC. This function + * gives us the latter, so we must adjust the result. + */ full_path = build_path_from_dentry(dentry); if (full_path == NULL) { rc = -ENOMEM; goto out_err; } - rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls, + rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb->local_nls, &num_referrals, &referrals, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); From 359d67d6ad054ae11ad459665fdfb883aca87782 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 22 Dec 2008 21:53:40 +0000 Subject: [PATCH 31/31] [CIFS] Remove redundant test In fs/cifs/cifssmb.c, pLockData is tested for being NULL at the beginning of the function, and not reassigned subsequently. A simplified version of the semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) Signed-off-by: Julia Lawall Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 824df142f28812..552642a507c4be 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1871,10 +1871,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, rc = -EIO; /* bad smb */ goto plk_err_exit; } - if (pLockData == NULL) { - rc = -EINVAL; - goto plk_err_exit; - } data_offset = le16_to_cpu(pSMBr->t2.DataOffset); data_count = le16_to_cpu(pSMBr->t2.DataCount); if (data_count < sizeof(struct cifs_posix_lock)) {