Commit bb40784f authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  [CIFS] Fix check after use error in ACL code
  [CIFS] Fix potential data corruption when writing out cached dirty pages
  [CIFS] Fix spurious reconnect on 2nd peek from read of SMB length
  [CIFS] remove build warning
  [CIFS] Have CIFS_SessSetup build correct SPNEGO SessionSetup request
  [CIFS] minor checkpatch cleanup
  [CIFS] have cifs_get_spnego_key get the hostname from TCP_Server_Info
  [CIFS] add hostname field to TCP_Server_Info struct
  [CIFS] clean up error handling in cifs_mount
  [CIFS] add ver= prefix to upcall format version
  [CIFS] Fix buffer overflow if server sends corrupt response to small
parents 3050d45c 2b83457b
Version 1.52 Version 1.52
------------ ------------
Fix oops on second mount to server when null auth is used. Fix oops on second mount to server when null auth is used.
Enable experimental Kerberos support. Return writebehind errors on flush
and sync so that events like out of disk space get reported properly on
cached files.
Version 1.51 Version 1.51
------------ ------------
......
...@@ -225,12 +225,9 @@ If no password is provided, mount.cifs will prompt for password entry ...@@ -225,12 +225,9 @@ If no password is provided, mount.cifs will prompt for password entry
Restrictions Restrictions
============ ============
Servers must support the NTLM SMB dialect (which is the most recent, supported
by Samba and Windows NT version 4, 2000 and XP and many other SMB/CIFS servers)
Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC
1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a 1001/1002 support for "Netbios-Over-TCP/IP." This is not likely to be a
problem as most servers support this. IPv6 support is planned for the future, problem as most servers support this.
and is almost complete.
Valid filenames differ between Windows and Linux. Windows typically restricts Valid filenames differ between Windows and Linux. Windows typically restricts
filenames which contain certain reserved characters (e.g.the character : filenames which contain certain reserved characters (e.g.the character :
...@@ -458,6 +455,8 @@ A partial list of the supported mount options follows: ...@@ -458,6 +455,8 @@ A partial list of the supported mount options follows:
byte range locks). byte range locks).
remount remount the share (often used to change from ro to rw mounts remount remount the share (often used to change from ro to rw mounts
or vice versa) or vice versa)
cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for
the file. (EXPERIMENTAL)
servern Specify the server 's netbios name (RFC1001 name) to use servern Specify the server 's netbios name (RFC1001 name) to use
when attempting to setup a session to the server. This is when attempting to setup a session to the server. This is
This is needed for mounting to some older servers (such This is needed for mounting to some older servers (such
...@@ -584,8 +583,8 @@ Experimental When set to 1 used to enable certain experimental ...@@ -584,8 +583,8 @@ Experimental When set to 1 used to enable certain experimental
performance enhancement was disabled when performance enhancement was disabled when
signing turned on in case buffer was modified signing turned on in case buffer was modified
just before it was sent, also this flag will just before it was sent, also this flag will
be used to use the new experimental sessionsetup be used to use the new experimental directory change
code). notification code).
These experimental features and tracing can be enabled by changing flags in These experimental features and tracing can be enabled by changing flags in
/proc/fs/cifs (after the cifs module has been installed or built into the /proc/fs/cifs (after the cifs module has been installed or built into the
...@@ -608,7 +607,8 @@ the start of smb requests and responses can be enabled via: ...@@ -608,7 +607,8 @@ the start of smb requests and responses can be enabled via:
Two other experimental features are under development. To test these Two other experimental features are under development. To test these
requires enabling CONFIG_CIFS_EXPERIMENTAL requires enabling CONFIG_CIFS_EXPERIMENTAL
ipv6 enablement cifsacl support needed to retrieve approximated mode bits based on
the contents on the CIFS ACL.
DNOTIFY fcntl: needed for support of directory change DNOTIFY fcntl: needed for support of directory change
notification and perhaps later for file leases) notification and perhaps later for file leases)
...@@ -625,10 +625,7 @@ that they represent all for that share, not just those for which the server ...@@ -625,10 +625,7 @@ that they represent all for that share, not just those for which the server
returned success. returned success.
Also note that "cat /proc/fs/cifs/DebugData" will display information about Also note that "cat /proc/fs/cifs/DebugData" will display information about
the active sessions and the shares that are mounted. Note: NTLMv2 enablement the active sessions and the shares that are mounted.
will not work since its implementation is not quite complete yet. Do not alter Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is enabled
the ExtendedSecurity configuration value unless you are doing specific testing. but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
Enabling extended security works to Windows 2000 Workstations and XP but not to LANMAN support do not require this helpr.
Windows 2000 server or Samba since it does not usually send "raw NTLMSSP"
(instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not
complete in the CIFS VFS yet).
...@@ -16,7 +16,7 @@ SecurityDescriptors ...@@ -16,7 +16,7 @@ SecurityDescriptors
c) Better pam/winbind integration (e.g. to handle uid mapping c) Better pam/winbind integration (e.g. to handle uid mapping
better) better)
d) Kerberos/SPNEGO session setup support - (started) d) Verify that Kerberos signing works
e) Cleanup now unneeded SessSetup code in e) Cleanup now unneeded SessSetup code in
fs/cifs/connect.c and add back in NTLMSSP code if any servers fs/cifs/connect.c and add back in NTLMSSP code if any servers
......
...@@ -66,20 +66,26 @@ struct key_type cifs_spnego_key_type = { ...@@ -66,20 +66,26 @@ struct key_type cifs_spnego_key_type = {
.describe = user_describe, .describe = user_describe,
}; };
#define MAX_VER_STR_LEN 9 /* length of longest version string e.g.
strlen(";ver=0xFF") */
#define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg
in future could have strlen(";sec=ntlmsspi") */
#define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
/* get a key struct with a SPNEGO security blob, suitable for session setup */ /* get a key struct with a SPNEGO security blob, suitable for session setup */
struct key * struct key *
cifs_get_spnego_key(struct cifsSesInfo *sesInfo, const char *hostname) cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
{ {
struct TCP_Server_Info *server = sesInfo->server; struct TCP_Server_Info *server = sesInfo->server;
char *description, *dp; char *description, *dp;
size_t desc_len; size_t desc_len;
struct key *spnego_key; struct key *spnego_key;
const char *hostname = server->hostname;
/* BB: come up with better scheme for determining length */
/* version + ;ip{4|6}= + address + ;host=hostname + /* length of fields (with semicolons): ver=0xyz ipv4= ipaddress host=
;sec= + ;uid= + NULL */ hostname sec=mechanism uid=0x uid */
desc_len = 4 + 5 + 32 + 1 + 5 + strlen(hostname) + desc_len = MAX_VER_STR_LEN + 5 + MAX_IPV6_ADDR_LEN + 1 + 6 +
strlen(";sec=krb5") + 7 + sizeof(uid_t)*2 + 1; strlen(hostname) + MAX_MECH_STR_LEN + 8 + (sizeof(uid_t) * 2);
spnego_key = ERR_PTR(-ENOMEM); spnego_key = ERR_PTR(-ENOMEM);
description = kzalloc(desc_len, GFP_KERNEL); description = kzalloc(desc_len, GFP_KERNEL);
if (description == NULL) if (description == NULL)
...@@ -88,7 +94,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo, const char *hostname) ...@@ -88,7 +94,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo, const char *hostname)
dp = description; dp = description;
/* start with version and hostname portion of UNC string */ /* start with version and hostname portion of UNC string */
spnego_key = ERR_PTR(-EINVAL); spnego_key = ERR_PTR(-EINVAL);
sprintf(dp, "0x%2.2x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION, sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
hostname); hostname);
dp = description + strlen(description); dp = description + strlen(description);
......
...@@ -41,6 +41,7 @@ struct cifs_spnego_msg { ...@@ -41,6 +41,7 @@ struct cifs_spnego_msg {
#ifdef __KERNEL__ #ifdef __KERNEL__
extern struct key_type cifs_spnego_key_type; extern struct key_type cifs_spnego_key_type;
extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo);
#endif /* KERNEL */ #endif /* KERNEL */
#endif /* _CIFS_SPNEGO_H */ #endif /* _CIFS_SPNEGO_H */
...@@ -269,6 +269,13 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, ...@@ -269,6 +269,13 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
/* BB need to add parm so we can store the SID BB */ /* BB need to add parm so we can store the SID BB */
if (!pdacl) {
/* no DACL in the security descriptor, set
all the permissions for user/group/other */
inode->i_mode |= S_IRWXUGO;
return;
}
/* validate that we do not go past end of acl */ /* validate that we do not go past end of acl */
if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
cERROR(1, ("ACL too small to parse DACL")); cERROR(1, ("ACL too small to parse DACL"));
...@@ -286,12 +293,6 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, ...@@ -286,12 +293,6 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
user/group/other have no permissions */ user/group/other have no permissions */
inode->i_mode &= ~(S_IRWXUGO); inode->i_mode &= ~(S_IRWXUGO);
if (!pdacl) {
/* no DACL in the security descriptor, set
all the permissions for user/group/other */
inode->i_mode |= S_IRWXUGO;
return;
}
acl_base = (char *)pdacl; acl_base = (char *)pdacl;
acl_size = sizeof(struct cifs_acl); acl_size = sizeof(struct cifs_acl);
......
...@@ -266,6 +266,7 @@ cifs_alloc_inode(struct super_block *sb) ...@@ -266,6 +266,7 @@ cifs_alloc_inode(struct super_block *sb)
cifs_inode->cifsAttrs = 0x20; /* default */ cifs_inode->cifsAttrs = 0x20; /* default */
atomic_set(&cifs_inode->inUse, 0); atomic_set(&cifs_inode->inUse, 0);
cifs_inode->time = 0; cifs_inode->time = 0;
cifs_inode->write_behind_rc = 0;
/* Until the file is open and we have gotten oplock /* Until the file is open and we have gotten oplock
info back from the server, can not assume caching of info back from the server, can not assume caching of
file data or metadata */ file data or metadata */
...@@ -852,7 +853,7 @@ static int cifs_oplock_thread(void *dummyarg) ...@@ -852,7 +853,7 @@ static int cifs_oplock_thread(void *dummyarg)
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode *inode; struct inode *inode;
__u16 netfid; __u16 netfid;
int rc; int rc, waitrc = 0;
set_freezable(); set_freezable();
do { do {
...@@ -884,9 +885,11 @@ static int cifs_oplock_thread(void *dummyarg) ...@@ -884,9 +885,11 @@ static int cifs_oplock_thread(void *dummyarg)
filemap_fdatawrite(inode->i_mapping); filemap_fdatawrite(inode->i_mapping);
if (CIFS_I(inode)->clientCanCacheRead if (CIFS_I(inode)->clientCanCacheRead
== 0) { == 0) {
filemap_fdatawait(inode->i_mapping); waitrc = filemap_fdatawait(inode->i_mapping);
invalidate_remote_inode(inode); invalidate_remote_inode(inode);
} }
if (rc == 0)
rc = waitrc;
} else } else
rc = 0; rc = 0;
/* mutex_unlock(&inode->i_mutex);*/ /* mutex_unlock(&inode->i_mutex);*/
......
...@@ -110,6 +110,7 @@ struct mac_key { ...@@ -110,6 +110,7 @@ struct mac_key {
unsigned int len; unsigned int len;
union { union {
char ntlm[CIFS_SESS_KEY_SIZE + 16]; char ntlm[CIFS_SESS_KEY_SIZE + 16];
char krb5[CIFS_SESS_KEY_SIZE + 16]; /* BB: length correct? */
struct { struct {
char key[16]; char key[16];
struct ntlmv2_resp resp; struct ntlmv2_resp resp;
...@@ -139,6 +140,7 @@ struct TCP_Server_Info { ...@@ -139,6 +140,7 @@ struct TCP_Server_Info {
/* 15 character server name + 0x20 16th byte indicating type = srv */ /* 15 character server name + 0x20 16th byte indicating type = srv */
char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
char *hostname; /* hostname portion of UNC string */
struct socket *ssocket; struct socket *ssocket;
union { union {
struct sockaddr_in sockAddr; struct sockaddr_in sockAddr;
...@@ -471,6 +473,17 @@ struct dir_notify_req { ...@@ -471,6 +473,17 @@ struct dir_notify_req {
#define CIFS_LARGE_BUFFER 2 #define CIFS_LARGE_BUFFER 2
#define CIFS_IOVEC 4 /* array of response buffers */ #define CIFS_IOVEC 4 /* array of response buffers */
/* Type of Request to SendReceive2 */
#define CIFS_STD_OP 0 /* normal request timeout */
#define CIFS_LONG_OP 1 /* long op (up to 45 sec, oplock time) */
#define CIFS_VLONG_OP 2 /* sloow op - can take up to 180 seconds */
#define CIFS_BLOCKING_OP 4 /* operation can block */
#define CIFS_ASYNC_OP 8 /* do not wait for response */
#define CIFS_TIMEOUT_MASK 0x00F /* only one of 5 above set in req */
#define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */
#define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */
#define CIFS_NO_RESP 0x040 /* no response buffer required */
/* Security Flags: indicate type of session setup needed */ /* Security Flags: indicate type of session setup needed */
#define CIFSSEC_MAY_SIGN 0x00001 #define CIFSSEC_MAY_SIGN 0x00001
#define CIFSSEC_MAY_NTLM 0x00002 #define CIFSSEC_MAY_NTLM 0x00002
......
...@@ -48,10 +48,11 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, ...@@ -48,10 +48,11 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
struct smb_hdr * /* input */ , struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ , struct smb_hdr * /* out */ ,
int * /* bytes returned */ , const int long_op); int * /* bytes returned */ , const int long_op);
extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
struct smb_hdr *in_buf, int flags);
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
struct kvec *, int /* nvec to send */, struct kvec *, int /* nvec to send */,
int * /* type of buf returned */ , const int long_op, int * /* type of buf returned */ , const int flags);
const int logError /* whether to log status code*/ );
extern int SendReceiveBlockingLock(const unsigned int /* xid */ , extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
struct cifsTconInfo *, struct cifsTconInfo *,
struct smb_hdr * /* input */ , struct smb_hdr * /* input */ ,
...@@ -76,8 +77,6 @@ extern void header_assemble(struct smb_hdr *, char /* command */ , ...@@ -76,8 +77,6 @@ extern void header_assemble(struct smb_hdr *, char /* command */ ,
extern int small_smb_init_no_tc(const int smb_cmd, const int wct, extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
struct cifsSesInfo *ses, struct cifsSesInfo *ses,
void **request_buf); void **request_buf);
extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo,
const char *hostname);
extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
const int stage, const int stage,
const struct nls_table *nls_cp); const struct nls_table *nls_cp);
...@@ -248,15 +247,15 @@ extern int CIFSSMBQueryReparseLinkInfo(const int xid, ...@@ -248,15 +247,15 @@ extern int CIFSSMBQueryReparseLinkInfo(const int xid,
extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int disposition, const char *fileName, const int disposition,
const int access_flags, const int omode, const int access_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *, __u16 *netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int disposition, const char *fileName, const int disposition,
const int access_flags, const int omode, const int access_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *, __u16 *netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
u32 posix_flags, __u64 mode, __u16 * netfid, u32 posix_flags, __u64 mode, __u16 *netfid,
FILE_UNIX_BASIC_INFO *pRetData, FILE_UNIX_BASIC_INFO *pRetData,
__u32 *pOplock, const char *name, __u32 *pOplock, const char *name,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
...@@ -277,7 +276,7 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, ...@@ -277,7 +276,7 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
const __u64 offset, unsigned int *nbytes, const __u64 offset, unsigned int *nbytes,
struct kvec *iov, const int nvec, const int long_op); struct kvec *iov, const int nvec, const int long_op);
extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, __u64 * inode_number, const unsigned char *searchName, __u64 *inode_number,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
...@@ -352,5 +351,5 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, ...@@ -352,5 +351,5 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
const char *local_acl, const int buflen, const int acl_type, const char *local_acl, const int buflen, const int acl_type,
const struct nls_table *nls_codepage, int remap_special_chars); const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
const int netfid, __u64 * pExtAttrBits, __u64 *pMask); const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
#endif /* _CIFSPROTO_H */ #endif /* _CIFSPROTO_H */
This diff is collapsed.
...@@ -438,9 +438,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -438,9 +438,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
csocket = server->ssocket; csocket = server->ssocket;
wake_up(&server->response_q); wake_up(&server->response_q);
continue; continue;
} else if (length < 4) { } else if (length < pdu_length) {
cFYI(1, ("less than four bytes received (%d bytes)", cFYI(1, ("requested %d bytes but only got %d bytes",
length)); pdu_length, length));
pdu_length -= length; pdu_length -= length;
msleep(1); msleep(1);
goto incomplete_rcv; goto incomplete_rcv;
...@@ -752,6 +752,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -752,6 +752,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
kfree(server->hostname);
kfree(server); kfree(server);
if (length > 0) if (length > 0)
mempool_resize(cifs_req_poolp, length + cifs_min_rcv, mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
...@@ -760,6 +761,34 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -760,6 +761,34 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
return 0; return 0;
} }
/* extract the host portion of the UNC string */
static char *
extract_hostname(const char *unc)
{
const char *src;
char *dst, *delim;
unsigned int len;
/* skip double chars at beginning of string */
/* BB: check validity of these bytes? */
src = unc + 2;
/* delimiter between hostname and sharename is always '\\' now */
delim = strchr(src, '\\');
if (!delim)
return ERR_PTR(-EINVAL);
len = delim - src;
dst = kmalloc((len + 1), GFP_KERNEL);
if (dst == NULL)
return ERR_PTR(-ENOMEM);
memcpy(dst, src, len);
dst[len] = '\0';
return dst;
}
static int static int
cifs_parse_mount_options(char *options, const char *devname, cifs_parse_mount_options(char *options, const char *devname,
struct smb_vol *vol) struct smb_vol *vol)
...@@ -1781,11 +1810,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1781,11 +1810,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
memset(&volume_info, 0, sizeof(struct smb_vol)); 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)) {
kfree(volume_info.UNC); rc = -EINVAL;
kfree(volume_info.password); goto out;
kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
} }
if (volume_info.nullauth) { if (volume_info.nullauth) {
...@@ -1798,11 +1824,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1798,11 +1824,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cifserror("No username specified"); cifserror("No username specified");
/* In userspace mount helper we can get user name from alternate /* In userspace mount helper we can get user name from alternate
locations such as env variables and files on disk */ locations such as env variables and files on disk */
kfree(volume_info.UNC); rc = -EINVAL;
kfree(volume_info.password); goto out;
kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
} }
if (volume_info.UNCip && volume_info.UNC) { if (volume_info.UNCip && volume_info.UNC) {
...@@ -1821,11 +1844,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1821,11 +1844,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (rc <= 0) { if (rc <= 0) {
/* we failed translating address */ /* we failed translating address */
kfree(volume_info.UNC); rc = -EINVAL;
kfree(volume_info.password); goto out;
kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
} }
cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
...@@ -1835,20 +1855,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1835,20 +1855,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* BB using ip addr as server name to connect to the /* BB using ip addr as server name to connect to the
DFS root below */ DFS root below */
cERROR(1, ("Connecting to DFS root not implemented yet")); cERROR(1, ("Connecting to DFS root not implemented yet"));
kfree(volume_info.UNC); rc = -EINVAL;
kfree(volume_info.password); goto out;
kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
} else /* which servers DFS root would we conect to */ { } else /* which servers DFS root would we conect to */ {
cERROR(1, cERROR(1,
("CIFS mount error: No UNC path (e.g. -o " ("CIFS mount error: No UNC path (e.g. -o "
"unc=//192.168.1.100/public) specified")); "unc=//192.168.1.100/public) specified"));
kfree(volume_info.UNC); rc = -EINVAL;
kfree(volume_info.password); goto out;
kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
} }
/* this is needed for ASCII cp to Unicode converts */ /* this is needed for ASCII cp to Unicode converts */
...@@ -1860,11 +1874,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1860,11 +1874,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (cifs_sb->local_nls == NULL) { if (cifs_sb->local_nls == NULL) {
cERROR(1, ("CIFS mount error: iocharset %s not found", cERROR(1, ("CIFS mount error: iocharset %s not found",
volume_info.iocharset)); volume_info.iocharset));
kfree(volume_info.UNC); rc = -ELIBACC;
kfree(volume_info.password); goto out;
kfree(volume_info.prepath);
FreeXid(xid);
return -ELIBACC;
} }
} }
...@@ -1878,11 +1889,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1878,11 +1889,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
&sin_server6.sin6_addr, &sin_server6.sin6_addr,
volume_info.username, &srvTcp); volume_info.username, &srvTcp);
} else { } else {
kfree(volume_info.UNC); rc = -EINVAL;
kfree(volume_info.password); goto out;
kfree(volume_info.prepath);
FreeXid(xid);
return -EINVAL;
} }
if (srvTcp) { if (srvTcp) {
...@@ -1906,22 +1914,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1906,22 +1914,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
"Aborting operation")); "Aborting operation"));
if (csocket != NULL) if (csocket != NULL)
sock_release(csocket); sock_release(csocket);
kfree(volume_info.UNC); goto out;
kfree(volume_info.password);
kfree(volume_info.prepath);
FreeXid(xid);
return rc;
} }
srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
if (!srvTcp) { if (!srvTcp) {
rc = -ENOMEM; rc = -ENOMEM;
sock_release(csocket); sock_release(csocket);
kfree(volume_info.UNC); goto out;
kfree(volume_info.password);
kfree(volume_info.prepath);
FreeXid(xid);
return rc;
} else { } else {
memcpy(&srvTcp->addr.sockAddr, &sin_server, memcpy(&srvTcp->addr.sockAddr, &sin_server,
sizeof(struct sockaddr_in)); sizeof(struct sockaddr_in));
...@@ -1929,6 +1929,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1929,6 +1929,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* BB Add code for ipv6 case too */ /* BB Add code for ipv6 case too */
srvTcp->ssocket = csocket; srvTcp->ssocket = csocket;
srvTcp->protocolType = IPV4; srvTcp->protocolType = IPV4;
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->response_q);
init_waitqueue_head(&srvTcp->request_q); init_waitqueue_head(&srvTcp->request_q);
INIT_LIST_HEAD(&srvTcp->pending_mid_q); INIT_LIST_HEAD(&srvTcp->pending_mid_q);
...@@ -1938,16 +1944,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1938,16 +1944,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
srvTcp->tcpStatus = CifsNew; srvTcp->tcpStatus = CifsNew;
init_MUTEX(&srvTcp->tcpSem); init_MUTEX(&srvTcp->tcpSem);
srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd"); srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
if ( IS_ERR(srvTcp->tsk) ) { if (IS_ERR(srvTcp->tsk)) {
rc = PTR_ERR(srvTcp->tsk); rc = PTR_ERR(srvTcp->tsk);
cERROR(1, ("error %d create cifsd thread", rc)); cERROR(1, ("error %d create cifsd thread", rc));
srvTcp->tsk = NULL; srvTcp->tsk = NULL;
sock_release(csocket); sock_release(csocket);
kfree(volume_info.UNC); kfree(srvTcp->hostname);
kfree(volume_info.password); goto out;
kfree(volume_info.prepath);
FreeXid(xid);
return rc;
} }
wait_for_completion(&cifsd_complete); wait_for_completion(&cifsd_complete);
rc = 0; rc = 0;
...@@ -1962,8 +1965,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1962,8 +1965,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (existingCifsSes) { if (existingCifsSes) {
pSesInfo = existingCifsSes; pSesInfo = existingCifsSes;
cFYI(1, ("Existing smb sess found")); cFYI(1, ("Existing smb sess found"));
kfree(volume_info.password);
/* volume_info.UNC freed at end of function */
} else if (!rc) { } else if (!rc) {
cFYI(1, ("Existing smb sess not found")); cFYI(1, ("Existing smb sess not found"));
pSesInfo = sesInfoAlloc(); pSesInfo = sesInfoAlloc();
...@@ -1977,8 +1978,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1977,8 +1978,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (!rc) { if (!rc) {
/* volume_info.password freed at unmount */ /* volume_info.password freed at unmount */
if (volume_info.password) if (volume_info.password) {
pSesInfo->password = volume_info.password; pSesInfo->password = volume_info.password;
/* set to NULL to prevent freeing on exit */
volume_info.password = NULL;
}
if (volume_info.username) if (volume_info.username)
strncpy(pSesInfo->userName, strncpy(pSesInfo->userName,
volume_info.username, volume_info.username,
...@@ -2000,8 +2004,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2000,8 +2004,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
up(&pSesInfo->sesSem); up(&pSesInfo->sesSem);
if (!rc) if (!rc)
atomic_inc(&srvTcp->socketUseCount); atomic_inc(&srvTcp->socketUseCount);
} else }
kfree(volume_info.password);
} }
/* search for existing tcon to this server share */ /* search for existing tcon to this server share */
...@@ -2106,9 +2109,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2106,9 +2109,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
"", cifs_sb->local_nls, "", cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
kfree(volume_info.UNC); rc = -ENODEV;
FreeXid(xid); goto out;
return -ENODEV;
} else { } else {
/* BB Do we need to wrap sesSem around /* BB Do we need to wrap sesSem around
* this TCon call and Unix SetFS as * this TCon call and Unix SetFS as
...@@ -2231,6 +2233,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2231,6 +2233,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
(in which case it is not needed anymore) but when new sesion is created (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 the password ptr is put in the new session structure (in which case the
password will be freed at unmount time) */ 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);
}
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.prepath); kfree(volume_info.prepath);
FreeXid(xid); FreeXid(xid);
...@@ -2374,7 +2382,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2374,7 +2382,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pSMB->req_no_secext.ByteCount = cpu_to_le16(count); pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
&bytes_returned, 1); &bytes_returned, CIFS_LONG_OP);
if (rc) { if (rc) {
/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
} else if ((smb_buffer_response->WordCount == 3) } else if ((smb_buffer_response->WordCount == 3)
...@@ -2678,7 +2686,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2678,7 +2686,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
pSMB->req.ByteCount = cpu_to_le16(count); pSMB->req.ByteCount = cpu_to_le16(count);
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
&bytes_returned, 1); &bytes_returned, CIFS_LONG_OP);
if (smb_buffer_response->Status.CifsError == if (smb_buffer_response->Status.CifsError ==
cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
...@@ -3105,7 +3113,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3105,7 +3113,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pSMB->req.ByteCount = cpu_to_le16(count); pSMB->req.ByteCount = cpu_to_le16(count);
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
&bytes_returned, 1); &bytes_returned, CIFS_LONG_OP);
if (rc) { if (rc) {
/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ /* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
} else if ((smb_buffer_response->WordCount == 3) || } else if ((smb_buffer_response->WordCount == 3) ||
...@@ -3381,7 +3389,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3381,7 +3389,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
pSMB->hdr.smb_buf_length += count; pSMB->hdr.smb_buf_length += count;
pSMB->ByteCount = cpu_to_le16(count); pSMB->ByteCount = cpu_to_le16(count);
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
CIFS_STD_OP);
/* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
/* above now done in SendReceive */ /* above now done in SendReceive */
......
...@@ -130,7 +130,9 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, ...@@ -130,7 +130,9 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
if (file->f_path.dentry->d_inode->i_mapping) { if (file->f_path.dentry->d_inode->i_mapping) {
/* BB no need to lock inode until after invalidate /* BB no need to lock inode until after invalidate
since namei code should already have it locked? */ since namei code should already have it locked? */
filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping); rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
if (rc != 0)
CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
} }
cFYI(1, ("invalidating remote inode since open detected it " cFYI(1, ("invalidating remote inode since open detected it "
"changed")); "changed"));
...@@ -425,7 +427,9 @@ static int cifs_reopen_file(struct file *file, int can_flush) ...@@ -425,7 +427,9 @@ static int cifs_reopen_file(struct file *file, int can_flush)
pCifsInode = CIFS_I(inode); pCifsInode = CIFS_I(inode);
if (pCifsInode) { if (pCifsInode) {
if (can_flush) { if (can_flush) {
filemap_write_and_wait(inode->i_mapping); rc = filemap_write_and_wait(inode->i_mapping);
if (rc != 0)
CIFS_I(inode)->write_behind_rc = rc;
/* temporarily disable caching while we /* temporarily disable caching while we
go to server to get inode info */ go to server to get inode info */
pCifsInode->clientCanCacheAll = FALSE; pCifsInode->clientCanCacheAll = FALSE;
...@@ -835,9 +839,9 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -835,9 +839,9 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
xid = GetXid(); xid = GetXid();
if (*poffset > file->f_path.dentry->d_inode->i_size) if (*poffset > file->f_path.dentry->d_inode->i_size)
long_op = 2; /* writes past end of file can take a long time */ long_op = CIFS_VLONG_OP; /* writes past EOF take long time */
else else
long_op = 1; long_op = CIFS_LONG_OP;
for (total_written = 0; write_size > total_written; for (total_written = 0; write_size > total_written;
total_written += bytes_written) { total_written += bytes_written) {
...@@ -884,7 +888,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -884,7 +888,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
} }
} else } else
*poffset += bytes_written; *poffset += bytes_written;
long_op = FALSE; /* subsequent writes fast - long_op = CIFS_STD_OP; /* subsequent writes fast -
15 seconds is plenty */ 15 seconds is plenty */
} }
...@@ -934,9 +938,9 @@ static ssize_t cifs_write(struct file *file, const char *write_data, ...@@ -934,9 +938,9 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
xid = GetXid(); xid = GetXid();
if (*poffset > file->f_path.dentry->d_inode->i_size) if (*poffset > file->f_path.dentry->d_inode->i_size)
long_op = 2; /* writes past end of file can take a long time */ long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */
else else
long_op = 1; long_op = CIFS_LONG_OP;
for (total_written = 0; write_size > total_written; for (total_written = 0; write_size > total_written;
total_written += bytes_written) { total_written += bytes_written) {
...@@ -1002,7 +1006,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, ...@@ -1002,7 +1006,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
} }
} else } else
*poffset += bytes_written; *poffset += bytes_written;
long_op = FALSE; /* subsequent writes fast - long_op = CIFS_STD_OP; /* subsequent writes fast -
15 seconds is plenty */ 15 seconds is plenty */
} }
...@@ -1360,13 +1364,16 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -1360,13 +1364,16 @@ static int cifs_writepages(struct address_space *mapping,
open_file->netfid, open_file->netfid,
bytes_to_write, offset, bytes_to_write, offset,
&bytes_written, iov, n_iov, &bytes_written, iov, n_iov,
1); CIFS_LONG_OP);
atomic_dec(&open_file->wrtPending); atomic_dec(&open_file->wrtPending);
if (rc || bytes_written < bytes_to_write) { if (rc || bytes_written < bytes_to_write) {
cERROR(1, ("Write2 ret %d, wrote %d", cERROR(1, ("Write2 ret %d, wrote %d",
rc, bytes_written)); rc, bytes_written));
/* BB what if continued retry is /* BB what if continued retry is
requested via mount flags? */ requested via mount flags? */
if (rc == -ENOSPC)
set_bit(AS_ENOSPC, &mapping->flags);
else
set_bit(AS_EIO, &mapping->flags); set_bit(AS_EIO, &mapping->flags);
} else { } else {
cifs_stats_bytes_written(cifs_sb->tcon, cifs_stats_bytes_written(cifs_sb->tcon,
...@@ -1499,9 +1506,11 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) ...@@ -1499,9 +1506,11 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
cFYI(1, ("Sync file - name: %s datasync: 0x%x", cFYI(1, ("Sync file - name: %s datasync: 0x%x",
dentry->d_name.name, datasync)); dentry->d_name.name, datasync));
rc = filemap_fdatawrite(inode->i_mapping); rc = filemap_write_and_wait(inode->i_mapping);
if (rc == 0) if (rc == 0) {
rc = CIFS_I(inode)->write_behind_rc;
CIFS_I(inode)->write_behind_rc = 0; CIFS_I(inode)->write_behind_rc = 0;
}
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
...@@ -1553,8 +1562,11 @@ int cifs_flush(struct file *file, fl_owner_t id) ...@@ -1553,8 +1562,11 @@ int cifs_flush(struct file *file, fl_owner_t id)
filemapfdatawrite appears easier for the time being */ filemapfdatawrite appears easier for the time being */
rc = filemap_fdatawrite(inode->i_mapping); rc = filemap_fdatawrite(inode->i_mapping);
if (!rc) /* reset wb rc if we were able to write out dirty pages */ /* reset wb rc if we were able to write out dirty pages */
if (!rc) {
rc = CIFS_I(inode)->write_behind_rc;
CIFS_I(inode)->write_behind_rc = 0; CIFS_I(inode)->write_behind_rc = 0;
}
cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc)); cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
......
...@@ -1233,7 +1233,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, ...@@ -1233,7 +1233,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
int cifs_revalidate(struct dentry *direntry) int cifs_revalidate(struct dentry *direntry)
{ {
int xid; int xid;
int rc = 0; int rc = 0, wbrc = 0;
char *full_path; char *full_path;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsInodeInfo *cifsInode; struct cifsInodeInfo *cifsInode;
...@@ -1333,7 +1333,9 @@ int cifs_revalidate(struct dentry *direntry) ...@@ -1333,7 +1333,9 @@ int cifs_revalidate(struct dentry *direntry)
if (direntry->d_inode->i_mapping) { if (direntry->d_inode->i_mapping) {
/* do we need to lock inode until after invalidate completes /* do we need to lock inode until after invalidate completes
below? */ below? */
filemap_fdatawrite(direntry->d_inode->i_mapping); wbrc = filemap_fdatawrite(direntry->d_inode->i_mapping);
if (wbrc)
CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
} }
if (invalidate_inode) { if (invalidate_inode) {
/* shrink_dcache not necessary now that cifs dentry ops /* shrink_dcache not necessary now that cifs dentry ops
...@@ -1342,7 +1344,9 @@ int cifs_revalidate(struct dentry *direntry) ...@@ -1342,7 +1344,9 @@ int cifs_revalidate(struct dentry *direntry)
shrink_dcache_parent(direntry); */ shrink_dcache_parent(direntry); */
if (S_ISREG(direntry->d_inode->i_mode)) { if (S_ISREG(direntry->d_inode->i_mode)) {
if (direntry->d_inode->i_mapping) if (direntry->d_inode->i_mapping)
filemap_fdatawait(direntry->d_inode->i_mapping); wbrc = filemap_fdatawait(direntry->d_inode->i_mapping);
if (wbrc)
CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
/* may eventually have to do this for open files too */ /* may eventually have to do this for open files too */
if (list_empty(&(cifsInode->openFileList))) { if (list_empty(&(cifsInode->openFileList))) {
/* changed on server - flush read ahead pages */ /* changed on server - flush read ahead pages */
...@@ -1485,10 +1489,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1485,10 +1489,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
/* BB check if we need to refresh inode from server now ? BB */ /* BB check if we need to refresh inode from server now ? BB */
/* need to flush data before changing file size on server */
filemap_write_and_wait(direntry->d_inode->i_mapping);
if (attrs->ia_valid & ATTR_SIZE) { if (attrs->ia_valid & ATTR_SIZE) {
/*
Flush data before changing file size on server. If the
flush returns error, store it to report later and continue.
BB: This should be smarter. Why bother flushing pages that
will be truncated anyway? Also, should we error out here if
the flush returns error?
*/
rc = filemap_write_and_wait(direntry->d_inode->i_mapping);
if (rc != 0) {
CIFS_I(direntry->d_inode)->write_behind_rc = rc;
rc = 0;
}
/* To avoid spurious oplock breaks from server, in the case of /* To avoid spurious oplock breaks from server, in the case of
inodes that we already have open, avoid doing path based inodes that we already have open, avoid doing path based
setting of file size if we can do it by handle. setting of file size if we can do it by handle.
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "ntlmssp.h" #include "ntlmssp.h"
#include "nterr.h" #include "nterr.h"
#include <linux/utsname.h> #include <linux/utsname.h>
#include "cifs_spnego.h"
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24); unsigned char *p24);
...@@ -340,11 +341,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -340,11 +341,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
SESSION_SETUP_ANDX *pSMB; SESSION_SETUP_ANDX *pSMB;
__u32 capabilities; __u32 capabilities;
int count; int count;
int resp_buf_type = 0; int resp_buf_type;
struct kvec iov[2]; struct kvec iov[3];
enum securityEnum type; enum securityEnum type;
__u16 action; __u16 action;
int bytes_remaining; int bytes_remaining;
struct key *spnego_key = NULL;
if (ses == NULL) if (ses == NULL)
return -EINVAL; return -EINVAL;
...@@ -377,24 +379,32 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -377,24 +379,32 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
capabilities = cifs_ssetup_hdr(ses, pSMB); capabilities = cifs_ssetup_hdr(ses, pSMB);
/* we will send the SMB in two pieces, /* we will send the SMB in three pieces:
a fixed length beginning part, and a a fixed length beginning part, an optional
second part which will include the strings SPNEGO blob (which can be zero length), and a
and rest of bcc area, in order to avoid having last part which will include the strings
to do a large buffer 17K allocation */ and rest of bcc area. This allows us to avoid
a large buffer 17K allocation */
iov[0].iov_base = (char *)pSMB; iov[0].iov_base = (char *)pSMB;
iov[0].iov_len = smb_buf->smb_buf_length + 4; iov[0].iov_len = smb_buf->smb_buf_length + 4;
/* setting this here allows the code at the end of the function
to free the request buffer if there's an error */
resp_buf_type = CIFS_SMALL_BUFFER;
/* 2000 big enough to fit max user, domain, NOS name etc. */ /* 2000 big enough to fit max user, domain, NOS name etc. */
str_area = kmalloc(2000, GFP_KERNEL); str_area = kmalloc(2000, GFP_KERNEL);
if (str_area == NULL) { if (str_area == NULL) {
cifs_small_buf_release(smb_buf); rc = -ENOMEM;
return -ENOMEM; goto ssetup_exit;
} }
bcc_ptr = str_area; bcc_ptr = str_area;
ses->flags &= ~CIFS_SES_LANMAN; ses->flags &= ~CIFS_SES_LANMAN;
iov[1].iov_base = NULL;
iov[1].iov_len = 0;
if (type == LANMAN) { if (type == LANMAN) {
#ifdef CONFIG_CIFS_WEAK_PW_HASH #ifdef CONFIG_CIFS_WEAK_PW_HASH
char lnm_session_key[CIFS_SESS_KEY_SIZE]; char lnm_session_key[CIFS_SESS_KEY_SIZE];
...@@ -463,8 +473,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -463,8 +473,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
struct ntlmv2_resp */ struct ntlmv2_resp */
if (v2_sess_key == NULL) { if (v2_sess_key == NULL) {
cifs_small_buf_release(smb_buf); rc = -ENOMEM;
return -ENOMEM; goto ssetup_exit;
} }
pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
...@@ -499,22 +509,67 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -499,22 +509,67 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
} else } else
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
} else /* NTLMSSP or SPNEGO */ { } else if (type == Kerberos) {
#ifdef CONFIG_CIFS_UPCALL
struct cifs_spnego_msg *msg;
spnego_key = cifs_get_spnego_key(ses);
if (IS_ERR(spnego_key)) {
rc = PTR_ERR(spnego_key);
spnego_key = NULL;
goto ssetup_exit;
}
msg = spnego_key->payload.data;
/* bail out if key is too long */
if (msg->sesskey_len >
sizeof(ses->server->mac_signing_key.data.krb5)) {
cERROR(1, ("Kerberos signing key too long (%u bytes)",
msg->sesskey_len));
rc = -EOVERFLOW;
goto ssetup_exit;
}
ses->server->mac_signing_key.len = msg->sesskey_len;
memcpy(ses->server->mac_signing_key.data.krb5, msg->data,
msg->sesskey_len);
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
capabilities |= CAP_EXTENDED_SECURITY; capabilities |= CAP_EXTENDED_SECURITY;
pSMB->req.Capabilities = cpu_to_le32(capabilities); pSMB->req.Capabilities = cpu_to_le32(capabilities);
/* BB set password lengths */ iov[1].iov_base = msg->data + msg->sesskey_len;
iov[1].iov_len = msg->secblob_len;
pSMB->req.SecurityBlobLength = cpu_to_le16(iov[1].iov_len);
if (ses->capabilities & CAP_UNICODE) {
/* unicode strings must be word aligned */
if (iov[0].iov_len % 2) {
*bcc_ptr = 0;
bcc_ptr++;
} }
unicode_oslm_strings(&bcc_ptr, nls_cp);
unicode_domain_string(&bcc_ptr, ses, nls_cp);
} else
/* BB: is this right? */
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
#else /* ! CONFIG_CIFS_UPCALL */
cERROR(1, ("Kerberos negotiated but upcall support disabled!"));
rc = -ENOSYS;
goto ssetup_exit;
#endif /* CONFIG_CIFS_UPCALL */
} else {
cERROR(1, ("secType %d not supported!", type));
rc = -ENOSYS;
goto ssetup_exit;
}
iov[2].iov_base = str_area;
iov[2].iov_len = (long) bcc_ptr - (long) str_area;
count = (long) bcc_ptr - (long) str_area; count = iov[1].iov_len + iov[2].iov_len;
smb_buf->smb_buf_length += count; smb_buf->smb_buf_length += count;
BCC_LE(smb_buf) = cpu_to_le16(count); BCC_LE(smb_buf) = cpu_to_le16(count);
iov[1].iov_base = str_area; rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
iov[1].iov_len = count; CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR);
rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type,
0 /* not long op */, 1 /* log NT STATUS if any */ );
/* SMB request buf freed in SendReceive2 */ /* SMB request buf freed in SendReceive2 */
cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); cFYI(1, ("ssetup rc from sendrecv2 is %d", rc));
...@@ -560,6 +615,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -560,6 +615,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
ses, nls_cp); ses, nls_cp);
ssetup_exit: ssetup_exit:
if (spnego_key)
key_put(spnego_key);
kfree(str_area); kfree(str_area);
if (resp_buf_type == CIFS_SMALL_BUFFER) { if (resp_buf_type == CIFS_SMALL_BUFFER) {
cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base)); cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base));
......
...@@ -308,7 +308,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, ...@@ -308,7 +308,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
{ {
if (long_op == -1) { if (long_op == CIFS_ASYNC_OP) {
/* oplock breaks must not be held up */ /* oplock breaks must not be held up */
atomic_inc(&ses->server->inFlight); atomic_inc(&ses->server->inFlight);
} else { } else {
...@@ -337,7 +337,7 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) ...@@ -337,7 +337,7 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
as they are allowed to block on server */ as they are allowed to block on server */
/* update # of requests on the wire to server */ /* update # of requests on the wire to server */
if (long_op < 3) if (long_op != CIFS_BLOCKING_OP)
atomic_inc(&ses->server->inFlight); atomic_inc(&ses->server->inFlight);
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
break; break;
...@@ -415,17 +415,48 @@ static int wait_for_response(struct cifsSesInfo *ses, ...@@ -415,17 +415,48 @@ static int wait_for_response(struct cifsSesInfo *ses,
} }
} }
/*
*
* Send an SMB Request. No response info (other than return code)
* needs to be parsed.
*
* flags indicate the type of request buffer and how long to wait
* and whether to log NT STATUS code (error) before mapping it to POSIX error
*
*/
int
SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
struct smb_hdr *in_buf, int flags)
{
int rc;
struct kvec iov[1];
int resp_buf_type;
iov[0].iov_base = (char *)in_buf;
iov[0].iov_len = in_buf->smb_buf_length + 4;
flags |= CIFS_NO_RESP;
rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("SendRcvNoR flags %d rc %d", flags, rc));
#endif
return rc;
}
int int
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
struct kvec *iov, int n_vec, int *pRespBufType /* ret */, struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
const int long_op, const int logError) const int flags)
{ {
int rc = 0; int rc = 0;
int long_op;
unsigned int receive_len; unsigned int receive_len;
unsigned long timeout; unsigned long timeout;
struct mid_q_entry *midQ; struct mid_q_entry *midQ;
struct smb_hdr *in_buf = iov[0].iov_base; struct smb_hdr *in_buf = iov[0].iov_base;
long_op = flags & CIFS_TIMEOUT_MASK;
*pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
if ((ses == NULL) || (ses->server == NULL)) { if ((ses == NULL) || (ses->server == NULL)) {
...@@ -483,15 +514,22 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -483,15 +514,22 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
if (rc < 0) if (rc < 0)
goto out; goto out;
if (long_op == -1) if (long_op == CIFS_STD_OP)
goto out; timeout = 15 * HZ;
else if (long_op == 2) /* writes past end of file can take loong time */ else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
timeout = 180 * HZ; timeout = 180 * HZ;
else if (long_op == 1) else if (long_op == CIFS_LONG_OP)
timeout = 45 * HZ; /* should be greater than timeout = 45 * HZ; /* should be greater than
servers oplock break timeout (about 43 seconds) */ servers oplock break timeout (about 43 seconds) */
else else if (long_op == CIFS_ASYNC_OP)
timeout = 15 * HZ; goto out;
else if (long_op == CIFS_BLOCKING_OP)
timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
else {
cERROR(1, ("unknown timeout flag %d", long_op));
rc = -EIO;
goto out;
}
/* wait for 15 seconds or until woken up due to response arriving or /* wait for 15 seconds or until woken up due to response arriving or
due to last connection to this server being unmounted */ due to last connection to this server being unmounted */
...@@ -566,7 +604,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -566,7 +604,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
} }
/* BB special case reconnect tid and uid here? */ /* BB special case reconnect tid and uid here? */
rc = map_smb_to_linux_error(midQ->resp_buf, logError); rc = map_smb_to_linux_error(midQ->resp_buf,
flags & CIFS_LOG_ERROR);
/* convert ByteCount if necessary */ /* convert ByteCount if necessary */
if (receive_len >= sizeof(struct smb_hdr) - 4 if (receive_len >= sizeof(struct smb_hdr) - 4
...@@ -574,8 +613,10 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -574,8 +613,10 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
(2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
BCC(midQ->resp_buf) = BCC(midQ->resp_buf) =
le16_to_cpu(BCC_LE(midQ->resp_buf)); le16_to_cpu(BCC_LE(midQ->resp_buf));
midQ->resp_buf = NULL; /* mark it so will not be freed if ((flags & CIFS_NO_RESP) == 0)
by DeleteMidQEntry */ midQ->resp_buf = NULL; /* mark it so buf will
not be freed by
DeleteMidQEntry */
} else { } else {
rc = -EIO; rc = -EIO;
cFYI(1, ("Bad MID state?")); cFYI(1, ("Bad MID state?"));
...@@ -663,17 +704,25 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -663,17 +704,25 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
if (rc < 0) if (rc < 0)
goto out; goto out;
if (long_op == -1) if (long_op == CIFS_STD_OP)
timeout = 15 * HZ;
/* wait for 15 seconds or until woken up due to response arriving or
due to last connection to this server being unmounted */
else if (long_op == CIFS_ASYNC_OP)
goto out; goto out;
else if (long_op == 2) /* writes past end of file can take loong time */ else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
timeout = 180 * HZ; timeout = 180 * HZ;
else if (long_op == 1) else if (long_op == CIFS_LONG_OP)
timeout = 45 * HZ; /* should be greater than timeout = 45 * HZ; /* should be greater than
servers oplock break timeout (about 43 seconds) */ servers oplock break timeout (about 43 seconds) */
else else if (long_op == CIFS_BLOCKING_OP)
timeout = 15 * HZ; timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
/* wait for 15 seconds or until woken up due to response arriving or else {
due to last connection to this server being unmounted */ cERROR(1, ("unknown timeout flag %d", long_op));
rc = -EIO;
goto out;
}
if (signal_pending(current)) { if (signal_pending(current)) {
/* if signal pending do not hold up user for full smb timeout /* if signal pending do not hold up user for full smb timeout
but we still give response a chance to complete */ but we still give response a chance to complete */
...@@ -812,7 +861,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon, ...@@ -812,7 +861,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
pSMB->hdr.Mid = GetNextMid(ses->server); pSMB->hdr.Mid = GetNextMid(ses->server);
return SendReceive(xid, ses, in_buf, out_buf, return SendReceive(xid, ses, in_buf, out_buf,
&bytes_returned, 0); &bytes_returned, CIFS_STD_OP);
} }
int int
...@@ -844,7 +893,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, ...@@ -844,7 +893,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
to the same server. We may make this configurable later or to the same server. We may make this configurable later or
use ses->maxReq */ use ses->maxReq */
rc = wait_for_free_request(ses, 3); rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
if (rc) if (rc)
return rc; return rc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment