From ad009ac96509e005d9978d0ae9e9ec4d63ad2990 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:05 -0700 Subject: [PATCH] cifs: Fix multiuser packet signing to use the right sequence number and mac session key Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/connect.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 40470b9d5477..814e709ca0ca 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -182,7 +182,8 @@ cifs_reconnect(struct TCP_Server_Info *server) spin_lock(&GlobalMid_Lock); if(server->tcpStatus != CifsExiting) server->tcpStatus = CifsGood; - spin_unlock(&GlobalMid_Lock); + server->sequence_number = 0; + spin_unlock(&GlobalMid_Lock); /* atomic_set(&server->inFlight,0);*/ wake_up(&server->response_q); } @@ -1352,6 +1353,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, } else rc = 0; memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); + srvTcp->sequence_number = 0; } } @@ -2959,6 +2961,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, int rc = 0; char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; int ntlmv2_flag = FALSE; + int first_time = 0; /* what if server changes its buffer size after dropping the session? */ if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { @@ -2977,12 +2980,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, spin_unlock(&GlobalMid_Lock); } + first_time = 1; } if (!rc) { pSesInfo->capabilities = pSesInfo->server->capabilities; if(linuxExtEnabled == 0) pSesInfo->capabilities &= (~CAP_UNIX); - pSesInfo->sequence_number = 0; + /* pSesInfo->sequence_number = 0;*/ cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", pSesInfo->server->secMode, pSesInfo->server->capabilities, @@ -3015,7 +3019,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); if(v2_response) { CalcNTLMv2_response(pSesInfo,v2_response); -/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ + /* if(first_time) + cifs_calculate_ntlmv2_mac_key( + pSesInfo->server->mac_signing_key, + response, ntlm_session_key, */ kfree(v2_response); /* BB Put dummy sig in SessSetup PDU? */ } else { @@ -3028,9 +3035,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, pSesInfo->server->cryptKey, ntlm_session_key); - cifs_calculate_mac_key(pSesInfo->mac_signing_key, - ntlm_session_key, - pSesInfo->password); + if(first_time) + cifs_calculate_mac_key( + pSesInfo->server->mac_signing_key, + ntlm_session_key, + pSesInfo->password); } /* for better security the weaker lanman hash not sent in AuthSessSetup so we no longer calculate it */ @@ -3046,8 +3055,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, pSesInfo->server->cryptKey, ntlm_session_key); - cifs_calculate_mac_key(pSesInfo->mac_signing_key, - ntlm_session_key, pSesInfo->password); + if(first_time) + cifs_calculate_mac_key( + pSesInfo->server->mac_signing_key, + ntlm_session_key, pSesInfo->password); + rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info); } -- cgit v1.2.3-59-g8ed1b From 6a0b48245a135cd132e747815854e3999967f8a7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:05 -0700 Subject: [PATCH] cifs: Add new mount parm mapchars For handling seven special characters that shells use for filenames. This first parts implements conversions from Unicode. Signed-off-by: Steve French Signed-off-by: Linus Torvalds --- fs/cifs/CHANGES | 4 ++- fs/cifs/README | 11 +++++++++ fs/cifs/TODO | 19 ++++++++------- fs/cifs/cifs_fs_sb.h | 1 + fs/cifs/cifsproto.h | 2 ++ fs/cifs/connect.c | 7 ++++++ fs/cifs/misc.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/readdir.c | 15 ++++++++++-- 8 files changed, 116 insertions(+), 12 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index ce16b0ae772e..412b6d243d53 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -7,7 +7,9 @@ as new protocol extensions. Do not send Get/Set calls for POSIX ACLs unless server explicitly claims to support them in CIFS Unix extensions POSIX ACL capability bit. Fix packet signing when multiuser mounting with different users from the same client to the same server. Fix oops in -cifs_close. +cifs_close. Add mount option for remapping reserved characters in +filenames (also allow recognizing files with created by SFU which have any +of these seven reserved characters to be recognized). Version 1.31 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index 0f20edc935b5..83e054576258 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -376,6 +376,17 @@ A partial list of the supported mount options follows: attributes) to the server (default) e.g. via setfattr and getfattr utilities. nouser_xattr Do not allow getfattr/setfattr to get/set xattrs + mapchars Translate the seven reserved characters + *?<>|:\ + to the remap range (above 0xF000), which also + allows the CIFS client to recognize files created with + such characters by Windows's POSIX emulation. This can + also be useful when mounting to most versions of Samba + (which also forbids creating and opening files + whose names contain any of these seven characters). + This has no effect if the server does not support + Unicode on the wire. + nomapchars Do not translate any of these seven characters (default). The mount.cifs mount helper also accepts a few mount options before -o including: diff --git a/fs/cifs/TODO b/fs/cifs/TODO index f4e3e1f67ee4..a69227415a73 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -1,4 +1,4 @@ -version 1.22 July 30, 2004 +version 1.32 April 3, 2005 A Partial List of Missing Features ================================== @@ -14,7 +14,7 @@ b) Better pam/winbind integration (e.g. to handle uid mapping better) c) multi-user mounts - multiplexed sessionsetups over single vc -(ie tcp session) - prettying up needed, and more testing needed +(ie tcp session) - more testing needed d) Kerberos/SPNEGO session setup support - (started) @@ -67,12 +67,15 @@ q) implement support for security and trusted categories of xattrs r) Implement O_DIRECT flag on open (already supported on mount) -KNOWN BUGS (updated December 10, 2004) +KNOWN BUGS (updated April 3, 2005) ==================================== +See http://bugzilla.samba.org - search on product "CifsVFS" for +current bug list. + 1) existing symbolic links (Windows reparse points) are recognized but can not be created remotely. They are implemented for Samba and those that -support the CIFS Unix extensions but Samba has a bug currently handling -symlink text beginning with slash +support the CIFS Unix extensions, although earlier versions of Samba +overly restrict the pathnames. 2) follow_link and readdir code does not follow dfs junctions but recognizes them 3) create of new files to FAT partitions on Windows servers can @@ -98,7 +101,5 @@ there are some easy changes that can be done to parallelize sequential writes, and when signing is disabled to request larger read sizes (larger than negotiated size) and send larger write sizes to modern servers. -4) More exhaustively test the recently added NT4 support against various -NT4 service pack levels, and fix cifs_setattr for setting file times and -size to fall back to level 1 when error invalid level returned. - +4) More exhaustively test against less common servers. More testing +against Windows 9x, Windows ME servers. diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 77da902d8f32..ec00d61d5308 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -23,6 +23,7 @@ #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 */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index dd95c2bcbc25..b486ba738d95 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -212,6 +212,8 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 * inode_number, const struct nls_table *nls_codepage); +extern int cifs_convertUCSpath(char *target, const __u16 *source, int maxlen, + const struct nls_table * codepage); #endif /* CONFIG_CIFS_EXPERIMENTAL */ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 814e709ca0ca..3d036bf689d8 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -72,6 +72,7 @@ struct smb_vol { unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/ unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ unsigned direct_io:1; + unsigned remap:1; /* set to remap seven reserved chars in filenames */ unsigned int rsize; unsigned int wsize; unsigned int sockopt; @@ -771,6 +772,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) vol->noperm = 0; } else if (strnicmp(data, "noperm", 6) == 0) { vol->noperm = 1; + } else if (strnicmp(data, "mapchars", 8) == 0) { + vol->remap = 1; + } else if (strnicmp(data, "nomapchars", 10) == 0) { + vol->remap = 0; } else if (strnicmp(data, "setuids", 7) == 0) { vol->setuids = 1; } else if (strnicmp(data, "nosetuids", 9) == 0) { @@ -1421,6 +1426,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; if(volume_info.server_ino) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; + if(volume_info.remap) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; if(volume_info.no_xattr) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; if(volume_info.direct_io) { diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 7b38d3059a83..f2a026073b62 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -514,3 +514,72 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) printk( " | %s\n", debug_line); return; } + +#ifdef CONFIG_CIFS_EXPERIMENTAL +/* Windows maps these to the user defined 16 bit Unicode range since they are + reserved symbols (along with \ and /), otherwise illegal to store + in filenames in NTFS */ +#define UNI_ASTERIK cpu_to_le16('*' + 0xF000) +#define UNI_QUESTION cpu_to_le16('?' + 0xF000) +#define UNI_COLON cpu_to_le16(':' + 0xF000) +#define UNI_GRTRTHAN cpu_to_le16('>' + 0xF000) +#define UNI_LESSTHAN cpu_to_le16('<' + 0xF000) +#define UNI_PIPE cpu_to_le16('|' + 0xF000) +#define UNI_SLASH cpu_to_le16('\\' + 0xF000) + +/* Convert 16 bit Unicode pathname from wire format to string in current code + page. Conversion may involve remapping up the seven characters that are + only legal in POSIX-like OS (if they are present in the string). Path + names are little endian 16 bit Unicode on the wire */ +int +cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, + const struct nls_table * cp) +{ + int i,j,len; + wchar_t src_char; + + for(i = 0, j = 0; i < maxlen; i++) { + src_char = le16_to_cpu(source[i]); + switch (src_char) { + case 0: + goto cUCS_out; /* BB check this BB */ + case UNI_COLON: + target[j] = ':'; + break; + case UNI_ASTERIK: + target[j] = '*'; + break; + case UNI_QUESTION: + target[j] = '?'; + break; + case UNI_SLASH: + target[j] = '\\'; /* BB check this - is there risk here of converting path sep BB */ + break; + case UNI_PIPE: + target[j] = '|'; + break; + case UNI_GRTRTHAN: + target[j] = '>'; + break; + case UNI_LESSTHAN: + target[j] = '<'; + default: + len = cp->uni2char(src_char, &target[j], + NLS_MAX_CHARSET_SIZE); + if(len > 0) { + j += len; + continue; + } else { + target[j] = '?'; + } + } + j++; + /* check to make sure we do not overrun callers allocated temp buffer */ + if(j >= (2 * NAME_MAX)) + break; + } +cUCS_out: + target[j] = 0; + return j; +} +#endif /* CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 07838a5ba3a1..4a33add24d53 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -600,7 +600,14 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, if(unicode) { /* BB fixme - test with long names */ /* Note converted filename can be longer than in unicode */ - pqst->len = cifs_strfromUCS_le((char *)pqst->name,(wchar_t *)filename,len/2,nlt); +#ifdef CONFIG_CIFS_EXPERIMENTAL + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) + pqst->len = cifs_convertUCSpath((char *)pqst->name, + (__le16 *)filename, len/2, nlt); + else +#endif /* CIFS_EXPERIMENTAL */ + pqst->len = cifs_strfromUCS_le((char *)pqst->name, + (wchar_t *)filename,len/2,nlt); } else { pqst->name = filename; pqst->len = len; @@ -829,7 +836,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + smbCalcSize((struct smb_hdr *) cifsFile->srch_inf.ntwrk_buf_start); - tmp_buf = kmalloc(NAME_MAX+1,GFP_KERNEL); + /* To be safe - for UCS to UTF-8 with strings loaded + with the rare long characters alloc more to account for + such multibyte target UTF-8 characters. cifs_unicode.c, + which actually does the conversion, has the same limit */ + tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); for(i=0;(i Date: Thu, 28 Apr 2005 22:41:06 -0700 Subject: [PATCH] cifs: character mapping of special characters (part 3 of 3) Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/CHANGES | 2 +- fs/cifs/README | 4 +- fs/cifs/TODO | 3 + fs/cifs/cifsfs.c | 4 +- fs/cifs/cifsproto.h | 103 ++++++++++++++---------- fs/cifs/cifssmb.c | 226 +++++++++++++++++++++++++--------------------------- fs/cifs/connect.c | 25 +++--- fs/cifs/dir.c | 108 ++++--------------------- fs/cifs/fcntl.c | 3 +- fs/cifs/file.c | 10 ++- fs/cifs/inode.c | 106 +++++++++++++++++------- fs/cifs/link.c | 18 ++++- fs/cifs/readdir.c | 22 +---- fs/cifs/xattr.c | 35 +++++--- 14 files changed, 337 insertions(+), 332 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 412b6d243d53..de8858028d64 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -9,7 +9,7 @@ POSIX ACL capability bit. Fix packet signing when multiuser mounting with different users from the same client to the same server. Fix oops in cifs_close. Add mount option for remapping reserved characters in filenames (also allow recognizing files with created by SFU which have any -of these seven reserved characters to be recognized). +of these seven reserved characters, except backslash, to be recognized). Version 1.31 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index 83e054576258..93900fc4adaa 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -376,8 +376,8 @@ A partial list of the supported mount options follows: attributes) to the server (default) e.g. via setfattr and getfattr utilities. nouser_xattr Do not allow getfattr/setfattr to get/set xattrs - mapchars Translate the seven reserved characters - *?<>|:\ + mapchars Translate six of the seven reserved characters (not backslash) + *?<>|: to the remap range (above 0xF000), which also allows the CIFS client to recognize files created with such characters by Windows's POSIX emulation. This can diff --git a/fs/cifs/TODO b/fs/cifs/TODO index a69227415a73..1e8490ed6948 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -67,6 +67,9 @@ q) implement support for security and trusted categories of xattrs r) Implement O_DIRECT flag on open (already supported on mount) +s) Allow remapping of last remaining character (\) to +0xF000 which +(this character is valid for POSIX but not for Windows) + KNOWN BUGS (updated April 3, 2005) ==================================== See http://bugzilla.samba.org - search on product "CifsVFS" for diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ae48ef042977..3d5365b9f5ba 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -191,13 +191,13 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) #ifdef CONFIG_CIFS_EXPERIMENTAL /* BB we could add a second check for a QFS Unix capability bit */ if (pTcon->ses->capabilities & CAP_UNIX) - rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf, cifs_sb->local_nls); + rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf); /* Only need to call the old QFSInfo if failed on newer one */ if(rc) #endif /* CIFS_EXPERIMENTAL */ - rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls); + rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* int f_type; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index b486ba738d95..0010511083fc 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -57,10 +57,11 @@ extern int decode_negTokenInit(unsigned char *security_blob, int length, extern int cifs_inet_pton(int, char * source, void *dst); extern int map_smb_to_linux_error(struct smb_hdr *smb); extern void header_assemble(struct smb_hdr *, char /* command */ , - const struct cifsTconInfo *, int - /* length of fixed section (word count) in two byte units */ + const struct cifsTconInfo *, int /* specifies length + of fixed section (word count) in two byte units */ ); -extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *); +extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, + struct cifsTconInfo *); extern void DeleteOplockQEntry(struct oplock_q_entry *); extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); extern u64 cifs_UnixTimeToNT(struct timespec); @@ -88,7 +89,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, const char *searchName, const struct nls_table *nls_codepage, - __u16 *searchHandle, struct cifs_search_info * psrch_inf); + __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map); extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, __u16 searchHandle, struct cifs_search_info * psrch_inf); @@ -99,42 +100,42 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_ALL_INFO * findData, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap); extern int CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_UNIX_BASIC_INFO * pFindData, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap); extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, const unsigned char *searchName, unsigned char **targetUNCs, unsigned int *number_of_UNC_in_array, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap); extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap); extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, - const char *old_path, const struct nls_table *nls_codepage, - unsigned int *pnum_referrals, unsigned char ** preferrals); + const char *old_path, + const struct nls_table *nls_codepage, + unsigned int *pnum_referrals, + unsigned char ** preferrals, + int remap); extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, - struct kstatfs *FSData, - const struct nls_table *nls_codepage); + struct kstatfs *FSData); extern int CIFSSMBQFSAttributeInfo(const int xid, - struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage); -extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage); -extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage); + struct cifsTconInfo *tcon); +extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); +extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon); extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, - struct kstatfs *FSData, const struct nls_table *nls_codepage); + struct kstatfs *FSData); extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName, const FILE_BASIC_INFO * data, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, __u16 fid); #if 0 @@ -143,36 +144,49 @@ extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, const struct nls_table *nls_codepage); #endif /* possibly unneeded function */ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, - const char *fileName, __u64 size,int setAllocationSizeFlag, - const struct nls_table *nls_codepage); + const char *fileName, __u64 size, + int setAllocationSizeFlag, + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, - __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag); + __u64 size, __u16 fileHandle,__u32 opener_pid, + int AllocSizeFlag); extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon, char *full_path, __u64 mode, __u64 uid, - __u64 gid, dev_t dev, const struct nls_table *nls_codepage); + __u64 gid, dev_t dev, + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, const char *newName, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, - const char *name, const struct nls_table *nls_codepage); + const char *name, const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *name, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, - int netfid, char * target_name, const struct nls_table *nls_codepage); + int netfid, char * target_name, + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, @@ -192,7 +206,7 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const char *fileName, const int disposition, const int access_flags, const int omode, __u16 * netfid, int *pOplock, FILE_ALL_INFO *, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap); extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, const int smb_file_id); @@ -211,10 +225,13 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, const char __user *buf,const int long_op); extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 * inode_number, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); +#endif /* CONFIG_CIFS_EXPERIMENTAL */ extern int cifs_convertUCSpath(char *target, const __u16 *source, int maxlen, const struct nls_table * codepage); -#endif /* CONFIG_CIFS_EXPERIMENTAL */ +extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen, + const struct nls_table * cp, int mapChars); extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, const __u16 netfid, const __u64 len, @@ -243,29 +260,31 @@ extern int CIFSSMBCopy(int xid, const char *fromName, const __u16 target_tid, const char *toName, const int flags, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, + int remap_special_chars); extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, - const int notify_subdirs,const __u16 netfid,__u32 filter, - const struct nls_table *nls_codepage); + const int notify_subdirs,const __u16 netfid, + __u32 filter, const struct nls_table *nls_codepage); extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char * EAData, - size_t bufsize, const struct nls_table *nls_codepage); + size_t bufsize, const struct nls_table *nls_codepage, + int remap_special_chars); extern ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon, const unsigned char * searchName,const unsigned char * ea_name, unsigned char * ea_value, size_t buf_size, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap_special_chars); extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, const char * ea_name, const void * ea_value, const __u16 ea_value_len, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap_special_chars); extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char *acl_inf, const int buflen,const int acl_type, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap_special_chars); extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, const unsigned char *fileName, const char *local_acl, const int buflen, const int acl_type, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage, int remap_special_chars); extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, const int netfid, __u64 * pExtAttrBits, __u64 *pMask); #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 237e3bf94bfe..f7c4914c3dd9 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -538,8 +538,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) } int -CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, - const char *fileName, const struct nls_table *nls_codepage) +CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, + const struct nls_table *nls_codepage, int remap) { DELETE_FILE_REQ *pSMB = NULL; DELETE_FILE_RSP *pSMBr = NULL; @@ -555,9 +555,8 @@ DelFileRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->fileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -589,8 +588,8 @@ DelFileRetry: } int -CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, - const char *dirName, const struct nls_table *nls_codepage) +CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, + const struct nls_table *nls_codepage, int remap) { DELETE_DIRECTORY_REQ *pSMB = NULL; DELETE_DIRECTORY_RSP *pSMBr = NULL; @@ -606,9 +605,8 @@ RmDirRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -639,7 +637,7 @@ RmDirRetry: int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, - const char *name, const struct nls_table *nls_codepage) + const char *name, const struct nls_table *nls_codepage, int remap) { int rc = 0; CREATE_DIRECTORY_REQ *pSMB = NULL; @@ -655,9 +653,8 @@ MkDirRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + name_len = cifsConvertToUCS((__u16 *) pSMB->DirName, name, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -690,7 +687,7 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const char *fileName, const int openDisposition, const int access_flags, const int create_options, __u16 * netfid, int *pOplock, FILE_ALL_INFO * pfile_info, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { int rc = -EACCES; OPEN_REQ *pSMB = NULL; @@ -710,10 +707,8 @@ openRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { count = 1; /* account for one byte pad to word boundary */ name_len = - cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1), - fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) (pSMB->fileName + 1), + fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->NameLength = cpu_to_le16(name_len); @@ -1108,7 +1103,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { int rc = 0; RENAME_REQ *pSMB = NULL; @@ -1131,18 +1126,16 @@ renameRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0x04; /* pad */ /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; name_len2 = - cifs_strtoUCS((wchar_t *) & pSMB-> - OldFileName[name_len + 2], toName, PATH_MAX, - nls_codepage); + cifsConvertToUCS((__u16 *) &pSMB->OldFileName[name_len + 2], + toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ @@ -1182,7 +1175,8 @@ renameRetry: } int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, - int netfid, char * target_name, const struct nls_table * nls_codepage) + int netfid, char * target_name, + const struct nls_table * nls_codepage, int remap) { struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; @@ -1227,9 +1221,11 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, /* unicode only call */ if(target_name == NULL) { sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid); - len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage); + len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name, + dummy_string, 24, nls_codepage, remap); } else { - len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, PATH_MAX, nls_codepage); + len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name, + target_name, PATH_MAX, nls_codepage, remap); } rename_info->target_name_len = cpu_to_le32(2 * len_of_str); count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2; @@ -1263,7 +1259,7 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, int CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, const __u16 target_tid, const char *toName, const int flags, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { int rc = 0; COPY_REQ *pSMB = NULL; @@ -1285,18 +1281,16 @@ copyRetry: pSMB->Flags = cpu_to_le16(flags & COPY_TREE); if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, - fromName, - PATH_MAX /* find define for this maxpathcomponent */, - nls_codepage); + name_len = cifsConvertToUCS((__u16 *) pSMB->OldFileName, + fromName, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0x04; /* pad */ /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; - name_len2 = cifs_strtoUCS((wchar_t *) & pSMB-> - OldFileName[name_len + 2], toName, PATH_MAX, - nls_codepage); + name_len2 = cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2], + toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ @@ -1425,7 +1419,7 @@ createSymLinkRetry: int CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -1444,9 +1438,8 @@ createHardLinkRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + name_len = cifsConvertToUCS((__u16 *) pSMB->FileName, toName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -1468,9 +1461,8 @@ createHardLinkRetry: data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifs_strtoUCS((wchar_t *) data_offset, fromName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) data_offset, fromName, PATH_MAX, + nls_codepage, remap); name_len_target++; /* trailing null */ name_len_target *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -1512,7 +1504,7 @@ createHardLinkRetry: int CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon, const char *fromName, const char *toName, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { int rc = 0; NT_RENAME_REQ *pSMB = NULL; @@ -1539,17 +1531,15 @@ winCreateHardLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0; /* pad */ pSMB->OldFileName[name_len + 1] = 0x04; name_len2 = - cifs_strtoUCS((wchar_t *) & pSMB-> - OldFileName[name_len + 2], toName, PATH_MAX, - nls_codepage); + cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2], + toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ @@ -1659,6 +1649,7 @@ querySymLinkRetry: name_len = UniStrnlen((wchar_t *) ((char *) &pSMBr->hdr.Protocol +data_offset), min_t(const int, buflen,count) / 2); + /* BB FIXME investigate remapping reserved chars here */ cifs_strfromUCS_le(symlinkinfo, (wchar_t *) ((char *)&pSMBr->hdr.Protocol + data_offset), @@ -1793,7 +1784,8 @@ static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace } /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */ -static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,const int acl_type,const int size_of_data_area) +static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen, + const int acl_type,const int size_of_data_area) { int size = 0; int i; @@ -1912,7 +1904,7 @@ int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char *acl_inf, const int buflen, const int acl_type, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { /* SMB_QUERY_POSIX_ACL */ TRANSACTION2_QPI_REQ *pSMB = NULL; @@ -1932,8 +1924,8 @@ queryAclRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->FileName[name_len] = 0; @@ -1997,8 +1989,9 @@ queryAclRetry: int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, const unsigned char *fileName, - const char *local_acl, const int buflen, const int acl_type, - const struct nls_table *nls_codepage) + const char *local_acl, const int buflen, + const int acl_type, + const struct nls_table *nls_codepage, int remap) { struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; @@ -2016,8 +2009,8 @@ setAclRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2161,7 +2154,7 @@ int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_ALL_INFO * pFindData, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { /* level 263 SMB_QUERY_FILE_ALL_INFO */ TRANSACTION2_QPI_REQ *pSMB = NULL; @@ -2180,9 +2173,8 @@ QPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2243,7 +2235,7 @@ int CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_UNIX_BASIC_INFO * pFindData, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { /* SMB_QUERY_FILE_UNIX_BASIC */ TRANSACTION2_QPI_REQ *pSMB = NULL; @@ -2262,9 +2254,8 @@ UnixQPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2344,7 +2335,7 @@ findUniqueRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX + cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -2408,7 +2399,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, const char *searchName, const struct nls_table *nls_codepage, __u16 * pnetfid, - struct cifs_search_info * psrch_inf) + struct cifs_search_info * psrch_inf, int remap) { /* level 257 SMB_ */ TRANSACTION2_FFIRST_REQ *pSMB = NULL; @@ -2419,7 +2410,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, int name_len; __u16 params, byte_count; - cFYI(1, ("In FindFirst")); + cFYI(1, ("In FindFirst for %s",searchName)); findFirstRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, @@ -2429,12 +2420,20 @@ findFirstRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName,searchName, - PATH_MAX, nls_codepage); - name_len++; /* trailing null */ + cifsConvertToUCS((__u16 *) pSMB->FileName,searchName, + PATH_MAX, nls_codepage, remap); + /* We can not add the asterik earlier in case + it got remapped to 0xF03A as if it were part of the + directory name instead of a wildcard */ name_len *= 2; + pSMB->FileName[name_len] = '\\'; + pSMB->FileName[name_len+1] = 0; + pSMB->FileName[name_len+2] = '*'; + pSMB->FileName[name_len+3] = 0; + name_len += 4; /* now the trailing null */ pSMB->FileName[name_len] = 0; /* null terminate just in case */ pSMB->FileName[name_len+1] = 0; + name_len += 2; } else { /* BB add check for overrun of SMB buf BB */ name_len = strnlen(searchName, PATH_MAX); name_len++; /* trailing null */ @@ -2691,7 +2690,7 @@ int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 * inode_number, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { int rc = 0; TRANSACTION2_QPI_REQ *pSMB = NULL; @@ -2712,8 +2711,8 @@ GetInodeNumberRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, - PATH_MAX,nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + PATH_MAX,nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2787,7 +2786,7 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, const unsigned char *searchName, unsigned char **targetUNCs, unsigned int *number_of_UNC_in_array, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { /* TRANS2_GET_DFS_REFERRAL */ TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; @@ -2823,10 +2822,8 @@ getDFSRetry: if (ses->capabilities & CAP_UNICODE) { pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; name_len = - cifs_strtoUCS((wchar_t *) pSMB->RequestFileName, - searchName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->RequestFileName, + searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2954,8 +2951,7 @@ GetDFSRefExit: } int -CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, - struct kstatfs *FSData, const struct nls_table *nls_codepage) +CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) { /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -3038,8 +3034,7 @@ QFSInfoRetry: } int -CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage) +CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon) { /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -3107,8 +3102,7 @@ QFSAttributeRetry: } int -CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage) +CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon) { /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -3161,8 +3155,8 @@ QFSDeviceRetry: else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = - (FILE_SYSTEM_DEVICE_INFO - *) (((char *) &pSMBr->hdr.Protocol) + + (FILE_SYSTEM_DEVICE_INFO *) + (((char *) &pSMBr->hdr.Protocol) + data_offset); memcpy(&tcon->fsDevInfo, response_data, sizeof (FILE_SYSTEM_DEVICE_INFO)); @@ -3177,8 +3171,7 @@ QFSDeviceRetry: } int -CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage) +CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon) { /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -3249,7 +3242,7 @@ QFSUnixRetry: int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, - struct kstatfs *FSData, const struct nls_table *nls_codepage) + struct kstatfs *FSData) { /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -3341,7 +3334,8 @@ QFSPosixRetry: int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName, - __u64 size, int SetAllocation, const struct nls_table *nls_codepage) + __u64 size, int SetAllocation, + const struct nls_table *nls_codepage, int remap) { struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; @@ -3360,9 +3354,8 @@ SetEOFRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -3595,7 +3588,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName, const FILE_BASIC_INFO * data, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -3615,9 +3608,8 @@ SetTimesRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -3697,7 +3689,7 @@ SetAttrLgcyRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, + ConvertToUCS((wchar_t *) pSMB->fileName, fileName, PATH_MAX, nls_codepage); name_len++; /* trailing null */ name_len *= 2; @@ -3727,8 +3719,9 @@ SetAttrLgcyRetry: int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, - char *fileName, __u64 mode, __u64 uid, __u64 gid, - dev_t device, const struct nls_table *nls_codepage) + char *fileName, __u64 mode, __u64 uid, __u64 gid, + dev_t device, const struct nls_table *nls_codepage, + int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -3747,9 +3740,8 @@ setPermsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -3872,7 +3864,7 @@ ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char * EAData, size_t buf_size, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { /* BB assumes one setup word */ TRANSACTION2_QPI_REQ *pSMB = NULL; @@ -3893,9 +3885,8 @@ QAllEAsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -4017,7 +4008,7 @@ QAllEAsRetry: ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon, const unsigned char * searchName,const unsigned char * ea_name, unsigned char * ea_value, size_t buf_size, - const struct nls_table *nls_codepage) + const struct nls_table *nls_codepage, int remap) { TRANSACTION2_QPI_REQ *pSMB = NULL; TRANSACTION2_QPI_RSP *pSMBr = NULL; @@ -4037,9 +4028,8 @@ QEARetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -4165,7 +4155,8 @@ QEARetry: int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, const char * ea_name, const void * ea_value, - const __u16 ea_value_len, const struct nls_table *nls_codepage) + const __u16 ea_value_len, const struct nls_table *nls_codepage, + int remap) { struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; @@ -4184,9 +4175,8 @@ SetEARetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3d036bf689d8..1f22b85324cf 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -924,14 +924,15 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, - const char *old_path, const struct nls_table *nls_codepage) + const char *old_path, const struct nls_table *nls_codepage, + int remap) { unsigned char *referrals = NULL; unsigned int num_referrals; int rc = 0; rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, - &num_referrals, &referrals); + &num_referrals, &referrals, remap); /* BB Add in code to: if valid refrl, if not ip address contact the helper that resolves tcp names, mount to it, try to @@ -946,7 +947,8 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, const struct nls_table *nls_codepage, - unsigned int *pnum_referrals, unsigned char ** preferrals) + unsigned int *pnum_referrals, + unsigned char ** preferrals, int remap) { char *temp_unc; int rc = 0; @@ -971,7 +973,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, } if (rc == 0) rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, - pnum_referrals, nls_codepage); + pnum_referrals, nls_codepage, remap); return rc; } @@ -1456,11 +1458,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if ((strchr(volume_info.UNC + 3, '\\') == NULL) && (strchr(volume_info.UNC + 3, '/') == NULL)) { - rc = connect_to_dfs_path(xid, - pSesInfo, - "", - cifs_sb-> - local_nls); + rc = connect_to_dfs_path(xid, pSesInfo, + "", cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if(volume_info.UNC) kfree(volume_info.UNC); FreeXid(xid); @@ -1523,10 +1524,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, tcon->ses = pSesInfo; /* do not care if following two calls succeed - informational only */ - CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls); - CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls); + CIFSSMBQFSDeviceInfo(xid, tcon); + CIFSSMBQFSAttributeInfo(xid, tcon); if (tcon->ses->capabilities & CAP_UNIX) { - if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) { + if(!CIFSSMBQFSUnixInfo(xid, tcon)) { if(!volume_info.no_psx_acl) { if(CIFS_UNIX_POSIX_ACL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 12ba81d7b07f..e3137aa48cdd 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -101,68 +101,15 @@ cifs_bp_rename_retry: return full_path; } -/* Note: caller must free return buffer */ -char * -build_wildcard_path_from_dentry(struct dentry *direntry) +/* char * build_wildcard_path_from_dentry(struct dentry *direntry) { - struct dentry *temp; - int namelen = 0; - char *full_path; - - if(direntry == NULL) - return NULL; /* not much we can do if dentry is freed and - we need to reopen the file after it was closed implicitly - when the server crashed */ - -cifs_bwp_rename_retry: - for (temp = direntry; !IS_ROOT(temp);) { - namelen += (1 + temp->d_name.len); - temp = temp->d_parent; - if(temp == NULL) { - cERROR(1,("corrupt dentry")); - return NULL; - } - } - - full_path = kmalloc(namelen+3, GFP_KERNEL); if(full_path == NULL) return full_path; full_path[namelen] = '\\'; full_path[namelen+1] = '*'; - full_path[namelen+2] = 0; /* trailing null */ - - for (temp = direntry; !IS_ROOT(temp);) { - namelen -= 1 + temp->d_name.len; - if (namelen < 0) { - break; - } else { - full_path[namelen] = '\\'; - strncpy(full_path + namelen + 1, temp->d_name.name, - temp->d_name.len); - cFYI(0, (" name: %s ", full_path + namelen)); - } - temp = temp->d_parent; - if(temp == NULL) { - cERROR(1,("corrupt dentry")); - kfree(full_path); - return NULL; - } - } - if (namelen != 0) { - cERROR(1, - ("We did not end path lookup where we expected namelen is %d", - namelen)); - /* presumably this is only possible if we were racing with a rename - of one of the parent directories (we can not lock the dentries - above us to prevent this, but retrying should be harmless) */ - kfree(full_path); - namelen = 0; - goto cifs_bwp_rename_retry; - } - - return full_path; -} + full_path[namelen+2] = 0; +BB remove above eight lines BB */ /* Inode operations in similar order to how they appear in the Linux file fs.h */ @@ -235,7 +182,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, - &fileHandle, &oplock, buf, cifs_sb->local_nls); + &fileHandle, &oplock, buf, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { cFYI(1, ("cifs_create returned 0x%x ", rc)); } else { @@ -248,13 +196,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, (__u64)current->euid, (__u64)current->egid, 0 /* dev */, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, 0 /* dev */, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { /* BB implement via Windows security descriptors */ @@ -356,11 +308,15 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,(__u64)current->euid,(__u64)current->egid, - device_number, cifs_sb->local_nls); + device_number, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, - device_number, cifs_sb->local_nls); + device_number, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } if(!rc) { @@ -447,36 +403,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name return ERR_PTR(rc); } -int -cifs_dir_open(struct inode *inode, struct file *file) -{ /* NB: currently unused since searches are opened in readdir */ - int rc = 0; - int xid; - struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; - char *full_path = NULL; - - xid = GetXid(); - - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; - - if(file->f_dentry) { - down(&file->f_dentry->d_sb->s_vfs_rename_sem); - full_path = build_wildcard_path_from_dentry(file->f_dentry); - up(&file->f_dentry->d_sb->s_vfs_rename_sem); - } else { - FreeXid(xid); - return -EIO; - } - - cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path)); - - kfree(full_path); - FreeXid(xid); - return rc; -} - static int cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) { diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 9d24c40f1967..7d2a9202c39a 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c @@ -92,7 +92,8 @@ int cifs_dir_notify(struct file * file, unsigned long arg) cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ | SYNCHRONIZE, 0 /* create options */, - &netfid, &oplock,NULL, cifs_sb->local_nls); + &netfid, &oplock,NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); /* BB fixme - add this handle to a notify handle list */ if(rc) { cERROR(1,("Could not open directory for notify")); /* BB remove BB */ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 9c7755053099..1df26ddf68b1 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -254,7 +254,8 @@ int cifs_open(struct inode *inode, struct file *file) } rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, - cifs_sb->local_nls); + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags + & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { cFYI(1, ("cifs_open returned 0x%x ", rc)); goto out; @@ -287,7 +288,9 @@ int cifs_open(struct inode *inode, struct file *file) CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, (__u64)-1, (__u64)-1, 0 /* dev */, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { /* BB implement via Windows security descriptors eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, @@ -387,7 +390,8 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, } */ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, NULL, - cifs_sb->local_nls); + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { up(&pCifsFile->fh_sem); cFYI(1, ("cifs_open returned 0x%x ", rc)); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index d73b0aa86775..670947288262 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -44,7 +44,8 @@ int cifs_get_inode_info_unix(struct inode **pinode, cFYI(1, (" Getting info on %s ", search_path)); /* could have done a find first instead but this returns more info */ rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, - cifs_sb->local_nls); + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */ if (rc) { @@ -63,7 +64,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, strncat(tmp_path, search_path, MAX_PATHCONF); rc = connect_to_dfs_path(xid, pTcon->ses, /* treename + */ tmp_path, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); kfree(tmp_path); /* BB fix up inode etc. */ @@ -210,7 +213,8 @@ int cifs_get_inode_info(struct inode **pinode, pfindData = (FILE_ALL_INFO *)buf; /* could do find first instead but this returns more info */ rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, - cifs_sb->local_nls); + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ if (rc) { @@ -230,7 +234,9 @@ int cifs_get_inode_info(struct inode **pinode, strncat(tmp_path, search_path, MAX_PATHCONF); rc = connect_to_dfs_path(xid, pTcon->ses, /* treename + */ tmp_path, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); kfree(tmp_path); /* BB fix up inode etc. */ } else if (rc) { @@ -268,7 +274,9 @@ int cifs_get_inode_info(struct inode **pinode, rc1 = CIFSGetSrvInodeNumber(xid, pTcon, search_path, &inode_num, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if(rc1) { cFYI(1,("GetSrvInodeNum rc %d", rc1)); /* BB EOPNOSUPP disable SERVER_INUM? */ @@ -410,7 +418,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) FreeXid(xid); return -ENOMEM; } - rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls); + rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { direntry->d_inode->i_nlink--; @@ -422,10 +431,14 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, - &netfid, &oplock, NULL, cifs_sb->local_nls); + &netfid, &oplock, NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); direntry->d_inode->i_nlink--; } @@ -439,7 +452,9 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) if (!(pTcon->ses->flags & CIFS_SES_NT4)) rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); else rc = -EOPNOTSUPP; @@ -461,7 +476,9 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) FILE_OPEN, SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, 0, &netfid, &oplock, NULL, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { rc = CIFSSMBSetFileTimes(xid, pTcon, pinfo_buf, @@ -472,8 +489,10 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) kfree(pinfo_buf); } if (rc==0) { - rc = CIFSSMBDelFile(xid, pTcon, full_path, - cifs_sb->local_nls); + rc = CIFSSMBDelFile(xid, pTcon, full_path, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { direntry->d_inode->i_nlink--; } else if (rc == -ETXTBSY) { @@ -485,11 +504,15 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, &netfid, &oplock, NULL, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); direntry->d_inode->i_nlink--; } @@ -534,7 +557,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) return -ENOMEM; } /* BB add setting the equivalent of mode via CreateX w/ACLs */ - rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls); + rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); d_drop(direntry); @@ -558,12 +582,16 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) (__u64)current->euid, (__u64)current->egid, 0 /* dev_t */, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, 0 /* dev_t */, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } else { /* BB to be implemented via Windows secrty descriptors @@ -600,7 +628,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) return -ENOMEM; } - rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls); + rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { inode->i_nlink--; @@ -653,7 +682,9 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, } rc = CIFSSMBRename(xid, pTcon, fromName, toName, - cifs_sb_source->local_nls); + cifs_sb_source->local_nls, + cifs_sb_source->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc == -EEXIST) { /* check if they are the same file because rename of hardlinked files is a noop */ @@ -665,11 +696,16 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, if (info_buf_source != NULL) { info_buf_target = info_buf_source + 1; rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, - info_buf_source, cifs_sb_source->local_nls); + info_buf_source, cifs_sb_source->local_nls, + cifs_sb_source->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc == 0) { rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName, info_buf_target, - cifs_sb_target->local_nls); + cifs_sb_target->local_nls, + /* remap based on source sb */ + cifs_sb_source->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); } if ((rc == 0) && (info_buf_source->UniqueId == @@ -685,7 +721,9 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, cifs_unlink(target_inode, target_direntry); rc = CIFSSMBRename(xid, pTcon, fromName, toName, - cifs_sb_source->local_nls); + cifs_sb_source->local_nls, + cifs_sb_source->mnt_cifs_flags + & CIFS_MOUNT_MAP_SPECIAL_CHR); } kfree(info_buf_source); } /* if we can not get memory just leave rc as EEXIST */ @@ -705,10 +743,14 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, might not right be right access to request */ rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, CREATE_NOT_DIR, &netfid, &oplock, NULL, - cifs_sb_source->local_nls); + cifs_sb_source->local_nls, + cifs_sb_source->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName, - cifs_sb_source->local_nls); + cifs_sb_source->local_nls, + cifs_sb_source->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); } } @@ -962,7 +1004,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) it by handle */ rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, FALSE, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); } @@ -999,7 +1043,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, - 0 /* dev_t */, cifs_sb->local_nls); + 0 /* dev_t */, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); else if (attrs->ia_valid & ATTR_MODE) { if ((mode & S_IWUGO) == 0) /* not writeable */ { if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) @@ -1048,7 +1094,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) via Handle (SetFileInfo) instead of by path */ if (!(pTcon->ses->flags & CIFS_SES_NT4)) rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); else rc = -EOPNOTSUPP; @@ -1063,7 +1111,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, &netfid, &oplock, - NULL, cifs_sb->local_nls); + NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf, netfid); diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 1455810ba1cb..bde0fabfece0 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -59,10 +59,14 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX) rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, - cifs_sb_target->local_nls); + cifs_sb_target->local_nls, + cifs_sb_target->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); else { rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, - cifs_sb_target->local_nls); + cifs_sb_target->local_nls, + cifs_sb_target->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if(rc == -EIO) rc = -EOPNOTSUPP; } @@ -260,7 +264,10 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) cifs_sb->local_nls); else { rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, - OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls); + OPEN_REPARSE_POINT,&fid, &oplock, NULL, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if(!rc) { rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, tmpbuffer, @@ -279,7 +286,10 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); strncat(tmp_path, full_path, MAX_PATHCONF); rc = get_dfs_path(xid, pTcon->ses, tmp_path, - cifs_sb->local_nls, &num_referrals, &referrals); + cifs_sb->local_nls, + &num_referrals, &referrals, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc)); if((num_referrals == 0) && (rc == 0)) rc = -EACCES; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 4a33add24d53..7ca876b6f2ab 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -314,7 +314,7 @@ static int initiate_cifs_search(const int xid, struct file *file) return -EINVAL; down(&file->f_dentry->d_sb->s_vfs_rename_sem); - full_path = build_wildcard_path_from_dentry(file->f_dentry); + full_path = build_path_from_dentry(file->f_dentry); up(&file->f_dentry->d_sb->s_vfs_rename_sem); if(full_path == NULL) { @@ -333,8 +333,9 @@ ffirst_retry: cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; } - rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, - &cifsFile->netfid, &cifsFile->srch_inf); + rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, + &cifsFile->netfid, &cifsFile->srch_inf, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if(rc == 0) cifsFile->invalidHandle = FALSE; if((rc == -EOPNOTSUPP) && @@ -600,12 +601,10 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, if(unicode) { /* BB fixme - test with long names */ /* Note converted filename can be longer than in unicode */ -#ifdef CONFIG_CIFS_EXPERIMENTAL if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) pqst->len = cifs_convertUCSpath((char *)pqst->name, (__le16 *)filename, len/2, nlt); else -#endif /* CIFS_EXPERIMENTAL */ pqst->len = cifs_strfromUCS_le((char *)pqst->name, (wchar_t *)filename,len/2,nlt); } else { @@ -849,19 +848,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) break; } - /* BB FIXME - need to enable the below code BB */ - - /* if((!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) || - (cifsFile->srch_inf.info_level != - something that supports server inodes)) { - create dentry - create inode - fill in inode new_inode (getting local i_ino) - } - also create local inode for performance reasons (so we - have a cache of inode metadata) unless this new mount - parm says otherwise */ - rc = cifs_filldir(current_entry, file, filldir, direntry,tmp_buf); file->f_pos++; diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 9a41bee11c5a..c1e02eff1d25 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -83,7 +83,8 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name) ea_name+=5; /* skip past user. prefix */ rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,NULL, - (__u16)0, cifs_sb->local_nls); + (__u16)0, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } remove_ea_exit: if (full_path) @@ -147,14 +148,16 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, } ea_name += 5; /* skip past user. prefix */ rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, - (__u16)value_size, cifs_sb->local_nls); + (__u16)value_size, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) goto set_ea_exit; ea_name += 4; /* skip past os2. prefix */ rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, - (__u16)value_size, cifs_sb->local_nls); + (__u16)value_size, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else { int temp; temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS, @@ -164,7 +167,9 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, if(sb->s_flags & MS_POSIXACL) rc = CIFSSMBSetPosixACL(xid, pTcon,full_path, ea_value, (const int)value_size, - ACL_TYPE_ACCESS,cifs_sb->local_nls); + ACL_TYPE_ACCESS,cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); cFYI(1,("set POSIX ACL rc %d",rc)); #else cFYI(1,("set POSIX ACL not supported")); @@ -174,7 +179,9 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, if(sb->s_flags & MS_POSIXACL) rc = CIFSSMBSetPosixACL(xid, pTcon,full_path, ea_value, (const int)value_size, - ACL_TYPE_DEFAULT, cifs_sb->local_nls); + ACL_TYPE_DEFAULT, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); cFYI(1,("set POSIX default ACL rc %d",rc)); #else cFYI(1,("set default POSIX ACL not supported")); @@ -240,20 +247,24 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, } /* BB add else when above is implemented */ ea_name += 5; /* skip past user. prefix */ rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, - buf_size, cifs_sb->local_nls); + buf_size, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) goto get_ea_exit; ea_name += 4; /* skip past os2. prefix */ rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, - buf_size, cifs_sb->local_nls); + buf_size, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { #ifdef CONFIG_CIFS_POSIX if(sb->s_flags & MS_POSIXACL) rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, ea_value, buf_size, ACL_TYPE_ACCESS, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); #else cFYI(1,("query POSIX ACL not supported yet")); #endif /* CONFIG_CIFS_POSIX */ @@ -262,7 +273,9 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, if(sb->s_flags & MS_POSIXACL) rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, ea_value, buf_size, ACL_TYPE_DEFAULT, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); #else cFYI(1,("query POSIX default ACL not supported yet")); #endif @@ -328,7 +341,9 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) search server for EAs or streams to returns as xattrs */ rc = CIFSSMBQAllEAs(xid,pTcon,full_path,data,buf_size, - cifs_sb->local_nls); + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); if (full_path) kfree(full_path); -- cgit v1.2.3-59-g8ed1b From 848f3fce45d2ba93e10b5e9d65bcae0d9269ad0d Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:07 -0700 Subject: [PATCH] cifs: Do not interpret oplock break responses as responses to an unrelated command .. even if the multiplex ids match. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/CHANGES | 2 ++ fs/cifs/cifs_debug.c | 7 ++++++- fs/cifs/cifsglob.h | 2 +- fs/cifs/connect.c | 10 +++++++--- fs/cifs/transport.c | 1 - 5 files changed, 16 insertions(+), 6 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index de8858028d64..de63a0e3f4ce 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -10,6 +10,8 @@ different users from the same client to the same server. Fix oops in cifs_close. Add mount option for remapping reserved characters in filenames (also allow recognizing files with created by SFU which have any of these seven reserved characters, except backslash, to be recognized). +Fix invalid transact2 message (we were sometimes trying to interpret +oplock breaks as SMB responses). Version 1.31 ------------ diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index e7bd93e6226d..efa099165b22 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -111,7 +111,12 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, mid_q_entry, qhead); if(mid_entry) { - length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk,mid_entry->mid); + length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n", + mid_entry->midState, + (int)mid_entry->command, + mid_entry->pid, + mid_entry->tsk, + mid_entry->mid); buf += length; } } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 1b3082d79379..fe1409799513 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -313,12 +313,12 @@ struct mid_q_entry { __u16 mid; /* multiplex id */ __u16 pid; /* process id */ __u32 sequence_number; /* for CIFS signing */ - __u16 command; /* smb command code */ struct timeval when_sent; /* time when smb sent */ 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 */ + __u8 command; /* smb command code */ }; struct oplock_q_entry { diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 1f22b85324cf..383e55fa7d26 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -361,9 +361,13 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) mid_q_entry, qhead); - if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) { - cFYI(1, - (" Mid 0x%x matched - waking up ",mid_entry->mid)); + if ((mid_entry->mid == smb_buffer->Mid) + && (mid_entry->midState == + MID_REQUEST_SUBMITTED) + && (mid_entry->command == + smb_buffer->Command)) { + cFYI(1,("Found Mid 0x%x wake up" + ,mid_entry->mid)); task_to_wake = mid_entry->tsk; mid_entry->resp_buf = smb_buffer; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index a9e4f989b7f7..aab62ed46982 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -189,7 +189,6 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, struct msghdr smb_msg; number_of_pages += 1; /* account for SMB header */ struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec)); - if(i=0;i Date: Thu, 28 Apr 2005 22:41:07 -0700 Subject: [PATCH] cifs: Do not use large smb buffers in response path unless response is larger than 256 bytes. This cuts more than 1/3 of the large memory allocations that cifs does and should be a huge help to memory pressure under stress. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/cifs_debug.c | 11 +++++--- fs/cifs/connect.c | 80 ++++++++++++++++++++++++++++++++++------------------ fs/cifs/transport.c | 7 +++-- 3 files changed, 65 insertions(+), 33 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index efa099165b22..bff2ec6e054a 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -1,7 +1,7 @@ /* * fs/cifs_debug.c * - * Copyright (C) International Business Machines Corp., 2000,2003 + * Copyright (C) International Business Machines Corp., 2000,2005 * * Modified by Steve French (sfrench@us.ibm.com) * @@ -92,8 +92,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, length = sprintf(buf, "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", - i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), - ses->serverOS, ses->serverNOS, ses->capabilities,ses->status); + i, ses->serverName, ses->serverDomain, + atomic_read(&ses->inUse), + ses->serverOS, ses->serverNOS, + ses->capabilities,ses->status); buf += length; if(ses->server) { buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", @@ -207,7 +209,8 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, buf += item_length; item_length = sprintf(buf,"SMB Request/Response Buffer: %d Pool size: %d\n", - bufAllocCount.counter,cifs_min_rcv + tcpSesAllocCount.counter); + bufAllocCount.counter, + cifs_min_rcv + tcpSesAllocCount.counter); length += item_length; buf += item_length; item_length = diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 383e55fa7d26..390f22fa3439 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1,7 +1,7 @@ /* * fs/cifs/connect.c * - * Copyright (C) International Business Machines Corp., 2002,2004 + * Copyright (C) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include "cifspdu.h" @@ -198,6 +199,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) int length; unsigned int pdu_length, total_read; struct smb_hdr *smb_buffer = NULL; + struct smb_hdr *bigbuf = NULL; + struct smb_hdr *smallbuf = NULL; struct msghdr smb_msg; struct kvec iov; struct socket *csocket = server->ssocket; @@ -206,6 +209,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) struct task_struct *task_to_wake = NULL; struct mid_q_entry *mid_entry; char *temp; + int isLargeBuf = FALSE; daemonize("cifsd"); allow_signal(SIGKILL); @@ -223,17 +227,33 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } while (server->tcpStatus != CifsExiting) { - if (smb_buffer == NULL) - smb_buffer = cifs_buf_get(); - else - memset(smb_buffer, 0, sizeof (struct smb_hdr)); - - if (smb_buffer == NULL) { - cERROR(1,("Can not get memory for SMB response")); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ * 3); /* give system time to free memory */ - continue; + if (bigbuf == NULL) { + bigbuf = cifs_buf_get(); + if(bigbuf == NULL) { + cERROR(1,("No memory for large SMB response")); + msleep(3000); + /* retry will check if exiting */ + continue; + } + } else if(isLargeBuf) { + /* we are reusing a dirtry large buf, clear its start */ + memset(bigbuf, 0, sizeof (struct smb_hdr)); } + + if (smallbuf == NULL) { + smallbuf = cifs_small_buf_get(); + if(smallbuf == NULL) { + cERROR(1,("No memory for SMB response")); + msleep(1000); + /* retry will check if exiting */ + continue; + } + /* beginning of smb buffer is cleared in our buf_get */ + } else /* if existing small buf clear beginning */ + memset(smallbuf, 0, sizeof (struct smb_hdr)); + + isLargeBuf = FALSE; + smb_buffer = smallbuf; iov.iov_base = smb_buffer; iov.iov_len = 4; smb_msg.msg_control = NULL; @@ -251,8 +271,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) csocket = server->ssocket; continue; } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); /* minimum sleep to prevent looping + msleep(1); /* minimum sleep to prevent looping allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung */ continue; @@ -295,8 +314,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } else { /* give server a second to clean up before reconnect attempt */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + msleep(1000); /* always try 445 first on reconnect since we get NACK on some if we ever connected to port 139 (the NACK is @@ -325,6 +343,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) wake_up(&server->response_q); continue; } else { /* length ok */ + if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { + isLargeBuf = TRUE; + memcpy(bigbuf, smallbuf, 4); + smb_buffer = bigbuf; + } length = 0; iov.iov_base = 4 + (char *)smb_buffer; iov.iov_len = pdu_length; @@ -377,6 +400,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } spin_unlock(&GlobalMid_Lock); if (task_to_wake) { + if(isLargeBuf) + bigbuf = NULL; + else + smallbuf = NULL; smb_buffer = NULL; /* will be freed by users thread after he is done */ wake_up_process(task_to_wake); } else if (is_valid_oplock_break(smb_buffer) == FALSE) { @@ -406,15 +433,17 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) and get out of SendReceive. */ wake_up_all(&server->request_q); /* give those requests time to exit */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/8); - + msleep(125); + if(server->ssocket) { sock_release(csocket); server->ssocket = NULL; } - if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ - cifs_buf_release(smb_buffer); + /* buffer usuallly freed in free_mid - need to free it here on exit */ + if (bigbuf != NULL) + cifs_buf_release(bigbuf); + if (smallbuf != NULL) + cifs_small_buf_release(smallbuf); read_lock(&GlobalSMBSeslock); if (list_empty(&server->pending_mid_q)) { @@ -444,17 +473,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } spin_unlock(&GlobalMid_Lock); read_unlock(&GlobalSMBSeslock); - set_current_state(TASK_INTERRUPTIBLE); /* 1/8th of sec is more than enough time for them to exit */ - schedule_timeout(HZ/8); + msleep(125); } if (list_empty(&server->pending_mid_q)) { /* mpx threads have not exited yet give them at least the smb send timeout time for long ops */ cFYI(1, ("Wait for exit from demultiplex thread")); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(46 * HZ); + msleep(46); /* if threads still have not exited they are probably never coming home not much else we can do but free the memory */ } @@ -469,9 +496,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) length + cifs_min_rcv, GFP_KERNEL); } - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); + + msleep(250); return 0; } diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index aab62ed46982..f9e16b39898c 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -1,7 +1,7 @@ /* * fs/cifs/transport.c * - * Copyright (C) International Business Machines Corp., 2002,2004 + * Copyright (C) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -79,7 +79,10 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) list_del(&midEntry->qhead); atomic_dec(&midCount); spin_unlock(&GlobalMid_Lock); - cifs_buf_release(midEntry->resp_buf); + if(midEntry->largeBuf) + cifs_buf_release(midEntry->resp_buf); + else + cifs_small_buf_release(midEntry->resp_buf); mempool_free(midEntry, cifs_mid_poolp); } -- cgit v1.2.3-59-g8ed1b From 099a58f681ed951434574ec39bdfe87055bafe73 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:07 -0700 Subject: [PATCH] cifs: Missing initialization for largeBuf flag left out of previous changeset Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/CHANGES | 6 +++++- fs/cifs/README | 19 ++++++++++++++++++- fs/cifs/connect.c | 4 ++++ 3 files changed, 27 insertions(+), 2 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index de63a0e3f4ce..be3a57509e60 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -11,7 +11,11 @@ cifs_close. Add mount option for remapping reserved characters in filenames (also allow recognizing files with created by SFU which have any of these seven reserved characters, except backslash, to be recognized). Fix invalid transact2 message (we were sometimes trying to interpret -oplock breaks as SMB responses). +oplock breaks as SMB responses). Add ioctl for checking that the +current uid matches the uid of the mounter (needed by umount.cifs). +Reduce the number of large buffer allocations in cifs response processing +(significantly reduces memory pressure under heavy stress with multiple +processes accessing the same server at the same time). Version 1.31 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index 93900fc4adaa..48c37a6e9c3f 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -75,7 +75,7 @@ Allowing User Mounts ==================== To permit users to mount and unmount over directories they own is possible with the cifs vfs. A way to enable such mounting is to mark the mount.cifs -utility as suid (e.g. "chmod +s /sbin/mount/cifs). To enable users to +utility as suid (e.g. "chmod +s /sbin/mount.cifs). To enable users to umount shares they mount requires 1) mount.cifs version 1.4 or later 2) an entry for the share in /etc/fstab indicating that a user may @@ -97,6 +97,23 @@ mount.cifs with the following flag: There is a corresponding manual page for cifs mounting in the Samba 3.0 and later source tree in docs/manpages/mount.cifs.8 +Allowing User Unmounts +====================== +To permit users to ummount directories that they have user mounted (see above), +the utility umount.cifs may be used. It may be invoked directly, or if +umount.cifs is placed in /sbin, umount -i can invoke the cifs umount helper +(at least for most versions of the umount utility) for umount of cifs +mounts. As with mount.cifs, to enable user unmounts umount.cifs must be marked +as suid (e.g. "chmod +s /sbin/umount.cifs"). For this utility to succeed +the target path must be a cifs mount, and the uid of the current user must +match the uid of the user who mounted the resource. + +Also note that the customary way of allowing user mounts and unmounts is +(instead of using mount.cifs and unmount.cifs as suid) to add a line +to the file /etc/fstab for each //server/share you wish to mount, but +this can become unwieldy when potential mount targets include many +or unpredictable UNC names. + Samba Considerations ==================== To get the maximum benefit from the CIFS VFS, we recommend using a server that diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 390f22fa3439..c999583d11b0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -396,6 +396,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) smb_buffer; mid_entry->midState = MID_RESPONSE_RECEIVED; + if(isLargeBuf) + mid_entry->largeBuf = 1; + else + mid_entry->largeBuf = 0; } } spin_unlock(&GlobalMid_Lock); -- cgit v1.2.3-59-g8ed1b From 433dc24f24b409fb130f638aa85470a0eb666206 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:08 -0700 Subject: [PATCH] cifs: remove cifs_kcalloc and check for NULL return on kcalloc in session initialization Suggested by: Adrian Bunk and Dave Miller Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/cifs_debug.c | 15 +++++-- fs/cifs/connect.c | 124 ++++++++++++++++++++++++++++----------------------- 2 files changed, 80 insertions(+), 59 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index bff2ec6e054a..4061e43471c1 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -89,14 +89,21 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, list_for_each(tmp, &GlobalSMBSessionList) { i++; ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - length = - sprintf(buf, - "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", + if((ses->serverDomain == NULL) || (ses->serverOS == NULL) || + (ses->serverNOS == NULL)) { + buf += sprintf("\nentry for %s not fully displayed\n\t", + ses->serverName); + + } else { + length = + sprintf(buf, + "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), ses->serverOS, ses->serverNOS, ses->capabilities,ses->status); - buf += length; + buf += length; + } if(ses->server) { buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", ses->server->tcpStatus, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c999583d11b0..8a8aa785e7b7 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -505,16 +505,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) return 0; } -static void * -cifs_kcalloc(size_t size, unsigned int __nocast type) -{ - void *addr; - addr = kmalloc(size, type); - if (addr) - memset(addr, 0, size); - return addr; -} - static int cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) { @@ -632,7 +622,11 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) /* go from value to value + temp_len condensing double commas to singles. Note that this ends up allocating a few bytes too many, which is ok */ - vol->password = cifs_kcalloc(temp_len, GFP_KERNEL); + vol->password = kcalloc(1, temp_len, GFP_KERNEL); + if(vol->password == NULL) { + printk("CIFS: no memory for pass\n"); + return 1; + } for(i=0,j=0;ipassword[j] = value[i]; if(value[i] == separator[0] && value[i+1] == separator[0]) { @@ -642,7 +636,11 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) } vol->password[j] = 0; } else { - vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL); + vol->password = kcalloc(1, temp_len + 1, GFP_KERNEL); + if(vol->password == NULL) { + printk("CIFS: no memory for pass\n"); + return 1; + } strcpy(vol->password, value); } } else if (strnicmp(data, "ip", 2) == 0) { @@ -1104,7 +1102,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, sessinit is sent but no second negprot */ struct rfc1002_session_packet * ses_init_buf; struct smb_hdr * smb_buf; - ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); + ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL); if(ses_init_buf) { ses_init_buf->trailer.session_req.called_len = 32; rfc1002mangle(ses_init_buf->trailer.session_req.called_name, @@ -1751,7 +1749,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ - ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL); + if(ses->serverOS == NULL) + goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverOS, (wchar_t *)bcc_ptr, len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1761,7 +1761,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (remaining_words > 0) { len = UniStrnlen((wchar_t *)bcc_ptr, remaining_words-1); - ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL); + ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL); + if(ses->serverNOS == NULL) + goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverNOS, (wchar_t *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1774,10 +1776,12 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, } remaining_words -= len + 1; if (remaining_words > 0) { - len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); + len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = - cifs_kcalloc(2*(len+1),GFP_KERNEL); + kcalloc(1, 2*(len+1),GFP_KERNEL); + if(ses->serverDomain == NULL) + goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverDomain, (wchar_t *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1785,21 +1789,25 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ses->serverDomain[1+(2*len)] = 0; } /* else no more room so create dummy domain string */ else - ses->serverDomain = - cifs_kcalloc(2, - GFP_KERNEL); + ses->serverDomain = + kcalloc(1, 2, GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ + /* if these kcallocs fail not much we + can do, but better to not fail the + sesssetup itself */ ses->serverDomain = - cifs_kcalloc(2, GFP_KERNEL); + kcalloc(1, 2, GFP_KERNEL); ses->serverNOS = - cifs_kcalloc(2, GFP_KERNEL); + kcalloc(1, 2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); + ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL); + if(ses->serverOS == NULL) + goto sesssetup_nomem; strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; @@ -1807,14 +1815,18 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); + ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL); + if(ses->serverNOS == NULL) + goto sesssetup_nomem; strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL); + ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL); + if(ses->serverDomain == NULL) + goto sesssetup_nomem; strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -1834,7 +1846,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, smb_buffer_response->WordCount)); rc = -EIO; } - +sesssetup_nomem: /* do not return an error on nomem for the info strings, + since that could make reconnection harder, and + reconnection might be needed to free memory */ if (smb_buffer) cifs_buf_release(smb_buffer); @@ -2011,7 +2025,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -2025,7 +2039,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, remaining_words - 1); ses->serverNOS = - cifs_kcalloc(2 * (len + 1), + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverNOS, (wchar_t *)bcc_ptr, @@ -2038,7 +2052,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ - ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL); + ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverDomain, (wchar_t *)bcc_ptr, len, @@ -2049,10 +2063,10 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, } /* else no more room so create dummy domain string */ else ses->serverDomain = - cifs_kcalloc(2,GFP_KERNEL); + kcalloc(1, 2,GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ - ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); - ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); + ses->serverDomain = kcalloc(1, 2, GFP_KERNEL); + ses->serverNOS = kcalloc(1, 2, GFP_KERNEL); } } else { /* ASCII */ @@ -2060,7 +2074,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL); + ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL); strncpy(ses->serverOS, bcc_ptr, len); bcc_ptr += len; @@ -2068,14 +2082,14 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); + ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL); + ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -2325,7 +2339,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -2340,7 +2354,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, remaining_words - 1); ses->serverNOS = - cifs_kcalloc(2 * (len + 1), + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, @@ -2357,7 +2371,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = - cifs_kcalloc(2 * + kcalloc(1, 2 * (len + 1), GFP_KERNEL); @@ -2383,13 +2397,13 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, } /* else no more room so create dummy domain string */ else ses->serverDomain = - cifs_kcalloc(2, + kcalloc(1, 2, GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ ses->serverDomain = - cifs_kcalloc(2, GFP_KERNEL); + kcalloc(1, 2, GFP_KERNEL); ses->serverNOS = - cifs_kcalloc(2, GFP_KERNEL); + kcalloc(1, 2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); @@ -2397,7 +2411,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { ses->serverOS = - cifs_kcalloc(len + 1, + kcalloc(1, len + 1, GFP_KERNEL); strncpy(ses->serverOS, bcc_ptr, len); @@ -2408,7 +2422,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, len = strnlen(bcc_ptr, 1024); ses->serverNOS = - cifs_kcalloc(len + 1, + kcalloc(1, len + 1, GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; @@ -2417,7 +2431,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, len = strnlen(bcc_ptr, 1024); ses->serverDomain = - cifs_kcalloc(len + 1, + kcalloc(1, len + 1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; @@ -2719,7 +2733,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -2734,7 +2748,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, remaining_words - 1); ses->serverNOS = - cifs_kcalloc(2 * (len + 1), + kcalloc(1, 2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, @@ -2750,7 +2764,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string not always null terminated (e.g. for Windows XP & 2000) */ ses->serverDomain = - cifs_kcalloc(2 * + kcalloc(1, 2 * (len + 1), GFP_KERNEL); @@ -2775,17 +2789,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, = 0; } /* else no more room so create dummy domain string */ else - ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL); + ses->serverDomain = kcalloc(1, 2,GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ - ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); - ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); + ses->serverDomain = kcalloc(1, 2, GFP_KERNEL); + ses->serverNOS = kcalloc(1, 2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); + ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; @@ -2793,14 +2807,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL); + ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL); + ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -2912,7 +2926,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, if(tcon->nativeFileSystem) kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = - cifs_kcalloc(length + 2, GFP_KERNEL); + kcalloc(1, length + 2, GFP_KERNEL); cifs_strfromUCS_le(tcon->nativeFileSystem, (wchar_t *) bcc_ptr, length, nls_codepage); @@ -2930,7 +2944,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, if(tcon->nativeFileSystem) kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = - cifs_kcalloc(length + 1, GFP_KERNEL); + kcalloc(1, length + 1, GFP_KERNEL); strncpy(tcon->nativeFileSystem, bcc_ptr, length); } -- cgit v1.2.3-59-g8ed1b From 09d1db5c6131232f764046160c29118cd4e5e646 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:08 -0700 Subject: [PATCH] cifs: improve check for search entry going beyond end of SMB transact Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/README | 8 ++--- fs/cifs/cifssmb.c | 89 +++++++++++++++++++++++++++++++------------------------ fs/cifs/connect.c | 62 ++++++++++++++++++++++++-------------- fs/cifs/readdir.c | 11 +++++-- 4 files changed, 102 insertions(+), 68 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/README b/fs/cifs/README index 48c37a6e9c3f..bec7b3fc8a72 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -420,7 +420,7 @@ Misc /proc/fs/cifs Flags and Debug Info ======================================= Informational pseudo-files: DebugData Displays information about active CIFS sessions - and shares. + and shares, as well as the cifs.ko version. Stats Lists summary resource usage information as well as per share statistics, if CONFIG_CIFS_STATS in enabled in the kernel configuration. @@ -477,7 +477,7 @@ and for more extensive tracing including the start of smb requests and responses Two other experimental features are under development and to test require enabling CONFIG_CIFS_EXPERIMENTAL - More efficient write operations and SMB buffer handling + More efficient write operations DNOTIFY fcntl: needed for support of directory change notification and perhaps later for file leases) @@ -495,8 +495,8 @@ returned success. Also note that "cat /proc/fs/cifs/DebugData" will display information about the active sessions and the shares that are mounted. Note: NTLMv2 enablement -will not work since they its implementation is not quite complete yet. -Do not alter these configuration values unless you are doing specific testing. +will not work since its implementation is not quite complete yet. Do not alter +the ExtendedSecurity configuration value unless you are doing specific testing. Enabling extended security works to Windows 2000 Workstations and XP but not to 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 diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b102ddb977ca..834297f7b5e1 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -75,7 +75,8 @@ static void mark_open_files_invalid(struct cifsTconInfo * pTcon) } } write_unlock(&GlobalSMBSeslock); - /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */ + /* BB Add call to invalidate_inodes(sb) for all superblocks mounted + to this tcon */ } /* If the return code is zero, this function must fill in request_buf pointer */ @@ -92,8 +93,8 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, if((tcon->ses) && (tcon->ses->server)){ struct nls_table *nls_codepage; /* Give Demultiplex thread up to 10 seconds to - reconnect, should be greater than cifs socket - timeout which is 7 seconds */ + reconnect, should be greater than cifs socket + timeout which is 7 seconds */ while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { wait_event_interruptible_timeout(tcon->ses->server->response_q, (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); @@ -103,8 +104,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, (tcon->ses->status == CifsExiting)) { cFYI(1,("gave up waiting on reconnect in smb_init")); return -EHOSTDOWN; - } /* else "hard" mount - keep retrying until - process is killed or server comes back up */ + } /* else "hard" mount - keep retrying + until process is killed or server + comes back on-line */ } else /* TCP session is reestablished now */ break; @@ -115,23 +117,24 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, simultaneously reconnect the same SMB session */ down(&tcon->ses->sesSem); if(tcon->ses->status == CifsNeedReconnect) - rc = cifs_setup_session(0, tcon->ses, nls_codepage); + rc = cifs_setup_session(0, tcon->ses, + nls_codepage); if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { mark_open_files_invalid(tcon); - rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, - nls_codepage); + rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon + , nls_codepage); up(&tcon->ses->sesSem); if(rc == 0) atomic_inc(&tconInfoReconnectCount); cFYI(1, ("reconnect tcon rc = %d", rc)); /* Removed call to reopen open files here - - it is safer (and faster) to reopen files - one at a time as needed in read and write */ + it is safer (and faster) to reopen files + one at a time as needed in read and write */ /* Check if handle based operation so we - know whether we can continue or not without - returning to caller to reset file handle */ + know whether we can continue or not without + returning to caller to reset file handle */ switch(smb_command) { case SMB_COM_READ_ANDX: case SMB_COM_WRITE_ANDX: @@ -184,20 +187,22 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, if(tcon) { if((tcon->ses) && (tcon->ses->server)){ struct nls_table *nls_codepage; - /* Give Demultiplex thread up to 10 seconds to - reconnect, should be greater than cifs socket - timeout which is 7 seconds */ + /* Give Demultiplex thread up to 10 seconds to + reconnect, should be greater than cifs socket + timeout which is 7 seconds */ while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { wait_event_interruptible_timeout(tcon->ses->server->response_q, (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); - if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + if(tcon->ses->server->tcpStatus == + CifsNeedReconnect) { /* on "soft" mounts we wait once */ if((tcon->retry == FALSE) || (tcon->ses->status == CifsExiting)) { cFYI(1,("gave up waiting on reconnect in smb_init")); return -EHOSTDOWN; - } /* else "hard" mount - keep retrying until - process is killed or server comes back up */ + } /* else "hard" mount - keep retrying + until process is killed or server + comes on-line */ } else /* TCP session is reestablished now */ break; @@ -208,23 +213,24 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, simultaneously reconnect the same SMB session */ down(&tcon->ses->sesSem); if(tcon->ses->status == CifsNeedReconnect) - rc = cifs_setup_session(0, tcon->ses, nls_codepage); + rc = cifs_setup_session(0, tcon->ses, + nls_codepage); if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { mark_open_files_invalid(tcon); - rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, - nls_codepage); + rc = CIFSTCon(0, tcon->ses, tcon->treeName, + tcon, nls_codepage); up(&tcon->ses->sesSem); if(rc == 0) atomic_inc(&tconInfoReconnectCount); cFYI(1, ("reconnect tcon rc = %d", rc)); /* Removed call to reopen open files here - - it is safer (and faster) to reopen files - one at a time as needed in read and write */ + it is safer (and faster) to reopen files + one at a time as needed in read and write */ /* Check if handle based operation so we - know whether we can continue or not without - returning to caller to reset file handle */ + know whether we can continue or not without + returning to caller to reset file handle */ switch(smb_command) { case SMB_COM_READ_ANDX: case SMB_COM_WRITE_ANDX: @@ -286,7 +292,8 @@ static int validate_t2(struct smb_t2_rsp * pSMB) if(total_size < 512) { total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount); /* BCC le converted in SendReceive */ - pBCC = (pSMB->hdr.WordCount * 2) + sizeof(struct smb_hdr) + + pBCC = (pSMB->hdr.WordCount * 2) + + sizeof(struct smb_hdr) + (char *)pSMB; if((total_size <= (*(u16 *)pBCC)) && (total_size < @@ -337,8 +344,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc == 0) { server->secMode = pSMBr->SecurityMode; - server->secType = NTLM; /* BB override default for NTLMv2 or krb*/ - /* one byte - no need to convert this or EncryptionKeyLen from le,*/ + server->secType = NTLM; /* BB override default for + NTLMv2 or kerberos v5 */ + /* one byte - no need to convert this or EncryptionKeyLen + from little endian */ server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); /* probably no need to store and check maxvcs */ server->maxBuf = @@ -374,7 +383,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) pSMBr->u.extended_response. GUID, 16) != 0) { cFYI(1, - ("UID of server does not match previous connection to same ip address")); + ("UID of server does not match previous connection to same ip address")); memcpy(server-> server_GUID, pSMBr->u. @@ -454,7 +463,8 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) up(&tcon->tconSem); return -EIO; } - rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **)&smb_buffer); + rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, + (void **)&smb_buffer); if (rc) { up(&tcon->tconSem); return rc; @@ -559,7 +569,7 @@ DelFileRetry: PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; - } else { /* BB improve the check for buffer overruns BB */ + } else { /* BB improve check for buffer overruns BB */ name_len = strnlen(fileName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->fileName, fileName, name_len); @@ -609,7 +619,7 @@ RmDirRetry: PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; - } else { /* BB improve the check for buffer overruns BB */ + } else { /* BB improve check for buffer overruns BB */ name_len = strnlen(dirName, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->DirName, dirName, name_len); @@ -657,7 +667,7 @@ MkDirRetry: PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; - } else { /* BB improve the check for buffer overruns BB */ + } else { /* BB improve check for buffer overruns BB */ name_len = strnlen(name, PATH_MAX); name_len++; /* trailing null */ strncpy(pSMB->DirName, name, name_len); @@ -712,7 +722,7 @@ openRetry: name_len++; /* trailing null */ name_len *= 2; pSMB->NameLength = cpu_to_le16(name_len); - } else { /* BB improve the check for buffer overruns BB */ + } else { /* BB improve check for buffer overruns BB */ count = 0; /* no pad */ name_len = strnlen(fileName, PATH_MAX); name_len++; /* trailing null */ @@ -741,7 +751,8 @@ openRetry: pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); pSMB->CreateDisposition = cpu_to_le32(openDisposition); pSMB->CreateOptions = cpu_to_le32(create_options); - pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/ + /* BB Expirement with various impersonation levels and verify */ + pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); pSMB->SecurityFlags = SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY; @@ -755,7 +766,7 @@ openRetry: if (rc) { cFYI(1, ("Error in Open = %d", rc)); } else { - *pOplock = pSMBr->OplockLevel; /* one byte no need to le_to_cpu */ + *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */ *netfid = pSMBr->Fid; /* cifs fid stays in le */ /* Let caller know file was created so we can set the mode. */ /* Do we care about the CreateAction in any other cases? */ @@ -2504,7 +2515,9 @@ findFirstRetry: psrch_inf->srch_entries_start = (char *) &pSMBr->hdr.Protocol + le16_to_cpu(pSMBr->t2.DataOffset); - +/* if(le16_to_cpu(pSMBr->t2.DataCount) != le16_to_cpu(pSMBr->t2.TotalDataCount)) { + cERROR(1,("DC: %d TDC: %d",pSMBr->t2.DataCount,pSMBr->t2.TotalDataCount)); +} */ /* BB removeme BB */ parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol + le16_to_cpu(pSMBr->t2.ParameterOffset)); @@ -2516,7 +2529,7 @@ findFirstRetry: psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); psrch_inf->index_of_last_entry = psrch_inf->entries_in_buffer; -/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */ +/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */ /* BB removeme BB */ *pnetfid = parms->SearchHandle; } else { cifs_buf_release(pSMB); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8a8aa785e7b7..d5d49b584db4 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -157,9 +157,10 @@ cifs_reconnect(struct TCP_Server_Info *server) qhead); if(mid_entry) { if(mid_entry->midState == MID_REQUEST_SUBMITTED) { - /* Mark other intransit requests as needing retry so - we do not immediately mark the session bad again - (ie after we reconnect below) as they timeout too */ + /* Mark other intransit requests as needing + retry so we do not immediately mark the + session bad again (ie after we reconnect + below) as they timeout too */ mid_entry->midState = MID_RETRY_NEEDED; } } @@ -278,9 +279,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } else if (length <= 0) { if(server->tcpStatus == CifsNew) { cFYI(1,("tcp session abended prematurely (after SMBnegprot)")); - /* some servers kill tcp session rather than returning - smb negprot error in which case reconnecting here is - not going to help - return error to mount */ + /* some servers kill the TCP session rather than + returning an SMB negprot error, in which + case reconnecting here is not going to help, + and so simply return error to mount */ break; } if(length == -EINTR) { @@ -296,15 +298,19 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) pdu_length = ntohl(smb_buffer->smb_buf_length); /* Only read pdu_length after below checks for too short (due to e.g. int overflow) and too long ie beyond end of buf */ - cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); + cFYI(1,("rfc1002 length(big endian)0x%x)", + pdu_length+4)); temp = (char *) smb_buffer; if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { cFYI(0,("Received 4 byte keep alive packet")); - } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) { + } else if (temp[0] == + (char) RFC1002_POSITIVE_SESSION_RESPONSE) { cFYI(1,("Good RFC 1002 session rsp")); - } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { - /* we get this from Windows 98 instead of error on SMB negprot response */ + } else if (temp[0] == + (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { + /* we get this from Windows 98 instead of + an error on SMB negprot response */ cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); if(server->tcpStatus == CifsNew) { /* if nack on negprot (rather than @@ -320,7 +326,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) connected to port 139 (the NACK is since we do not begin with RFC1001 session initialize frame) */ - server->addr.sockAddr.sin_port = htons(CIFS_PORT); + server->addr.sockAddr.sin_port = + htons(CIFS_PORT); cifs_reconnect(server); csocket = server->ssocket; wake_up(&server->response_q); @@ -333,8 +340,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) csocket = server->ssocket; continue; } else { - if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) - || (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { + if((pdu_length > CIFSMaxBufSize + + MAX_CIFS_HDR_SIZE - 4) || + (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { cERROR(1, ("Invalid size SMB length %d and pdu_length %d", length, pdu_length+4)); @@ -377,6 +385,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) continue; } + /* BB FIXME - add checkTrans2SMBSecondary() */ + task_to_wake = NULL; spin_lock(&GlobalMid_Lock); list_for_each(tmp, &server->pending_mid_q) { @@ -408,7 +418,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) bigbuf = NULL; else smallbuf = NULL; - smb_buffer = NULL; /* will be freed by users thread after he is done */ + smb_buffer = NULL; /* will be freed by users thread after he is done */ wake_up_process(task_to_wake); } else if (is_valid_oplock_break(smb_buffer) == FALSE) { cERROR(1, ("No task to wake, unknown frame rcvd!")); @@ -432,7 +442,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) spin_unlock(&GlobalMid_Lock); /* Although there should not be any requests blocked on this queue it can not hurt to be paranoid and try to wake up requests - that may haven been blocked when more than 50 at time were on the wire + that may haven been blocked when more than 50 at time were on the wire to the same server - they now will see the session is in exit state and get out of SendReceive. */ wake_up_all(&server->request_q); @@ -451,7 +461,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) read_lock(&GlobalSMBSeslock); if (list_empty(&server->pending_mid_q)) { - /* loop through server session structures attached to this and mark them dead */ + /* loop through server session structures attached to this and + mark them dead */ list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, @@ -468,7 +479,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) mid_entry = list_entry(tmp, struct mid_q_entry, qhead); if (mid_entry->midState == MID_REQUEST_SUBMITTED) { cFYI(1, - (" Clearing Mid 0x%x - waking up ",mid_entry->mid)); + ("Clearing Mid 0x%x - waking up ",mid_entry->mid)); task_to_wake = mid_entry->tsk; if(task_to_wake) { wake_up_process(task_to_wake); @@ -521,7 +532,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) /* does not have to be a perfect mapping since the field is informational, only used for servers that do not support port 445 and it can be overridden at mount time */ - vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]); + vol->source_rfc1001_name[i] = + toupper(system_utsname.nodename[i]); } vol->source_rfc1001_name[15] = 0; @@ -596,14 +608,17 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) /* NB: password legally can have multiple commas and the only illegal character in a password is null */ - if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) { + if ((value[temp_len] == 0) && + (value[temp_len+1] == separator[0])) { /* reinsert comma */ value[temp_len] = separator[0]; temp_len+=2; /* move after the second comma */ while(value[temp_len] != 0) { if (value[temp_len] == separator[0]) { - if (value[temp_len+1] == separator[0]) { - temp_len++; /* skip second comma */ + if (value[temp_len+1] == + separator[0]) { + /* skip second comma */ + temp_len++; } else { /* single comma indicating start of next parm */ @@ -629,14 +644,15 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) } for(i=0,j=0;ipassword[j] = value[i]; - if(value[i] == separator[0] && value[i+1] == separator[0]) { + if(value[i] == separator[0] + && value[i+1] == separator[0]) { /* skip second comma */ i++; } } vol->password[j] = 0; } else { - vol->password = kcalloc(1, temp_len + 1, GFP_KERNEL); + vol->password = kcalloc(1, temp_len+1, GFP_KERNEL); if(vol->password == NULL) { printk("CIFS: no memory for pass\n"); return 1; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 39170cffcad8..22557716f9af 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -409,10 +409,15 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb) cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); /* validate that new_entry is not past end of SMB */ if(new_entry >= end_of_smb) { - cFYI(1,("search entry %p began after end of SMB %p old entry %p", - new_entry,end_of_smb,old_entry)); + cERROR(1, + ("search entry %p began after end of SMB %p old entry %p", + new_entry, end_of_smb, old_entry)); return NULL; - } else + } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) { + cERROR(1,("search entry %p extends after end of SMB %p", + new_entry, end_of_smb)); + return NULL; + } else return new_entry; } -- cgit v1.2.3-59-g8ed1b From 67010fbc6ff889aaf86592bc148d705c5b9e1a27 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:09 -0700 Subject: [PATCH] cifs: Better handle errors on second socket recv message call Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/cifsglob.h | 3 ++- fs/cifs/connect.c | 31 +++++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 322a12450ad3..8fc0801f8457 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifsglob.h * - * Copyright (C) International Business Machines Corp., 2002,2003 + * Copyright (C) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -321,6 +321,7 @@ struct mid_q_entry { __u8 command; /* smb command code */ unsigned multiPart:1; /* multiple responses to one SMB request */ unsigned largeBuf:1; /* if valid response, is pointer to large buf */ + unsigned multiResp:1 /* multiple trans2 responses for one request */ }; struct oplock_q_entry { diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d5d49b584db4..8c5d310514ea 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -359,20 +359,36 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) length = 0; iov.iov_base = 4 + (char *)smb_buffer; iov.iov_len = pdu_length; - for (total_read = 0; + for (total_read = 0; total_read < pdu_length; total_read += length) { - length = kernel_recvmsg(csocket, &smb_msg, + length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length - total_read, 0); - if (length == 0) { + if((server->tcpStatus == CifsExiting) || + (length == -EINTR)) { + /* then will exit */ + goto dmx_loop_end; + } else if (server->tcpStatus == + CifsNeedReconnect) { + cifs_reconnect(server); + csocket = server->ssocket; + /* Reconnect wakes up rspns q */ + /* Now we will reread sock */ + goto dmx_loop_end; + } else if ((length == -ERESTARTSYS) || + (length == -EAGAIN)) { + msleep(1); /* minimum sleep to prevent looping + allowing socket to clear and app threads to set + tcpStatus CifsNeedReconnect if server hung */ + continue; + } else if (length <= 0) { cERROR(1, - ("Zero length receive when expecting %d ", + ("Received no data, expecting %d", pdu_length - total_read)); cifs_reconnect(server); csocket = server->ssocket; - wake_up(&server->response_q); - continue; + goto dmx_loop_end; } } length += 4; /* account for rfc1002 hdr */ @@ -434,6 +450,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) wake_up(&server->response_q); continue; } +dmx_loop_end: + cFYI(1,("Exiting cifsd loop")); + } spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; -- cgit v1.2.3-59-g8ed1b From 46810cbf3d951c1ce8ce3311639996ad43ca4ed1 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:09 -0700 Subject: [PATCH] cifs: Ease memory pressure, do not use large buffers in byte range lock requests. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/cifssmb.c | 8 +- fs/cifs/connect.c | 295 +++++++++++++++++++++++++++--------------------------- 2 files changed, 154 insertions(+), 149 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 834297f7b5e1..a6e66974b286 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1023,11 +1023,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, __u16 count; cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock)); - rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); + if (rc) return rc; + pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */ + if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) { timeout = -1; /* no response expected */ pSMB->Timeout = 0; @@ -1065,7 +1067,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, if (rc) { cFYI(1, ("Send error in Lock = %d", rc)); } - cifs_buf_release(pSMB); + cifs_small_buf_release(pSMB); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8c5d310514ea..419f145c80b5 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -294,165 +294,168 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) csocket = server->ssocket; wake_up(&server->response_q); continue; - } else if (length > 3) { - pdu_length = ntohl(smb_buffer->smb_buf_length); - /* Only read pdu_length after below checks for too short (due - to e.g. int overflow) and too long ie beyond end of buf */ - cFYI(1,("rfc1002 length(big endian)0x%x)", - pdu_length+4)); - - temp = (char *) smb_buffer; - if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { - cFYI(0,("Received 4 byte keep alive packet")); - } else if (temp[0] == - (char) RFC1002_POSITIVE_SESSION_RESPONSE) { - cFYI(1,("Good RFC 1002 session rsp")); - } else if (temp[0] == - (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { - /* we get this from Windows 98 instead of - an error on SMB negprot response */ - cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); - if(server->tcpStatus == CifsNew) { - /* if nack on negprot (rather than - ret of smb negprot error) reconnecting - not going to help, ret error to mount */ - break; - } else { - /* give server a second to - clean up before reconnect attempt */ - msleep(1000); - /* always try 445 first on reconnect - since we get NACK on some if we ever - connected to port 139 (the NACK is - since we do not begin with RFC1001 - session initialize frame) */ - server->addr.sockAddr.sin_port = - htons(CIFS_PORT); - cifs_reconnect(server); - csocket = server->ssocket; - wake_up(&server->response_q); - continue; - } - } else if (temp[0] != (char) 0) { - cERROR(1,("Unknown RFC 1002 frame")); - cifs_dump_mem(" Received Data: ", temp, length); + } else if (length < 4) { + cFYI(1, + ("Frame less than four bytes received %d bytes long.", + length)); + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; + } + + /* the right amount was read from socket - 4 bytes */ + + pdu_length = ntohl(smb_buffer->smb_buf_length); + cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); + + temp = (char *) smb_buffer; + if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { + cFYI(0,("Received 4 byte keep alive packet")); + } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { + cFYI(1,("Good RFC 1002 session rsp")); + } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { + /* we get this from Windows 98 instead of + an error on SMB negprot response */ + cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); + if(server->tcpStatus == CifsNew) { + /* if nack on negprot (rather than + ret of smb negprot error) reconnecting + not going to help, ret error to mount */ + break; + } else { + /* give server a second to + clean up before reconnect attempt */ + msleep(1000); + /* always try 445 first on reconnect + since we get NACK on some if we ever + connected to port 139 (the NACK is + since we do not begin with RFC1001 + session initialize frame) */ + server->addr.sockAddr.sin_port = + htons(CIFS_PORT); cifs_reconnect(server); csocket = server->ssocket; + wake_up(&server->response_q); continue; - } else { - if((pdu_length > CIFSMaxBufSize + - MAX_CIFS_HDR_SIZE - 4) || - (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { - cERROR(1, - ("Invalid size SMB length %d and pdu_length %d", - length, pdu_length+4)); - cifs_reconnect(server); - csocket = server->ssocket; - wake_up(&server->response_q); - continue; - } else { /* length ok */ - if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { - isLargeBuf = TRUE; - memcpy(bigbuf, smallbuf, 4); - smb_buffer = bigbuf; - } - length = 0; - iov.iov_base = 4 + (char *)smb_buffer; - iov.iov_len = pdu_length; - for (total_read = 0; - total_read < pdu_length; - total_read += length) { - length = kernel_recvmsg(csocket, &smb_msg, - &iov, 1, - pdu_length - total_read, 0); - if((server->tcpStatus == CifsExiting) || - (length == -EINTR)) { - /* then will exit */ - goto dmx_loop_end; - } else if (server->tcpStatus == - CifsNeedReconnect) { - cifs_reconnect(server); - csocket = server->ssocket; - /* Reconnect wakes up rspns q */ + } + } else if (temp[0] != (char) 0) { + cERROR(1,("Unknown RFC 1002 frame")); + cifs_dump_mem(" Received Data: ", temp, length); + cifs_reconnect(server); + csocket = server->ssocket; + continue; + } else { /* we have an SMB response */ + if((pdu_length > CIFSMaxBufSize + + MAX_CIFS_HDR_SIZE - 4) || + (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { + cERROR(1, + ("Invalid size SMB length %d and pdu_length %d", + length, pdu_length+4)); + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; + } else { /* length ok */ + int reconnect = 0; + + if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { + isLargeBuf = TRUE; + memcpy(bigbuf, smallbuf, 4); + smb_buffer = bigbuf; + } + length = 0; + iov.iov_base = 4 + (char *)smb_buffer; + iov.iov_len = pdu_length; + for (total_read = 0; + total_read < pdu_length; + total_read += length) { + length = kernel_recvmsg(csocket, &smb_msg, + &iov, 1, + pdu_length - total_read, 0); + if((server->tcpStatus == CifsExiting) || + (length == -EINTR)) { + /* then will exit */ + reconnect = 2; + break; + } else if (server->tcpStatus == + CifsNeedReconnect) { + cifs_reconnect(server); + csocket = server->ssocket; + /* Reconnect wakes up rspns q */ /* Now we will reread sock */ - goto dmx_loop_end; - } else if ((length == -ERESTARTSYS) || - (length == -EAGAIN)) { - msleep(1); /* minimum sleep to prevent looping - allowing socket to clear and app threads to set - tcpStatus CifsNeedReconnect if server hung */ - continue; - } else if (length <= 0) { - cERROR(1, - ("Received no data, expecting %d", - pdu_length - total_read)); - cifs_reconnect(server); - csocket = server->ssocket; - goto dmx_loop_end; - } + reconnect = 1; + break; + } else if ((length == -ERESTARTSYS) || + (length == -EAGAIN)) { + msleep(1); /* minimum sleep to prevent looping + allowing socket to clear and app threads to set + tcpStatus CifsNeedReconnect if server hung */ + continue; + } else if (length <= 0) { + cERROR(1,("Received no data, expecting %d", + pdu_length - total_read)); + cifs_reconnect(server); + csocket = server->ssocket; + reconnect = 1; + break; } - length += 4; /* account for rfc1002 hdr */ } + if(reconnect == 2) + break; + else if(reconnect == 1) + continue; - dump_smb(smb_buffer, length); - if (checkSMB - (smb_buffer, smb_buffer->Mid, total_read+4)) { - cERROR(1, ("Bad SMB Received ")); - continue; - } + length += 4; /* account for rfc1002 hdr */ + } - /* BB FIXME - add checkTrans2SMBSecondary() */ - - task_to_wake = NULL; - spin_lock(&GlobalMid_Lock); - list_for_each(tmp, &server->pending_mid_q) { - mid_entry = list_entry(tmp, struct - mid_q_entry, - qhead); - - if ((mid_entry->mid == smb_buffer->Mid) - && (mid_entry->midState == - MID_REQUEST_SUBMITTED) - && (mid_entry->command == - smb_buffer->Command)) { - cFYI(1,("Found Mid 0x%x wake up" - ,mid_entry->mid)); - task_to_wake = mid_entry->tsk; - mid_entry->resp_buf = - smb_buffer; - mid_entry->midState = - MID_RESPONSE_RECEIVED; - if(isLargeBuf) - mid_entry->largeBuf = 1; - else - mid_entry->largeBuf = 0; - } - } - spin_unlock(&GlobalMid_Lock); - if (task_to_wake) { + dump_smb(smb_buffer, length); + if (checkSMB + (smb_buffer, smb_buffer->Mid, total_read+4)) { + cERROR(1, ("Bad SMB Received ")); + continue; + } + + + task_to_wake = NULL; + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct mid_q_entry, + qhead); + + if ((mid_entry->mid == smb_buffer->Mid) + && (mid_entry->midState == + MID_REQUEST_SUBMITTED) + && (mid_entry->command == + smb_buffer->Command)) { + cFYI(1,("Found Mid 0x%x wake up" + ,mid_entry->mid)); + /* BB FIXME - missing code here BB */ + /* check_2nd_t2(smb_buffer); */ + task_to_wake = mid_entry->tsk; + mid_entry->resp_buf = + smb_buffer; + mid_entry->midState = + MID_RESPONSE_RECEIVED; if(isLargeBuf) - bigbuf = NULL; + mid_entry->largeBuf = 1; else - smallbuf = NULL; - smb_buffer = NULL; /* will be freed by users thread after he is done */ - wake_up_process(task_to_wake); - } else if (is_valid_oplock_break(smb_buffer) == FALSE) { - cERROR(1, ("No task to wake, unknown frame rcvd!")); - cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + mid_entry->largeBuf = 0; } } - } else { - cFYI(1, - ("Frame less than four bytes received %d bytes long.", - length)); - cifs_reconnect(server); - csocket = server->ssocket; - wake_up(&server->response_q); - continue; + spin_unlock(&GlobalMid_Lock); + if (task_to_wake) { + if(isLargeBuf) + bigbuf = NULL; + else + smallbuf = NULL; + smb_buffer = NULL; /* will be freed by users thread after he is done */ + wake_up_process(task_to_wake); + } else if (is_valid_oplock_break(smb_buffer) == FALSE) { + cERROR(1, ("No task to wake, unknown frame rcvd!")); + cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + } } -dmx_loop_end: - cFYI(1,("Exiting cifsd loop")); - } spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; -- cgit v1.2.3-59-g8ed1b From e4eb295d38b57f4d4b956942a48887eb252d97c6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:09 -0700 Subject: [PATCH] cifs: Handle multiple response transact2 part 1 of 2 Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/cifspdu.h | 2 +- fs/cifs/connect.c | 348 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 246 insertions(+), 104 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e3e92615705e..aede6a813167 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -330,7 +330,7 @@ struct smb_hdr { }; /* given a pointer to an smb_hdr retrieve the value of byte count */ #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) - +#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 419f145c80b5..a8d592bc33fe 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -116,7 +116,7 @@ cifs_reconnect(struct TCP_Server_Info *server) spin_unlock(&GlobalMid_Lock); server->maxBuf = 0; - cFYI(1, ("Reconnecting tcp session ")); + cFYI(1, ("Reconnecting tcp session")); /* before reconnecting the tcp session, mark the smb session (uid) and the tid bad so they are not used until reconnected */ @@ -194,6 +194,121 @@ cifs_reconnect(struct TCP_Server_Info *server) return rc; } +/* + return codes: + 0 not a transact2, or all data present + >0 transact2 with that much data missing + -EINVAL = invalid transact2 + + */ +static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize) +{ + struct smb_t2_rsp * pSMBt; + int total_data_size; + int data_in_this_rsp; + int remaining; + + if(pSMB->Command != SMB_COM_TRANSACTION2) + return 0; + + /* check for plausible wct, bcc and t2 data and parm sizes */ + /* check for parm and data offset going beyond end of smb */ + if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */ + cFYI(1,("invalid transact2 word count")); + return -EINVAL; + } + + pSMBt = (struct smb_t2_rsp *)pSMB; + + total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); + data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount); + + remaining = total_data_size - data_in_this_rsp; + + if(remaining == 0) + return 0; + else if(remaining < 0) { + cFYI(1,("total data %d smaller than data in frame %d", + total_data_size, data_in_this_rsp)); + return -EINVAL; + } else { + cFYI(1,("missing %d bytes from transact2, check next response", + remaining)); + if(total_data_size > maxBufSize) { + cERROR(1,("TotalDataSize %d is over maximum buffer %d", + total_data_size,maxBufSize)); + return -EINVAL; + } + return remaining; + } +} + +static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) +{ + struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond; + struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB; + int total_data_size; + int total_in_buf; + int remaining; + int total_in_buf2; + char * data_area_of_target; + char * data_area_of_buf2; + __u16 byte_count; + + total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); + + if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) { + cFYI(1,("total data sizes of primary and secondary t2 differ")); + } + + total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount); + + remaining = total_data_size - total_in_buf; + + if(remaining < 0) + return -EINVAL; + + if(remaining == 0) /* nothing to do, ignore */ + return 0; + + total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount); + if(remaining < total_in_buf2) { + cFYI(1,("transact2 2nd response contains too much data")); + } + + /* find end of first SMB data area */ + data_area_of_target = (char *)&pSMBt->hdr.Protocol + + le16_to_cpu(pSMBt->t2_rsp.DataOffset); + /* validate target area */ + + data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol + + le16_to_cpu(pSMB2->t2_rsp.DataOffset); + + data_area_of_target += total_in_buf; + + /* copy second buffer into end of first buffer */ + memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2); + total_in_buf += total_in_buf2; + pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf); + byte_count = le16_to_cpu(BCC_LE(pTargetSMB)); + byte_count += total_in_buf2; + BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); + + byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); + byte_count += total_in_buf2; + + /* BB also add check that we are not beyond maximum buffer size */ + + pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); + + if(remaining == total_in_buf2) { + cFYI(1,("found the last secondary response")); + return 0; /* we are done */ + } else /* more responses to go */ + return 1; + +} + static int cifs_demultiplex_thread(struct TCP_Server_Info *server) { @@ -211,6 +326,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) struct mid_q_entry *mid_entry; char *temp; int isLargeBuf = FALSE; + int isMultiRsp; + int reconnect; daemonize("cifsd"); allow_signal(SIGKILL); @@ -254,6 +371,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) memset(smallbuf, 0, sizeof (struct smb_hdr)); isLargeBuf = FALSE; + isMultiRsp = FALSE; smb_buffer = smallbuf; iov.iov_base = smb_buffer; iov.iov_len = 4; @@ -311,13 +429,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) temp = (char *) smb_buffer; if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { - cFYI(0,("Received 4 byte keep alive packet")); + continue; } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { - cFYI(1,("Good RFC 1002 session rsp")); + cFYI(1,("Good RFC 1002 session rsp")); + continue; } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { /* we get this from Windows 98 instead of an error on SMB negprot response */ - cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); + cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", + temp[4])); if(server->tcpStatus == CifsNew) { /* if nack on negprot (rather than ret of smb negprot error) reconnecting @@ -345,118 +465,140 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) cifs_reconnect(server); csocket = server->ssocket; continue; - } else { /* we have an SMB response */ - if((pdu_length > CIFSMaxBufSize + - MAX_CIFS_HDR_SIZE - 4) || + } + + /* else we have an SMB response */ + if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { - cERROR(1, - ("Invalid size SMB length %d and pdu_length %d", + cERROR(1, ("Invalid size SMB length %d pdu_length %d", length, pdu_length+4)); + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; + } + + /* else length ok */ + reconnect = 0; + + if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { + isLargeBuf = TRUE; + memcpy(bigbuf, smallbuf, 4); + smb_buffer = bigbuf; + } + length = 0; + iov.iov_base = 4 + (char *)smb_buffer; + iov.iov_len = pdu_length; + for (total_read = 0; total_read < pdu_length; + total_read += length) { + length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, + pdu_length - total_read, 0); + if((server->tcpStatus == CifsExiting) || + (length == -EINTR)) { + /* then will exit */ + reconnect = 2; + break; + } else if (server->tcpStatus == CifsNeedReconnect) { cifs_reconnect(server); csocket = server->ssocket; - wake_up(&server->response_q); + /* Reconnect wakes up rspns q */ + /* Now we will reread sock */ + reconnect = 1; + break; + } else if ((length == -ERESTARTSYS) || + (length == -EAGAIN)) { + msleep(1); /* minimum sleep to prevent looping, + allowing socket to clear and app + threads to set tcpStatus + CifsNeedReconnect if server hung*/ continue; - } else { /* length ok */ - int reconnect = 0; - - if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { - isLargeBuf = TRUE; - memcpy(bigbuf, smallbuf, 4); - smb_buffer = bigbuf; - } - length = 0; - iov.iov_base = 4 + (char *)smb_buffer; - iov.iov_len = pdu_length; - for (total_read = 0; - total_read < pdu_length; - total_read += length) { - length = kernel_recvmsg(csocket, &smb_msg, - &iov, 1, - pdu_length - total_read, 0); - if((server->tcpStatus == CifsExiting) || - (length == -EINTR)) { - /* then will exit */ - reconnect = 2; - break; - } else if (server->tcpStatus == - CifsNeedReconnect) { - cifs_reconnect(server); - csocket = server->ssocket; - /* Reconnect wakes up rspns q */ - /* Now we will reread sock */ - reconnect = 1; - break; - } else if ((length == -ERESTARTSYS) || - (length == -EAGAIN)) { - msleep(1); /* minimum sleep to prevent looping - allowing socket to clear and app threads to set - tcpStatus CifsNeedReconnect if server hung */ - continue; - } else if (length <= 0) { - cERROR(1,("Received no data, expecting %d", - pdu_length - total_read)); - cifs_reconnect(server); - csocket = server->ssocket; - reconnect = 1; - break; - } - } - if(reconnect == 2) - break; - else if(reconnect == 1) - continue; - - length += 4; /* account for rfc1002 hdr */ + } else if (length <= 0) { + cERROR(1,("Received no data, expecting %d", + pdu_length - total_read)); + cifs_reconnect(server); + csocket = server->ssocket; + reconnect = 1; + break; } + } + if(reconnect == 2) + break; + else if(reconnect == 1) + continue; - dump_smb(smb_buffer, length); - if (checkSMB - (smb_buffer, smb_buffer->Mid, total_read+4)) { - cERROR(1, ("Bad SMB Received ")); - continue; - } + length += 4; /* account for rfc1002 hdr */ + + dump_smb(smb_buffer, length); + if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { + cERROR(1, ("Bad SMB Received ")); + continue; + } - task_to_wake = NULL; - spin_lock(&GlobalMid_Lock); - list_for_each(tmp, &server->pending_mid_q) { - mid_entry = list_entry(tmp, struct mid_q_entry, - qhead); - - if ((mid_entry->mid == smb_buffer->Mid) - && (mid_entry->midState == - MID_REQUEST_SUBMITTED) - && (mid_entry->command == - smb_buffer->Command)) { - cFYI(1,("Found Mid 0x%x wake up" - ,mid_entry->mid)); - /* BB FIXME - missing code here BB */ - /* check_2nd_t2(smb_buffer); */ - task_to_wake = mid_entry->tsk; - mid_entry->resp_buf = - smb_buffer; - mid_entry->midState = - MID_RESPONSE_RECEIVED; - if(isLargeBuf) - mid_entry->largeBuf = 1; - else - mid_entry->largeBuf = 0; - } - } - spin_unlock(&GlobalMid_Lock); - if (task_to_wake) { + + task_to_wake = NULL; + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct mid_q_entry, qhead); + + if ((mid_entry->mid == smb_buffer->Mid) && + (mid_entry->midState == MID_REQUEST_SUBMITTED) && + (mid_entry->command == smb_buffer->Command)) { + cFYI(1,("Found Mid 0x%x wake", mid_entry->mid)); + + if(check2ndT2(smb_buffer,server->maxBuf) > 0) { + /* We have a multipart transact2 resp */ + if(mid_entry->resp_buf) { + /* merge response - fix up 1st*/ + if(coalesce_t2(smb_buffer, + mid_entry->resp_buf)) { + isMultiRsp = TRUE; + break; + } else { + /* all parts received */ + goto multi_t2_fnd; + } + } else { + if(!isLargeBuf) { + cERROR(1,("1st trans2 resp needs bigbuf")); + /* BB maybe we can fix this up, switch + to already allocated large buffer? */ + } else { + mid_entry->resp_buf = + smb_buffer; + mid_entry->largeBuf = 1; + isMultiRsp = TRUE; + bigbuf = NULL; + } + } + break; + } + mid_entry->resp_buf = smb_buffer; if(isLargeBuf) - bigbuf = NULL; + mid_entry->largeBuf = 1; else - smallbuf = NULL; - smb_buffer = NULL; /* will be freed by users thread after he is done */ - wake_up_process(task_to_wake); - } else if (is_valid_oplock_break(smb_buffer) == FALSE) { - cERROR(1, ("No task to wake, unknown frame rcvd!")); - cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + mid_entry->largeBuf = 0; +multi_t2_fnd: + task_to_wake = mid_entry->tsk; + mid_entry->midState = MID_RESPONSE_RECEIVED; + break; } } - } + spin_unlock(&GlobalMid_Lock); + if (task_to_wake) { + if(isLargeBuf) + bigbuf = NULL; + else + smallbuf = NULL; + /* smb buffer freed by user thread when done */ + wake_up_process(task_to_wake); + } else if ((is_valid_oplock_break(smb_buffer) == FALSE) + && (isMultiRsp == FALSE)) { + cERROR(1, ("No task to wake, unknown frame rcvd!")); + cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + } + } /* end while !EXITING */ + spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; server->tsk = NULL; -- cgit v1.2.3-59-g8ed1b From cd63499cbe37e53e6cc084c8a35d911a4613c797 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:10 -0700 Subject: [PATCH] cifs: Handle case of multiple trans2 responses for one SMB request (part 2 of 2) Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/CHANGES | 2 ++ fs/cifs/cifssmb.c | 22 +++++++++++----------- fs/cifs/connect.c | 19 ++++++++++--------- 3 files changed, 23 insertions(+), 20 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 0414eb325468..3d61d96d7407 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -4,6 +4,8 @@ Fix caching problem, in which readdir of directory containing a file which was cached could cause the file's time stamp to be updated without invalidating the readahead data (so we could get stale file data on the client for that file even as the server copy changed). +Cleanup response processing so cifsd can not loop when abnormally +terminated. Version 1.32 diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index a6e66974b286..f8edf816b4be 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -470,7 +470,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) return rc; } else { smb_buffer_response = smb_buffer; /* BB removeme BB */ - } + } rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, &length, 0); if (rc) @@ -2517,9 +2517,6 @@ findFirstRetry: psrch_inf->srch_entries_start = (char *) &pSMBr->hdr.Protocol + le16_to_cpu(pSMBr->t2.DataOffset); -/* if(le16_to_cpu(pSMBr->t2.DataCount) != le16_to_cpu(pSMBr->t2.TotalDataCount)) { - cERROR(1,("DC: %d TDC: %d",pSMBr->t2.DataCount,pSMBr->t2.TotalDataCount)); -} */ /* BB removeme BB */ parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol + le16_to_cpu(pSMBr->t2.ParameterOffset)); @@ -2531,7 +2528,6 @@ findFirstRetry: psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount); psrch_inf->index_of_last_entry = psrch_inf->entries_in_buffer; -/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */ /* BB removeme BB */ *pnetfid = parms->SearchHandle; } else { cifs_buf_release(pSMB); @@ -3451,11 +3447,13 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, cFYI(1, ("SetFileSize (via SetFileInfo) %lld", (long long)size)); - rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); + if (rc) return rc; + pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; + pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); @@ -3515,7 +3513,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, } if (pSMB) - cifs_buf_release(pSMB); + cifs_small_buf_release(pSMB); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ @@ -3541,11 +3539,13 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I __u16 params, param_offset, offset, byte_count, count; cFYI(1, ("Set Times (via SetFileInfo)")); - rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); + if (rc) return rc; + pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; + /* At this point there is no need to override the current pid with the pid of the opener, but that could change if we someday use an existing handle (rather than opening one on the fly) */ @@ -3591,7 +3591,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc)); } - cifs_buf_release(pSMB); + cifs_small_buf_release(pSMB); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index a8d592bc33fe..e3b177a90b37 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -544,15 +544,13 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED) && (mid_entry->command == smb_buffer->Command)) { - cFYI(1,("Found Mid 0x%x wake", mid_entry->mid)); - if(check2ndT2(smb_buffer,server->maxBuf) > 0) { /* We have a multipart transact2 resp */ + isMultiRsp = TRUE; if(mid_entry->resp_buf) { /* merge response - fix up 1st*/ if(coalesce_t2(smb_buffer, mid_entry->resp_buf)) { - isMultiRsp = TRUE; break; } else { /* all parts received */ @@ -564,10 +562,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) /* BB maybe we can fix this up, switch to already allocated large buffer? */ } else { + /* Have first buffer */ mid_entry->resp_buf = smb_buffer; mid_entry->largeBuf = 1; - isMultiRsp = TRUE; bigbuf = NULL; } } @@ -586,11 +584,14 @@ multi_t2_fnd: } spin_unlock(&GlobalMid_Lock); if (task_to_wake) { - if(isLargeBuf) - bigbuf = NULL; - else - smallbuf = NULL; - /* smb buffer freed by user thread when done */ + /* Was previous buf put in mpx struct for multi-rsp? */ + if(!isMultiRsp) { + /* smb buffer will be freed by user thread */ + if(isLargeBuf) { + bigbuf = NULL; + } else + smallbuf = NULL; + } wake_up_process(task_to_wake); } else if ((is_valid_oplock_break(smb_buffer) == FALSE) && (isMultiRsp == FALSE)) { -- cgit v1.2.3-59-g8ed1b From 57337e42f1393941d59d5154eed27a63988ff2be Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:10 -0700 Subject: [PATCH] cifs: handle termination of cifs oplockd kernel thread Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/CHANGES | 1 + fs/cifs/cifsfs.c | 1 + fs/cifs/connect.c | 11 ++++++----- fs/cifs/misc.c | 25 +++++++++++++++---------- 4 files changed, 23 insertions(+), 15 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 21a246473a91..bd3b55e1be17 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,6 +1,7 @@ Version 1.34 ------------ Fix error mapping of the TOO_MANY_LINKS (hardlinks) case. +Do not oops if user kills cifs oplock kernel thread. Version 1.33 ------------ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 6322aada491f..8cc23e7d0d5d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -835,6 +835,7 @@ static int cifs_oplock_thread(void * dummyarg) } } while(!signal_pending(current)); complete_and_exit (&cifs_oplock_exited, 0); + oplockThread = NULL; } static int __init diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e3b177a90b37..437be1efe99e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -384,7 +384,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) if(server->tcpStatus == CifsExiting) { break; } else if (server->tcpStatus == CifsNeedReconnect) { - cFYI(1,("Reconnecting after server stopped responding")); + cFYI(1,("Reconnect after server stopped responding")); cifs_reconnect(server); cFYI(1,("call to reconnect done")); csocket = server->ssocket; @@ -396,7 +396,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) continue; } else if (length <= 0) { if(server->tcpStatus == CifsNew) { - cFYI(1,("tcp session abended prematurely (after SMBnegprot)")); + cFYI(1,("tcp session abend after SMBnegprot")); /* some servers kill the TCP session rather than returning an SMB negprot error, in which case reconnecting here is not going to help, @@ -407,14 +407,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) cFYI(1,("cifsd thread killed")); break; } - cFYI(1,("Reconnecting after unexpected peek error %d",length)); + cFYI(1,("Reconnect after unexpected peek error %d", + length)); cifs_reconnect(server); csocket = server->ssocket; wake_up(&server->response_q); continue; } else if (length < 4) { cFYI(1, - ("Frame less than four bytes received %d bytes long.", + ("Frame under four bytes received (%d bytes long)", length)); cifs_reconnect(server); csocket = server->ssocket; @@ -593,7 +594,7 @@ multi_t2_fnd: smallbuf = NULL; } wake_up_process(task_to_wake); - } else if ((is_valid_oplock_break(smb_buffer) == FALSE) + } else if ((is_valid_oplock_break(smb_buffer) == FALSE) && (isMultiRsp == FALSE)) { cERROR(1, ("No task to wake, unknown frame rcvd!")); cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 75fd3bd6e233..db14b503d89e 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -452,25 +452,30 @@ is_valid_oplock_break(struct smb_hdr *buf) atomic_inc(&tcon->num_oplock_brks); #endif list_for_each(tmp1,&tcon->openFileList){ - netfile = list_entry(tmp1,struct cifsFileInfo,tlist); + netfile = list_entry(tmp1,struct cifsFileInfo, + tlist); if(pSMB->Fid == netfile->netfid) { struct cifsInodeInfo *pCifsInode; read_unlock(&GlobalSMBSeslock); - cFYI(1,("Matching file id, processing oplock break")); + cFYI(1,("file id match, oplock break")); pCifsInode = CIFS_I(netfile->pInode); pCifsInode->clientCanCacheAll = FALSE; if(pSMB->OplockLevel == 0) - pCifsInode->clientCanCacheRead = FALSE; + pCifsInode->clientCanCacheRead + = FALSE; pCifsInode->oplockPending = TRUE; - AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon); + AllocOplockQEntry(netfile->pInode, + netfile->netfid, + tcon); cFYI(1,("about to wake up oplock thd")); - wake_up_process(oplockThread); + if(oplockThread) + wake_up_process(oplockThread); return TRUE; } } read_unlock(&GlobalSMBSeslock); - cFYI(1,("No matching file for oplock break on connection")); + cFYI(1,("No matching file for oplock break")); return TRUE; } } @@ -491,7 +496,7 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) buffer = (unsigned char *) smb_buf; for (i = 0, j = 0; i < smb_buf_length; i++, j++) { - if (i % 8 == 0) { /* we have reached the beginning of line */ + if (i % 8 == 0) { /* have reached the beginning of line */ printk(KERN_DEBUG "| "); j = 0; } @@ -502,7 +507,7 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) else debug_line[1 + (2 * j)] = '_'; - if (i % 8 == 7) { /* we have reached end of line, time to print ascii */ + if (i % 8 == 7) { /* reached end of line, time to print ascii */ debug_line[16] = 0; printk(" | %s\n", debug_line); } @@ -577,7 +582,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, } } j++; - /* check to make sure we do not overrun callers allocated temp buffer */ + /* make sure we do not overrun callers allocated temp buffer */ if(j >= (2 * NAME_MAX)) break; } @@ -599,7 +604,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, char src_char; if(!mapChars) - return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); + return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); for(i = 0, j = 0; i < maxlen; j++) { src_char = source[i]; -- cgit v1.2.3-59-g8ed1b From 31ca3bc3c569f9fe02aae6974ac3a9126f14902f Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:11 -0700 Subject: [PATCH] cifs: Do not init smb requests or block when sending requests if cifsd thread is no longer running to demultixplex responses. Do not send FindClose request when FindFirst failed without reaching end of search. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/CHANGES | 5 ++++- fs/cifs/cifssmb.c | 6 ++++-- fs/cifs/connect.c | 40 +++++++++++++++++++++++++++++++++++++--- fs/cifs/file.c | 3 ++- fs/cifs/transport.c | 6 ++++++ 5 files changed, 53 insertions(+), 7 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index bd3b55e1be17..4d2404305ab6 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,7 +1,10 @@ Version 1.34 ------------ Fix error mapping of the TOO_MANY_LINKS (hardlinks) case. -Do not oops if user kills cifs oplock kernel thread. +Do not oops if root user kills cifs oplock kernel thread or +kills the cifsd thread (NB: killing the cifs kernel threads is not +recommended, unmount and rmmod cifs will kill them when they are +no longer needed). Version 1.33 ------------ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f8edf816b4be..b004fef0a42b 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -90,7 +90,8 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, check for tcp and smb session status done differently for those three - in the calling routine */ if(tcon) { - if((tcon->ses) && (tcon->ses->server)){ + if((tcon->ses) && (tcon->ses->status != CifsExiting) && + (tcon->ses->server)){ struct nls_table *nls_codepage; /* Give Demultiplex thread up to 10 seconds to reconnect, should be greater than cifs socket @@ -185,7 +186,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, check for tcp and smb session status done differently for those three - in the calling routine */ if(tcon) { - if((tcon->ses) && (tcon->ses->server)){ + if((tcon->ses) && (tcon->ses->status != CifsExiting) && + (tcon->ses->server)){ struct nls_table *nls_codepage; /* Give Demultiplex thread up to 10 seconds to reconnect, should be greater than cifs socket diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 437be1efe99e..ac1f970e5369 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -604,7 +604,13 @@ multi_t2_fnd: spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; server->tsk = NULL; - atomic_set(&server->inFlight, 0); + /* check if we have blocked requests that need to free */ + /* Note that cifs_max_pending is normally 50, but + can be set at module install time to as little as two */ + if(atomic_read(&server->inFlight) >= cifs_max_pending) + atomic_set(&server->inFlight, cifs_max_pending - 1); + /* We do not want to set the max_pending too low or we + could end up with the counter going negative */ spin_unlock(&GlobalMid_Lock); /* Although there should not be any requests blocked on this queue it can not hurt to be paranoid and try to wake up requests @@ -640,6 +646,17 @@ multi_t2_fnd: } read_unlock(&GlobalSMBSeslock); } else { + /* although we can not zero the server struct pointer yet, + since there are active requests which may depnd on them, + mark the corresponding SMB sessions as exiting too */ + list_for_each(tmp, &GlobalSMBSessionList) { + ses = list_entry(tmp, struct cifsSesInfo, + cifsSessionList); + if (ses->server == server) { + ses->status = CifsExiting; + } + } + spin_lock(&GlobalMid_Lock); list_for_each(tmp, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, qhead); @@ -661,17 +678,34 @@ multi_t2_fnd: if (list_empty(&server->pending_mid_q)) { /* mpx threads have not exited yet give them at least the smb send timeout time for long ops */ + /* due to delays on oplock break requests, we need + to wait at least 45 seconds before giving up + on a request getting a response and going ahead + and killing cifsd */ cFYI(1, ("Wait for exit from demultiplex thread")); - msleep(46); + msleep(46000); /* if threads still have not exited they are probably never coming home not much else we can do but free the memory */ } - kfree(server); write_lock(&GlobalSMBSeslock); atomic_dec(&tcpSesAllocCount); length = tcpSesAllocCount.counter; + + /* last chance to mark ses pointers invalid + if there are any pointing to this (e.g + if a crazy root user tried to kill cifsd + kernel thread explicitly this might happen) */ + list_for_each(tmp, &GlobalSMBSessionList) { + ses = list_entry(tmp, struct cifsSesInfo, + cifsSessionList); + if (ses->server == server) { + ses->server = NULL; + } + } write_unlock(&GlobalSMBSeslock); + + kfree(server); if(length > 0) { mempool_resize(cifs_req_poolp, length + cifs_min_rcv, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 1df26ddf68b1..dde2d251fc3d 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -512,7 +512,8 @@ int cifs_closedir(struct inode *inode, struct file *file) pTcon = cifs_sb->tcon; cFYI(1, ("Freeing private data in close dir")); - if (pCFileStruct->srch_inf.endOfSearch == FALSE) { + if ((pCFileStruct->srch_inf.endOfSearch == FALSE) && + (pCFileStruct->invalidHandle == FALSE)) { pCFileStruct->invalidHandle = TRUE; rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); cFYI(1, ("Closing uncompleted readdir with rc %d", diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 79bf686a2a19..0046c219833d 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -270,6 +270,9 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, + if(ses->server->tcpStatus == CIFS_EXITING) + return -ENOENT; + /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ @@ -401,6 +404,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, return -EIO; } + if(ses->server->tcpStatus == CifsExiting) + return -ENOENT; + /* Ensure that we do not send more than 50 overlapping requests to the same server. We may make this configurable later or use ses->maxReq */ -- cgit v1.2.3-59-g8ed1b From 0cb766ae629c70d53040f85de73db0583eadb233 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:11 -0700 Subject: [PATCH] cifs: Do not sleep interruptible after socket connect failure .. since it can be due to pending kill. Update readme information to better describe cifs umount Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds --- fs/cifs/README | 15 ++++++++++----- fs/cifs/connect.c | 3 +-- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/README b/fs/cifs/README index bec7b3fc8a72..7b4ac096cd11 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -101,12 +101,15 @@ Allowing User Unmounts ====================== To permit users to ummount directories that they have user mounted (see above), the utility umount.cifs may be used. It may be invoked directly, or if -umount.cifs is placed in /sbin, umount -i can invoke the cifs umount helper +umount.cifs is placed in /sbin, umount can invoke the cifs umount helper (at least for most versions of the umount utility) for umount of cifs -mounts. As with mount.cifs, to enable user unmounts umount.cifs must be marked -as suid (e.g. "chmod +s /sbin/umount.cifs"). For this utility to succeed -the target path must be a cifs mount, and the uid of the current user must -match the uid of the user who mounted the resource. +mounts, unless umount is invoked with -i (which will avoid invoking a umount +helper). As with mount.cifs, to enable user unmounts umount.cifs must be marked +as suid (e.g. "chmod +s /sbin/umount.cifs") or equivalent (some distributions +allow adding entries to a file to the /etc/permissions file to achieve the +equivalent suid effect). For this utility to succeed the target path +must be a cifs mount, and the uid of the current user must match the uid +of the user who mounted the resource. Also note that the customary way of allowing user mounts and unmounts is (instead of using mount.cifs and unmount.cifs as suid) to add a line @@ -404,6 +407,8 @@ A partial list of the supported mount options follows: This has no effect if the server does not support Unicode on the wire. nomapchars Do not translate any of these seven characters (default). + remount remount the share (often used to change from ro to rw mounts + or vice versa) The mount.cifs mount helper also accepts a few mount options before -o including: diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ac1f970e5369..e568cc47a7f9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -178,8 +178,7 @@ cifs_reconnect(struct TCP_Server_Info *server) server->workstation_RFC1001_name); } if(rc) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(3 * HZ); + msleep(3000); } else { atomic_inc(&tcpSesReconnectCount); spin_lock(&GlobalMid_Lock); -- cgit v1.2.3-59-g8ed1b