From 1da0c78b32abe122a959d2a57ba3d41563d8e39f Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:04 -0700
Subject: [PATCH] cifs: Only send POSIX ACL calls to server if server claims to
 support that capability bit

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/xattr.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 549afa184fd6..9a41bee11c5a 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -161,18 +161,20 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
 			strlen(POSIX_ACL_XATTR_ACCESS));
 		if (temp == 0) {
 #ifdef CONFIG_CIFS_POSIX
-			rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value,
-				(const int)value_size, ACL_TYPE_ACCESS,
-				cifs_sb->local_nls);
+			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);
 			cFYI(1,("set POSIX ACL rc %d",rc));
 #else
 			cFYI(1,("set POSIX ACL not supported"));
 #endif
 		} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
-			rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value,
-				(const int)value_size, ACL_TYPE_DEFAULT,
-				cifs_sb->local_nls);
+			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);
 			cFYI(1,("set POSIX default ACL rc %d",rc));
 #else
 			cFYI(1,("set default POSIX ACL not supported"));
@@ -248,7 +250,8 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
 			buf_size, cifs_sb->local_nls);
 	} else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
-		rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
+		if(sb->s_flags & MS_POSIXACL)
+			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 				ea_value, buf_size, ACL_TYPE_ACCESS, 
 				cifs_sb->local_nls);
 #else 
@@ -256,7 +259,8 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
 #endif /* CONFIG_CIFS_POSIX */
 	} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
 #ifdef CONFIG_CIFS_POSIX
-		rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
+		if(sb->s_flags & MS_POSIXACL)
+			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
 				ea_value, buf_size, ACL_TYPE_DEFAULT, 
 				cifs_sb->local_nls);
 #else 
-- 
cgit v1.2.2


From f654bac2227adc5c6956405290eeb4f81f09e9ff Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:04 -0700
Subject: [PATCH] cifs: add support for chattr/lsattr in new CIFS POSIX
 extensions

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/CHANGES     |  9 +++++-
 fs/cifs/cifsfs.h    |  6 ++--
 fs/cifs/cifspdu.h   | 69 ++++++++++++++++++++++++++++++++++++++----
 fs/cifs/cifsproto.h |  4 ++-
 fs/cifs/cifssmb.c   | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/cifs/ioctl.c     | 52 ++++++++++++++++++++++++++++++--
 6 files changed, 212 insertions(+), 14 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 5316c8dd6bff..7fd02697b12e 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,7 +1,14 @@
-Version 1.31
+Version 1.32
 ------------
 Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one
 transact response for an SMB request and search entry split across two frames.
+Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server)
+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.
+
+Version 1.31
+------------
 Fix updates of DOS attributes and time fields so that files on NT4 servers
 do not get marked delete on close. Display sizes of cifs buffer pools in
 cifs stats. Fix oops in unmount when cifsd thread being killed by 
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 451f18af3206..e0e46f4bff97 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -91,8 +91,10 @@ extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
 			const char *symname);
 extern int	cifs_removexattr(struct dentry *, const char *);
 extern int 	cifs_setxattr(struct dentry *, const char *, const void *,
-			 size_t, int);
+			size_t, int);
 extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
-#define CIFS_VERSION   "1.31"
+extern int cifs_ioctl (struct inode * inode, struct file * filep,
+		       unsigned int command, unsigned long arg);
+#define CIFS_VERSION   "1.32"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index bcd4a6136f08..085109d2b55e 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -762,6 +762,16 @@ typedef struct smb_com_lock_req {
 	LOCKING_ANDX_RANGE Locks[1];
 } LOCK_REQ;
 
+
+typedef struct cifs_posix_lock {
+	__le16  lock_type;  /* 0 = Read, 1 = Write, 2 = Unlock */
+	__le16  lock_flags; /* 1 = Wait (only valid for setlock) */
+	__le32  pid;
+	__le64	start;
+	__le64	length;
+	/* BB what about additional owner info to identify network client */
+} CIFS_POSIX_LOCK;
+
 typedef struct smb_com_lock_rsp {
 	struct smb_hdr hdr;	/* wct = 2 */
 	__u8 AndXCommand;
@@ -1098,6 +1108,8 @@ struct smb_t2_rsp {
 #define SMB_QUERY_POSIX_ACL             0x204
 #define SMB_QUERY_XATTR                 0x205
 #define SMB_QUERY_ATTR_FLAGS            0x206  /* append,immutable etc. */
+#define SMB_QUERY_POSIX_PERMISSION      0x207
+#define SMB_QUERY_POSIX_LOCK            0x208
 #define SMB_QUERY_FILE_INTERNAL_INFO    0x3ee
 #define SMB_QUERY_FILE_ACCESS_INFO      0x3f0
 #define SMB_QUERY_FILE_NAME_INFO2       0x3f1 /* 0x30 bytes */
@@ -1116,6 +1128,7 @@ struct smb_t2_rsp {
 #define SMB_SET_POSIX_ACL               0x204
 #define SMB_SET_XATTR                   0x205
 #define SMB_SET_ATTR_FLAGS              0x206  /* append, immutable etc. */
+#define SMB_SET_POSIX_LOCK              0x208
 #define SMB_SET_FILE_BASIC_INFO2        0x3ec
 #define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */
 #define SMB_FILE_ALL_INFO2              0x3fa
@@ -1237,9 +1250,27 @@ struct smb_com_transaction2_sfi_rsp {
 	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
 	struct trans2_resp t2;
 	__u16 ByteCount;
-	__u16 Reserved2;	/* parameter word reserved - present for infolevels > 100 */
+	__u16 Reserved2;	/* parameter word reserved - 
+					present for infolevels > 100 */
+};
+
+struct smb_t2_qfi_req {
+        struct	smb_hdr hdr;
+        struct	trans2_req t2;
+	__u8	Pad;
+	__u16	Pad1;
+	__u16	Fid;
+	__le16	InformationLevel;
+	__u16	Pad2;
 };
 
+struct smb_t2_qfi_rsp {
+        struct smb_hdr hdr;     /* wct = 10 + SetupCount */
+        struct trans2_resp t2;
+        __u16 ByteCount;
+        __u16 Reserved2;        /* parameter word reserved - 
+					present for infolevels > 100 */
+};
 
 /*
  * Flags on T2 FINDFIRST and FINDNEXT 
@@ -1524,8 +1555,9 @@ typedef struct {
 } FILE_SYSTEM_UNIX_INFO;	/* Unix extensions info, level 0x200 */
 /* Linux/Unix extensions capability flags */
 #define CIFS_UNIX_FCNTL_CAP             0x00000001 /* support for fcntl locks */
-#define CIFS_UNIX_POSIX_ACL_CAP         0x00000002
-#define CIFS_UNIX_XATTR_CAP             0x00000004 /*support for new namespace*/
+#define CIFS_UNIX_POSIX_ACL_CAP         0x00000002 /* support getfacl/setfacl */
+#define CIFS_UNIX_XATTR_CAP             0x00000004 /* support new namespace   */
+#define CIFS_UNIX_EXTATTR_CAP           0x00000008 /* support chattr/chflag   */
 
 typedef struct {
 	/* For undefined recommended transfer size return -1 in that field */
@@ -1971,14 +2003,39 @@ struct xsymlink {
 	char path[1024];  
 };
 
-typedef struct {
+typedef struct file_xattr_info {
 	/* BB do we need another field for flags? BB */
 	__u32 xattr_name_len;
 	__u32 xattr_value_len;
 	char  xattr_name[0];
 	/* followed by xattr_value[xattr_value_len], no pad */
-} FILE_XATTR_INFO;	/* extended attribute, info level 205 */
-
+} FILE_XATTR_INFO;	/* extended attribute, info level 0x205 */
+
+
+/* flags for chattr command */
+#define EXT_SECURE_DELETE		0x00000001 /* EXT3_SECRM_FL */
+#define EXT_ENABLE_UNDELETE		0x00000002 /* EXT3_UNRM_FL */
+/* Reserved for compress file 0x4 */
+#define EXT_SYNCHRONOUS			0x00000008 /* EXT3_SYNC_FL */
+#define EXT_IMMUTABLE_FL		0x00000010 /* EXT3_IMMUTABLE_FL */
+#define EXT_OPEN_APPEND_ONLY		0x00000020 /* EXT3_APPEND_FL */
+#define EXT_DO_NOT_BACKUP		0x00000040 /* EXT3_NODUMP_FL */
+#define EXT_NO_UPDATE_ATIME		0x00000080 /* EXT3_NOATIME_FL */
+/* 0x100 through 0x800 reserved for compression flags and are GET-ONLY */
+#define EXT_HASH_TREE_INDEXED_DIR	0x00001000 /* GET-ONLY EXT3_INDEX_FL */
+/* 0x2000 reserved for IMAGIC_FL */
+#define EXT_JOURNAL_THIS_FILE	0x00004000 /* GET-ONLY EXT3_JOURNAL_DATA_FL */
+/* 0x8000 reserved for EXT3_NOTAIL_FL */
+#define EXT_SYNCHRONOUS_DIR		0x00010000 /* EXT3_DIRSYNC_FL */
+#define EXT_TOPDIR			0x00020000 /* EXT3_TOPDIR_FL */
+
+#define EXT_SET_MASK			0x000300FF
+#define EXT_GET_MASK			0x0003DFFF
+
+typedef struct file_chattr_info {
+	__le64	mask; /* list of all possible attribute bits */
+	__le64	mode; /* list of actual attribute bits on this inode */
+} FILE_CHATTR_INFO;  /* ext attributes (chattr, chflags) level 0x206 */
 
 #endif 
 
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 787eef4d86d3..82ae59d7cf9d 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -264,6 +264,8 @@ 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);
-int cifs_ioctl (struct inode * inode, struct file * filep,
+extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
+                const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
+extern int cifs_ioctl (struct inode * inode, struct file * filep,
                 unsigned int command, unsigned long arg);
 #endif			/* _CIFSPROTO_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index df6a619a6821..36d3c128a58b 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2072,7 +2072,91 @@ setACLerrorExit:
 	return rc;
 }
 
-#endif
+/* BB fix tabs in this function FIXME BB */
+int
+CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
+                const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
+{
+        int rc = 0;
+        struct smb_t2_qfi_req *pSMB = NULL;
+        struct smb_t2_qfi_rsp *pSMBr = NULL;
+        int bytes_returned;
+        __u16 params, byte_count;
+
+        cFYI(1,("In GetExtAttr"));
+        if(tcon == NULL)
+                return -ENODEV;
+
+GetExtAttrRetry:
+        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                      (void **) &pSMBr);
+        if (rc)
+                return rc;
+
+        params = 2 /* level */ +2 /* fid */ + 2 /* rsrvd */;
+        pSMB->t2.TotalDataCount = 0;
+        pSMB->t2.MaxParameterCount = cpu_to_le16(2);
+        /* BB find exact max data count below from sess structure BB */
+        pSMB->t2.MaxDataCount = cpu_to_le16(4000);
+        pSMB->t2.MaxSetupCount = 0;
+        pSMB->t2.Reserved = 0;
+        pSMB->t2.Flags = 0;
+        pSMB->t2.Timeout = 0;
+        pSMB->t2.Reserved2 = 0;
+        pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(
+                struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+        pSMB->t2.DataCount = 0;
+        pSMB->t2.DataOffset = 0;
+        pSMB->t2.SetupCount = 1;
+        pSMB->t2.Reserved3 = 0;
+        pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+        byte_count = params + 3 /* pad */ ;
+        pSMB->t2.TotalParameterCount = cpu_to_le16(params);
+        pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
+        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
+        pSMB->Pad1 = 0;
+	pSMB->Pad2 = 0;
+	pSMB->Fid = netfid;
+        pSMB->hdr.smb_buf_length += byte_count;
+        pSMB->t2.ByteCount = cpu_to_le16(byte_count);
+
+        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+        if (rc) {
+                cFYI(1, ("error %d in GetExtAttr", rc));
+        } else {
+                /* decode response */
+                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+                if (rc || (pSMBr->ByteCount < 2))
+                /* BB also check enough total bytes returned */
+                        /* If rc should we check for EOPNOSUPP and
+                        disable the srvino flag? or in caller? */
+                        rc = -EIO;      /* bad smb */
+                else {
+                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+                        struct file_chattr_info * pfinfo;
+                        /* BB Do we need a cast or hash here ? */
+                        if(count != 16) {
+                                cFYI(1, ("Illegal size ret in GetExtAttr"));
+                                rc = -EIO;
+                                goto GetExtAttrOut;
+                        }
+                        pfinfo = (struct file_chattr_info *)
+                                (data_offset + (char *) &pSMBr->hdr.Protocol);
+                        *pExtAttrBits = le64_to_cpu(pfinfo->mode);
+			*pMask = le64_to_cpu(pfinfo->mask);
+                }
+        }
+GetExtAttrOut:
+        cifs_buf_release(pSMB);
+        if (rc == -EAGAIN)
+                goto GetExtAttrRetry;
+        return rc;
+}
+
+
+#endif /* CONFIG_POSIX */
 
 int
 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index b4b8e201d428..7b84b2bb8c4a 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -20,6 +20,7 @@
  *   along with this library; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
+
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
 #include "cifspdu.h"
@@ -32,18 +33,63 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
 {
 	int rc = -ENOTTY; /* strange error - but the precedent */
 #ifdef CONFIG_CIFS_POSIX
+	__u64	ExtAttrBits = 0;
+	__u64	ExtAttrMask = 0;
+	__u64   caps;
+#endif /* CONFIG_CIFS_POSIX */
+	int xid;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *tcon;
+	struct cifsFileInfo *pSMBFile =
+		(struct cifsFileInfo *)filep->private_data;
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+	tcon = cifs_sb->tcon;
+	if (pSMBFile == NULL)
+		goto cifs_ioctl_out;
+
+#ifdef CONFIG_CIFS_POSIX
+	if(tcon)
+		caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
+	else {
+		rc = -EIO;
+		goto cifs_ioctl_out;
+	}
+
 	cFYI(1,("ioctl file %p  cmd %u  arg %lu",filep,command,arg));
 	switch(command) {
 		case EXT2_IOC_GETFLAGS:
-			cFYI(1,("get flags not implemented yet"));
-			return -EOPNOTSUPP;
+			if(CIFS_UNIX_EXTATTR_CAP & caps) {
+				rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
+					&ExtAttrBits, &ExtAttrMask);
+				if(rc == 0)
+					rc = put_user(ExtAttrBits &
+						EXT2_FL_USER_VISIBLE,
+						(int __user *)arg);
+			}
+			break;
+
 		case EXT2_IOC_SETFLAGS:
+			if(CIFS_UNIX_EXTATTR_CAP & caps) {
+				if(get_user(ExtAttrBits,(int __user *)arg)) {
+					rc = -EFAULT;
+					goto cifs_ioctl_out;
+				}
+			  /* rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
+					extAttrBits, &ExtAttrMask);*/
+				
+			}
 			cFYI(1,("set flags not implemented yet"));
-			return -EOPNOTSUPP;
+			break;
 		default:
 			cFYI(1,("unsupported ioctl"));
 			return rc;
 	}
 #endif /* CONFIG_CIFS_POSIX */
+
+cifs_ioctl_out:
+	FreeXid(xid);
 	return rc;
 } 
-- 
cgit v1.2.2


From 75cf6bdc52d86ca815f1129529e43f0d904b18d5 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:04 -0700
Subject: [PATCH] cifs: Gracefully turn off serverino (when serverino is
 enabled on mount)

Old servers such as NT4 do not support this level of FindFirst (and
retry with a lower infolevel)

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/netmisc.c | 2 +-
 fs/cifs/readdir.c | 6 ++++++
 2 files changed, 7 insertions(+), 1 deletion(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 4e34c89cec5d..dfaabc8d8fb6 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -206,7 +206,7 @@ static const struct {
 	{
 	ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, {
 	ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, {
-	ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS}, {
+	ERRDOS, ERRinvlevel, NT_STATUS_INVALID_INFO_CLASS}, {
 	ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, {
 	ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, {
 	ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, {
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index f8bea395ec9e..07838a5ba3a1 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -323,6 +323,7 @@ static int initiate_cifs_search(const int xid, struct file *file)
 
 	cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
 
+ffirst_retry:
 	/* test for Unix extensions */
 	if (pTcon->ses->capabilities & CAP_UNIX) {
 		cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; 
@@ -336,6 +337,11 @@ static int initiate_cifs_search(const int xid, struct file *file)
 		&cifsFile->netfid, &cifsFile->srch_inf); 
 	if(rc == 0)
 		cifsFile->invalidHandle = FALSE;
+	if((rc == -EOPNOTSUPP) && 
+		(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
+		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
+		goto ffirst_retry;
+	}
 	kfree(full_path);
 	return rc;
 }
-- 
cgit v1.2.2


From c67593a03129967eae8939c4899767182eb6d6cd Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:04 -0700
Subject: [PATCH] cifs: Enable ioctl support in POSIX extensions to handle
 lsattr

remove sparse warnings, unnecessary pad in QueryFileInfo and redundant
function define.

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/cifsfs.c    |  8 ++++++++
 fs/cifs/cifspdu.h   |  2 --
 fs/cifs/cifsproto.h |  2 --
 fs/cifs/cifssmb.c   | 13 ++++++-------
 fs/cifs/ioctl.c     |  1 +
 5 files changed, 15 insertions(+), 11 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 5082fce3c566..ae48ef042977 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -559,6 +559,10 @@ struct file_operations cifs_file_ops = {
 	.flush = cifs_flush,
 	.mmap  = cifs_file_mmap,
 	.sendfile = generic_file_sendfile,
+#ifdef CONFIG_CIFS_POSIX
+	.ioctl	= cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 	.readv = generic_file_readv,
 	.writev = generic_file_writev,
@@ -579,6 +583,10 @@ struct file_operations cifs_file_direct_ops = {
 	.fsync = cifs_fsync,
 	.flush = cifs_flush,
 	.sendfile = generic_file_sendfile, /* BB removeme BB */
+#ifdef CONFIG_CIFS_POSIX
+	.ioctl  = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 	.dir_notify = cifs_dir_notify,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 085109d2b55e..5b352890f092 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1258,10 +1258,8 @@ struct smb_t2_qfi_req {
         struct	smb_hdr hdr;
         struct	trans2_req t2;
 	__u8	Pad;
-	__u16	Pad1;
 	__u16	Fid;
 	__le16	InformationLevel;
-	__u16	Pad2;
 };
 
 struct smb_t2_qfi_rsp {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 82ae59d7cf9d..1b0070dfc51c 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -266,6 +266,4 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
 		const struct nls_table *nls_codepage);
 extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
-extern int cifs_ioctl (struct inode * inode, struct file * filep,
-                unsigned int command, unsigned long arg);
 #endif			/* _CIFSPROTO_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 36d3c128a58b..237e3bf94bfe 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2093,9 +2093,9 @@ GetExtAttrRetry:
         if (rc)
                 return rc;
 
-        params = 2 /* level */ +2 /* fid */ + 2 /* rsrvd */;
+        params = 2 /* level */ +2 /* fid */;
         pSMB->t2.TotalDataCount = 0;
-        pSMB->t2.MaxParameterCount = cpu_to_le16(2);
+        pSMB->t2.MaxParameterCount = cpu_to_le16(4);
         /* BB find exact max data count below from sess structure BB */
         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
         pSMB->t2.MaxSetupCount = 0;
@@ -2103,19 +2103,18 @@ GetExtAttrRetry:
         pSMB->t2.Flags = 0;
         pSMB->t2.Timeout = 0;
         pSMB->t2.Reserved2 = 0;
-        pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(
-                struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+        pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
+			Fid) - 4);
         pSMB->t2.DataCount = 0;
         pSMB->t2.DataOffset = 0;
         pSMB->t2.SetupCount = 1;
         pSMB->t2.Reserved3 = 0;
         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
-        byte_count = params + 3 /* pad */ ;
+        byte_count = params + 1 /* pad */ ;
         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
-        pSMB->Pad1 = 0;
-	pSMB->Pad2 = 0;
+        pSMB->Pad = 0;
 	pSMB->Fid = netfid;
         pSMB->hdr.smb_buf_length += byte_count;
         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 7b84b2bb8c4a..a4f1c34a8dc7 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -27,6 +27,7 @@
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
+#include "cifsfs.h"
 
 int cifs_ioctl (struct inode * inode, struct file * filep, 
 		unsigned int command, unsigned long arg)
-- 
cgit v1.2.2


From ad009ac96509e005d9978d0ae9e9ec4d63ad2990 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 fs/cifs/CHANGES       |  3 ++-
 fs/cifs/cifsencrypt.c | 16 ++++++++--------
 fs/cifs/cifsglob.h    | 11 ++++++-----
 fs/cifs/cifsproto.h   |  2 +-
 fs/cifs/connect.c     | 28 ++++++++++++++++++++--------
 fs/cifs/transport.c   | 22 +++++++++++++---------
 6 files changed, 50 insertions(+), 32 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 7fd02697b12e..43b3119a16ed 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -5,7 +5,8 @@ transact response for an SMB request and search entry split across two frames.
 Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server)
 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.
+POSIX ACL capability bit. Fix packet signing when multiuser mounting with
+different users from the same client to the same server.
 
 Version 1.31
 ------------
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 78829e7d8cd0..1959c7c4b185 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -50,7 +50,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char
 	return 0;
 }
 
-int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
+int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
 	__u32 * pexpected_response_sequence_number)
 {
 	int rc = 0;
@@ -59,21 +59,21 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
 	/* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */
 	/* BB remember to add code to save expected sequence number in midQ entry BB */
 
-	if((cifs_pdu == NULL) || (ses == NULL))
+	if((cifs_pdu == NULL) || (server == NULL))
 		return -EINVAL;
 
 	if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) 
 		return rc;
 
 	spin_lock(&GlobalMid_Lock);
-	cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number);
+	cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number);
 	cifs_pdu->Signature.Sequence.Reserved = 0;
 	
-	*pexpected_response_sequence_number = ses->sequence_number++;
-	ses->sequence_number++;
+	*pexpected_response_sequence_number = server->sequence_number++;
+	server->sequence_number++;
 	spin_unlock(&GlobalMid_Lock);
 
-	rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature);
+	rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature);
 	if(rc)
 		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
 	else
@@ -190,7 +190,7 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
 	hmac_md5_update((const unsigned char *) unicode_buf,
 		(user_name_len+dom_name_len)*2,&ctx);
 
-	hmac_md5_final(ses->mac_signing_key,&ctx);
+	hmac_md5_final(ses->server->mac_signing_key,&ctx);
 	kfree(ucase_buf);
 	kfree(unicode_buf);
 	return 0;
@@ -200,7 +200,7 @@ void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_respon
 	struct HMACMD5Context context;
 	memcpy(v2_session_response + 8, ses->server->cryptKey,8);
 	/* gen_blob(v2_session_response + 16); */
-	hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context);
+	hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context);
 
 	hmac_md5_update(ses->server->cryptKey,8,&context);
 /*	hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 69aff1a7da9b..1b3082d79379 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -149,6 +149,8 @@ struct TCP_Server_Info {
 	__u16 timeZone;
 	char cryptKey[CIFS_CRYPTO_KEY_SIZE];
 	char workstation_RFC1001_name[16]; /* 16th byte is always zero */
+	__u32 sequence_number; /* needed for CIFS PDU signature */
+	char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; 
 };
 
 /*
@@ -174,17 +176,16 @@ struct cifsSesInfo {
 	struct TCP_Server_Info *server;	/* pointer to server info */
 	atomic_t inUse; /* # of mounts (tree connections) on this ses */
 	enum statusEnum status;
-	__u32 sequence_number;  /* needed for CIFS PDU signature */
 	__u16 ipc_tid;		/* special tid for connection to IPC share */
 	__u16 flags;
-	char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];	
-	char *serverOS;		/* name of operating system underlying the server */
-	char *serverNOS;	/* name of network operating system that the server is running */
+	char *serverOS;		/* name of operating system underlying server */
+	char *serverNOS;	/* name of network operating system of server */
 	char *serverDomain;	/* security realm of server */
 	int Suid;		/* remote smb uid  */
 	uid_t linux_uid;        /* local Linux uid */
 	int capabilities;
-	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */
+	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for 
+				TCP names - will ipv6 and sctp addresses fit? */
 	char userName[MAX_USERNAME_SIZE + 1];
 	char domainName[MAX_USERNAME_SIZE + 1];
 	char * password;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 1b0070dfc51c..dd95c2bcbc25 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -230,7 +230,7 @@ extern void tconInfoFree(struct cifsTconInfo *);
 
 extern int cifs_reconnect(struct TCP_Server_Info *server);
 
-extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *);
+extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
 extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
 	__u32 expected_sequence_number);
 extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
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);
 		}
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index af13e526b150..a9e4f989b7f7 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -346,7 +346,7 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
 	}
 
 	/* BB can we sign efficiently in this path? */
-	rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
+	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
 /*	rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec,
@@ -475,7 +475,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 		return -EIO;
 	}
 
-	rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
+	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
 	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
@@ -559,8 +559,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 	}
   
 	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
-		cERROR(1,
-		       ("Frame too large received.  Length: %d  Xid: %d",
+		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
 			receive_len, xid));
 		rc = -EIO;
 	} else {		/* rcvd frame is ok */
@@ -575,15 +574,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 			dump_smb(out_buf, 92);
 			/* convert the length into a more usable form */
 			if((receive_len > 24) &&
-			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) {
-				rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */
-				if(rc)
-					cFYI(1,("Unexpected signature received from server"));
+			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+					SECMODE_SIGN_ENABLED))) {
+				rc = cifs_verify_signature(out_buf,
+						ses->server->mac_signing_key,
+						midQ->sequence_number+1);
+				if(rc) {
+					cERROR(1,("Unexpected packet signature received from server"));
+					/* BB FIXME - add code to kill session here */
+				}
 			}
 
 			*pbytes_returned = out_buf->smb_buf_length;
 
-			/* BB special case reconnect tid and reconnect uid here? */
+			/* BB special case reconnect tid and uid here? */
 			rc = map_smb_to_linux_error(out_buf);
 
 			/* convert ByteCount if necessary */
-- 
cgit v1.2.2


From cbe0476fa6a76b01b79e7c117963d45ed0a28758 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:05 -0700
Subject: [PATCH] cifs: fix rare oops in cifs_close

Protect access to cifs file list in cifs_close path

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/CHANGES | 3 ++-
 fs/cifs/file.c  | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 43b3119a16ed..ce16b0ae772e 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -6,7 +6,8 @@ Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server)
 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.
+different users from the same client to the same server. Fix oops in
+cifs_close.
 
 Version 1.31
 ------------
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index dcab7cf1b53b..9c7755053099 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -465,8 +465,10 @@ int cifs_close(struct inode *inode, struct file *file)
 				write_lock(&file->f_owner.lock);
 			}
 		}
+		write_lock(&GlobalSMBSeslock);
 		list_del(&pSMBFile->flist);
 		list_del(&pSMBFile->tlist);
+		write_unlock(&GlobalSMBSeslock);
 		write_unlock(&file->f_owner.lock);
 		kfree(pSMBFile->search_resume_name);
 		kfree(file->private_data);
-- 
cgit v1.2.2


From 6a0b48245a135cd132e747815854e3999967f8a7 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 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')

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<num_to_fill) && (rc == 0);i++) {
 			if(current_entry == NULL) {
 				/* evaluate whether this case is an error */
-- 
cgit v1.2.2


From d14537f103bf746ca766f739f9f5a5bf7a8b4806 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:05 -0700
Subject: [PATCH] cifs: remove a few redundant null pointer checks, and cleanup
 misc source formatting

Mostly suggested by Jesper Juhl

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/dir.c    |  83 ++++++++++----------
 fs/cifs/smberr.h | 227 +++++++++++++++++++++++++++++++++++--------------------
 2 files changed, 182 insertions(+), 128 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index f54e1866f0f4..12ba81d7b07f 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -284,51 +284,48 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 			/* mknod case - do not leave file open */
 			CIFSSMBClose(xid, pTcon, fileHandle);
 		} else if(newinode) {
-			pCifsFile = (struct cifsFileInfo *)
+			pCifsFile =
 			   kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
-		
-			if (pCifsFile) {
-				memset((char *)pCifsFile, 0,
-				       sizeof (struct cifsFileInfo));
-				pCifsFile->netfid = fileHandle;
-				pCifsFile->pid = current->tgid;
-				pCifsFile->pInode = newinode;
-				pCifsFile->invalidHandle = FALSE;
-				pCifsFile->closePend     = FALSE;
-				init_MUTEX(&pCifsFile->fh_sem);
-				/* put the following in at open now */
-				/* pCifsFile->pfile = file; */ 
-				write_lock(&GlobalSMBSeslock);
-				list_add(&pCifsFile->tlist,&pTcon->openFileList);
-				pCifsInode = CIFS_I(newinode);
-				if(pCifsInode) {
+			
+			if(pCifsFile == NULL)
+				goto cifs_create_out;
+			memset((char *)pCifsFile, 0,
+			       sizeof (struct cifsFileInfo));
+			pCifsFile->netfid = fileHandle;
+			pCifsFile->pid = current->tgid;
+			pCifsFile->pInode = newinode;
+			pCifsFile->invalidHandle = FALSE;
+			pCifsFile->closePend     = FALSE;
+			init_MUTEX(&pCifsFile->fh_sem);
+			/* set the following in open now 
+				pCifsFile->pfile = file; */
+			write_lock(&GlobalSMBSeslock);
+			list_add(&pCifsFile->tlist,&pTcon->openFileList);
+			pCifsInode = CIFS_I(newinode);
+			if(pCifsInode) {
 				/* if readable file instance put first in list*/
-					if (write_only == TRUE) {
-                                        	list_add_tail(&pCifsFile->flist,
-							&pCifsInode->openFileList);
-					} else {
-						list_add(&pCifsFile->flist,
-							&pCifsInode->openFileList);
-					}
-					if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-						pCifsInode->clientCanCacheAll = TRUE;
-						pCifsInode->clientCanCacheRead = TRUE;
-						cFYI(1,("Exclusive Oplock granted on inode %p",
-							newinode));
-					} else if((oplock & 0xF) == OPLOCK_READ)
-						pCifsInode->clientCanCacheRead = TRUE;
+				if (write_only == TRUE) {
+                                       	list_add_tail(&pCifsFile->flist,
+						&pCifsInode->openFileList);
+				} else {
+					list_add(&pCifsFile->flist,
+						&pCifsInode->openFileList);
 				}
-				write_unlock(&GlobalSMBSeslock);
+				if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+					pCifsInode->clientCanCacheAll = TRUE;
+					pCifsInode->clientCanCacheRead = TRUE;
+					cFYI(1,("Exclusive Oplock for inode %p",
+						newinode));
+				} else if((oplock & 0xF) == OPLOCK_READ)
+					pCifsInode->clientCanCacheRead = TRUE;
 			}
+			write_unlock(&GlobalSMBSeslock);
 		}
 	} 
-
-	if (buf)
-	    kfree(buf);
-	if (full_path)
-	    kfree(full_path);
+cifs_create_out:
+	kfree(buf);
+	kfree(full_path);
 	FreeXid(xid);
-
 	return rc;
 }
 
@@ -375,10 +372,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
 		}
 	}
 
-	if (full_path)
-		kfree(full_path);
+	kfree(full_path);
 	FreeXid(xid);
-
 	return rc;
 }
 
@@ -447,8 +442,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
 		if file exists or not but no access BB */
 	}
 
-	if (full_path)
-		kfree(full_path);
+	kfree(full_path);
 	FreeXid(xid);
 	return ERR_PTR(rc);
 }
@@ -478,8 +472,7 @@ cifs_dir_open(struct inode *inode, struct file *file)
 
 	cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path));
 
-	if (full_path)
-		kfree(full_path);
+	kfree(full_path);
 	FreeXid(xid);
 	return rc;
 }
diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h
index e21f1384661f..1b53dcd0f2eb 100644
--- a/fs/cifs/smberr.h
+++ b/fs/cifs/smberr.h
@@ -22,94 +22,155 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
  */
 
-#define SUCCESS 0		/* The request was successful. */
-#define ERRDOS 0x01		/* Error is from the core DOS operating system set */
-#define ERRSRV 0x02		/* Error is generated by the file server daemon */
-#define ERRHRD 0x03		/* Error is a hardware error. */
-#define ERRCMD 0xFF		/*  Command was not in the "SMB" format. */
+#define SUCCESS	0x00	/* The request was successful. */
+#define ERRDOS	0x01	/* Error is from the core DOS operating system set */
+#define ERRSRV	0x02	/* Error is generated by the file server daemon */
+#define ERRHRD	0x03	/* Error is a hardware error. */
+#define ERRCMD	0xFF	/* Command was not in the "SMB" format. */
 
 /* The following error codes may be generated with the SUCCESS error class.*/
 
-#define SUCCESS 0		/* The request was successful. */
+/*#define SUCCESS	0	The request was successful. */
 
 /* The following error codes may be generated with the ERRDOS error class.*/
 
-#define ERRbadfunc 1		/* Invalid function. The server did not recognize or could not perform a system call generated by the server, e.g., set the DIRECTORY attribute on a data file, invalid seek mode. */
-#define ERRbadfile 2		/*File not found. The last component of a file's pathname could not be found. */
-#define ERRbadpath 3		/* Directory invalid. A directory component in a pathname could not be found. */
-#define ERRnofids 4		/* Too many open files. The server has no file handles available. */
-#define ERRnoaccess 5		/* Access denied, the client's context does not permit the requested function. This includes the following conditions: invalid rename command, write to Fid open for read only, read on Fid open for write only, attempt to delete a non-empty directory */
-#define ERRbadfid 6		/* Invalid file handle. The file handle specified was not recognized by the server. */
-#define ERRbadmcb 7		/* Memory control blocks destroyed. */
-#define ERRnomem 8		/* Insufficient server memory to perform the requested function. */
-#define ERRbadmem 9		/* Invalid memory block address. */
-#define ERRbadenv 10		/* Invalid environment. */
-#define ERRbadformat 11		/* Invalid format. */
-#define ERRbadaccess 12		/* Invalid open mode. */
-#define ERRbaddata 13		/* Invalid data (generated only by IOCTL calls within the server). */
-#define ERRbaddrive 15		/* Invalid drive specified. */
-#define ERRremcd 16		/* A Delete Directory request attempted to remove the server's current directory. */
-#define ERRdiffdevice 17	/* Not same device (e.g., a cross volume rename was attempted */
-#define ERRnofiles 18		/* A File Search command can find no more files matching the specified criteria. */
-#define ERRgeneral 31
-#define ERRbadshare 32		/* The sharing mode specified for an Open conflicts with existing FIDs on the file. */
-#define ERRlock 33		/* A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process. */
-#define ERRunsup     50
-#define ERRnosuchshare 67
-#define ERRfilexists 80		/* The file named in the request already exists. */
-#define ERRinvparm   87
-#define ERRdiskfull  112
-#define ERRinvname   123
-#define ERRinvlevel  124
-#define ERRdirnotempty 145
-#define ERRnotlocked   158
-#define ERRalreadyexists 183
-#define ERRbadpipe 230
-#define ERRpipebusy 231
-#define ERRpipeclosing 232
-#define ERRnotconnected 233
-#define ERRmoredata    234
-#define ERReasnotsupported 282
-#define ErrQuota 0x200		/* The operation would cause a quota limit to be exceeded. */
-#define ErrNotALink 0x201	/* A link operation was performed on a pathname that
-				   was not a link. */
+#define ERRbadfunc		1	/* Invalid function. The server did not
+					   recognize or could not perform a
+					   system call generated by the server,
+					   e.g., set the DIRECTORY attribute on
+					   a data file, invalid seek mode. */
+#define ERRbadfile		2	/* File not found. The last component
+					   of a file's pathname could not be
+					   found. */
+#define ERRbadpath		3	/* Directory invalid. A directory
+					   component in a pathname could not be
+					   found. */
+#define ERRnofids		4	/* Too many open files. The server has
+					   no file handles available. */
+#define ERRnoaccess		5	/* Access denied, the client's context
+					   does not permit the requested
+					   function. This includes the
+					   following conditions: invalid rename
+					   command, write to Fid open for read
+					   only, read on Fid open for write
+					   only, attempt to delete a non-empty
+					   directory */
+#define ERRbadfid		6	/* Invalid file handle. The file handle
+					   specified was not recognized by the
+					   server. */
+#define ERRbadmcb		7	/* Memory control blocks destroyed. */
+#define ERRnomem		8	/* Insufficient server memory to
+					   perform the requested function. */
+#define ERRbadmem		9	/* Invalid memory block address. */
+#define ERRbadenv		10	/* Invalid environment. */
+#define ERRbadformat		11	/* Invalid format. */
+#define ERRbadaccess		12	/* Invalid open mode. */
+#define ERRbaddata		13	/* Invalid data (generated only by
+					   IOCTL calls within the server). */
+#define ERRbaddrive		15	/* Invalid drive specified. */
+#define ERRremcd		16	/* A Delete Directory request attempted
+					   to remove the server's current
+					   directory. */
+#define ERRdiffdevice		17	/* Not same device (e.g., a cross
+					   volume rename was attempted */
+#define ERRnofiles		18	/* A File Search command can find no
+					   more files matching the specified
+					   criteria. */
+#define ERRgeneral		31
+#define ERRbadshare		32	/* The sharing mode specified for an
+					   Open conflicts with existing FIDs on
+					   the file. */
+#define ERRlock			33	/* A Lock request conflicted with an
+					   existing lock or specified an
+					   invalid mode, or an Unlock requested
+					   attempted to remove a lock held by
+					   another process. */
+#define ERRunsup		50
+#define ERRnosuchshare		67
+#define ERRfilexists		80	/* The file named in the request
+					   already exists. */
+#define ERRinvparm		87
+#define ERRdiskfull		112
+#define ERRinvname		123
+#define ERRinvlevel		124
+#define ERRdirnotempty		145
+#define ERRnotlocked		158
+#define ERRalreadyexists	183
+#define ERRbadpipe		230
+#define ERRpipebusy		231
+#define ERRpipeclosing		232
+#define ERRnotconnected		233
+#define ERRmoredata		234
+#define ERReasnotsupported	282
+#define ErrQuota		0x200	/* The operation would cause a quota
+					   limit to be exceeded. */
+#define ErrNotALink		0x201	/* A link operation was performed on a
+					   pathname that was not a link. */
 
-/* Following error codes may be generated with the ERRSRV error
-class.*/
+/* Following error codes may be generated with the ERRSRV error class.*/
 
-#define ERRerror 1		/* Non-specific error code. It is returned under the following conditions: resource other than disk space exhausted (e.g. TIDs), first SMB command was not negotiate, multiple negotiates attempted, and internal server error. */
-#define ERRbadpw 2		/* Bad password - name/password pair in a TreeConnect or Session Setup are invalid. */
-#define ERRbadtype 3		/* used for indicating DFS referral needed */
-#define ERRaccess 4		/* The client does not have the necessary access rights within the specified context for requested function. */
-#define ERRinvtid 5		/* The Tid specified in a command was invalid. */
-#define ERRinvnetname 6		/* Invalid network name in tree connect. */
-#define ERRinvdevice 7		/* Invalid device - printer request made to non-printer connection or non-printer request made to printer connection. */
-#define ERRqfull 49		/* Print queue full (files) -- returned by open print file. */
-#define ERRqtoobig 50		/* Print queue full -- no space. */
-#define ERRqeof         51	/* EOF on print queue dump */
-#define ERRinvpfid      52	/* Invalid print file FID. */
-#define ERRsmbcmd       64	/* The server did not recognize the command received. */
-#define ERRsrverror     65	/* The server encountered an internal error, e.g., system file unavailable. */
-#define ERRbadBID       66	/* (obsolete) */
-#define ERRfilespecs    67	/* The Fid and pathname parameters contained an invalid combination of values. */
-#define ERRbadLink      68	/* (obsolete) */
-#define ERRbadpermits   69	/* The access permissions specified for a file or directory are not a valid combination. */
-#define ERRbadPID       70
-#define ERRsetattrmode  71	/* attribute (mode) is invalid */
-#define ERRpaused       81	/* Server is paused */
-#define ERRmsgoff	82	/* reserved - messaging off */
-#define ERRnoroom       83	/* reserved - no room for message */
-#define ERRrmuns        87	/* reserved - too many remote names */
-#define ERRtimeout      88	/* operation timed out */
-#define ERRnoresource   89	/* No resources available for request */
-#define ERRtoomanyuids  90	/* Too many UIDs active on this session */
-#define ERRbaduid       91	/* The UID is not known as a valid user */
-#define ERRusempx      250	/* temporarily unable to use raw */
-#define ERRusestd      251	/* temporarily unable to use either raw or mpx */
-#define ERR_NOTIFY_ENUM_DIR 1024
-#define ERRaccountexpired 2239
-#define ERRbadclient      2240
-#define ERRbadLogonTime   2241
-#define ERRpasswordExpired 2242
-#define ERRnetlogonNotStarted 2455
-#define ERRnosupport       0xFFFF
+#define ERRerror		1	/* Non-specific error code. It is
+					   returned under the following
+					   conditions: resource other than disk
+					   space exhausted (e.g. TIDs), first
+					   SMB command was not negotiate,
+					   multiple negotiates attempted, and
+					   internal server error. */
+#define ERRbadpw		2	/* Bad password - name/password pair in
+					   a TreeConnect or Session Setup are
+					   invalid. */
+#define ERRbadtype		3	/* used for indicating DFS referral
+					   needed */
+#define ERRaccess		4	/* The client does not have the
+					   necessary access rights within the
+					   specified context for requested
+					   function. */
+#define ERRinvtid		5	/* The Tid specified in a command was
+					   invalid. */
+#define ERRinvnetname		6	/* Invalid network name in tree
+					   connect. */
+#define ERRinvdevice		7	/* Invalid device - printer request
+					   made to non-printer connection or
+					   non-printer request made to printer
+					   connection. */
+#define ERRqfull		49	/* Print queue full (files) -- returned
+					   by open print file. */
+#define ERRqtoobig		50	/* Print queue full -- no space. */
+#define ERRqeof			51	/* EOF on print queue dump */
+#define ERRinvpfid		52	/* Invalid print file FID. */
+#define ERRsmbcmd		64	/* The server did not recognize the
+					   command received. */
+#define ERRsrverror		65	/* The server encountered an internal
+					   error, e.g., system file
+					   unavailable. */
+#define ERRbadBID		66	/* (obsolete) */
+#define ERRfilespecs		67	/* The Fid and pathname parameters
+					   contained an invalid combination of
+					   values. */
+#define ERRbadLink		68	/* (obsolete) */
+#define ERRbadpermits		69	/* The access permissions specified for
+					   a file or directory are not a valid
+					   combination. */
+#define ERRbadPID		70
+#define ERRsetattrmode		71	/* attribute (mode) is invalid */
+#define ERRpaused		81	/* Server is paused */
+#define ERRmsgoff		82	/* reserved - messaging off */
+#define ERRnoroom		83	/* reserved - no room for message */
+#define ERRrmuns		87	/* reserved - too many remote names */
+#define ERRtimeout		88	/* operation timed out */
+#define ERRnoresource		89	/* No resources available for request
+					   */
+#define ERRtoomanyuids		90	/* Too many UIDs active on this session
+					   */
+#define ERRbaduid		91	/* The UID is not known as a valid user
+					   */
+#define ERRusempx		250	/* temporarily unable to use raw */
+#define ERRusestd		251	/* temporarily unable to use either raw
+					   or mpx */
+#define ERR_NOTIFY_ENUM_DIR	1024
+#define ERRaccountexpired	2239
+#define ERRbadclient		2240
+#define ERRbadLogonTime		2241
+#define ERRpasswordExpired	2242
+#define ERRnetlogonNotStarted	2455
+#define ERRnosupport		0xFFFF
-- 
cgit v1.2.2


From 6c91d362f1e1ebbd4513adb68fc79d552c11e2c0 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:06 -0700
Subject: [PATCH] cifs: finish up of special character mapping capable unicode
 conversion routine part 2 of 3

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/cifs_debug.c   | 10 ++++---
 fs/cifs/cifs_unicode.c |  4 +--
 fs/cifs/misc.c         | 80 ++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 83 insertions(+), 11 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index db28b561cd4b..e7bd93e6226d 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -29,6 +29,7 @@
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
+#include "cifsfs.h"
 
 void
 cifs_dump_mem(char *label, void *data, int length)
@@ -78,8 +79,9 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 		    "Display Internal CIFS Data Structures for Debugging\n"
 		    "---------------------------------------------------\n");
 	buf += length;
-
-	length = sprintf(buf, "Servers:\n");
+	length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION);
+	buf += length;
+	length = sprintf(buf, "Servers:");
 	buf += length;
 
 	i = 0;
@@ -100,7 +102,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 				ses->server->secMode,
 				atomic_read(&ses->server->inFlight));
 			
-			length = sprintf(buf, "\nMIDs: \n");
+			length = sprintf(buf, "\nMIDs:\n");
 			buf += length;
 
 			spin_lock(&GlobalMid_Lock);
@@ -121,7 +123,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 	sprintf(buf, "\n");
 	buf++;
 
-	length = sprintf(buf, "\nShares:\n");
+	length = sprintf(buf, "Shares:");
 	buf += length;
 
 	i = 0;
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index a17adf4cb9ba..99a096d3f84d 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -76,8 +76,8 @@ cifs_strtoUCS(wchar_t * to, const char *from, int len,
 				charlen));
 			to[i] = cpu_to_le16(0x003f);	/* a question mark */
 			charlen = 1;
-		}
-		to[i] = cpu_to_le16(to[i]);
+		} else 
+			to[i] = cpu_to_le16(to[i]);
 
 	}
 
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index f2a026073b62..6d7bb427e4fa 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -28,6 +28,7 @@
 #include "cifs_debug.h"
 #include "smberr.h"
 #include "nterr.h"
+#include "cifs_unicode.h"
 
 extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
@@ -515,7 +516,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
 	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 */
@@ -552,9 +552,12 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
 			case UNI_QUESTION:
 				target[j] = '?';
 				break;
-			case UNI_SLASH:
-				target[j] = '\\'; /* BB check this - is there risk here of converting path sep BB */
-				break;
+			/* BB We can not handle remapping slash until
+			   all the calls to build_path_from_dentry
+			   are modified, as they use slash as separator BB */
+			/* case UNI_SLASH:
+				target[j] = '\\';
+				break;*/
 			case UNI_PIPE:
 				target[j] = '|';
 				break;
@@ -582,4 +585,71 @@ cUCS_out:
 	target[j] = 0;
 	return j;
 }
-#endif /* CIFS_EXPERIMENTAL */
+
+/* Convert 16 bit Unicode pathname to wire format from 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
+cifsConvertToUCS(__le16 * target, const char *source, int maxlen, 
+		 const struct nls_table * cp, int mapChars)
+{
+	int i,j,charlen;
+	int len_remaining = maxlen;
+	char src_char;
+
+	if(!mapChars) 
+		return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp);	
+
+	for(i = 0, j = 0; i < maxlen; j++) {
+		src_char = source[i];
+		switch (src_char) {
+			case 0:
+				goto ctoUCS_out;
+			case ':':
+				target[j] = cpu_to_le16(UNI_COLON);
+				break;
+			case '*':
+				target[j] = cpu_to_le16(UNI_ASTERIK);
+				break;
+			case '?':
+				target[j] = cpu_to_le16(UNI_QUESTION);
+				break;
+			case '<':
+				target[j] = cpu_to_le16(UNI_LESSTHAN);
+				break;
+			case '>':
+				target[j] = cpu_to_le16(UNI_GRTRTHAN);
+				break;
+			case '|':
+				target[j] = cpu_to_le16(UNI_PIPE);
+				break;			
+			/* BB We can not handle remapping slash until
+			   all the calls to build_path_from_dentry
+			   are modified, as they use slash as separator BB */
+			/* case '\\':
+				target[j] = cpu_to_le16(UNI_SLASH);
+				break;*/
+			default:
+				charlen = cp->char2uni(source+i,
+					len_remaining, target+j);
+				/* if no match, use question mark, which
+				at least in some cases servers as wild card */
+				if(charlen < 1) {
+					target[j] = cpu_to_le16(0x003f);
+					charlen = 1;
+				}
+				len_remaining -= charlen;
+				/* character may take more than one byte in the
+				   the source string, but will take exactly two
+				   bytes in the target string */
+				i+= charlen;
+				continue;
+		}
+		i++; /* move to next char in source string */
+		len_remaining--;
+	}
+
+ctoUCS_out:
+	return i;
+}
-- 
cgit v1.2.2


From 737b758c965a9b223ac1243ab38d9e507ac86c64 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 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')

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.2


From d0724714fd49aeec1383b94807174de7e96021bf Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:06 -0700
Subject: [PATCH] cifs: Fix PPC64 compile error

.. and do not double endian convert the special characters whem mounted
with mapchars mount parm.

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/misc.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 6d7bb427e4fa..75fd3bd6e233 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -519,13 +519,13 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
 /* 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)
+#define UNI_ASTERIK     (__u16) ('*' + 0xF000)
+#define UNI_QUESTION    (__u16) ('?' + 0xF000)
+#define UNI_COLON       (__u16) (':' + 0xF000)
+#define UNI_GRTRTHAN    (__u16) ('>' + 0xF000)
+#define UNI_LESSTHAN    (__u16) ('<' + 0xF000)
+#define UNI_PIPE        (__u16) ('|' + 0xF000)
+#define UNI_SLASH       (__u16) ('\\' + 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
@@ -536,7 +536,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
 		    const struct nls_table * cp)
 {
 	int i,j,len;
-	wchar_t src_char;
+	__u16 src_char;
 
 	for(i = 0, j = 0; i < maxlen; i++) {
 		src_char = le16_to_cpu(source[i]);
-- 
cgit v1.2.2


From 848f3fce45d2ba93e10b5e9d65bcae0d9269ad0d Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 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')

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<num_pages-1;i++
 	unsigned len = smb_buf_length + 4;
 
 	if(ssocket == NULL)
-- 
cgit v1.2.2


From f28ac91b0541a49d5bc7bfb9f0efd5289a7dd181 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:07 -0700
Subject: [PATCH] cifs: CIFS ioctl needed by umount.cifs utility

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/cifsfs.c  |  4 ++++
 fs/cifs/cifspdu.h |  2 +-
 fs/cifs/ioctl.c   | 31 +++++++++++++++++++++++--------
 3 files changed, 28 insertions(+), 9 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 3d5365b9f5ba..461a706b237b 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -190,6 +190,7 @@ 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 */
+/* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */
     if (pTcon->ses->capabilities & CAP_UNIX)
 	    rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf);
 
@@ -599,6 +600,9 @@ struct file_operations cifs_dir_ops = {
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 	.dir_notify = cifs_dir_notify,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
+#ifdef CONFIG_CIFS_POSIX
+        .ioctl  = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
 };
 
 static void
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 5b352890f092..e3e92615705e 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1556,7 +1556,7 @@ typedef struct {
 #define CIFS_UNIX_POSIX_ACL_CAP         0x00000002 /* support getfacl/setfacl */
 #define CIFS_UNIX_XATTR_CAP             0x00000004 /* support new namespace   */
 #define CIFS_UNIX_EXTATTR_CAP           0x00000008 /* support chattr/chflag   */
-
+#define CIFS_POSIX_EXTENSIONS           0x00000010 /* support for new QFSInfo */
 typedef struct {
 	/* For undefined recommended transfer size return -1 in that field */
 	__le32 OptimalTransferSize;  /* bsize on some os, iosize on other os */
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index a4f1c34a8dc7..711bb7a3a98e 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -29,6 +29,8 @@
 #include "cifs_debug.h"
 #include "cifsfs.h"
 
+#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
+
 int cifs_ioctl (struct inode * inode, struct file * filep, 
 		unsigned int command, unsigned long arg)
 {
@@ -36,8 +38,8 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
 #ifdef CONFIG_CIFS_POSIX
 	__u64	ExtAttrBits = 0;
 	__u64	ExtAttrMask = 0;
-	__u64   caps;
 #endif /* CONFIG_CIFS_POSIX */
+	__u64   caps;
 	int xid;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *tcon;
@@ -46,12 +48,11 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
 
 	xid = GetXid();
 
+        cFYI(1,("ioctl file %p  cmd %u  arg %lu",filep,command,arg));
+
 	cifs_sb = CIFS_SB(inode->i_sb);
 	tcon = cifs_sb->tcon;
-	if (pSMBFile == NULL)
-		goto cifs_ioctl_out;
 
-#ifdef CONFIG_CIFS_POSIX
 	if(tcon)
 		caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
 	else {
@@ -59,10 +60,22 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
 		goto cifs_ioctl_out;
 	}
 
-	cFYI(1,("ioctl file %p  cmd %u  arg %lu",filep,command,arg));
 	switch(command) {
+		case CIFS_IOC_CHECKUMOUNT:
+			cFYI(1,("User unmount attempted"));
+			/* BB FIXME - add missing code here FIXME */
+			if(cifs_sb->mnt_uid == current->uid)
+				rc = 0;
+			else {
+				rc = -EACCES;
+				cFYI(1,("uids do not match"));
+			}
+			break;
+#ifdef CONFIG_CIFS_POSIX
 		case EXT2_IOC_GETFLAGS:
 			if(CIFS_UNIX_EXTATTR_CAP & caps) {
+				if (pSMBFile == NULL)
+					goto cifs_ioctl_out;
 				rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
 					&ExtAttrBits, &ExtAttrMask);
 				if(rc == 0)
@@ -78,17 +91,19 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
 					rc = -EFAULT;
 					goto cifs_ioctl_out;
 				}
-			  /* rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
+				if (pSMBFile == NULL)
+					goto cifs_ioctl_out;
+				/* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
 					extAttrBits, &ExtAttrMask);*/
 				
 			}
 			cFYI(1,("set flags not implemented yet"));
 			break;
+#endif /* CONFIG_CIFS_POSIX */
 		default:
 			cFYI(1,("unsupported ioctl"));
-			return rc;
+			break;
 	}
-#endif /* CONFIG_CIFS_POSIX */
 
 cifs_ioctl_out:
 	FreeXid(xid);
-- 
cgit v1.2.2


From c81156dd217818c143a09b6a744e797a04571e99 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:07 -0700
Subject: [PATCH] cifs: cleanup of ifdefs usage so it is more consistent

And fix to not needlessly send new POSIX QFSInfo when server does not
explicitly claim support for the new protocol extensions.

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/cifsfs.c   | 21 +++++++++++----------
 fs/cifs/cifsglob.h |  4 +++-
 fs/cifs/ioctl.c    | 21 +++++++++++----------
 3 files changed, 25 insertions(+), 21 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 461a706b237b..6322aada491f 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -169,7 +169,8 @@ cifs_put_super(struct super_block *sb)
 static int
 cifs_statfs(struct super_block *sb, struct kstatfs *buf)
 {
-	int xid, rc = -EOPNOTSUPP;
+	int xid; 
+	int rc = -EOPNOTSUPP;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 
@@ -181,17 +182,18 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
 	buf->f_type = CIFS_MAGIC_NUMBER;
 
 	/* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */
-	buf->f_namelen = PATH_MAX;	/* PATH_MAX may be too long - it would presumably
-					   be length of total path, note that some servers may be 
-					   able to support more than this, but best to be safe
-					   since Win2k and others can not handle very long filenames */
+	buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would 
+				      presumably be total path, but note
+				      that some servers (includinng Samba 3)
+				      have a shorter maximum path */
 	buf->f_files = 0;	/* undefined */
 	buf->f_ffree = 0;	/* unlimited */
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 /* BB we could add a second check for a QFS Unix capability bit */
 /* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */
-    if (pTcon->ses->capabilities & CAP_UNIX)
+    if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS &
+			le64_to_cpu(pTcon->fsUnixInfo.Capability)))
 	    rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf);
 
     /* Only need to call the old QFSInfo if failed
@@ -204,9 +206,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
 	   int f_type;
 	   __fsid_t f_fsid;
 	   int f_namelen;  */
-	/* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */
+	/* BB get from info in tcon struct at mount time call to QFSAttrInfo */
 	FreeXid(xid);
-	return 0;		/* always return success? what if volume is no longer available? */
+	return 0;		/* always return success? what if volume is no
+				   longer available? */
 }
 
 static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd)
@@ -600,9 +603,7 @@ struct file_operations cifs_dir_ops = {
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 	.dir_notify = cifs_dir_notify,
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
-#ifdef CONFIG_CIFS_POSIX
         .ioctl  = cifs_ioctl,
-#endif /* CONFIG_CIFS_POSIX */
 };
 
 static void
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index fe1409799513..322a12450ad3 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -318,7 +318,9 @@ struct mid_q_entry {
 	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 */
+	__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 */
 };
 
 struct oplock_q_entry {
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 711bb7a3a98e..b0ea6687ab55 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -35,35 +35,37 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
 		unsigned int command, unsigned long arg)
 {
 	int rc = -ENOTTY; /* strange error - but the precedent */
+	int xid;
+	struct cifs_sb_info *cifs_sb;
 #ifdef CONFIG_CIFS_POSIX
 	__u64	ExtAttrBits = 0;
 	__u64	ExtAttrMask = 0;
-#endif /* CONFIG_CIFS_POSIX */
 	__u64   caps;
-	int xid;
-	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *tcon;
 	struct cifsFileInfo *pSMBFile =
 		(struct cifsFileInfo *)filep->private_data;
+#endif /* CONFIG_CIFS_POSIX */
 
 	xid = GetXid();
 
         cFYI(1,("ioctl file %p  cmd %u  arg %lu",filep,command,arg));
 
 	cifs_sb = CIFS_SB(inode->i_sb);
-	tcon = cifs_sb->tcon;
 
+#ifdef CONFIG_CIFS_POSIX
+	tcon = cifs_sb->tcon;
 	if(tcon)
 		caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
 	else {
 		rc = -EIO;
-		goto cifs_ioctl_out;
+		FreeXid(xid);
+		return -EIO;
 	}
+#endif /* CONFIG_CIFS_POSIX */
 
 	switch(command) {
 		case CIFS_IOC_CHECKUMOUNT:
 			cFYI(1,("User unmount attempted"));
-			/* BB FIXME - add missing code here FIXME */
 			if(cifs_sb->mnt_uid == current->uid)
 				rc = 0;
 			else {
@@ -75,7 +77,7 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
 		case EXT2_IOC_GETFLAGS:
 			if(CIFS_UNIX_EXTATTR_CAP & caps) {
 				if (pSMBFile == NULL)
-					goto cifs_ioctl_out;
+					break;
 				rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
 					&ExtAttrBits, &ExtAttrMask);
 				if(rc == 0)
@@ -89,10 +91,10 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
 			if(CIFS_UNIX_EXTATTR_CAP & caps) {
 				if(get_user(ExtAttrBits,(int __user *)arg)) {
 					rc = -EFAULT;
-					goto cifs_ioctl_out;
+					break;
 				}
 				if (pSMBFile == NULL)
-					goto cifs_ioctl_out;
+					break;
 				/* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
 					extAttrBits, &ExtAttrMask);*/
 				
@@ -105,7 +107,6 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
 			break;
 	}
 
-cifs_ioctl_out:
 	FreeXid(xid);
 	return rc;
 } 
-- 
cgit v1.2.2


From b8643e1b5253a6a51da5574a55a2f9148e255cfd Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 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')

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 <linux/ctype.h>
 #include <linux/utsname.h>
 #include <linux/mempool.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #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.2


From 099a58f681ed951434574ec39bdfe87055bafe73 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 fs/cifs/CHANGES   |  6 +++++-
 fs/cifs/README    | 19 ++++++++++++++++++-
 fs/cifs/connect.c |  4 ++++
 3 files changed, 27 insertions(+), 2 deletions(-)

(limited to 'fs/cifs')

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.2


From 433dc24f24b409fb130f638aa85470a0eb666206 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 fs/cifs/cifs_debug.c |  15 +++++--
 fs/cifs/connect.c    | 124 ++++++++++++++++++++++++++++-----------------------
 2 files changed, 80 insertions(+), 59 deletions(-)

(limited to 'fs/cifs')

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;i<temp_len;i++,j++) {
 					vol->password[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.2


From 966ca9234754ece58870075972ef103e354de075 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:08 -0700
Subject: [PATCH] cifs: Fix caching problem

pointed out by Dave Stahl and Vince Negri in which cifs can update the
last modify time on a server modified file without invalidating the
local cached data due to an intervening readdir.

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/AUTHORS   | 24 ++++++++++++-------
 fs/cifs/CHANGES   |  8 +++++++
 fs/cifs/cifsfs.h  |  4 ++--
 fs/cifs/cifssmb.c |  2 +-
 fs/cifs/readdir.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-----------
 5 files changed, 83 insertions(+), 25 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS
index acce36e25d2e..72fdc10dfdd7 100644
--- a/fs/cifs/AUTHORS
+++ b/fs/cifs/AUTHORS
@@ -4,13 +4,16 @@ Steve French (sfrench@samba.org)
 
 The author wishes to express his appreciation and thanks to:
 Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS
-improvements. Thanks to IBM for allowing me the time and test resources to pursue
-this project. Jim McDonough from IBM (and the Samba Team) for his help.
-The IBM Linux JFS team for explaining many esoteric Linux filesystem features.
+improvements. Thanks to IBM for allowing me time and test resources to pursue
+this project, to Jim McDonough from IBM (and the Samba Team) for his help, to
+the IBM Linux JFS team for explaining many esoteric Linux filesystem features.
+Jeremy Allison of the Samba team has done invaluable work in adding the server
+side of the original CIFS Unix extensions and reviewing and implementing
+portions of the newer CIFS POSIX extensions into the Samba 3 file server. Thank
 Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client)
-for proving years ago that a very good smb/cifs client could be done on a Unix like 
-operating system.  Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin 
-and others for their work on the Linux smbfs module over the years. Thanks to
+for proving years ago that very good smb/cifs clients could be done on Unix-like
+operating systems.  Volker Lendecke, Andrew Tridgell, Urban Widmark, John 
+Newbigin and others for their work on the Linux smbfs module.  Thanks to
 the other members of the Storage Network Industry Association CIFS Technical
 Workgroup for their work specifying this highly complex protocol and finally
 thanks to the Samba team for their technical advice and encouragement.
@@ -24,9 +27,11 @@ Shobhit Dayal
 Sergey Vlasov
 Richard Hughes
 Yury Umanets
-Mark Hamzy
+Mark Hamzy (for some of the early cifs IPv6 work)
 Domen Puncer
-Jesper Juhl
+Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
+Vince Negri and Dave Stahl (for finding an important caching bug)
+Adrian Bunk (kcalloc cleanups)
 
 Test case and Bug Report contributors
 -------------------------------------
@@ -36,7 +41,8 @@ Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori,
 Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen,
 Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special
 mention to the Stanford Checker (SWAT) which pointed out many minor
-bugs in error paths.
+bugs in error paths.  Valuable suggestions also have come from Al Viro
+and Dave Miller.
 
 And thanks to the IBM LTC and Power test teams and SuSE testers for
 finding multiple bugs during excellent stress test runs.
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index be3a57509e60..0414eb325468 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,11 @@
+Version 1.33
+------------
+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).
+
+
 Version 1.32
 ------------
 Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index e0e46f4bff97..8f742796a627 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsfs.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002
+ *   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
@@ -96,5 +96,5 @@ extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
 extern int cifs_ioctl (struct inode * inode, struct file * filep,
 		       unsigned int command, unsigned long arg);
-#define CIFS_VERSION   "1.32"
+#define CIFS_VERSION   "1.33"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index f7c4914c3dd9..b102ddb977ca 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -464,7 +464,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
 	rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
 			 &length, 0);
 	if (rc)
-		cFYI(1, (" Tree disconnect failed %d", rc));
+		cFYI(1, ("Tree disconnect failed %d", rc));
 
 	if (smb_buffer)
 		cifs_small_buf_release(smb_buffer);
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 7ca876b6f2ab..39170cffcad8 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -3,7 +3,7 @@
  *
  *   Directory search handling
  * 
- *   Copyright (C) International Business Machines  Corp., 2004
+ *   Copyright (C) International Business Machines  Corp., 2004, 2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -65,14 +65,14 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
 	struct cifsTconInfo *pTcon;
 	int rc = 0;
 
-	cFYI(1, ("For %s ", qstring->name));
+	cFYI(1, ("For %s", qstring->name));
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
 
 	qstring->hash = full_name_hash(qstring->name, qstring->len);
 	tmp_dentry = d_lookup(file->f_dentry, qstring);
 	if (tmp_dentry) {
-		cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode));
+		cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode));
 		*ptmp_inode = tmp_dentry->d_inode;
 /* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
 		if(*ptmp_inode == NULL) {
@@ -105,8 +105,11 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
 }
 
 static void fill_in_inode(struct inode *tmp_inode,
-	FILE_DIRECTORY_INFO *pfindData, int *pobject_type)
+	FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode)
 {
+	loff_t local_size;
+	struct timespec local_mtime;
+
 	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
 	__u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
@@ -116,6 +119,10 @@ static void fill_in_inode(struct inode *tmp_inode,
 	cifsInfo->cifsAttrs = attr;
 	cifsInfo->time = jiffies;
 
+	/* save mtime and size */
+	local_mtime = tmp_inode->i_mtime;
+	local_size  = tmp_inode->i_size;
+
 	/* Linux can not store file creation time unfortunately so ignore it */
 	tmp_inode->i_atime =
 	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
@@ -134,7 +141,6 @@ static void fill_in_inode(struct inode *tmp_inode,
 		tmp_inode->i_mode = cifs_sb->mnt_file_mode;
 	}
 
-	cFYI(0,("CIFS FFIRST: Attributes came in as 0x%x",attr));
 	if (attr & ATTR_DIRECTORY) {
 		*pobject_type = DT_DIR;
 		/* override default perms since we do not lock dirs */
@@ -175,30 +181,46 @@ static void fill_in_inode(struct inode *tmp_inode,
 	      (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks,
 	      tmp_inode->i_blksize));
 	if (S_ISREG(tmp_inode->i_mode)) {
-		cFYI(1, (" File inode "));
+		cFYI(1, ("File inode"));
 		tmp_inode->i_op = &cifs_file_inode_ops;
 		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
 			tmp_inode->i_fop = &cifs_file_direct_ops;
 		else
 			tmp_inode->i_fop = &cifs_file_ops;
 		tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
+		if(isNewInode)
+			return; /* No sense invalidating pages for new inode since we
+					   have not started caching readahead file data yet */
+
+		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
+			(local_size == tmp_inode->i_size)) {
+			cFYI(1, ("inode exists but unchanged"));
+		} else {
+			/* file may have changed on server */
+			cFYI(1, ("invalidate inode, readdir detected change"));
+			invalidate_remote_inode(tmp_inode);
+		}
 	} else if (S_ISDIR(tmp_inode->i_mode)) {
-		cFYI(1, (" Directory inode"));
+		cFYI(1, ("Directory inode"));
 		tmp_inode->i_op = &cifs_dir_inode_ops;
 		tmp_inode->i_fop = &cifs_dir_ops;
 	} else if (S_ISLNK(tmp_inode->i_mode)) {
-		cFYI(1, (" Symbolic Link inode "));
+		cFYI(1, ("Symbolic Link inode"));
 		tmp_inode->i_op = &cifs_symlink_inode_ops;
 	} else {
-		cFYI(1, (" Init special inode "));
+		cFYI(1, ("Init special inode"));
 		init_special_inode(tmp_inode, tmp_inode->i_mode,
 				   tmp_inode->i_rdev);
 	}
 }
 
 static void unix_fill_in_inode(struct inode *tmp_inode,
-	FILE_UNIX_INFO *pfindData, int *pobject_type)
+	FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode)
 {
+	loff_t local_size;
+	struct timespec local_mtime;
+
 	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
 
@@ -208,6 +230,10 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
 	cifsInfo->time = jiffies;
 	atomic_inc(&cifsInfo->inUse);
 
+	/* save mtime and size */
+	local_mtime = tmp_inode->i_mtime;
+	local_size  = tmp_inode->i_size;
+
 	tmp_inode->i_atime =
 	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
 	tmp_inode->i_mtime =
@@ -265,6 +291,19 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
 		else
 			tmp_inode->i_fop = &cifs_file_ops;
 		tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
+		if(isNewInode)
+			return; /* No sense invalidating pages for new inode since we
+					   have not started caching readahead file data yet */
+
+		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
+			(local_size == tmp_inode->i_size)) {
+			cFYI(1, ("inode exists but unchanged"));
+		} else {
+			/* file may have changed on server */
+			cFYI(1, ("invalidate inode, readdir detected change"));
+			invalidate_remote_inode(tmp_inode);
+		}
 	} else if (S_ISDIR(tmp_inode->i_mode)) {
 		cFYI(1, ("Directory inode"));
 		tmp_inode->i_op = &cifs_dir_inode_ops;
@@ -321,7 +360,7 @@ static int initiate_cifs_search(const int xid, struct file *file)
 		return -ENOMEM;
 	}
 
-	cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
+	cFYI(1, ("Full path: %s start at: %lld", full_path, file->f_pos));
 
 ffirst_retry:
 	/* test for Unix extensions */
@@ -666,10 +705,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
 		insert_inode_hash(tmp_inode);
 	}
 
+	/* we pass in rc below, indicating whether it is a new inode,
+	   so we can figure out whether to invalidate the inode cached
+	   data if the file has changed */
 	if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
-		unix_fill_in_inode(tmp_inode,(FILE_UNIX_INFO *)pfindEntry,&obj_type);
+		unix_fill_in_inode(tmp_inode,
+				   (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc);
 	} else {
-		fill_in_inode(tmp_inode,(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type);
+		fill_in_inode(tmp_inode,
+			      (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
 	}
 	
 	rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type);
-- 
cgit v1.2.2


From 09d1db5c6131232f764046160c29118cd4e5e646 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 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')

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;i<temp_len;i++,j++) {
 					vol->password[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.2


From 67010fbc6ff889aaf86592bc148d705c5b9e1a27 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 fs/cifs/cifsglob.h |  3 ++-
 fs/cifs/connect.c  | 31 +++++++++++++++++++++++++------
 2 files changed, 27 insertions(+), 7 deletions(-)

(limited to 'fs/cifs')

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.2


From 79944bf71352f33f984ac3973b159b5c2cee139d Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:09 -0700
Subject: [PATCH] cifs: missing semicolon from previous fix

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/cifsglob.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 8fc0801f8457..81babab265e1 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -321,7 +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  */
+	unsigned multiResp:1;   /* multiple trans2 responses for one request  */
 };
 
 struct oplock_q_entry {
-- 
cgit v1.2.2


From 46810cbf3d951c1ce8ce3311639996ad43ca4ed1 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 fs/cifs/cifssmb.c |   8 +-
 fs/cifs/connect.c | 295 +++++++++++++++++++++++++++---------------------------
 2 files changed, 154 insertions(+), 149 deletions(-)

(limited to 'fs/cifs')

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.2


From e4eb295d38b57f4d4b956942a48887eb252d97c6 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 fs/cifs/cifspdu.h |   2 +-
 fs/cifs/connect.c | 348 ++++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 246 insertions(+), 104 deletions(-)

(limited to 'fs/cifs')

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.2


From 275cde1a1f3880601509c851d72c82bb8d3ee67c Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:10 -0700
Subject: [PATCH] cifs: cleanup various long lines

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/transport.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index f9e16b39898c..79bf686a2a19 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -41,7 +41,7 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
 	struct mid_q_entry *temp;
 
 	if (ses == NULL) {
-		cERROR(1, ("Null session passed in to AllocMidQEntry "));
+		cERROR(1, ("Null session passed in to AllocMidQEntry"));
 		return NULL;
 	}
 	if (ses->server == NULL) {
@@ -185,7 +185,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
 
 int
 smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
-	 unsigned int smb_buf_length, struct kvec * write_vector /* page list */, struct sockaddr *sin)
+	 unsigned int smb_buf_length, struct kvec * write_vector 
+	  /* page list */, struct sockaddr *sin)
 {
 	int rc = 0;
 	int i = 0;
@@ -215,7 +216,8 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
 	dump_smb(smb_buffer, len);
 
 	while (len > 0) {
-		rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, len?);
+		rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, 
+				    len);
 		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
 			i++;
 			if(i > 60) {
@@ -351,8 +353,9 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
 	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
-/*	rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec,
-		      (struct sockaddr *) &(ses->server->addr.sockAddr));*/
+/*	rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
+		       piovec, 
+		       (struct sockaddr *) &(ses->server->addr.sockAddr));*/
 	if(rc < 0) {
 		DeleteMidQEntry(midQ);
 		up(&ses->server->tcpSem);
@@ -407,7 +410,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 	} else {
 		spin_lock(&GlobalMid_Lock); 
 		while(1) {        
-			if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){
+			if(atomic_read(&ses->server->inFlight) >= 
+					cifs_max_pending){
 				spin_unlock(&GlobalMid_Lock);
 				wait_event(ses->server->request_q,
 					atomic_read(&ses->server->inFlight)
@@ -495,7 +499,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 		up(&ses->server->tcpSem);
 	if (long_op == -1)
 		goto cifs_no_response_exit;
-	else if (long_op == 2) /* writes past end of file can take looooong time */
+	else if (long_op == 2) /* writes past end of file can take loong time */
 		timeout = 300 * HZ;
 	else if (long_op == 1)
 		timeout = 45 * HZ; /* should be greater than 
@@ -582,8 +586,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 						ses->server->mac_signing_key,
 						midQ->sequence_number+1);
 				if(rc) {
-					cERROR(1,("Unexpected packet signature received from server"));
-					/* BB FIXME - add code to kill session here */
+					cERROR(1,("Unexpected SMB signature"));
+					/* BB FIXME add code to kill session */
 				}
 			}
 
-- 
cgit v1.2.2


From cd63499cbe37e53e6cc084c8a35d911a4613c797 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 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')

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.2


From 11aa0149d0e49ee1791735ec4ae3079b27b9a68e Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Thu, 28 Apr 2005 22:41:10 -0700
Subject: [PATCH] cifs: Fix mapping of EMLINK case

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/CHANGES   | 4 ++++
 fs/cifs/cifsfs.h  | 2 +-
 fs/cifs/netmisc.c | 3 ++-
 fs/cifs/smberr.h  | 4 ++++
 4 files changed, 11 insertions(+), 2 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 3d61d96d7407..21a246473a91 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,7 @@
+Version 1.34
+------------
+Fix error mapping of the TOO_MANY_LINKS (hardlinks) case.
+
 Version 1.33
 ------------
 Fix caching problem, in which readdir of directory containing a file
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 8f742796a627..d00b3bfe1a52 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -96,5 +96,5 @@ extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
 extern int cifs_ioctl (struct inode * inode, struct file * filep,
 		       unsigned int command, unsigned long arg);
-#define CIFS_VERSION   "1.33"
+#define CIFS_VERSION   "1.34"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index dfaabc8d8fb6..a92af41d4411 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -78,6 +78,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
 	{ErrQuota, -EDQUOT},
 	{ErrNotALink, -ENOLINK},
 	{ERRnetlogonNotStarted,-ENOPROTOOPT},
+	{ErrTooManyLinks,-EMLINK},
 	{0, 0}
 };
 
@@ -742,7 +743,7 @@ static const struct {
 	ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, {
 	ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, {
 	ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, {
-	ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, {
+	ERRDOS, ErrTooManyLinks, NT_STATUS_TOO_MANY_LINKS}, {
 	ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, {
 	ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, {
 	ERRDOS, 21, 0xc000026e}, {
diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h
index 1b53dcd0f2eb..cd41c67ff8d3 100644
--- a/fs/cifs/smberr.h
+++ b/fs/cifs/smberr.h
@@ -107,6 +107,10 @@
 #define ErrNotALink		0x201	/* A link operation was performed on a
 					   pathname that was not a link. */
 
+/* Below errors are used internally (do not come over the wire) for passthrough
+   from STATUS codes to POSIX only  */
+#define ErrTooManyLinks         0xFFFE   
+
 /* Following error codes may be generated with the ERRSRV error class.*/
 
 #define ERRerror		1	/* Non-specific error code. It is
-- 
cgit v1.2.2


From 57337e42f1393941d59d5154eed27a63988ff2be Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 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')

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.2


From 31ca3bc3c569f9fe02aae6974ac3a9126f14902f Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 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')

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.2


From 0cb766ae629c70d53040f85de73db0583eadb233 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
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 <torvalds@osdl.org>
---
 fs/cifs/README    | 15 ++++++++++-----
 fs/cifs/connect.c |  3 +--
 2 files changed, 11 insertions(+), 7 deletions(-)

(limited to 'fs/cifs')

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.2


From 68575476718ed1c6d6ddafeec8310b109e7a7a7f Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Sat, 30 Apr 2005 11:10:57 -0700
Subject: [PATCH] cifs: append \* properly on ASCII servers

For older servers which do not support Unicode

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/CHANGES   | 4 +++-
 fs/cifs/cifssmb.c | 6 ++++--
 2 files changed, 7 insertions(+), 3 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 4d2404305ab6..95483baab706 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -4,7 +4,9 @@ Fix error mapping of the TOO_MANY_LINKS (hardlinks) case.
 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).
+no longer needed).  Fix readdir to ASCII servers (ie older servers
+which do not support Unicode) and also require asterik.
+
 
 Version 1.33
 ------------
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index b004fef0a42b..741ff0c69f37 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2451,12 +2451,14 @@ findFirstRetry:
 		name_len += 2;
 	} else {	/* BB add check for overrun of SMB buf BB */
 		name_len = strnlen(searchName, PATH_MAX);
-		name_len++;	/* trailing null */
 /* BB fix here and in unicode clause above ie
 		if(name_len > buffersize-header)
 			free buffer exit; BB */
 		strncpy(pSMB->FileName, searchName, name_len);
-		pSMB->FileName[name_len] = 0; /* just in case */
+		pSMB->FileName[name_len] = '\\';
+		pSMB->FileName[name_len+1] = '*';
+		pSMB->FileName[name_len+2] = 0;
+		name_len += 3;
 	}
 
 	params = 12 + name_len /* includes null */ ;
-- 
cgit v1.2.2


From 9ea1f8f505f6f770bd593e689960ac4f893509b2 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@austin.rr.com>
Date: Sat, 30 Apr 2005 11:10:58 -0700
Subject: [PATCH] cifs: Update cifs todo list

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
 fs/cifs/TODO | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

(limited to 'fs/cifs')

diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index 1e8490ed6948..8cc881694e29 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -1,4 +1,4 @@
-version 1.32 April 3, 2005
+version 1.34 April 29, 2005
 
 A Partial List of Missing Features
 ==================================
@@ -70,7 +70,15 @@ 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)
+t) Create UID mapping facility so server UIDs can be mapped on a per
+mount or a per server basis to client UIDs or nobody if no mapping
+exists.  This is helpful when Unix extensions are negotiated to
+allow better permission checking when UIDs differ on the server
+and client.  Add new protocol request to the CIFS protocol 
+standard for asking the server for the corresponding name of a
+particular uid.
+
+KNOWN BUGS (updated April 29, 2005)
 ====================================
 See http://bugzilla.samba.org - search on product "CifsVFS" for
 current bug list.
-- 
cgit v1.2.2