Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 157311 Details for
Bug 239339
update CIFS client to 1.48aRH
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
patch -- update RHEL4 CIFS code to 1.48aRH
0021-BZ-239939-Update-CIFS-to-1.48aRH.patch (text/plain), 163.17 KB, created by
Jeff Layton
on 2007-06-18 18:51:32 UTC
(
hide
)
Description:
patch -- update RHEL4 CIFS code to 1.48aRH
Filename:
MIME Type:
Creator:
Jeff Layton
Created:
2007-06-18 18:51:32 UTC
Size:
163.17 KB
patch
obsolete
>From 6eabd40296526915a116f666e370a21910ca7e8a Mon Sep 17 00:00:00 2001 >From: Jeff Layton <jlayton@redhat.com> >Date: Mon, 18 Jun 2007 12:46:12 -0400 >Subject: [PATCH] BZ#239939: Update CIFS to 1.48aRH > >--- > fs/cifs/CHANGES | 38 +++- > fs/cifs/Makefile | 2 +- > fs/cifs/README | 4 +- > fs/cifs/TODO | 16 +- > fs/cifs/asn1.c | 4 +- > fs/cifs/cifs_debug.c | 4 +- > fs/cifs/cifs_fs_sb.h | 2 + > fs/cifs/cifs_unicode.c | 4 +- > fs/cifs/cifsencrypt.c | 7 +- > fs/cifs/cifsfs.c | 158 ++++++++---- > fs/cifs/cifsfs.h | 64 ++++- > fs/cifs/cifsglob.h | 46 +++- > fs/cifs/cifspdu.h | 121 +++++++-- > fs/cifs/cifsproto.h | 23 +- > fs/cifs/cifssmb.c | 156 +++++++++-- > fs/cifs/connect.c | 136 ++++++++- > fs/cifs/dir.c | 55 +++- > fs/cifs/export.c | 52 ++++ > fs/cifs/file.c | 300 +++++++++++++++++---- > fs/cifs/inode.c | 158 +++++++++--- > fs/cifs/link.c | 43 +++- > fs/cifs/misc.c | 50 ++-- > fs/cifs/netmisc.c | 136 +++++++++ > fs/cifs/readdir.c | 91 ++++++- > fs/cifs/sess.c | 70 +++-- > fs/cifs/smbdes.c | 10 +- > fs/cifs/smberr.h | 1 + > fs/cifs/transport.c | 711 +++++++++++++++++++++++++++++------------------- > fs/cifs/xattr.c | 11 +- > 29 files changed, 1847 insertions(+), 626 deletions(-) > create mode 100644 fs/cifs/export.c > >diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES >index 333a436..5072b17 100644 >--- a/fs/cifs/CHANGES >+++ b/fs/cifs/CHANGES >@@ -1,8 +1,44 @@ >+Verison 1.48 >+------------ >+Fix mtime bouncing around from local idea of last write times to remote time. >+Fix hang (in i_size_read) when simultaneous size update of same remote file >+on smp system corrupts sequence number. Do not reread unnecessarily partial page >+(which we are about to overwrite anyway) when writing out file opened rw. >+When DOS attribute of file on non-Unix server's file changes on the server side >+from read-only back to read-write, reflect this change in default file mode >+(we had been leaving a file's mode read-only until the inode were reloaded). >+Allow setting of attribute back to ATTR_NORMAL (removing readonly dos attribute >+when archive dos attribute not set and we are changing mode back to writeable >+on server which does not support the Unix Extensions). >+ >+Version 1.47 >+------------ >+Fix oops in list_del during mount caused by unaligned string. >+Fix file corruption which could occur on some large file >+copies caused by writepages page i/o completion bug. >+Seek to SEEK_END forces check for update of file size for non-cached >+files. >+ >+Version 1.46 >+------------ >+Support deep tree mounts. Better support OS/2, Win9x (DOS) time stamps. >+Allow null user to be specified on mount ("username="). Do not return >+EINVAL on readdir when filldir fails due to overwritten blocksize >+(fixes FC problem). Return error in rename 2nd attempt retry (ie report >+if rename by handle also fails, after rename by path fails, we were >+not reporting whether the retry worked or not). Fix NTLMv2 to >+work to Windows servers (mount with option "sec=ntlmv2"). >+ > Version 1.45 > ------------ > Do not time out lockw calls when using posix extensions. Do not > time out requests if server still responding reasonably fast >-on requests on other threads >+on requests on other threads. Improve POSIX locking emulation, >+(lock cancel now works, and unlock of merged range works even >+to Windows servers now). Fix oops on mount to lanman servers >+(win9x, os/2 etc.) when null password. Do not send listxattr >+(SMB to query all EAs) if nouser_xattr specified. Fix SE Linux >+problem (instantiate inodes/dentries in right order for readdir). > > Version 1.44 > ------------ >diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile >index a26f26e..6ecd9d6 100644 >--- a/fs/cifs/Makefile >+++ b/fs/cifs/Makefile >@@ -3,4 +3,4 @@ > # > obj-$(CONFIG_CIFS) += cifs.o > >-cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o >+cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o export.o >diff --git a/fs/cifs/README b/fs/cifs/README >index 7986d0d..d4be92b 100644 >--- a/fs/cifs/README >+++ b/fs/cifs/README >@@ -1,5 +1,5 @@ > The CIFS VFS support for Linux supports many advanced network filesystem >-features such as heirarchical dfs like namespace, hardlinks, locking and more. >+features such as hierarchical dfs like namespace, hardlinks, locking and more. > It was designed to comply with the SNIA CIFS Technical Reference (which > supersedes the 1992 X/Open SMB Standard) as well as to perform best practice > practical interoperability with Windows 2000, Windows XP, Samba and equivalent >@@ -408,7 +408,7 @@ A partial list of the supported mount options follows: > user_xattr Allow getting and setting user xattrs as OS/2 EAs (extended > attributes) to the server (default) e.g. via setfattr > and getfattr utilities. >- nouser_xattr Do not allow getfattr/setfattr to get/set xattrs >+ nouser_xattr Do not allow getfattr/setfattr to get/set/list xattrs > mapchars Translate six of the seven reserved characters (not backslash) > *?<>|: > to the remap range (above 0xF000), which also >diff --git a/fs/cifs/TODO b/fs/cifs/TODO >index fc34c74..267a762 100644 >--- a/fs/cifs/TODO >+++ b/fs/cifs/TODO >@@ -18,7 +18,9 @@ better) > > d) Kerberos/SPNEGO session setup support - (started) > >-e) NTLMv2 authentication (mostly implemented) >+e) NTLMv2 authentication (mostly implemented - double check >+that NTLMv2 signing works, also need to cleanup now unneeded SessSetup code in >+fs/cifs/connect.c) > > f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup > used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM >@@ -88,11 +90,12 @@ w) Finish up the dos time conversion routines needed to return old server > time to the client (default time, of now or time 0 is used now for these > very old servers) > >-x) Add support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) >+x) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) >+need to add ability to set time to server (utimes command) > > y) Finish testing of Windows 9x/Windows ME server support (started). > >-KNOWN BUGS (updated April 29, 2005) >+KNOWN BUGS (updated February 26, 2007) > ==================================== > See http://bugzilla.samba.org - search on product "CifsVFS" for > current bug list. >@@ -107,11 +110,6 @@ but recognizes them > succeed but still return access denied (appears to be Windows > server not cifs client problem) and has not been reproduced recently. > NTFS partitions do not have this problem. >-4) debug connectathon lock test case 10 which fails against >-Samba (may be unmappable due to POSIX to Windows lock model >-differences but worth investigating). Also debug Samba to >-see why lock test case 7 takes longer to complete to Samba >-than to Windows. > > Misc testing to do > ================== >@@ -119,7 +117,7 @@ Misc testing to do > types. Try nested symlinks (8 deep). Return max path name in stat -f information > > 2) Modify file portion of ltp so it can run against a mounted network >-share and run it against cifs vfs. >+share and run it against cifs vfs in automated fashion. > > 3) Additional performance testing and optimization using iozone and similar - > there are some easy changes that can be done to parallelize sequential writes, >diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c >index 031cdf2..6c1833b 100644 >--- a/fs/cifs/asn1.c >+++ b/fs/cifs/asn1.c >@@ -17,7 +17,6 @@ > * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > */ > >-#include <linux/config.h> > #include <linux/module.h> > #include <linux/types.h> > #include <linux/kernel.h> >@@ -27,6 +26,9 @@ > #include "cifsglob.h" > #include "cifs_debug.h" > #include "cifsproto.h" >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) >+#include <linux/config.h> >+#endif > > /***************************************************************************** > * >diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c >index 96abeb7..6017c46 100644 >--- a/fs/cifs/cifs_debug.c >+++ b/fs/cifs/cifs_debug.c >@@ -143,8 +143,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, > ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); > if((ses->serverDomain == NULL) || (ses->serverOS == NULL) || > (ses->serverNOS == NULL)) { >- buf += sprintf("\nentry for %s not fully displayed\n\t", >- ses->serverName); >+ buf += sprintf(buf, "\nentry for %s not fully " >+ "displayed\n\t", ses->serverName); > > } else { > length = >diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h >index ad58eb0..fd1e52e 100644 >--- a/fs/cifs/cifs_fs_sb.h >+++ b/fs/cifs/cifs_fs_sb.h >@@ -40,5 +40,7 @@ struct cifs_sb_info { > mode_t mnt_file_mode; > mode_t mnt_dir_mode; > int mnt_cifs_flags; >+ int prepathlen; >+ char * prepath; > }; > #endif /* _CIFS_FS_SB_H */ >diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c >index d2a8b29..793c4b9 100644 >--- a/fs/cifs/cifs_unicode.c >+++ b/fs/cifs/cifs_unicode.c >@@ -74,8 +74,8 @@ cifs_strtoUCS(__le16 * to, const char *from, int len, > charlen = codepage->char2uni(from, len, &wchar_to[i]); > if (charlen < 1) { > cERROR(1, >- ("cifs_strtoUCS: char2uni returned %d", >- charlen)); >+ ("strtoUCS: char2uni of %d returned %d", >+ (int)*from, charlen)); > /* A question mark */ > to[i] = cpu_to_le16(0x003f); > charlen = 1; >diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c >index a89efaf..fdeda51 100644 >--- a/fs/cifs/cifsencrypt.c >+++ b/fs/cifs/cifsencrypt.c >@@ -277,7 +277,8 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) > return; > > memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); >- strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); >+ if(ses->password) >+ strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); > > if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) > if(extended_security & CIFSSEC_MAY_PLNTXT) { >@@ -371,8 +372,10 @@ void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, > buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); > get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); > buf->reserved2 = 0; >- buf->names[0].type = 0; >+ buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); > buf->names[0].length = 0; >+ buf->names[1].type = 0; >+ buf->names[1].length = 0; > > /* calculate buf->ntlmv2_hash */ > rc = calc_ntlmv2_hash(ses, nls_cp); >diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c >index 4d2f784..56aff02 100644 >--- a/fs/cifs/cifsfs.c >+++ b/fs/cifs/cifsfs.c >@@ -1,7 +1,7 @@ > /* > * fs/cifs/cifsfs.c > * >- * Copyright (C) International Business Machines Corp., 2002,2004 >+ * Copyright (C) International Business Machines Corp., 2002,2007 > * Author(s): Steve French (sfrench@us.ibm.com) > * > * Common Internet FileSystem (CIFS) client >@@ -43,12 +43,19 @@ > #include <linux/mm.h> > #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) > #include <linux/moduleparam.h> >-#endif >-#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ >+#endif /* 2.6.9 */ >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19) >+#include <linux/freezer.h> >+#endif /* 2.6.19 */ >+#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ > > #ifdef CONFIG_CIFS_QUOTA > static struct quotactl_ops cifs_quotactl_ops; >-#endif >+#endif /* QUOTA */ >+ >+#ifdef CONFIG_CIFS_EXPERIMENTAL >+extern struct export_operations cifs_export_ops; >+#endif /* EXPERIMENTAL */ > > int cifsFYI = 0; > int cifsERROR = 1; >@@ -63,8 +70,8 @@ unsigned int extended_security = CIFSSEC_DEF; > unsigned int sign_CIFS_PDUs = 1; > extern struct task_struct * oplockThread; /* remove sparse warning */ > struct task_struct * oplockThread = NULL; >-extern struct task_struct * dnotifyThread; /* remove sparse warning */ >-struct task_struct * dnotifyThread = NULL; >+/* extern struct task_struct * dnotifyThread; remove sparse warning */ >+static struct task_struct * dnotifyThread = NULL; > unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; > module_param(CIFSMaxBufSize, int, 0); > MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); >@@ -94,8 +101,9 @@ cifs_read_super(struct super_block *sb, void *data, > struct inode *inode; > struct cifs_sb_info *cifs_sb; > int rc = 0; >- >- sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */ >+ >+ /* BB should we make this contingent on mount parm? */ >+ sb->s_flags |= MS_NODIRATIME | MS_NOATIME; > sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info),GFP_KERNEL); > cifs_sb = CIFS_SB(sb); > if(cifs_sb == NULL) >@@ -112,6 +120,10 @@ cifs_read_super(struct super_block *sb, void *data, > > sb->s_magic = CIFS_MAGIC_NUMBER; > sb->s_op = &cifs_super_ops; >+#ifdef CONFIG_CIFS_EXPERIMENTAL >+ if(experimEnabled != 0) >+ sb->s_export_op = &cifs_export_ops; >+#endif /* EXPERIMENTAL */ > /* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) > sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ > #ifdef CONFIG_CIFS_QUOTA >@@ -170,23 +182,16 @@ cifs_put_super(struct super_block *sb) > return; > } > >-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) >-#if LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 9) >-void * kzalloc(size_t size, unsigned flgs) >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) >+static int >+cifs_statfs(struct dentry *dentry, struct kstatfs *buf) > { >- void * buf; >- buf = kmalloc(size, flgs); >- if(buf != NULL) >- memset(buf, 0, size); >- return buf; >-} >-#endif >-#endif >- >- >+ struct super_block *sb = dentry->d_sb; >+#else > static int > cifs_statfs(struct super_block *sb, struct kstatfs *buf) > { >+#endif > int xid; > int rc = -EOPNOTSUPP; > struct cifs_sb_info *cifs_sb; >@@ -207,7 +212,6 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) > 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) && (CIFS_POSIX_EXTENSIONS & >@@ -217,11 +221,12 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) > /* Only need to call the old QFSInfo if failed > on newer one */ > if(rc) >-#endif /* CIFS_EXPERIMENTAL */ >- rc = CIFSSMBQFSInfo(xid, pTcon, buf); >+ if(pTcon->ses->capabilities & CAP_NT_SMBS) >+ rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */ > >- /* Old Windows servers do not support level 103, retry with level >- one if old server failed the previous call */ >+ /* Some old Windows servers also do not support level 103, retry with >+ older level one if old server failed the previous call or we >+ bypassed it because we detected that this was an older LANMAN sess */ > if(rc) > rc = SMBOldQFSInfo(xid, pTcon, buf); > /* >@@ -277,9 +282,14 @@ cifs_alloc_inode(struct super_block *sb) > file data or metadata */ > cifs_inode->clientCanCacheRead = FALSE; > cifs_inode->clientCanCacheAll = FALSE; >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) > cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; >+#endif > cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ >- cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; >+ >+ /* Can not set i_flags here - they get immediately overwritten >+ to zero by the VFS */ >+/* cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;*/ > INIT_LIST_HEAD(&cifs_inode->openFileList); > return &cifs_inode->vfs_inode; > } >@@ -304,6 +314,7 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) > > if (cifs_sb) { > if (cifs_sb->tcon) { >+/* BB add prepath to mount options displayed */ > seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); > if (cifs_sb->tcon->ses) { > if (cifs_sb->tcon->ses->userName) >@@ -424,12 +435,22 @@ static struct quotactl_ops cifs_quotactl_ops = { > }; > #endif > >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 16) >+static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags) >+#else > static void cifs_umount_begin(struct super_block * sblock) >+#endif > { > struct cifs_sb_info *cifs_sb; > struct cifsTconInfo * tcon; > >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 16) >+ if (!(flags & MNT_FORCE)) >+ return; >+ cifs_sb = CIFS_SB(vfsmnt->mnt_sb); >+#else > cifs_sb = CIFS_SB(sblock); >+#endif > if(cifs_sb == NULL) > return; > >@@ -479,9 +500,16 @@ struct super_operations cifs_super_ops = { > .remount_fs = cifs_remount, > }; > >+ >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) >+static int >+cifs_get_sb(struct file_system_type *fs_type, >+ int flags, const char *dev_name, void *data, struct vfsmount *mnt) >+#else > static struct super_block * > cifs_get_sb(struct file_system_type *fs_type, > int flags, const char *dev_name, void *data) >+#endif > { > int rc; > struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL); >@@ -489,7 +517,11 @@ cifs_get_sb(struct file_system_type *fs_type, > cFYI(1, ("Devname: %s flags: %d ", dev_name, flags)); > > if (IS_ERR(sb)) >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) >+ return PTR_ERR(sb); >+#else > return sb; >+#endif > > sb->s_flags = flags; > >@@ -497,12 +529,30 @@ cifs_get_sb(struct file_system_type *fs_type, > if (rc) { > up_write(&sb->s_umount); > deactivate_super(sb); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) >+ return rc; >+#else > return ERR_PTR(rc); >+#endif > } > sb->s_flags |= MS_ACTIVE; >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) >+ return simple_set_mnt(mnt, sb); >+#else > return sb; >+#endif > } > >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) >+static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, >+ unsigned long nr_segs, loff_t pos) >+{ >+ struct inode *inode = iocb->ki_filp->f_dentry->d_inode; >+ ssize_t written; >+ >+ written = generic_file_aio_write(iocb, iov, nr_segs, pos); >+#else >+ > static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov, > unsigned long nr_segs, loff_t *ppos) > { >@@ -522,6 +572,7 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf, > ssize_t written; > > written = generic_file_aio_write(iocb, buf, count, pos); >+#endif > if (!CIFS_I(inode)->clientCanCacheAll) > filemap_fdatawrite(inode->i_mapping); > return written; >@@ -531,7 +582,21 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) > { > /* origin == SEEK_END => we must revalidate the cached file length */ > if (origin == 2) { >- int retval = cifs_revalidate(file->f_dentry); >+ int retval; >+ >+ /* some applications poll for the file length in this strange >+ way so we must seek to end on non-oplocked files by >+ setting the revalidate time to zero */ >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) >+ if(file->f_path.dentry->d_inode) >+ CIFS_I(file->f_path.dentry->d_inode)->time = 0; >+ >+ retval = cifs_revalidate(file->f_path.dentry); >+#else >+ if(file->f_dentry->d_inode) >+ CIFS_I(file->f_dentry->d_inode)->time = 0; >+ retval = cifs_revalidate(file->f_dentry); >+#endif > if (retval < 0) > return (loff_t)retval; > } >@@ -601,11 +666,13 @@ struct inode_operations cifs_symlink_inode_ops = { > #endif > }; > >-struct file_operations cifs_file_ops = { >+const struct file_operations cifs_file_ops = { > .read = do_sync_read, > .write = do_sync_write, >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) > .readv = generic_file_readv, > .writev = cifs_file_writev, >+#endif > .aio_read = generic_file_aio_read, > .aio_write = cifs_file_aio_write, > .open = cifs_open, >@@ -625,7 +692,7 @@ struct file_operations cifs_file_ops = { > #endif /* CONFIG_CIFS_EXPERIMENTAL */ > }; > >-struct file_operations cifs_file_direct_ops = { >+const struct file_operations cifs_file_direct_ops = { > /* no mmap, no aio, no readv - > BB reevaluate whether they can be done with directio, no cache */ > .read = cifs_user_read, >@@ -644,11 +711,14 @@ struct file_operations cifs_file_direct_ops = { > .dir_notify = cifs_dir_notify, > #endif /* CONFIG_CIFS_EXPERIMENTAL */ > }; >-struct file_operations cifs_file_nobrl_ops = { >+ >+const struct file_operations cifs_file_nobrl_ops = { > .read = do_sync_read, > .write = do_sync_write, >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) > .readv = generic_file_readv, > .writev = cifs_file_writev, >+#endif > .aio_read = generic_file_aio_read, > .aio_write = cifs_file_aio_write, > .open = cifs_open, >@@ -667,7 +737,7 @@ struct file_operations cifs_file_nobrl_ops = { > #endif /* CONFIG_CIFS_EXPERIMENTAL */ > }; > >-struct file_operations cifs_file_direct_nobrl_ops = { >+const struct file_operations cifs_file_direct_nobrl_ops = { > /* no mmap, no aio, no readv - > BB reevaluate whether they can be done with directio, no cache */ > .read = cifs_user_read, >@@ -686,7 +756,7 @@ struct file_operations cifs_file_direct_nobrl_ops = { > #endif /* CONFIG_CIFS_EXPERIMENTAL */ > }; > >-struct file_operations cifs_dir_ops = { >+const struct file_operations cifs_dir_ops = { > .readdir = cifs_readdir, > .release = cifs_closedir, > .read = generic_read_dir, >@@ -724,8 +794,7 @@ cifs_init_inodecache(void) > static void > cifs_destroy_inodecache(void) > { >- if (kmem_cache_destroy(cifs_inode_cachep)) >- printk(KERN_WARNING "cifs_inode_cache: error freeing\n"); >+ kmem_cache_destroy(cifs_inode_cachep); > } > > static int >@@ -807,13 +876,9 @@ static void > cifs_destroy_request_bufs(void) > { > mempool_destroy(cifs_req_poolp); >- if (kmem_cache_destroy(cifs_req_cachep)) >- printk(KERN_WARNING >- "cifs_destroy_request_cache: error not all structures were freed\n"); >+ kmem_cache_destroy(cifs_req_cachep); > mempool_destroy(cifs_sm_req_poolp); >- if (kmem_cache_destroy(cifs_sm_req_cachep)) >- printk(KERN_WARNING >- "cifs_destroy_request_cache: cifs_small_rq free error\n"); >+ kmem_cache_destroy(cifs_sm_req_cachep); > } > > static int >@@ -850,13 +915,8 @@ static void > cifs_destroy_mids(void) > { > mempool_destroy(cifs_mid_poolp); >- if (kmem_cache_destroy(cifs_mid_cachep)) >- printk(KERN_WARNING >- "cifs_destroy_mids: error not all structures were freed\n"); >- >- if (kmem_cache_destroy(cifs_oplock_cachep)) >- printk(KERN_WARNING >- "error not all oplock structures were freed\n"); >+ kmem_cache_destroy(cifs_mid_cachep); >+ kmem_cache_destroy(cifs_oplock_cachep); > } > > static int cifs_oplock_thread(void * dummyarg) >@@ -972,7 +1032,7 @@ init_cifs(void) > #ifdef CONFIG_PROC_FS > cifs_proc_init(); > #endif >- INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */ >+/* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */ > INIT_LIST_HEAD(&GlobalSMBSessionList); > INIT_LIST_HEAD(&GlobalTreeConnectionList); > INIT_LIST_HEAD(&GlobalOplock_Q); >diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h >index 9e7abc8..7933187 100644 >--- a/fs/cifs/cifsfs.h >+++ b/fs/cifs/cifsfs.h >@@ -31,48 +31,80 @@ > #ifndef TRUE > #define TRUE 1 > #endif >+ >+#ifndef __user >+#define __user >+#endif >+ > #include <linux/version.h> > #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) > #define current_fs_time(arg) CURRENT_TIME > #endif >-extern struct address_space_operations cifs_addr_ops; >-extern struct address_space_operations cifs_addr_ops_smallbuf; >+ >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 25) >+#define filemap_fdatawrite filemap_fdatasync >+#endif >+ >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) >+static inline int timespec_equal(time_t *time1, time_t *time2) >+{ >+ return (time1 == time2); >+} >+ >+static inline void invalidate_remote_inode(struct inode * inode) >+{ >+ invalidate_inode_pages(inode); >+} >+ >+static inline void i_size_write(struct inode *inode, loff_t size) >+{ >+ inode->i_size = size; >+} >+#ifndef PageUptodate >+#define PageUptodate(page) Page_Uptodate(page) >+#endif >+#endif >+ >+extern const struct address_space_operations cifs_addr_ops; >+extern const struct address_space_operations cifs_addr_ops_smallbuf; > > /* Functions related to super block operations */ > extern struct super_operations cifs_super_ops; > extern void cifs_read_inode(struct inode *); >-extern void cifs_delete_inode(struct inode *); >-/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */ >+/*extern void cifs_delete_inode(struct inode *);*/ /* BB not needed yet */ >+/* extern void cifs_write_inode(struct inode *); */ /* BB not needed yet */ > > /* Functions related to inodes */ > extern struct inode_operations cifs_dir_inode_ops; > #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > extern int cifs_create(struct inode *, struct dentry *, int, > struct nameidata *); >+extern struct dentry * cifs_lookup(struct inode *, struct dentry *, >+ struct nameidata *); >+extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t); >+extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); > #else > extern int cifs_create(struct inode *, struct dentry *, int); >+extern struct dentry * cifs_lookup(struct inode *, struct dentry *); >+extern int cifs_mknod(struct inode *, struct dentry *, int, int); > #endif >-extern struct dentry * cifs_lookup(struct inode *, struct dentry *, >- struct nameidata *); > extern int cifs_unlink(struct inode *, struct dentry *); > extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); >-extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t); > extern int cifs_mkdir(struct inode *, struct dentry *, int); > extern int cifs_rmdir(struct inode *, struct dentry *); > extern int cifs_rename(struct inode *, struct dentry *, struct inode *, > struct dentry *); > extern int cifs_revalidate(struct dentry *); >-extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); > extern int cifs_setattr(struct dentry *, struct iattr *); > > extern struct inode_operations cifs_file_inode_ops; > extern struct inode_operations cifs_symlink_inode_ops; > > /* Functions related to files and directories */ >-extern struct file_operations cifs_file_ops; >-extern struct file_operations cifs_file_direct_ops; /* if directio mount */ >-extern struct file_operations cifs_file_nobrl_ops; >-extern struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */ >+extern const struct file_operations cifs_file_ops; >+extern const struct file_operations cifs_file_direct_ops; /* if directio mount */ >+extern const struct file_operations cifs_file_nobrl_ops; >+extern const struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */ > extern int cifs_open(struct inode *inode, struct file *file); > extern int cifs_close(struct inode *inode, struct file *file); > extern int cifs_closedir(struct inode *inode, struct file *file); >@@ -82,9 +114,13 @@ extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, > size_t write_size, loff_t * poffset); > extern int cifs_lock(struct file *, int, struct file_lock *); > extern int cifs_fsync(struct file *, struct dentry *, int); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) >+extern int cifs_flush(struct file *, fl_owner_t id); >+#else > extern int cifs_flush(struct file *); >+#endif /* 2.6.17 */ > extern int cifs_file_mmap(struct file * , struct vm_area_struct *); >-extern struct file_operations cifs_dir_ops; >+extern const struct file_operations cifs_dir_ops; > extern int cifs_dir_open(struct inode *inode, struct file *file); > extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); > extern int cifs_dir_notify(struct file *, unsigned long arg); >@@ -112,5 +148,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.45" >+#define CIFS_VERSION "1.48a.RH" > #endif /* _CIFSFS_H */ >diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h >index 685db48..2bb636c 100644 >--- a/fs/cifs/cifsglob.h >+++ b/fs/cifs/cifsglob.h >@@ -3,6 +3,7 @@ > * > * Copyright (C) International Business Machines Corp., 2002,2006 > * Author(s): Steve French (sfrench@us.ibm.com) >+ * Jeremy Allison (jra@samba.org) > * > * This library is free software; you can redistribute it and/or modify > * it under the terms of the GNU Lesser General Public License as published >@@ -68,6 +69,14 @@ > #define XATTR_DOS_ATTRIB "user.DOSATTRIB" > #endif > >+#ifndef SLAB_NOFS >+#define SLAB_NOFS GFP_NOFS >+#endif >+ >+#ifndef SLAB_KERNEL >+#define SLAB_KERNEL GFP_KERNEL >+#endif >+ > /* > * This information is kept on every Server we know about. > * >@@ -153,7 +162,7 @@ struct TCP_Server_Info { > char sessid[4]; /* unique token id for this session */ > /* (returned on Negotiate */ > int capabilities; /* allow selective disabling of caps by smb sess */ >- __u16 timeZone; >+ int timeAdj; /* Adjust for difference in server time zone in sec */ > __u16 CurrentMid; /* multiplex id - rotating counter */ > char cryptKey[CIFS_CRYPTO_KEY_SIZE]; > /* 16th byte of RFC1001 workstation name is always null */ >@@ -203,9 +212,14 @@ struct cifsSesInfo { > char * domainName; > char * password; > }; >-/* session flags */ >+/* no more than one of the following three session flags may be set */ > #define CIFS_SES_NT4 1 >- >+#define CIFS_SES_OS2 2 >+#define CIFS_SES_W9X 4 >+/* following flag is set for old servers such as OS2 (and Win95?) >+ which do not negotiate NTLM or POSIX dialects, but instead >+ negotiate one of the older LANMAN dialects */ >+#define CIFS_SES_LANMAN 8 > /* > * there is one of these for each connection to a resource on a particular > * session >@@ -268,14 +282,14 @@ struct cifsTconInfo { > }; > > /* >- * This info hangs off the cifsFileInfo structure. This is used to track >- * byte stream locks on the file >+ * This info hangs off the cifsFileInfo structure, pointed to by llist. >+ * This is used to track byte stream locks on the file > */ > struct cifsLockInfo { >- struct cifsLockInfo *next; >- int start; >- int length; >- int type; >+ struct list_head llist; /* pointer to next cifsLockInfo */ >+ __u64 offset; >+ __u64 length; >+ __u8 type; > }; > > /* >@@ -306,6 +320,8 @@ struct cifsFileInfo { > /* lock scope id (0 if none) */ > struct file * pfile; /* needed for writepage */ > struct inode * pInode; /* needed for oplock break */ >+ struct semaphore lock_sem; >+ struct list_head llist; /* list of byte range locks we have. */ > unsigned closePend:1; /* file is marked to close */ > unsigned invalidHandle:1; /* file closed via session abend */ > atomic_t wrtPending; /* handle in use - defer close */ >@@ -329,7 +345,9 @@ struct cifsInodeInfo { > unsigned clientCanCacheRead:1; /* read oplock */ > unsigned clientCanCacheAll:1; /* read and writebehind oplock */ > unsigned oplockPending:1; >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > struct inode vfs_inode; >+#endif > }; > > #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) >@@ -356,6 +374,8 @@ CIFS_SB(struct super_block *sb) > { > return (struct cifs_sb_info *) &(sb->u); > } >+ >+extern struct inode * get_cifs_inode(struct super_block * sb); > #endif > > static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) >@@ -531,15 +551,17 @@ GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */ > */ > GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH]; > >-GLOBAL_EXTERN struct list_head GlobalServerList; /* BB not implemented yet */ >+/* GLOBAL_EXTERN struct list_head GlobalServerList; BB not implemented yet */ > GLOBAL_EXTERN struct list_head GlobalSMBSessionList; > GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; > GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ > > GLOBAL_EXTERN struct list_head GlobalOplock_Q; > >-GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */ >-GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q;/* DirNotify response queue */ >+/* Outstanding dir notify requests */ >+GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; >+/* DirNotify response queue */ >+GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; > > /* > * Global transaction id (XID) information >diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h >index 14d91e9..40d1730 100644 >--- a/fs/cifs/cifspdu.h >+++ b/fs/cifs/cifspdu.h >@@ -1,7 +1,7 @@ > /* > * fs/cifs/cifspdu.h > * >- * Copyright (c) International Business Machines Corp., 2002,2005 >+ * Copyright (c) International Business Machines Corp., 2002,2007 > * Author(s): Steve French (sfrench@us.ibm.com) > * > * This library is free software; you can redistribute it and/or modify >@@ -26,7 +26,8 @@ > > #ifdef CONFIG_CIFS_WEAK_PW_HASH > #define LANMAN_PROT 0 >-#define CIFS_PROT 1 >+#define LANMAN2_PROT 1 >+#define CIFS_PROT 2 > #else > #define CIFS_PROT 0 > #endif >@@ -34,9 +35,11 @@ > #define BAD_PROT 0xFFFF > > /* SMB command codes */ >-/* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses >- (ie which include no useful data other than the SMB error code itself). >- Knowing this helps avoid response buffer allocations and copy in some cases */ >+/* >+ * Some commands have minimal (wct=0,bcc=0), or uninteresting, responses >+ * (ie which include no useful data other than the SMB error code itself). >+ * Knowing this helps avoid response buffer allocations and copy in some cases >+ */ > #define SMB_COM_CREATE_DIRECTORY 0x00 /* trivial response */ > #define SMB_COM_DELETE_DIRECTORY 0x01 /* trivial response */ > #define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ >@@ -226,6 +229,9 @@ > */ > #define CIFS_NO_HANDLE 0xFFFF > >+#define NO_CHANGE_64 0xFFFFFFFFFFFFFFFFULL >+#define NO_CHANGE_32 0xFFFFFFFFUL >+ > /* IPC$ in ASCII */ > #define CIFS_IPC_RESOURCE "\x49\x50\x43\x24" > >@@ -417,6 +423,8 @@ typedef struct negotiate_req { > > /* Dialect index is 13 for LANMAN */ > >+#define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */ >+ > typedef struct lanman_neg_rsp { > struct smb_hdr hdr; /* wct = 13 */ > __le16 DialectIndex; >@@ -426,7 +434,10 @@ typedef struct lanman_neg_rsp { > __le16 MaxNumberVcs; > __le16 RawMode; > __le32 SessionKey; >- __le32 ServerTime; >+ struct { >+ __le16 Time; >+ __le16 Date; >+ } __attribute__((packed)) SrvTime; > __le16 ServerTimeZone; > __le16 EncryptionKeyLength; > __le16 Reserved; >@@ -547,7 +558,8 @@ typedef union smb_com_session_setup_andx { > /* unsigned char * NativeOS; */ > /* unsigned char * NativeLanMan; */ > /* unsigned char * PrimaryDomain; */ >- } __attribute__((packed)) resp; /* NTLM response with or without extended sec*/ >+ } __attribute__((packed)) resp; /* NTLM response >+ (with or without extended sec) */ > > struct { /* request format */ > struct smb_hdr hdr; /* wct = 10 */ >@@ -583,6 +595,12 @@ typedef union smb_com_session_setup_andx { > > /* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */ > >+#define NTLMSSP_SERVER_TYPE 1 >+#define NTLMSSP_DOMAIN_TYPE 2 >+#define NTLMSSP_FQ_DOMAIN_TYPE 3 >+#define NTLMSSP_DNS_DOMAIN_TYPE 4 >+#define NTLMSSP_DNS_PARENT_TYPE 5 >+ > struct ntlmssp2_name { > __le16 type; > __le16 length; >@@ -596,7 +614,7 @@ struct ntlmv2_resp { > __le64 time; > __u64 client_chal; /* random */ > __u32 reserved2; >- struct ntlmssp2_name names[1]; >+ struct ntlmssp2_name names[2]; > /* array of name entries could follow ending in minimum 4 byte struct */ > } __attribute__((packed)); > >@@ -683,7 +701,7 @@ typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on > typedef struct smb_com_close_req { > struct smb_hdr hdr; /* wct = 3 */ > __u16 FileID; >- __u32 LastWriteTime; /* should be zero */ >+ __u32 LastWriteTime; /* should be zero or -1 */ > __u16 ByteCount; /* 0 */ > } __attribute__((packed)) CLOSE_REQ; > >@@ -792,6 +810,8 @@ typedef struct smb_com_openx_rsp { > __u16 ByteCount; > } __attribute__((packed)) OPENX_RSP; > >+/* For encoding of POSIX Open Request - see trans2 function 0x209 data struct */ >+ > /* Legacy write request for older servers */ > typedef struct smb_com_writex_req { > struct smb_hdr hdr; /* wct = 12 */ >@@ -1349,10 +1369,13 @@ struct smb_t2_rsp { > #define SMB_QUERY_FILE_UNIX_BASIC 0x200 > #define SMB_QUERY_FILE_UNIX_LINK 0x201 > #define SMB_QUERY_POSIX_ACL 0x204 >-#define SMB_QUERY_XATTR 0x205 >+#define SMB_QUERY_XATTR 0x205 /* e.g. system EA name space */ > #define SMB_QUERY_ATTR_FLAGS 0x206 /* append,immutable etc. */ > #define SMB_QUERY_POSIX_PERMISSION 0x207 > #define SMB_QUERY_POSIX_LOCK 0x208 >+/* #define SMB_POSIX_OPEN 0x209 */ >+/* #define SMB_POSIX_UNLINK 0x20a */ >+#define SMB_QUERY_FILE__UNIX_INFO2 0x20b > #define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee > #define SMB_QUERY_FILE_ACCESS_INFO 0x3f0 > #define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */ >@@ -1372,8 +1395,11 @@ struct smb_t2_rsp { > #define SMB_SET_XATTR 0x205 > #define SMB_SET_ATTR_FLAGS 0x206 /* append, immutable etc. */ > #define SMB_SET_POSIX_LOCK 0x208 >+#define SMB_POSIX_OPEN 0x209 >+#define SMB_POSIX_UNLINK 0x20a >+#define SMB_SET_FILE_UNIX_INFO2 > #define SMB_SET_FILE_BASIC_INFO2 0x3ec >-#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo level too */ >+#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */ > #define SMB_FILE_ALL_INFO2 0x3fa > #define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb > #define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc >@@ -1423,7 +1449,7 @@ typedef struct smb_com_transaction2_qpi_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 is present for infolevels > 100 */ > } __attribute__((packed)) TRANSACTION2_QPI_RSP; > > typedef struct smb_com_transaction2_spi_req { >@@ -1456,7 +1482,7 @@ typedef struct smb_com_transaction2_spi_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 is present for infolevels > 100 */ > } __attribute__((packed)) TRANSACTION2_SPI_RSP; > > struct set_file_rename { >@@ -1622,6 +1648,7 @@ typedef struct smb_com_transaction2_fnext_rsp_parms { > #define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105 > #define SMB_QUERY_CIFS_UNIX_INFO 0x200 > #define SMB_QUERY_POSIX_FS_INFO 0x201 >+#define SMB_QUERY_POSIX_WHO_AM_I 0x202 > #define SMB_QUERY_LABEL_INFO 0x3ea > #define SMB_QUERY_FS_QUOTA_INFO 0x3ee > #define SMB_QUERY_FS_FULL_SIZE_INFO 0x3ef >@@ -1654,9 +1681,21 @@ typedef struct smb_com_transaction_qfsi_rsp { > struct smb_hdr hdr; /* wct = 10 + SetupCount */ > struct trans2_resp t2; > __u16 ByteCount; >- __u8 Pad; /* may be three bytes *//* followed by data area */ >+ __u8 Pad; /* may be three bytes? *//* followed by data area */ > } __attribute__((packed)) TRANSACTION2_QFSI_RSP; > >+typedef struct whoami_rsp_data { /* Query level 0x202 */ >+ __u32 flags; /* 0 = Authenticated user 1 = GUEST */ >+ __u32 mask; /* which flags bits server understands ie 0x0001 */ >+ __u64 unix_user_id; >+ __u64 unix_user_gid; >+ __u32 number_of_supplementary_gids; /* may be zero */ >+ __u32 number_of_sids; /* may be zero */ >+ __u32 length_of_sid_array; /* in bytes - may be zero */ >+ __u32 pad; /* reserved - MBZ */ >+ /* __u64 gid_array[0]; */ /* may be empty */ >+ /* __u8 * psid_list */ /* may be empty */ >+} __attribute__((packed)) WHOAMI_RSP_DATA; > > /* SETFSInfo Levels */ > #define SMB_SET_CIFS_UNIX_INFO 0x200 >@@ -1853,8 +1892,17 @@ typedef struct { > #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ > #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ > #define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Allow POSIX path chars */ >+#define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based >+ calls including posix open >+ and posix unlink */ > #ifdef CONFIG_CIFS_POSIX >-#define CIFS_UNIX_CAP_MASK 0x0000001b >+/* Can not set pathnames cap yet until we send new posix create SMB since >+ otherwise server can treat such handles opened with older ntcreatex >+ (by a new client which knows how to send posix path ops) >+ as non-posix handles (can affect write behavior with byte range locks. >+ We can add back in POSIX_PATH_OPS cap when Posix Create/Mkdir finished */ >+/* #define CIFS_UNIX_CAP_MASK 0x0000003b */ >+#define CIFS_UNIX_CAP_MASK 0x0000001b > #else > #define CIFS_UNIX_CAP_MASK 0x00000013 > #endif /* CONFIG_CIFS_POSIX */ >@@ -1941,7 +1989,7 @@ typedef struct { /* data block encoding of response to level 263 QPathInfo */ > __le32 AlignmentRequirement; > __le32 FileNameLength; > char FileName[1]; >-} __attribute__((packed)) FILE_ALL_INFO; /* level 0x107 QPathInfo */ >+} __attribute__((packed)) FILE_ALL_INFO; /* level 0x107 QPathInfo */ > > /* defines for enumerating possible values of the Unix type field below */ > #define UNIX_FILE 0 >@@ -1965,11 +2013,11 @@ typedef struct { > __u64 UniqueId; > __le64 Permissions; > __le64 Nlinks; >-} __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ >+} __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ > > typedef struct { > char LinkDest[1]; >-} __attribute__((packed)) FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ >+} __attribute__((packed)) FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ > > /* The following three structures are needed only for > setting time to NT4 and some older servers via >@@ -2006,7 +2054,7 @@ typedef struct { > __le64 ChangeTime; > __le32 Attributes; > __u32 Pad; >-} __attribute__((packed)) FILE_BASIC_INFO; /* size info, level 0x101 */ >+} __attribute__((packed)) FILE_BASIC_INFO; /* size info, level 0x101 */ > > struct file_allocation_info { > __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ >@@ -2015,7 +2063,7 @@ struct file_allocation_info { > > struct file_end_of_file_info { > __le64 FileSize; /* offset to end of file */ >-} __attribute__((packed)); /* size info, level 0x104 for set, 0x106 for query */ >+} __attribute__((packed)); /* size info, level 0x104 for set, 0x106 for query */ > > struct file_alt_name_info { > __u8 alt_name[1]; >@@ -2070,6 +2118,19 @@ struct cifs_posix_acl { /* access conrol list (ACL) */ > > /* end of POSIX ACL definitions */ > >+typedef struct { >+ __u32 OpenFlags; /* same as NT CreateX */ >+ __u32 PosixOpenFlags; >+ __u32 Mode; >+ __u16 Level; /* reply level requested (see QPathInfo levels) */ >+ __u16 Pad; /* reserved - MBZ */ >+} __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */ >+ >+typedef struct { >+ /* reply varies based on requested level */ >+} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ >+ >+ > struct file_internal_info { > __u64 UniqueId; /* inode number */ > } __attribute__((packed)); /* level 0x3ee */ >@@ -2233,7 +2294,8 @@ struct data_blob { > 1) PosixCreateX - to set and return the mode, inode#, device info and > perhaps add a CreateDevice - to create Pipes and other special .inodes > Also note POSIX open flags >- 2) Close - to return the last write time to do cache across close more safely >+ 2) Close - to return the last write time to do cache across close >+ more safely > 3) FindFirst return unique inode number - what about resume key, two > forms short (matches readdir) and full (enough info to cache inodes) > 4) Mkdir - set mode >@@ -2268,7 +2330,8 @@ struct data_blob { > TRANSACTION2 (18 cases) > SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2 > (BB verify that never need to set allocation size) >- SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?) >+ SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via >+ Unix ext?) > > COPY (note support for copy across directories) - FUTURE, OPTIONAL > setting/getting OS/2 EAs - FUTURE (BB can this handle >@@ -2288,13 +2351,13 @@ struct data_blob { > T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields > Actually need QUERY_FILE_UNIX_INFO since has inode num > BB what about a) blksize/blkbits/blocks >- b) i_version >- c) i_rdev >- d) notify mask? >- e) generation >- f) size_seqcount >+ b) i_version >+ c) i_rdev >+ d) notify mask? >+ e) generation >+ f) size_seqcount > T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX >- TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended >+ TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended > T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL > > >@@ -2333,7 +2396,7 @@ typedef struct file_xattr_info { > __u32 xattr_value_len; > char xattr_name[0]; > /* followed by xattr_value[xattr_value_len], no pad */ >-} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ >+} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ > > > /* flags for chattr command */ >diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h >index e6d0bd2..a71c03f 100644 >--- a/fs/cifs/cifsproto.h >+++ b/fs/cifs/cifsproto.h >@@ -33,6 +33,10 @@ struct statfs; > #define msleep(x) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(x * HZ / 1000); } > #endif > >+#ifndef __user >+#define __user >+#endif >+ > /* > ***************************************************************** > * All Prototypes >@@ -51,7 +55,7 @@ extern void _FreeXid(unsigned int); > #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));} > extern char *build_path_from_dentry(struct dentry *); > extern char *build_wildcard_path_from_dentry(struct dentry *direntry); >-extern void renew_parental_timestamps(struct dentry *direntry); >+/* extern void renew_parental_timestamps(struct dentry *direntry);*/ > extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, > struct smb_hdr * /* input */ , > struct smb_hdr * /* out */ , >@@ -59,10 +63,14 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, > extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, > struct kvec *, int /* nvec to send */, > int * /* type of buf returned */ , const int long_op); >+extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *, >+ struct smb_hdr * /* input */ , >+ struct smb_hdr * /* out */ , >+ int * /* bytes returned */); > extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); >-extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); >+extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); > extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); >-extern int is_size_safe_to_change(struct cifsInodeInfo *); >+extern int is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); > extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); > extern unsigned int smbCalcSize(struct smb_hdr *ptr); > extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); >@@ -86,10 +94,13 @@ extern void DeleteOplockQEntry(struct oplock_q_entry *); > #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) > extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); > extern u64 cifs_UnixTimeToNT(struct timespec); >+extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time); > #else > extern u64 cifs_UnixTimeToNT(time_t); > extern time_t cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); >+extern time_t cnvrtDosUnixTm(__u16 date, __u16 time); > #endif >+extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time); > > extern int cifs_get_inode_info(struct inode **pinode, > const unsigned char *search_path, >@@ -127,6 +138,7 @@ 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, >+ int legacy /* whether to use old info level */, > const struct nls_table *nls_codepage, int remap); > extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, > const unsigned char *searchName, >@@ -353,9 +365,4 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, > 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); >-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) >-#if LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 9) >-extern void * kzalloc(size_t size, unsigned flgs); /* workaround RHEL4 */ >-#endif >-#endif > #endif /* _CIFSPROTO_H */ >diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c >index f1ad85c..80fc491 100644 >--- a/fs/cifs/cifssmb.c >+++ b/fs/cifs/cifssmb.c >@@ -49,6 +49,7 @@ static struct { > } protocols[] = { > #ifdef CONFIG_CIFS_WEAK_PW_HASH > {LANMAN_PROT, "\2LM1.2X002"}, >+ {LANMAN2_PROT, "\2LANMAN2.1"}, > #endif /* weak password hashing for legacy clients */ > {CIFS_PROT, "\2NT LM 0.12"}, > {POSIX_PROT, "\2POSIX 2"}, >@@ -61,6 +62,7 @@ static struct { > } protocols[] = { > #ifdef CONFIG_CIFS_WEAK_PW_HASH > {LANMAN_PROT, "\2LM1.2X002"}, >+ {LANMAN2_PROT, "\2LANMAN2.1"}, > #endif /* weak password hashing for legacy clients */ > {CIFS_PROT, "\2NT LM 0.12"}, > {BAD_PROT, "\2"} >@@ -70,13 +72,13 @@ static struct { > /* define the number of elements in the cifs dialect array */ > #ifdef CONFIG_CIFS_POSIX > #ifdef CONFIG_CIFS_WEAK_PW_HASH >-#define CIFS_NUM_PROT 3 >+#define CIFS_NUM_PROT 4 > #else > #define CIFS_NUM_PROT 2 > #endif /* CIFS_WEAK_PW_HASH */ > #else /* not posix */ > #ifdef CONFIG_CIFS_WEAK_PW_HASH >-#define CIFS_NUM_PROT 2 >+#define CIFS_NUM_PROT 3 > #else > #define CIFS_NUM_PROT 1 > #endif /* CONFIG_CIFS_WEAK_PW_HASH */ >@@ -136,12 +138,17 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, > while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { > #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) > int timeout = 10 * HZ; >- while ((tcon->ses->server->tcpStatus != CifsGood) && (timeout > 0)) { >- timeout = interruptible_sleep_on_timeout(&tcon->ses->server->response_q,timeout); >+ while((tcon->ses->server->tcpStatus != CifsGood) >+ && (timeout > 0)) { >+ timeout = interruptible_sleep_on_timeout( >+ &tcon->ses->server->response_q, >+ timeout); > } > #else >- wait_event_interruptible_timeout(tcon->ses->server->response_q, >- (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); >+ wait_event_interruptible_timeout( >+ tcon->ses->server->response_q, >+ (tcon->ses->server->tcpStatus == CifsGood), >+ 10 * HZ); > #endif > if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { > /* on "soft" mounts we wait once */ >@@ -277,8 +284,20 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, > 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 LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) >+ int timeout = 10 * HZ; >+ while((tcon->ses->server->tcpStatus != CifsGood) >+ && (timeout > 0)) { >+ timeout = interruptible_sleep_on_timeout >+ (&tcon->ses->server->response_q, >+ timeout); >+ } >+#else >+ wait_event_interruptible_timeout( >+ tcon->ses->server->response_q, >+ (tcon->ses->server->tcpStatus == CifsGood), >+ 10 * HZ); >+#endif > if(tcon->ses->server->tcpStatus == > CifsNeedReconnect) { > /* on "soft" mounts we wait once */ >@@ -407,6 +426,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) > struct TCP_Server_Info * server; > u16 count; > unsigned int secFlags; >+ u16 dialect; > > if(ses->server) > server = ses->server; >@@ -446,9 +466,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) > if (rc != 0) > goto neg_err_exit; > >- cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); >+ dialect = le16_to_cpu(pSMBr->DialectIndex); >+ cFYI(1,("Dialect: %d", dialect)); > /* Check wct = 1 error case */ >- if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) { >+ if((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) { > /* core returns wct = 1, but we do not ask for core - otherwise > small wct just comes when dialect index is -1 indicating we > could not negotiate a common dialect */ >@@ -456,7 +477,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) > goto neg_err_exit; > #ifdef CONFIG_CIFS_WEAK_PW_HASH > } else if((pSMBr->hdr.WordCount == 13) >- && (pSMBr->DialectIndex == LANMAN_PROT)) { >+ && ((dialect == LANMAN_PROT) >+ || (dialect == LANMAN2_PROT))) { >+ __s16 tmp; > struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; > > if((secFlags & CIFSSEC_MAY_LANMAN) || >@@ -482,12 +505,44 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) > server->maxRw = 0;/* we do not need to use raw anyway */ > server->capabilities = CAP_MPX_MODE; > } >- server->timeZone = le16_to_cpu(rsp->ServerTimeZone); >+ tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); >+ if (tmp == -1) { >+ /* OS/2 often does not set timezone therefore >+ * we must use server time to calc time zone. >+ * Could deviate slightly from the right zone. >+ * Smallest defined timezone difference is 15 minutes >+ * (i.e. Nepal). Rounding up/down is done to match >+ * this requirement. >+ */ >+ int val, seconds, remain, result; >+ struct timespec ts, utc; >+ utc = CURRENT_TIME; >+ ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date), >+ le16_to_cpu(rsp->SrvTime.Time)); >+ cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d", >+ (int)ts.tv_sec, (int)utc.tv_sec, >+ (int)(utc.tv_sec - ts.tv_sec))); >+ val = (int)(utc.tv_sec - ts.tv_sec); >+ seconds = val < 0 ? -val : val; >+ result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; >+ remain = seconds % MIN_TZ_ADJ; >+ if(remain >= (MIN_TZ_ADJ / 2)) >+ result += MIN_TZ_ADJ; >+ if(val < 0) >+ result = - result; >+ server->timeAdj = result; >+ } else { >+ server->timeAdj = (int)tmp; >+ server->timeAdj *= 60; /* also in seconds */ >+ } >+ cFYI(1,("server->timeAdj: %d seconds", server->timeAdj)); >+ > > /* BB get server time for time conversions and add > code to use it and timezone since this is not UTC */ > >- if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { >+ if (rsp->EncryptionKeyLength == >+ cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { > memcpy(server->cryptKey, rsp->EncryptionKey, > CIFS_CRYPTO_KEY_SIZE); > } else if (server->secMode & SECMODE_PW_ENCRYPT) { >@@ -541,7 +596,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) > cFYI(0, ("Max buf = %d", ses->server->maxBuf)); > GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); > server->capabilities = le32_to_cpu(pSMBr->Capabilities); >- server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); >+ server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); >+ server->timeAdj *= 60; > if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { > memcpy(server->cryptKey, pSMBr->u.EncryptionKey, > CIFS_CRYPTO_KEY_SIZE); >@@ -1470,8 +1526,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, > pSMB->hdr.smb_buf_length += count; > pSMB->ByteCount = cpu_to_le16(count); > >- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, >+ if (waitFlag) { >+ rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, >+ (struct smb_hdr *) pSMBr, &bytes_returned); >+ } else { >+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, > (struct smb_hdr *) pSMBr, &bytes_returned, timeout); >+ } > cifs_stats_inc(&tcon->num_locks); > if (rc) { > cFYI(1, ("Send error in Lock = %d", rc)); >@@ -1556,8 +1617,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, > pSMB->Reserved4 = 0; > pSMB->hdr.smb_buf_length += byte_count; > pSMB->ByteCount = cpu_to_le16(byte_count); >- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, >+ if (waitFlag) { >+ rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, >+ (struct smb_hdr *) pSMBr, &bytes_returned); >+ } else { >+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, > (struct smb_hdr *) pSMBr, &bytes_returned, timeout); >+ } >+ > if (rc) { > cFYI(1, ("Send error in Posix Lock = %d", rc)); > } else if (get_flag) { >@@ -1616,7 +1683,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) > pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ > > pSMB->FileID = (__u16) smb_file_id; >- pSMB->LastWriteTime = 0; >+ pSMB->LastWriteTime = 0xFFFFFFFF; > pSMB->ByteCount = 0; > rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, > (struct smb_hdr *) pSMBr, &bytes_returned, 0); >@@ -2855,7 +2922,6 @@ qsec_out: > return rc; > } > >- > /* Legacy Query Path Information call for lookup to old servers such > as Win9x/WinME */ > int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, >@@ -2897,7 +2963,20 @@ QInfRetry: > if (rc) { > cFYI(1, ("Send error in QueryInfo = %d", rc)); > } else if (pFinfo) { /* decode response */ >+ struct timespec ts; >+ __u32 time = le32_to_cpu(pSMBr->last_write_time); >+ /* BB FIXME - add time zone adjustment BB */ > memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); >+ ts.tv_nsec = 0; >+ ts.tv_sec = time; >+ /* decode time fields */ >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) >+ pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts)); >+#else >+ pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(time)); >+#endif >+ pFinfo->LastWriteTime = pFinfo->ChangeTime; >+ pFinfo->LastAccessTime = 0; > pFinfo->AllocationSize = > cpu_to_le64(le32_to_cpu(pSMBr->size)); > pFinfo->EndOfFile = pFinfo->AllocationSize; >@@ -2921,6 +3000,7 @@ int > CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, > const unsigned char *searchName, > FILE_ALL_INFO * pFindData, >+ int legacy /* old style infolevel */, > const struct nls_table *nls_codepage, int remap) > { > /* level 263 SMB_QUERY_FILE_ALL_INFO */ >@@ -2969,7 +3049,10 @@ QPathInfoRetry: > byte_count = params + 1 /* pad */ ; > pSMB->TotalParameterCount = cpu_to_le16(params); > pSMB->ParameterCount = pSMB->TotalParameterCount; >- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); >+ if(legacy) >+ pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD); >+ else >+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); > pSMB->Reserved4 = 0; > pSMB->hdr.smb_buf_length += byte_count; > pSMB->ByteCount = cpu_to_le16(byte_count); >@@ -2981,13 +3064,24 @@ QPathInfoRetry: > } else { /* decode response */ > rc = validate_t2((struct smb_t2_rsp *)pSMBr); > >- if (rc || (pSMBr->ByteCount < 40)) >+ if (rc) /* BB add auto retry on EOPNOTSUPP? */ >+ rc = -EIO; >+ else if (!legacy && (pSMBr->ByteCount < 40)) > rc = -EIO; /* bad smb */ >+ else if(legacy && (pSMBr->ByteCount < 24)) >+ rc = -EIO; /* 24 or 26 expected but we do not read last field */ > else if (pFindData){ >+ int size; > __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); >+ if(legacy) /* we do not read the last field, EAsize, fortunately >+ since it varies by subdialect and on Set vs. Get, is >+ two bytes or 4 bytes depending but we don't care here */ >+ size = sizeof(FILE_INFO_STANDARD); >+ else >+ size = sizeof(FILE_ALL_INFO); > memcpy((char *) pFindData, > (char *) &pSMBr->hdr.Protocol + >- data_offset, sizeof (FILE_ALL_INFO)); >+ data_offset, size); > } else > rc = -ENOMEM; > } >@@ -3612,6 +3706,14 @@ getDFSRetry: > strncpy(pSMB->RequestFileName, searchName, name_len); > } > >+ if(ses->server) { >+ if(ses->server->secMode & >+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) >+ pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; >+ } >+ >+ pSMB->hdr.Uid = ses->Suid; >+ > params = 2 /* level */ + name_len /*includes null */ ; > pSMB->TotalDataCount = 0; > pSMB->DataCount = 0; >@@ -4730,6 +4832,16 @@ setPermsRetry: > pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); > pSMB->Reserved4 = 0; > pSMB->hdr.smb_buf_length += byte_count; >+ /* Samba server ignores set of file size to zero due to bugs in some >+ older clients, but we should be precise - we use SetFileSize to >+ set file size and do not want to truncate file size to zero >+ accidently as happened on one Samba server beta by putting >+ zero instead of -1 here */ >+ data_offset->EndOfFile = NO_CHANGE_64; >+ data_offset->NumOfBytes = NO_CHANGE_64; >+ data_offset->LastStatusChange = NO_CHANGE_64; >+ data_offset->LastAccessTime = NO_CHANGE_64; >+ data_offset->LastModificationTime = NO_CHANGE_64; > data_offset->Uid = cpu_to_le64(uid); > data_offset->Gid = cpu_to_le64(gid); > /* better to leave device as zero when it is */ >@@ -4815,7 +4927,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, > } else { > /* Add file to outstanding requests */ > /* BB change to kmem cache alloc */ >- dnotify_req = (struct dir_notify_req *) kmalloc( >+ dnotify_req = kmalloc( > sizeof(struct dir_notify_req), > GFP_KERNEL); > if(dnotify_req) { >diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c >index 8edb990..9009d59 100644 >--- a/fs/cifs/connect.c >+++ b/fs/cifs/connect.c >@@ -33,6 +33,9 @@ > #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > #include <linux/mempool.h> > #include <linux/pagevec.h> >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19) >+#include <linux/freezer.h> >+#endif /* 2.6.19 */ > #endif > #include <asm/uaccess.h> > #include <asm/processor.h> >@@ -101,6 +104,7 @@ struct smb_vol { > unsigned int wsize; > unsigned int sockopt; > unsigned short int port; >+ char * prepath; > }; > > static int ipv4_connect(struct sockaddr_in *psin_server, >@@ -822,12 +826,21 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) > separator[1] = 0; > > memset(vol->source_rfc1001_name,0x20,15); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) >+ for(i=0;i < strnlen(utsname()->nodename,15);i++) { >+ /* 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(utsname()->nodename[i]); >+#else > for(i=0;i < strnlen(system_utsname.nodename,15);i++) { > /* 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]); >+#endif > } > vol->source_rfc1001_name[15] = 0; > /* null target name indicates to use *SMBSERVR default called name >@@ -867,10 +880,13 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) > } else if (strnicmp(data, "nouser_xattr",12) == 0) { > vol->no_xattr = 1; > } else if (strnicmp(data, "user", 4) == 0) { >- if (!value || !*value) { >+ if (!value) { > printk(KERN_WARNING > "CIFS: invalid or missing username\n"); > return 1; /* needs_arg; */ >+ } else if(!*value) { >+ /* null user, ie anonymous, authentication */ >+ vol->nullauth = 1; > } > if (strnlen(value, 200) < 200) { > vol->username = value; >@@ -1044,6 +1060,28 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) > printk(KERN_WARNING "CIFS: domain name too long\n"); > return 1; > } >+ } else if (strnicmp(data, "prefixpath", 10) == 0) { >+ if (!value || !*value) { >+ printk(KERN_WARNING >+ "CIFS: invalid path prefix\n"); >+ return 1; /* needs_arg; */ >+ } >+ if ((temp_len = strnlen(value, 1024)) < 1024) { >+ if(value[0] != '/') >+ temp_len++; /* missing leading slash */ >+ vol->prepath = kmalloc(temp_len+1,GFP_KERNEL); >+ if(vol->prepath == NULL) >+ return 1; >+ if(value[0] != '/') { >+ vol->prepath[0] = '/'; >+ strcpy(vol->prepath+1,value); >+ } else >+ strcpy(vol->prepath,value); >+ cFYI(1,("prefix path %s",vol->prepath)); >+ } else { >+ printk(KERN_WARNING "CIFS: prefix too long\n"); >+ return 1; >+ } > } else if (strnicmp(data, "iocharset", 9) == 0) { > if (!value || !*value) { > printk(KERN_WARNING "CIFS: invalid iocharset specified\n"); >@@ -1322,33 +1360,35 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) > > read_lock(&GlobalSMBSeslock); > list_for_each(tmp, &GlobalTreeConnectionList) { >- cFYI(1, ("Next tcon - ")); >+ cFYI(1, ("Next tcon")); > tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); > if (tcon->ses) { > if (tcon->ses->server) { > cFYI(1, >- (" old ip addr: %x == new ip %x ?", >+ ("old ip addr: %x == new ip %x ?", > tcon->ses->server->addr.sockAddr.sin_addr. > s_addr, new_target_ip_addr)); > if (tcon->ses->server->addr.sockAddr.sin_addr. > s_addr == new_target_ip_addr) { >- /* BB lock tcon and server and tcp session and increment use count here? */ >+ /* BB lock tcon, server and tcp session and increment use count here? */ > /* found a match on the TCP session */ > /* BB check if reconnection needed */ >- cFYI(1,("Matched ip, old UNC: %s == new: %s ?", >+ cFYI(1,("IP match, old UNC: %s new: %s", > tcon->treeName, uncName)); > if (strncmp > (tcon->treeName, uncName, > MAX_TREE_SIZE) == 0) { > cFYI(1, >- ("Matched UNC, old user: %s == new: %s ?", >+ ("and old usr: %s new: %s", > tcon->treeName, uncName)); > if (strncmp > (tcon->ses->userName, > userName, > MAX_USERNAME_SIZE) == 0) { > read_unlock(&GlobalSMBSeslock); >- return tcon;/* also matched user (smb session)*/ >+ /* matched smb session >+ (user name */ >+ return tcon; > } > } > } >@@ -1676,11 +1716,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { > kfree(volume_info.UNC); > kfree(volume_info.password); >+ kfree(volume_info.prepath); > FreeXid(xid); > return -EINVAL; > } > >- if (volume_info.username) { >+ if (volume_info.nullauth) { >+ cFYI(1,("null user")); >+ volume_info.username = NULL; >+ } else if (volume_info.username) { > /* BB fixme parse for domain name here */ > cFYI(1, ("Username: %s ", volume_info.username)); > >@@ -1690,6 +1734,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > locations such as env variables and files on disk */ > kfree(volume_info.UNC); > kfree(volume_info.password); >+ kfree(volume_info.prepath); > FreeXid(xid); > return -EINVAL; > } >@@ -1710,6 +1755,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > /* we failed translating address */ > kfree(volume_info.UNC); > kfree(volume_info.password); >+ kfree(volume_info.prepath); > FreeXid(xid); > return -EINVAL; > } >@@ -1722,6 +1768,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > cERROR(1,("Connecting to DFS root not implemented yet")); > kfree(volume_info.UNC); > kfree(volume_info.password); >+ kfree(volume_info.prepath); > FreeXid(xid); > return -EINVAL; > } else /* which servers DFS root would we conect to */ { >@@ -1729,6 +1776,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified")); > kfree(volume_info.UNC); > kfree(volume_info.password); >+ kfree(volume_info.prepath); > FreeXid(xid); > return -EINVAL; > } >@@ -1743,6 +1791,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); > kfree(volume_info.UNC); > kfree(volume_info.password); >+ kfree(volume_info.prepath); > FreeXid(xid); > return -ELIBACC; > } >@@ -1759,6 +1808,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > else { > kfree(volume_info.UNC); > kfree(volume_info.password); >+ kfree(volume_info.prepath); > FreeXid(xid); > return -EINVAL; > } >@@ -1781,6 +1831,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > sock_release(csocket); > kfree(volume_info.UNC); > kfree(volume_info.password); >+ kfree(volume_info.prepath); > FreeXid(xid); > return rc; > } >@@ -1791,6 +1842,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > sock_release(csocket); > kfree(volume_info.UNC); > kfree(volume_info.password); >+ kfree(volume_info.prepath); > FreeXid(xid); > return rc; > } else { >@@ -1815,6 +1867,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > sock_release(csocket); > kfree(volume_info.UNC); > kfree(volume_info.password); >+ kfree(volume_info.prepath); > FreeXid(xid); > return rc; > } >@@ -1902,6 +1955,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > /* Windows ME may prefer this */ > cFYI(1,("readsize set to minimum 2048")); > } >+ /* calculate prepath */ >+ cifs_sb->prepath = volume_info.prepath; >+ if(cifs_sb->prepath) { >+ cifs_sb->prepathlen = strlen(cifs_sb->prepath); >+ cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb); >+ volume_info.prepath = NULL; >+ } else >+ cifs_sb->prepathlen = 0; > cifs_sb->mnt_uid = volume_info.linux_uid; > cifs_sb->mnt_gid = volume_info.linux_gid; > cifs_sb->mnt_file_mode = volume_info.file_mode; >@@ -2084,6 +2145,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, > the password ptr is put in the new session structure (in which case the > password will be freed at unmount time) */ > kfree(volume_info.UNC); >+ kfree(volume_info.prepath); > FreeXid(xid); > return rc; > } >@@ -2187,8 +2249,14 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, > 32, nls_codepage); > bcc_ptr += 2 * bytes_returned; > bytes_returned = >- cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) >+ cifs_strtoUCS((__le16 *)bcc_ptr, utsname()->release, >+ 32, nls_codepage); >+ >+#else >+ cifs_strtoUCS((__le16 *)bcc_ptr, system_utsname.release, > 32, nls_codepage); >+#endif > bcc_ptr += 2 * bytes_returned; > bcc_ptr += 2; > bytes_returned = >@@ -2214,8 +2282,13 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, > } > strcpy(bcc_ptr, "Linux version "); > bcc_ptr += strlen("Linux version "); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) >+ strcpy(bcc_ptr, utsname()->release); >+ bcc_ptr += strlen(utsname()->release) + 1; >+#else > strcpy(bcc_ptr, system_utsname.release); > bcc_ptr += strlen(system_utsname.release) + 1; >+#endif > strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); > bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; > } >@@ -2479,8 +2552,14 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, > 32, nls_codepage); > bcc_ptr += 2 * bytes_returned; > bytes_returned = >- cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, >- nls_codepage); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) >+ cifs_strtoUCS((__le16 *)bcc_ptr, utsname()->release, 32, >+ nls_codepage); >+ >+#else >+ cifs_strtoUCS((__le16 *)bcc_ptr, system_utsname.release, 32, >+ nls_codepage); >+#endif > bcc_ptr += 2 * bytes_returned; > bcc_ptr += 2; /* null terminate Linux version */ > bytes_returned = >@@ -2496,8 +2575,13 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, > } else { /* ASCII */ > strcpy(bcc_ptr, "Linux version "); > bcc_ptr += strlen("Linux version "); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) >+ strcpy(bcc_ptr, utsname()->release); >+ bcc_ptr += strlen(utsname()->release) + 1; >+#else > strcpy(bcc_ptr, system_utsname.release); > bcc_ptr += strlen(system_utsname.release) + 1; >+#endif > strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); > bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; > bcc_ptr++; /* empty domain field */ >@@ -2870,8 +2954,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, > 32, nls_codepage); > bcc_ptr += 2 * bytes_returned; > bytes_returned = >+ >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) >+ cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, >+ nls_codepage); >+#else > cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, > nls_codepage); >+#endif > bcc_ptr += 2 * bytes_returned; > bcc_ptr += 2; /* null term version string */ > bytes_returned = >@@ -2922,8 +3012,13 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, > > strcpy(bcc_ptr, "Linux version "); > bcc_ptr += strlen("Linux version "); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) >+ strcpy(bcc_ptr, utsname()->release); >+ bcc_ptr += strlen(utsname()->release) + 1; >+#else > strcpy(bcc_ptr, system_utsname.release); > bcc_ptr += strlen(system_utsname.release) + 1; >+#endif > strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); > bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; > bcc_ptr++; /* null domain */ >@@ -3249,7 +3344,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, > } > /* else do not bother copying these informational fields */ > } >- if(smb_buffer_response->WordCount == 3) >+ if((smb_buffer_response->WordCount == 3) || >+ (smb_buffer_response->WordCount == 7)) >+ /* field is in same location */ > tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); > else > tcon->Flags = 0; >@@ -3271,6 +3368,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) > int xid; > struct cifsSesInfo *ses = NULL; > struct task_struct *cifsd_task; >+ char * tmp; > > xid = GetXid(); > >@@ -3304,6 +3402,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) > } > > cifs_sb->tcon = NULL; >+ tmp = cifs_sb->prepath; >+ cifs_sb->prepathlen = 0; >+ cifs_sb->prepath = NULL; >+ kfree(tmp); > if (ses) > #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) > set_current_state(TASK_INTERRUPTIBLE); >@@ -3346,19 +3448,21 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, > first_time = 1; > } > if (!rc) { >+ pSesInfo->flags = 0; > pSesInfo->capabilities = pSesInfo->server->capabilities; > if(linuxExtEnabled == 0) > pSesInfo->capabilities &= (~CAP_UNIX); > /* pSesInfo->sequence_number = 0;*/ >- cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", >+ cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", > pSesInfo->server->secMode, > pSesInfo->server->capabilities, >- pSesInfo->server->timeZone)); >+ pSesInfo->server->timeAdj)); > if(experimEnabled < 2) > rc = CIFS_SessSetup(xid, pSesInfo, > first_time, nls_info); > else if (extended_security >- && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) >+ && (pSesInfo->capabilities >+ & CAP_EXTENDED_SECURITY) > && (pSesInfo->server->secType == NTLMSSP)) { > rc = -EOPNOTSUPP; > } else if (extended_security >@@ -3372,7 +3476,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, > if (!rc) { > if(ntlmv2_flag) { > char * v2_response; >- cFYI(1,("Can use more secure NTLM version 2 password hash")); >+ cFYI(1,("more secure NTLM ver2 hash")); > if(CalcNTLMv2_partial_mac_key(pSesInfo, > nls_info)) { > rc = -ENOMEM; >diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c >index 8eed9c4..7be188c 100644 >--- a/fs/cifs/dir.c >+++ b/fs/cifs/dir.c >@@ -37,7 +37,7 @@ > #include <linux/ctype.h> > #endif > >-void >+static void > renew_parental_timestamps(struct dentry *direntry) > { > /* BB check if there is a way to get the kernel to do this or if we really need this */ >@@ -52,7 +52,8 @@ char * > build_path_from_dentry(struct dentry *direntry) > { > struct dentry *temp; >- int namelen = 0; >+ int namelen; >+ int pplen; > char *full_path; > char dirsep; > >@@ -62,7 +63,9 @@ build_path_from_dentry(struct dentry *direntry) > when the server crashed */ > > dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); >+ pplen = CIFS_SB(direntry->d_sb)->prepathlen; > cifs_bp_rename_retry: >+ namelen = pplen; > for (temp = direntry; !IS_ROOT(temp);) { > namelen += (1 + temp->d_name.len); > temp = temp->d_parent; >@@ -76,7 +79,6 @@ cifs_bp_rename_retry: > if(full_path == NULL) > return full_path; > full_path[namelen] = 0; /* trailing null */ >- > for (temp = direntry; !IS_ROOT(temp);) { > namelen -= 1 + temp->d_name.len; > if (namelen < 0) { >@@ -85,7 +87,7 @@ cifs_bp_rename_retry: > full_path[namelen] = dirsep; > strncpy(full_path + namelen + 1, temp->d_name.name, > temp->d_name.len); >- cFYI(0, (" name: %s ", full_path + namelen)); >+ cFYI(0, ("name: %s", full_path + namelen)); > } > temp = temp->d_parent; > if(temp == NULL) { >@@ -94,18 +96,23 @@ cifs_bp_rename_retry: > return NULL; > } > } >- if (namelen != 0) { >+ if (namelen != pplen) { > cERROR(1, >- ("We did not end path lookup where we expected namelen is %d", >+ ("did not end path lookup where expected namelen is %d", > namelen)); >- /* presumably this is only possible if we were racing with a rename >+ /* presumably this is only possible if 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_bp_rename_retry; > } >- >+ /* DIR_SEP already set for byte 0 / vs \ but not for >+ subsequent slashes in prepath which currently must >+ be entered the right way - not sure if there is an alternative >+ since the '\' is a valid posix character so we can not switch >+ those safely to '/' if any are found in the middle of the prepath */ >+ /* BB test paths to Windows with '/' in the midst of prepath */ >+ strncpy(full_path,CIFS_SB(direntry->d_sb)->prepath,pplen); > return full_path; > } > >@@ -139,10 +146,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) > char *full_path = NULL; > FILE_ALL_INFO * buf = NULL; > struct inode *newinode = NULL; >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > struct cifsFileInfo * pCifsFile = NULL; > struct cifsInodeInfo * pCifsInode; >- int disposition = FILE_OVERWRITE_IF; > int write_only = FALSE; >+#endif >+ int disposition = FILE_OVERWRITE_IF; > > xid = GetXid(); > >@@ -286,6 +295,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) > pCifsFile->invalidHandle = FALSE; > pCifsFile->closePend = FALSE; > init_MUTEX(&pCifsFile->fh_sem); >+ init_MUTEX(&pCifsFile->lock_sem); >+ INIT_LIST_HEAD(&pCifsFile->llist); >+ atomic_set(&pCifsFile->wrtPending,0); >+ > /* set the following in open now > pCifsFile->pfile = file; */ > write_lock(&GlobalSMBSeslock); >@@ -310,19 +323,24 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) > } > write_unlock(&GlobalSMBSeslock); > } >+ } >+cifs_create_out: > #else /* 2.4 does not pass open flags so must reopen on cifs_open */ > CIFSSMBClose(xid, pTcon, fileHandle); >+ } > #endif >- } >-cifs_create_out: > kfree(buf); > kfree(full_path); > FreeXid(xid); > return rc; > } > >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, >- dev_t device_number) >+ dev_t device_number) >+#else >+int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int device_number) >+#endif > { > int rc = -EPERM; > int xid; >@@ -443,9 +461,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, > return rc; > } > >- >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > struct dentry * > cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct nameidata *nd) >+#else >+struct dentry * >+cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry) >+#endif > { > int xid; > int rc = 0; /* to get around spurious gcc warning, set to zero here */ >@@ -539,8 +561,13 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name > return ERR_PTR(rc); > } > >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > static int > cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) >+#else >+static int >+cifs_d_revalidate(struct dentry *direntry, int flags) >+#endif > { > int isValid = 1; > >diff --git a/fs/cifs/export.c b/fs/cifs/export.c >new file mode 100644 >index 0000000..1d71639 >--- /dev/null >+++ b/fs/cifs/export.c >@@ -0,0 +1,52 @@ >+/* >+ * fs/cifs/export.c >+ * >+ * Copyright (C) International Business Machines Corp., 2007 >+ * Author(s): Steve French (sfrench@us.ibm.com) >+ * >+ * Common Internet FileSystem (CIFS) client >+ * >+ * Operations related to support for exporting files via NFSD >+ * >+ * This library is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU Lesser General Public License as published >+ * by the Free Software Foundation; either version 2.1 of the License, or >+ * (at your option) any later version. >+ * >+ * This library is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See >+ * the GNU Lesser General Public License for more details. >+ * >+ * You should have received a copy of the GNU Lesser General Public License >+ * along with this library; if not, write to the Free Software >+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA >+ */ >+ >+ /* >+ * See Documentation/filesystems/Exporting >+ * and examples in fs/exportfs >+ */ >+ >+#include <linux/fs.h> >+ >+#ifdef CONFIG_CIFS_EXPERIMENTAL >+ >+static struct dentry *cifs_get_parent(struct dentry *dentry) >+{ >+ /* BB need to add code here eventually to enable export via NFSD */ >+ return ERR_PTR(-EACCES); >+} >+ >+struct export_operations cifs_export_ops = { >+ .get_parent = cifs_get_parent, >+/* Following five export operations are unneeded so far and can default */ >+/* .get_dentry = >+ .get_name = >+ .find_exported_dentry = >+ .decode_fh = >+ .encode_fs = */ >+ }; >+ >+#endif /* EXPERIMENTAL */ >+ >diff --git a/fs/cifs/file.c b/fs/cifs/file.c >index 99c5491..26e5453 100644 >--- a/fs/cifs/file.c >+++ b/fs/cifs/file.c >@@ -5,6 +5,7 @@ > * > * Copyright (C) International Business Machines Corp., 2002,2003 > * Author(s): Steve French (sfrench@us.ibm.com) >+ * Jeremy Allison (jra@samba.org) > * > * This library is free software; you can redistribute it and/or modify > * it under the terms of the GNU Lesser General Public License as published >@@ -21,17 +22,26 @@ > * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > */ > #include <linux/fs.h> >-#include <linux/backing-dev.h> > #include <linux/stat.h> > #include <linux/fcntl.h> >-#include <linux/mpage.h> > #include <linux/pagemap.h> >-#include <linux/pagevec.h> > #include <linux/smp_lock.h> >-#include <linux/writeback.h> > #include <linux/delay.h> > #include <asm/div64.h> > #include "cifsfs.h" >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) >+#include <linux/backing-dev.h> >+#include <linux/mpage.h> >+#include <linux/pagevec.h> >+#include <linux/writeback.h> >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) >+#include <linux/task_io_accounting_ops.h> >+#endif /* 2.6.19 */ >+#endif >+#include <asm/uaccess.h> >+#ifndef FL_SLEEP >+#define FL_SLEEP 0 >+#endif > #include "cifspdu.h" > #include "cifsglob.h" > #include "cifsproto.h" >@@ -47,6 +57,8 @@ static inline struct cifsFileInfo *cifs_init_private( > private_data->netfid = netfid; > private_data->pid = current->tgid; > init_MUTEX(&private_data->fh_sem); >+ init_MUTEX(&private_data->lock_sem); >+ INIT_LIST_HEAD(&private_data->llist); > private_data->pfile = file; /* needed for writepage */ > private_data->pInode = inode; > private_data->invalidHandle = FALSE; >@@ -79,7 +91,11 @@ static inline int cifs_convert_flags(unsigned int flags) > static inline int cifs_get_disposition(unsigned int flags) > { > if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > return FILE_CREATE; >+#else >+ return FILE_OPEN_IF; >+#endif > else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) > return FILE_OVERWRITE_IF; > else if ((flags & O_CREAT) == O_CREAT) >@@ -96,7 +112,11 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, > struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf, > char *full_path, int xid) > { >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > struct timespec temp; >+#else >+ time_t temp; >+#endif > int rc; > > /* want handles we can use to read with first >@@ -329,7 +349,7 @@ out: > return rc; > } > >-/* Try to reaquire byte range locks that were released when session */ >+/* Try to reacquire byte range locks that were released when session */ > /* to server was lost */ > static int cifs_relock_file(struct cifsFileInfo *cifsFile) > { >@@ -484,6 +504,8 @@ int cifs_close(struct inode *inode, struct file *file) > cifs_sb = CIFS_SB(inode->i_sb); > pTcon = cifs_sb->tcon; > if (pSMBFile) { >+ struct cifsLockInfo *li, *tmp; >+ > pSMBFile->closePend = TRUE; > if (pTcon) { > /* no sense reconnecting to close a file that is >@@ -499,14 +521,28 @@ int cifs_close(struct inode *inode, struct file *file) > the struct would be in each open file, > but this should give enough time to > clear the socket */ >- cERROR(1,("close with pending writes")); >+#ifdef CONFIG_CIFS_DEBUG2 >+ cFYI(1,("close delay, write pending")); >+#endif /* DEBUG2 */ > msleep(timeout); > timeout *= 4; >- } >+ } >+ if(atomic_read(&pSMBFile->wrtPending)) >+ cERROR(1,("close with pending writes")); > rc = CIFSSMBClose(xid, pTcon, > pSMBFile->netfid); > } > } >+ >+ /* Delete any outstanding lock records. >+ We'll lose them when the file is closed anyway. */ >+ down(&pSMBFile->lock_sem); >+ list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) { >+ list_del(&li->llist); >+ kfree(li); >+ } >+ up(&pSMBFile->lock_sem); >+ > write_lock(&GlobalSMBSeslock); > list_del(&pSMBFile->flist); > list_del(&pSMBFile->tlist); >@@ -581,6 +617,21 @@ int cifs_closedir(struct inode *inode, struct file *file) > return rc; > } > >+static int store_file_lock(struct cifsFileInfo *fid, __u64 len, >+ __u64 offset, __u8 lockType) >+{ >+ struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); >+ if (li == NULL) >+ return -ENOMEM; >+ li->offset = offset; >+ li->length = len; >+ li->type = lockType; >+ down(&fid->lock_sem); >+ list_add(&li->llist, &fid->llist); >+ up(&fid->lock_sem); >+ return 0; >+} >+ > int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) > { > int rc, xid; >@@ -592,6 +643,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) > struct cifsTconInfo *pTcon; > __u16 netfid; > __u8 lockType = LOCKING_ANDX_LARGE_FILES; >+ int posix_locking; > > length = 1 + pfLock->fl_end - pfLock->fl_start; > rc = -EACCES; >@@ -650,14 +702,14 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) > } > netfid = ((struct cifsFileInfo *)file->private_data)->netfid; > >+ posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) && >+ (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability)); > > /* BB add code here to normalize offset and length to > account for negative length which we can not accept over the > wire */ > if (IS_GETLK(cmd)) { >- if((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && >- (CIFS_UNIX_FCNTL_CAP & >- le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) { >+ if(posix_locking) { > int posix_lock_type; > if(lockType & LOCKING_ANDX_SHARED_LOCK) > posix_lock_type = CIFS_RDLCK; >@@ -693,9 +745,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) > FreeXid(xid); > return rc; > } >- if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && >- (CIFS_UNIX_FCNTL_CAP & >- le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) { >+ >+ if (!numLock && !numUnlock) { >+ /* if no lock or unlock then nothing >+ to do since we do not know what it is */ >+ FreeXid(xid); >+ return -EOPNOTSUPP; >+ } >+ >+ if (posix_locking) { > int posix_lock_type; > if(lockType & LOCKING_ANDX_SHARED_LOCK) > posix_lock_type = CIFS_RDLCK; >@@ -704,18 +762,47 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) > > if(numUnlock == 1) > posix_lock_type = CIFS_UNLCK; >- else if(numLock == 0) { >- /* if no lock or unlock then nothing >- to do since we do not know what it is */ >- FreeXid(xid); >- return -EOPNOTSUPP; >- } >+ > rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */, > length, pfLock, > posix_lock_type, wait_flag); >- } else >- rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, >- numUnlock, numLock, lockType, wait_flag); >+ } else { >+ struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data; >+ >+ if (numLock) { >+ rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, >+ 0, numLock, lockType, wait_flag); >+ >+ if (rc == 0) { >+ /* For Windows locks we must store them. */ >+ rc = store_file_lock(fid, length, >+ pfLock->fl_start, lockType); >+ } >+ } else if (numUnlock) { >+ /* For each stored lock that this unlock overlaps >+ completely, unlock it. */ >+ int stored_rc = 0; >+ struct cifsLockInfo *li, *tmp; >+ >+ rc = 0; >+ down(&fid->lock_sem); >+ list_for_each_entry_safe(li, tmp, &fid->llist, llist) { >+ if (pfLock->fl_start <= li->offset && >+ length >= li->length) { >+ stored_rc = CIFSSMBLock(xid, pTcon, netfid, >+ li->length, li->offset, >+ 1, 0, li->type, FALSE); >+ if (stored_rc) >+ rc = stored_rc; >+ >+ list_del(&li->llist); >+ kfree(li); >+ } >+ } >+ up(&fid->lock_sem); >+ } >+ } >+ > #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) > if (pfLock->fl_flags & FL_POSIX) > posix_lock_file_wait(file, pfLock); >@@ -957,8 +1044,9 @@ static ssize_t cifs_write(struct file *file, const char *write_data, > /* since the write may have blocked check these pointers again */ > if (file->f_dentry) { > if (file->f_dentry->d_inode) { >- file->f_dentry->d_inode->i_ctime = >- file->f_dentry->d_inode->i_mtime = CURRENT_TIME; >+/*BB We could make this contingent on superblock ATIME flag too */ >+/* file->f_dentry->d_inode->i_ctime = >+ file->f_dentry->d_inode->i_mtime = CURRENT_TIME;*/ > if (total_written > 0) { > if (*poffset > file->f_dentry->d_inode->i_size) > i_size_write(file->f_dentry->d_inode, >@@ -982,7 +1070,9 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) > > if(cifs_inode == NULL) { > cERROR(1,("Null inode passed to cifs_writeable_file")); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 19) > dump_stack(); >+#endif > return NULL; > } > >@@ -997,7 +1087,11 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) > read_unlock(&GlobalSMBSeslock); > if((open_file->invalidHandle) && > (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) { >- rc = cifs_reopen_file(&cifs_inode->vfs_inode, >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) >+ rc = cifs_reopen_file(open_file->pfile->f_dentry->d_inode, >+#else >+ rc = cifs_reopen_file(&cifs_inode->vfs_inode, >+#endif > open_file->pfile, FALSE); > /* if it fails, try another handle - might be */ > /* dangerous to hold up writepages with retry */ >@@ -1090,8 +1184,12 @@ static int cifs_writepages(struct address_space *mapping, > int done = 0; > pgoff_t end = -1; > pgoff_t index; >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) >+ int range_whole = 0; >+#else > int is_range = 0; >- struct kvec iov[32]; >+#endif /* 2.6.17 */ >+ struct kvec * iov; > int len; > int n_iov = 0; > pgoff_t next; >@@ -1116,21 +1214,39 @@ static int cifs_writepages(struct address_space *mapping, > if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) > if(cifs_sb->tcon->ses->server->secMode & > (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) >- if(!experimEnabled) >+ if(!experimEnabled) > return generic_writepages(mapping, wbc); > >+ iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL); >+ if(iov == NULL) >+ return generic_writepages(mapping, wbc); >+ >+ > /* > * BB: Is this meaningful for a non-block-device file system? > * If it is, we should test it again after we do I/O > */ > if (wbc->nonblocking && bdi_write_congested(bdi)) { > wbc->encountered_congestion = 1; >+ kfree(iov); > return 0; > } > > xid = GetXid(); > > pagevec_init(&pvec, 0); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) >+ if (wbc->range_cyclic) { >+ index = mapping->writeback_index; /* Start from prev offset */ >+ end = -1; >+ } else { >+ index = wbc->range_start >> PAGE_CACHE_SHIFT; >+ end = wbc->range_end >> PAGE_CACHE_SHIFT; >+ if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) >+ range_whole = 1; >+ scanned = 1; >+ } >+#else > if (wbc->sync_mode == WB_SYNC_NONE) > index = mapping->writeback_index; /* Start from prev offset */ > else { >@@ -1143,6 +1259,7 @@ static int cifs_writepages(struct address_space *mapping, > is_range = 1; > scanned = 1; > } >+#endif /* 2.6.17 */ > retry: > while (!done && (index <= end) && > (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, >@@ -1176,7 +1293,11 @@ retry: > break; > } > >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) >+ if (!wbc->range_cyclic && page->index > end) { >+#else > if (unlikely(is_range) && (page->index > end)) { >+#endif /* 2.6.17 */ > done = 1; > unlock_page(page); > break; >@@ -1192,14 +1313,21 @@ retry: > wait_on_page_writeback(page); > > if (PageWriteback(page) || >- !test_clear_page_dirty(page)) { >+ !clear_page_dirty_for_io(page)) { > unlock_page(page); > break; > } > >+ /* >+ * This actually clears the dirty bit in the radix tree. >+ * See cifs_writepage() for more commentary. >+ */ >+ set_page_writeback(page); >+ > if (page_offset(page) >= mapping->host->i_size) { > done = 1; > unlock_page(page); >+ end_page_writeback(page); > break; > } > >@@ -1263,6 +1391,7 @@ retry: > SetPageError(page); > kunmap(page); > unlock_page(page); >+ end_page_writeback(page); > page_cache_release(page); > } > if ((wbc->nr_to_write -= n_iov) <= 0) >@@ -1280,16 +1409,24 @@ retry: > index = 0; > goto retry; > } >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) >+ if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) >+#else > if (!is_range) >+#endif /* 2.6.17 */ > mapping->writeback_index = index; > > FreeXid(xid); >- >+ kfree(iov); > return rc; > } > #endif /* KERNEL_VERSION > 2.6.14 */ > >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) >+static int cifs_writepage(struct page* page) >+#else > static int cifs_writepage(struct page* page, struct writeback_control *wbc) >+#endif > { > int rc = -EFAULT; > int xid; >@@ -1300,11 +1437,23 @@ static int cifs_writepage(struct page* page, struct writeback_control *wbc) > if (!PageUptodate(page)) { > cFYI(1, ("ppw - page not up to date")); > } >- >+ >+ /* >+ * Set the "writeback" flag, and clear "dirty" in the radix tree. >+ * >+ * A writepage() implementation always needs to do either this, >+ * or re-dirty the page with "redirty_page_for_writepage()" in >+ * the case of a failure. >+ * >+ * Just unlocking the page will cause the radix tree tag-bits >+ * to fail to update with the state of the page correctly. >+ */ >+ set_page_writeback(page); > rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE); > SetPageUptodate(page); /* BB add check for error and Clearuptodate? */ > unlock_page(page); >- page_cache_release(page); >+ end_page_writeback(page); >+ page_cache_release(page); > FreeXid(xid); > return rc; > } >@@ -1321,6 +1470,7 @@ static int cifs_commit_write(struct file *file, struct page *page, > xid = GetXid(); > cFYI(1, ("commit write for page %p up to position %lld for %d", > page, position, to)); >+ spin_lock(&inode->i_lock); > if (position > inode->i_size) { > i_size_write(inode, position); > /* if (file->private_data == NULL) { >@@ -1350,6 +1500,7 @@ static int cifs_commit_write(struct file *file, struct page *page, > cFYI(1, (" SetEOF (commit write) rc = %d", rc)); > } */ > } >+ spin_unlock(&inode->i_lock); > if (!PageUptodate(page)) { > position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; > /* can not rely on (or let) writepage write this data */ >@@ -1427,7 +1578,11 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) > * As file closes, flush all cached write data for this inode checking > * for write behind errors. > */ >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) >+int cifs_flush(struct file *file, fl_owner_t id) >+#else > int cifs_flush(struct file *file) >+#endif /* 2.6.17 */ > { > struct inode * inode = file->f_dentry->d_inode; > int rc = 0; >@@ -1766,6 +1921,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, > } > break; > } else if (bytes_read > 0) { >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) >+ task_io_account_read(bytes_read); >+#endif > pSMBr = (struct smb_com_read_rsp *)smb_read_data; > cifs_copy_cache_pages(mapping, page_list, bytes_read, > smb_read_data + 4 /* RFC1001 hdr */ + >@@ -1895,7 +2053,7 @@ static int cifs_readpage(struct file *file, struct page *page) > refreshing the inode only on increases in the file size > but this is tricky to do without racing with writebehind > page caching in the current Linux kernel design */ >-int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) >+int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file) > { > struct cifsFileInfo *open_file = NULL; > >@@ -1909,14 +2067,20 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) > this handle go free and allow it to > be closable if needed */ > atomic_dec(&open_file->wrtPending); >- >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb); >+#else >+ cifs_sb = CIFS_SB(open_file->pfile->f_dentry->d_inode->i_sb); >+#endif > if ( cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO ) { > /* since no page cache to corrupt on directio > we can change size safely */ > return 1; > } > >+ if(i_size_read(&cifsInode->vfs_inode) < end_of_file) >+ return 1; >+ > return 0; > } else > return 1; >@@ -1926,38 +2090,56 @@ static int cifs_prepare_write(struct file *file, struct page *page, > unsigned from, unsigned to) > { > int rc = 0; >- loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; >+ loff_t i_size; >+ loff_t offset; >+ > cFYI(1, ("prepare write for page %p from %d to %d",page,from,to)); >- if (!PageUptodate(page)) { >- /* if (to - from != PAGE_CACHE_SIZE) { >- void *kaddr = kmap_atomic(page, KM_USER0); >+ if (PageUptodate(page)) >+ return 0; >+ >+ /* If we are writing a full page it will be up to date, >+ no need to read from the server */ >+ if ((to == PAGE_CACHE_SIZE) && (from == 0)) { >+ SetPageUptodate(page); >+ return 0; >+ } >+ >+ offset = (loff_t)page->index << PAGE_CACHE_SHIFT; >+ i_size = i_size_read(page->mapping->host); >+ >+ if ((offset >= i_size) || >+ ((from == 0) && (offset + to) >= i_size)) { >+ /* >+ * We don't need to read data beyond the end of the file. >+ * zero it, and set the page uptodate >+ */ >+ void *kaddr = kmap_atomic(page, KM_USER0); >+ >+ if (from) > memset(kaddr, 0, from); >+ if (to < PAGE_CACHE_SIZE) > memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); >- flush_dcache_page(page); >- kunmap_atomic(kaddr, KM_USER0); >- } */ >- /* If we are writing a full page it will be up to date, >- no need to read from the server */ >- if ((to == PAGE_CACHE_SIZE) && (from == 0)) >- SetPageUptodate(page); >- >+ flush_dcache_page(page); >+ kunmap_atomic(kaddr, KM_USER0); >+ SetPageUptodate(page); >+ } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) { > /* might as well read a page, it is fast enough */ >- if ((file->f_flags & O_ACCMODE) != O_WRONLY) { >- rc = cifs_readpage_worker(file, page, &offset); >- } else { >- /* should we try using another file handle if there is one - >- how would we lock it to prevent close of that handle >- racing with this read? >- In any case this will be written out by commit_write */ >- } >+ rc = cifs_readpage_worker(file, page, &offset); >+ } else { >+ /* we could try using another file handle if there is one - >+ but how would we lock it to prevent close of that handle >+ racing with this read? In any case >+ this will be written out by commit_write so is fine */ > } > >- /* BB should we pass any errors back? >- e.g. if we do not have read access to the file */ >+ /* we do not need to pass errors back >+ e.g. if we do not have read access to the file >+ because cifs_commit_write will do the right thing. -- shaggy */ >+ > return 0; > } > >-struct address_space_operations cifs_addr_ops = { >+const struct address_space_operations cifs_addr_ops = { > .readpage = cifs_readpage, > #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > .readpages = cifs_readpages, >@@ -1968,7 +2150,9 @@ struct address_space_operations cifs_addr_ops = { > #endif > .prepare_write = cifs_prepare_write, > .commit_write = cifs_commit_write, >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > .set_page_dirty = __set_page_dirty_nobuffers, >+#endif > /* .sync_page = cifs_sync_page, */ > /* .direct_IO = */ > }; >@@ -1978,7 +2162,7 @@ struct address_space_operations cifs_addr_ops = { > * contain the header plus one complete page of data. Otherwise, we need > * to leave cifs_readpages out of the address space operations. > */ >-struct address_space_operations cifs_addr_ops_smallbuf = { >+const struct address_space_operations cifs_addr_ops_smallbuf = { > .readpage = cifs_readpage, > .writepage = cifs_writepage, > #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 14) >@@ -1986,7 +2170,9 @@ struct address_space_operations cifs_addr_ops_smallbuf = { > #endif > .prepare_write = cifs_prepare_write, > .commit_write = cifs_commit_write, >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > .set_page_dirty = __set_page_dirty_nobuffers, >+#endif > /* .sync_page = cifs_sync_page, */ > /* .direct_IO = */ > }; >diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c >index dc4e806..df0e3fd 100644 >--- a/fs/cifs/inode.c >+++ b/fs/cifs/inode.c >@@ -19,7 +19,6 @@ > * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > */ > #include <linux/fs.h> >-#include <linux/buffer_head.h> > #include <linux/stat.h> > #include <linux/pagemap.h> > #include <asm/div64.h> >@@ -29,6 +28,9 @@ > #include "cifsproto.h" > #include "cifs_debug.h" > #include "cifs_fs_sb.h" >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) >+#include <linux/buffer_head.h> >+#endif > > int cifs_get_inode_info_unix(struct inode **pinode, > const unsigned char *search_path, struct super_block *sb, int xid) >@@ -91,6 +93,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, > (*pinode)->i_ino = > (unsigned long)findData.UniqueId; > } /* note ino incremented to unique num in new_inode */ >+ if(sb->s_flags & MS_NOATIME) >+ (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; >+ > insert_inode_hash(*pinode); > } > >@@ -141,15 +146,11 @@ int cifs_get_inode_info_unix(struct inode **pinode, > inode->i_gid = le64_to_cpu(findData.Gid); > inode->i_nlink = le64_to_cpu(findData.Nlinks); > >- if (is_size_safe_to_change(cifsInfo)) { >+ spin_lock(&inode->i_lock); >+ if (is_size_safe_to_change(cifsInfo, end_of_file)) { > /* can not safely change the file size here if the > client is writing to it due to potential races */ >-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > i_size_write(inode, end_of_file); >-#else >- inode->i_size = end_of_file; >-#endif >- > > /* blksize needs to be multiple of two. So safer to default to > blksize and blkbits set in superblock so 2**blkbits and blksize >@@ -164,12 +165,13 @@ int cifs_get_inode_info_unix(struct inode **pinode, > /* for this calculation */ > inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; > } >+ spin_unlock(&inode->i_lock); > > if (num_of_bytes < end_of_file) > cFYI(1, ("allocation size less than end of file")); >- cFYI(1, >- ("Size %ld and blocks %ld", >- (unsigned long) inode->i_size, inode->i_blocks)); >+ cFYI(1, ("Size %ld and blocks %llu", >+ (unsigned long) inode->i_size, >+ (unsigned long long)inode->i_blocks)); > if (S_ISREG(inode->i_mode)) { > cFYI(1, ("File inode")); > inode->i_op = &cifs_file_inode_ops; >@@ -324,6 +326,7 @@ int cifs_get_inode_info(struct inode **pinode, > struct cifs_sb_info *cifs_sb = CIFS_SB(sb); > char *tmp_path; > char *buf = NULL; >+ int adjustTZ = FALSE; > > pTcon = cifs_sb->tcon; > cFYI(1,("Getting info on %s", search_path)); >@@ -343,6 +346,7 @@ 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, >+ 0 /* not legacy */, > cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & > CIFS_MOUNT_MAP_SPECIAL_CHR); > /* BB optimize code so we do not make the above call >@@ -353,6 +357,7 @@ int cifs_get_inode_info(struct inode **pinode, > pfindData, cifs_sb->local_nls, > cifs_sb->mnt_cifs_flags & > CIFS_MOUNT_MAP_SPECIAL_CHR); >+ adjustTZ = TRUE; > } > > } >@@ -390,8 +395,10 @@ int cifs_get_inode_info(struct inode **pinode, > /* get new inode */ > if (*pinode == NULL) { > *pinode = new_inode(sb); >- if (*pinode == NULL) >+ if (*pinode == NULL) { >+ kfree(buf); > return -ENOMEM; >+ } > /* Is an i_ino of zero legal? Can we use that to check > if the server supports returning inode numbers? Are > there other sanity checks we can use to ensure that >@@ -422,6 +429,8 @@ int cifs_get_inode_info(struct inode **pinode, > } else /* do we need cast or hash to ino? */ > (*pinode)->i_ino = inode_num; > } /* else ino incremented to unique num in new_inode*/ >+ if(sb->s_flags & MS_NOATIME) >+ (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; > insert_inode_hash(*pinode); > } > inode = *pinode; >@@ -437,13 +446,20 @@ int cifs_get_inode_info(struct inode **pinode, > (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ > > /* Linux can not store file creation time so ignore it */ >- inode->i_atime = >- cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); >+ if(pfindData->LastAccessTime) >+ inode->i_atime = cifs_NTtimeToUnix >+ (le64_to_cpu(pfindData->LastAccessTime)); >+ else /* do not need to use current_fs_time - time not stored */ >+ inode->i_atime = CURRENT_TIME; > inode->i_mtime = > cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); > inode->i_ctime = > cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); > cFYI(0, ("Attributes came in as 0x%x", attr)); >+ if(adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { >+ inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; >+ inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; >+ } > > /* set default mode. will override for dirs below */ > if (atomic_read(&cifsInfo->inUse) == 0) >@@ -491,20 +507,19 @@ int cifs_get_inode_info(struct inode **pinode, > /* BB add code here - > validate if device or weird share or device type? */ > } >- if (is_size_safe_to_change(cifsInfo)) { >- /* can not safely change the file size here if the >+ >+ spin_lock(&inode->i_lock); >+ if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) { >+ /* can not safely shrink the file size here if the > client is writing to it due to potential races */ >-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > i_size_write(inode,le64_to_cpu(pfindData->EndOfFile)); >-#else >- inode->i_size = pfindData->EndOfFile; >-#endif > > /* 512 bytes (2**9) is the fake blocksize that must be > used for this calculation */ > inode->i_blocks = (512 - 1 + le64_to_cpu( > pfindData->AllocationSize)) >> 9; > } >+ spin_unlock(&inode->i_lock); > > inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); > >@@ -834,12 +849,10 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) > > if (!rc) { > inode->i_nlink--; >-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) >+ spin_lock(&direntry->d_inode->i_lock); > i_size_write(direntry->d_inode,0); >-#else >- direntry->d_inode->i_size = 0; >-#endif > direntry->d_inode->i_nlink = 0; >+ spin_unlock(&direntry->d_inode->i_lock); > } > > cifsInode = CIFS_I(direntry->d_inode); >@@ -900,10 +913,14 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, > kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); > 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, >- cifs_sb_source->mnt_cifs_flags & >- CIFS_MOUNT_MAP_SPECIAL_CHR); >+ if (pTcon->ses->capabilities & CAP_UNIX) >+ rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, >+ info_buf_source, >+ cifs_sb_source->local_nls, >+ cifs_sb_source->mnt_cifs_flags & >+ CIFS_MOUNT_MAP_SPECIAL_CHR); >+ /* else rc is still EEXIST so will fall through to >+ unlink the target and retry rename */ > if (rc == 0) { > rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName, > info_buf_target, >@@ -952,7 +969,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, > cifs_sb_source->mnt_cifs_flags & > CIFS_MOUNT_MAP_SPECIAL_CHR); > if (rc==0) { >- CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName, >+ rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName, > cifs_sb_source->local_nls, > cifs_sb_source->mnt_cifs_flags & > CIFS_MOUNT_MAP_SPECIAL_CHR); >@@ -975,7 +992,11 @@ int cifs_revalidate(struct dentry *direntry) > struct cifs_sb_info *cifs_sb; > struct cifsInodeInfo *cifsInode; > loff_t local_size; >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > struct timespec local_mtime; >+#else >+ time_t local_mtime; >+#endif > int invalidate_inode = FALSE; > > if (direntry->d_inode == NULL) >@@ -1096,18 +1117,26 @@ int cifs_revalidate(struct dentry *direntry) > return rc; > } > >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, > struct kstat *stat) > { > int err = cifs_revalidate(dentry); >- if (!err) >+ if (!err) { > generic_fillattr(dentry->d_inode, stat); >+ stat->blksize = CIFS_MAX_MSGSIZE; >+ } > return err; > } >+#endif > > static int cifs_truncate_page(struct address_space *mapping, loff_t from) > { >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > pgoff_t index = from >> PAGE_CACHE_SHIFT; >+#else >+ unsigned long index = from >> PAGE_CACHE_SHIFT; >+#endif > unsigned offset = from & (PAGE_CACHE_SIZE - 1); > struct page *page; > char *kaddr; >@@ -1126,6 +1155,56 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from) > return rc; > } > >+static int cifs_vmtruncate(struct inode * inode, loff_t offset) >+{ >+ struct address_space *mapping = inode->i_mapping; >+ unsigned long limit; >+ >+ spin_lock(&inode->i_lock); >+ if (inode->i_size < offset) >+ goto do_expand; >+ /* >+ * truncation of in-use swapfiles is disallowed - it would cause >+ * subsequent swapout to scribble on the now-freed blocks. >+ */ >+ if (IS_SWAPFILE(inode)) { >+ spin_unlock(&inode->i_lock); >+ goto out_busy; >+ } >+ i_size_write(inode, offset); >+ spin_unlock(&inode->i_lock); >+ unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); >+ truncate_inode_pages(mapping, offset); >+ goto out_truncate; >+ >+do_expand: >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 9, 0) >+ limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; >+#else >+ limit = current->rlim[RLIMIT_FSIZE].rlim_cur; >+#endif >+ if (limit != RLIM_INFINITY && offset > limit) { >+ spin_unlock(&inode->i_lock); >+ goto out_sig; >+ } >+ if (offset > inode->i_sb->s_maxbytes) { >+ spin_unlock(&inode->i_lock); >+ goto out_big; >+ } >+ i_size_write(inode, offset); >+ spin_unlock(&inode->i_lock); >+out_truncate: >+ if (inode->i_op && inode->i_op->truncate) >+ inode->i_op->truncate(inode); >+ return 0; >+out_sig: >+ send_sig(SIGXFSZ, current, 0); >+out_big: >+ return -EFBIG; >+out_busy: >+ return -ETXTBSY; >+} >+ > int cifs_setattr(struct dentry *direntry, struct iattr *attrs) > { > int xid; >@@ -1136,6 +1215,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) > struct cifsFileInfo *open_file = NULL; > FILE_BASIC_INFO time_buf; > int set_time = FALSE; >+ int set_dosattr = FALSE; > __u64 mode = 0xFFFFFFFFFFFFFFFFULL; > __u64 uid = 0xFFFFFFFFFFFFFFFFULL; > __u64 gid = 0xFFFFFFFFFFFFFFFFULL; >@@ -1247,7 +1327,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) > */ > > if (rc == 0) { >- rc = vmtruncate(direntry->d_inode, attrs->ia_size); >+ rc = cifs_vmtruncate(direntry->d_inode, attrs->ia_size); > cifs_truncate_page(direntry->d_inode->i_mapping, > direntry->d_inode->i_size); > } else >@@ -1277,15 +1357,23 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) > else if (attrs->ia_valid & ATTR_MODE) { > rc = 0; > if ((mode & S_IWUGO) == 0) /* not writeable */ { >- if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) >+ if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) { >+ set_dosattr = TRUE; > time_buf.Attributes = > cpu_to_le32(cifsInode->cifsAttrs | > ATTR_READONLY); >+ } > } else if ((mode & S_IWUGO) == S_IWUGO) { >- if (cifsInode->cifsAttrs & ATTR_READONLY) >+ if (cifsInode->cifsAttrs & ATTR_READONLY) { >+ set_dosattr = TRUE; > time_buf.Attributes = > cpu_to_le32(cifsInode->cifsAttrs & > (~ATTR_READONLY)); >+ /* Windows ignores set to zero */ >+ if(time_buf.Attributes == 0) >+ time_buf.Attributes |= >+ cpu_to_le32(ATTR_NORMAL); >+ } > } > /* BB to be implemented - > via Windows security descriptors or streams */ >@@ -1323,7 +1411,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) > } else > time_buf.ChangeTime = 0; > >- if (set_time || time_buf.Attributes) { >+ if (set_time || set_dosattr) { > time_buf.CreationTime = 0; /* do not change */ > /* In the future we should experiment - try setting timestamps > via Handle (SetFileInfo) instead of by path */ >@@ -1367,7 +1455,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) > and this check ensures that we are not being called from > sys_utimes in which case we ought to fail the call back to > the user when the server rejects the call */ >- if((rc) && (attrs->ia_valid && >+ if((rc) && (attrs->ia_valid & > (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) > rc = 0; > } >@@ -1382,9 +1470,11 @@ cifs_setattr_exit: > return rc; > } > >+#if 0 > void cifs_delete_inode(struct inode *inode) > { > cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode)); > /* may have to add back in if and when safe distributed caching of > directories added e.g. via FindNotify */ > } >+#endif >diff --git a/fs/cifs/link.c b/fs/cifs/link.c >index 97df251..6fbba03 100644 >--- a/fs/cifs/link.c >+++ b/fs/cifs/link.c >@@ -20,7 +20,10 @@ > */ > #include <linux/fs.h> > #include <linux/stat.h> >+#include <linux/version.h> >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) > #include <linux/namei.h> >+#endif > #include "cifsfs.h" > #include "cifspdu.h" > #include "cifsglob.h" >@@ -69,17 +72,31 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, > rc = -EOPNOTSUPP; > } > >-/* if (!rc) */ >- { >- /* renew_parental_timestamps(old_file); >- inode->i_nlink++; >- mark_inode_dirty(inode); >- d_instantiate(direntry, inode); */ >- /* BB add call to either mark inode dirty or refresh its data and timestamp to current time */ >+ d_drop(direntry); /* force new lookup from server of target */ >+ >+ /* if source file is cached (oplocked) revalidate will not go to server >+ until the file is closed or oplock broken so update nlinks locally */ >+ if(old_file->d_inode) { >+ cifsInode = CIFS_I(old_file->d_inode); >+ if(rc == 0) { >+ old_file->d_inode->i_nlink++; >+/* BB should we make this contingent on superblock flag NOATIME? */ >+/* old_file->d_inode->i_ctime = CURRENT_TIME;*/ >+ /* parent dir timestamps will update from srv >+ within a second, would it really be worth it >+ to set the parent dir cifs inode time to zero >+ to force revalidate (faster) for it too? */ >+ } >+ /* if not oplocked will force revalidate to get info >+ on source file from srv */ >+ cifsInode->time = 0; >+ >+ /* Will update parent dir timestamps from srv within a second. >+ Would it really be worth it to set the parent dir (cifs >+ inode) time field to zero to force revalidate on parent >+ directory faster ie >+ CIFS_I(inode)->time = 0; */ > } >- d_drop(direntry); /* force new lookup from server */ >- cifsInode = CIFS_I(old_file->d_inode); >- cifsInode->time = 0; /* will force revalidate to go get info when needed */ > > cifs_hl_exit: > kfree(fromName); >@@ -267,7 +284,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) > tmpbuffer, > len - 1, > cifs_sb->local_nls); >- else { >+ else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { >+ cERROR(1,("SFU style symlinks not implemented yet")); >+ /* add open and read as in fs/cifs/inode.c */ >+ >+ } else { > rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, > OPEN_REPARSE_POINT,&fid, &oplock, NULL, > cifs_sb->local_nls, >diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c >index d7497ff..e5e544d 100644 >--- a/fs/cifs/misc.c >+++ b/fs/cifs/misc.c >@@ -79,9 +79,7 @@ sesInfoAlloc(void) > { > struct cifsSesInfo *ret_buf; > >- ret_buf = >- (struct cifsSesInfo *) kzalloc(sizeof (struct cifsSesInfo), >- GFP_KERNEL); >+ ret_buf = kzalloc(sizeof (struct cifsSesInfo), GFP_KERNEL); > if (ret_buf) { > write_lock(&GlobalSMBSeslock); > atomic_inc(&sesInfoAllocCount); >@@ -117,9 +115,7 @@ struct cifsTconInfo * > tconInfoAlloc(void) > { > struct cifsTconInfo *ret_buf; >- ret_buf = >- (struct cifsTconInfo *) kzalloc(sizeof (struct cifsTconInfo), >- GFP_KERNEL); >+ ret_buf = kzalloc(sizeof (struct cifsTconInfo), GFP_KERNEL); > if (ret_buf) { > write_lock(&GlobalSMBSeslock); > atomic_inc(&tconInfoAllocCount); >@@ -441,26 +437,42 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) > } > > int >-checkSMB(struct smb_hdr *smb, __u16 mid, int length) >+checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) > { > __u32 len = smb->smb_buf_length; > __u32 clc_len; /* calculated length */ > cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len)); >- if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || >- (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { >- if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { >- if (((unsigned int)length >= >- sizeof (struct smb_hdr) - 1) >+ >+ if (length < 2 + sizeof (struct smb_hdr)) { >+ if ((length >= sizeof (struct smb_hdr) - 1) > && (smb->Status.CifsError != 0)) { >- smb->WordCount = 0; >- /* some error cases do not return wct and bcc */ >+ smb->WordCount = 0; >+ /* some error cases do not return wct and bcc */ >+ return 0; >+ } else if ((length == sizeof(struct smb_hdr) + 1) && >+ (smb->WordCount == 0)) { >+ char * tmp = (char *)smb; >+ /* Need to work around a bug in two servers here */ >+ /* First, check if the part of bcc they sent was zero */ >+ if (tmp[sizeof(struct smb_hdr)] == 0) { >+ /* some servers return only half of bcc >+ * on simple responses (wct, bcc both zero) >+ * in particular have seen this on >+ * ulogoffX and FindClose. This leaves >+ * one byte of bcc potentially unitialized >+ */ >+ /* zero rest of bcc */ >+ tmp[sizeof(struct smb_hdr)+1] = 0; > return 0; >- } else { >- cERROR(1, ("Length less than smb header size")); > } >+ cERROR(1,("rcvd invalid byte count (bcc)")); >+ } else { >+ cERROR(1, ("Length less than smb header size")); > } >- if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) >- cERROR(1, ("smb length greater than MaxBufSize, mid=%d", >+ return 1; >+ } >+ if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { >+ cERROR(1, ("smb length greater than MaxBufSize, mid=%d", > smb->Mid)); > return 1; > } >@@ -469,7 +481,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) > return 1; > clc_len = smbCalcSize_LE(smb); > >- if(4 + len != (unsigned int)length) { >+ if(4 + len != length) { > cERROR(1, ("Length read does not match RFC1001 length %d",len)); > return 1; > } >diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c >index 927c6be..d5aff51 100644 >--- a/fs/cifs/netmisc.c >+++ b/fs/cifs/netmisc.c >@@ -72,6 +72,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { > {ERRinvlevel,-EOPNOTSUPP}, > {ERRdirnotempty, -ENOTEMPTY}, > {ERRnotlocked, -ENOLCK}, >+ {ERRcancelviolation, -ENOLCK}, > {ERRalreadyexists, -EEXIST}, > {ERRmoredata, -EOVERFLOW}, > {ERReasnotsupported,-EOPNOTSUPP}, >@@ -887,6 +888,16 @@ smbCalcSize_LE(struct smb_hdr *ptr) > * into Unix UTC (based 1970-01-01, in seconds). > */ > >+ >+static int total_days_of_prev_months[] = >+{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; >+ >+ >+__le64 cnvrtDosCifsTm(__u16 date, __u16 time) >+{ >+ return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time))); >+} >+ > #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) > struct timespec > cifs_NTtimeToUnix(u64 ntutc) >@@ -910,4 +921,129 @@ cifs_UnixTimeToNT(struct timespec t) > /* Convert to 100ns intervals and then add the NTFS time offset. */ > return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET; > } >+ >+struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) >+{ >+ struct timespec ts; >+ int sec, min, days, month, year; >+ SMB_TIME * st = (SMB_TIME *)&time; >+ SMB_DATE * sd = (SMB_DATE *)&date; >+ >+ cFYI(1,("date %d time %d",date, time)); >+ >+ sec = 2 * st->TwoSeconds; >+ min = st->Minutes; >+ if((sec > 59) || (min > 59)) >+ cERROR(1,("illegal time min %d sec %d", min, sec)); >+ sec += (min * 60); >+ sec += 60 * 60 * st->Hours; >+ if(st->Hours > 24) >+ cERROR(1,("illegal hours %d",st->Hours)); >+ days = sd->Day; >+ month = sd->Month; >+ if((days > 31) || (month > 12)) >+ cERROR(1,("illegal date, month %d day: %d", month, days)); >+ month -= 1; >+ days += total_days_of_prev_months[month]; >+ days += 3652; /* account for difference in days between 1980 and 1970 */ >+ year = sd->Year; >+ days += year * 365; >+ days += (year/4); /* leap year */ >+ /* generalized leap year calculation is more complex, ie no leap year >+ for years/100 except for years/400, but since the maximum number for DOS >+ year is 2**7, the last year is 1980+127, which means we need only >+ consider 2 special case years, ie the years 2000 and 2100, and only >+ adjust for the lack of leap year for the year 2100, as 2000 was a >+ leap year (divisable by 400) */ >+ if(year >= 120) /* the year 2100 */ >+ days = days - 1; /* do not count leap year for the year 2100 */ >+ >+ /* adjust for leap year where we are still before leap day */ >+ if(year != 120) >+ days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); >+ sec += 24 * 60 * 60 * days; >+ >+ ts.tv_sec = sec; >+ >+ /* cFYI(1,("sec after cnvrt dos to unix time %d",sec)); */ >+ >+ ts.tv_nsec = 0; >+ return ts; >+} >+#else >+/* Did not merge changeset 268f3be177ce93791da38facc34126b5038cd851 >+ * and related time fixes into this function for 2.4 case >+ */ >+time_t >+cifs_NTtimeToUnix(__u64 ntutc) >+{ >+ /* BB what about the timezone? BB */ >+ >+ /* Subtract the NTFS time offset, then convert to 1s intervals. */ >+ u64 t; >+ >+ t = ntutc - NTFS_TIME_OFFSET; >+ do_div(t, 10000000); >+ return (time_t)t; >+} >+ >+/* Convert the Unix UTC into NT UTC. */ >+__u64 >+cifs_UnixTimeToNT(time_t t) >+{ >+ __u64 dce_time; >+ /* Convert to 100ns intervals and then add the NTFS time offset. */ >+ dce_time = (__u64) t * 10000000; >+ dce_time += NTFS_TIME_OFFSET; >+ return dce_time; >+} >+time_t cnvrtDosUnixTm(__u16 date, __u16 time) >+{ >+ __u8 dt[2]; >+ __u8 tm[2]; >+ time_t ts; >+ int sec,min, days, month, year; >+/* SMB_TIME * st = (SMB_TIME *)&time;*/ >+ >+ cFYI(1,("date %d time %d",date, time)); >+ >+ dt[0] = date & 0xFF; >+ dt[1] = (date & 0xFF00) >> 8; >+ tm[0] = time & 0xFF; >+ tm[1] = (time & 0xFF00) >> 8; >+ >+ sec = tm[0] & 0x1F; >+ sec = 2 * sec; >+ min = ((tm[0] >>5)&0xFF) + ((tm[1] & 0x7)<<3); >+ >+ sec += (min * 60); >+ sec += 60 * 60 * ((tm[1] >> 3) &0xFF) /* hours */; >+ days = (dt[0] & 0x1F) - 1; >+ month = ((dt[0] >> 5) & 0xFF) + ((dt[1] & 0x1) <<3); >+ if(month > 12) >+ cERROR(1,("illegal month %d in date", month)); >+ month -= 1; >+ days += total_days_of_prev_months[month]; >+ days += 3653; /* account for difference in days between 1980 and 1970 */ >+ year = (dt[1]>>1) & 0xFF; >+ days += year * 365; >+ days += (year/4); /* leap year */ >+ /* generalized leap year calculation is more complex, ie no leap year >+ for years/100 except for years/400, but since the maximum number for DOS >+ year is 2**7, the last year is 1980+127, which means we need only >+ consider 2 special case years, ie the years 2000 and 2100, and only >+ adjust for the lack of leap year for the year 2100, as 2000 was a >+ leap year (divisable by 400) */ >+ if(year >= 120) /* the year 2100 */ >+ days = days - 1; /* do not count leap year for the year 2100 */ >+ >+ /* adjust for leap year where we are still before leap day */ >+ days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); >+ sec += 24 * 60 * 60 * days; >+ >+ ts = (time_t)sec; >+ >+ return ts; >+} > #endif >+ >diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c >index b9bc252..5999729 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, 2005 >+ * Copyright (C) International Business Machines Corp., 2004, 2007 > * Author(s): Steve French (sfrench@us.ibm.com) > * > * This library is free software; you can redistribute it and/or modify >@@ -82,8 +82,13 @@ static int construct_dentry(struct qstr *qstring, struct file *file, > if(*ptmp_inode == NULL) > return rc; > rc = 1; >- d_instantiate(tmp_dentry, *ptmp_inode); > } >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) >+ if(file->f_path.dentry->d_sb->s_flags & MS_NOATIME) >+#else >+ if(file->f_dentry->d_sb->s_flags & MS_NOATIME) >+#endif >+ (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; > } else { > tmp_dentry = d_alloc(file->f_dentry, qstring); > if(tmp_dentry == NULL) { >@@ -99,9 +104,13 @@ static int construct_dentry(struct qstr *qstring, struct file *file, > tmp_dentry->d_op = &cifs_dentry_ops; > if(*ptmp_inode == NULL) > return rc; >- rc = 1; >- d_instantiate(tmp_dentry, *ptmp_inode); >- d_rehash(tmp_dentry); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) >+ if(file->f_path.dentry->d_sb->s_flags & MS_NOATIME) >+#else >+ if(file->f_dentry->d_sb->s_flags & MS_NOATIME) >+#endif >+ (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; >+ rc = 2; > } > > tmp_dentry->d_time = jiffies; >@@ -109,11 +118,32 @@ static int construct_dentry(struct qstr *qstring, struct file *file, > return rc; > } > >+static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode) >+{ >+ if((tcon) && (tcon->ses) && (tcon->ses->server)) { >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) >+ inode->i_ctime.tv_sec += tcon->ses->server->timeAdj; >+ inode->i_mtime.tv_sec += tcon->ses->server->timeAdj; >+ inode->i_atime.tv_sec += tcon->ses->server->timeAdj; >+#else >+ inode->i_ctime += tcon->ses->server->timeAdj; >+ inode->i_mtime += tcon->ses->server->timeAdj; >+ inode->i_atime += tcon->ses->server->timeAdj; >+#endif >+ } >+ return; >+} >+ >+ > static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, > char * buf, int *pobject_type, int isNewInode) > { > loff_t local_size; >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > struct timespec local_mtime; >+#else >+ time_t local_mtime; >+#endif > > struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); > struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); >@@ -138,12 +168,26 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, > tmp_inode->i_ctime = > cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); > } else { /* legacy, OS2 and DOS style */ >+/* struct timespec ts;*/ > FIND_FILE_STANDARD_INFO * pfindData = > (FIND_FILE_STANDARD_INFO *)buf; > >+ tmp_inode->i_mtime = cnvrtDosUnixTm( >+ le16_to_cpu(pfindData->LastWriteDate), >+ le16_to_cpu(pfindData->LastWriteTime)); >+ tmp_inode->i_atime = cnvrtDosUnixTm( >+ le16_to_cpu(pfindData->LastAccessDate), >+ le16_to_cpu(pfindData->LastAccessTime)); >+ tmp_inode->i_ctime = cnvrtDosUnixTm( >+ le16_to_cpu(pfindData->LastWriteDate), >+ le16_to_cpu(pfindData->LastWriteTime)); >+ AdjustForTZ(cifs_sb->tcon, tmp_inode); > attr = le16_to_cpu(pfindData->Attributes); > allocation_size = le32_to_cpu(pfindData->AllocationSize); > end_of_file = le32_to_cpu(pfindData->DataSize); >+ /* do not need to use current_fs_time helper function since >+ time not stored for this case so atime can not "go backwards" >+ by pulling newer older from disk when inode refrenshed */ > tmp_inode->i_atime = CURRENT_TIME; > /* tmp_inode->i_mtime = BB FIXME - add dos time handling > tmp_inode->i_ctime = 0; BB FIXME */ >@@ -211,7 +255,8 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, > atomic_set(&cifsInfo->inUse, 1); > } > >- if (is_size_safe_to_change(cifsInfo)) { >+ spin_lock(&tmp_inode->i_lock); >+ if (is_size_safe_to_change(cifsInfo, end_of_file)) { > /* can not safely change the file size here if the > client is writing to it due to potential races */ > i_size_write(tmp_inode, end_of_file); >@@ -220,13 +265,13 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, > /* for this calculation, even though the reported blocksize is larger */ > tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; > } >+ spin_unlock(&tmp_inode->i_lock); > > if (allocation_size < end_of_file) > cFYI(1, ("May be sparse file, allocation less than file size")); >- cFYI(1, >- ("File Size %ld and blocks %ld and blocksize %ld", >- (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks, >- tmp_inode->i_blksize)); >+ cFYI(1, ("File Size %ld and blocks %llu", >+ (unsigned long)tmp_inode->i_size, >+ (unsigned long long)tmp_inode->i_blocks)); > if (S_ISREG(tmp_inode->i_mode)) { > cFYI(1, ("File inode")); > tmp_inode->i_op = &cifs_file_inode_ops; >@@ -279,7 +324,11 @@ static void unix_fill_in_inode(struct inode *tmp_inode, > FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode) > { > loff_t local_size; >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > struct timespec local_mtime; >+#else >+ time_t local_mtime; >+#endif > > struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); > struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); >@@ -341,15 +390,17 @@ static void unix_fill_in_inode(struct inode *tmp_inode, > tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); > tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); > >- if (is_size_safe_to_change(cifsInfo)) { >+ spin_lock(&tmp_inode->i_lock); >+ if (is_size_safe_to_change(cifsInfo, end_of_file)) { > /* can not safely change the file size here if the > client is writing to it due to potential races */ >- i_size_write(tmp_inode,end_of_file); >+ i_size_write(tmp_inode, end_of_file); > > /* 512 bytes (2**9) is the fake blocksize that must be used */ > /* for this calculation, not the real blocksize */ > tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; > } >+ spin_unlock(&tmp_inode->i_lock); > > if (S_ISREG(tmp_inode->i_mode)) { > cFYI(1, ("File inode")); >@@ -874,12 +925,22 @@ static int cifs_filldir(char *pfindEntry, struct file *file, > pfindEntry, &obj_type, rc); > else > fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); >+ >+ if(rc) /* new inode - needs to be tied to dentry */ { >+ d_instantiate(tmp_dentry, tmp_inode); >+ if(rc == 2) >+ d_rehash(tmp_dentry); >+ } > > > rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, > tmp_inode->i_ino,obj_type); > if(rc) { > cFYI(1,("filldir rc = %d",rc)); >+ /* we can not return filldir errors to the caller >+ since they are "normal" when the stat blocksize >+ is too small - we return remapped error instead */ >+ rc = -EOVERFLOW; > } > > dput(tmp_dentry); >@@ -940,6 +1001,7 @@ static int cifs_save_resume_key(const char *current_entry, > filename = &pFindData->FileName[0]; > /* one byte length, no name conversion */ > len = (unsigned int)pFindData->FileNameLength; >+ cifsFile->srch_inf.resume_key = pFindData->ResumeKey; > } else { > cFYI(1,("Unknown findfirst level %d",level)); > return -EINVAL; >@@ -1057,6 +1119,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) > we want to check for that here? */ > rc = cifs_filldir(current_entry, file, > filldir, direntry, tmp_buf, max_len); >+ if(rc == -EOVERFLOW) { >+ rc = 0; >+ break; >+ } >+ > file->f_pos++; > if(file->f_pos == > cifsFile->srch_inf.index_of_last_entry) { >diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c >index 7202d53..9a5c286 100644 >--- a/fs/cifs/sess.c >+++ b/fs/cifs/sess.c >@@ -21,6 +21,7 @@ > * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > */ > >+#include <linux/fs.h> > #include "cifspdu.h" > #include "cifsglob.h" > #include "cifsproto.h" >@@ -90,7 +91,9 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, > } */ > /* copy user */ > if(ses->userName == NULL) { >- /* BB what about null user mounts - check that we do this BB */ >+ /* null user mount */ >+ *bcc_ptr = 0; >+ *(bcc_ptr+1) = 0; > } else { /* 300 should be long enough for any conceivable user name */ > bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName, > 300, nls_cp); >@@ -98,10 +101,13 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, > bcc_ptr += 2 * bytes_ret; > bcc_ptr += 2; /* account for null termination */ > /* copy domain */ >- if(ses->domainName == NULL) >- bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, >- "CIFS_LINUX_DOM", 32, nls_cp); >- else >+ if(ses->domainName == NULL) { >+ /* Sending null domain better than using a bogus domain name (as >+ we did briefly in 2.6.18) since server will use its default */ >+ *bcc_ptr = 0; >+ *(bcc_ptr+1) = 0; >+ bytes_ret = 0; >+ } else > bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, > 256, nls_cp); > bcc_ptr += 2 * bytes_ret; >@@ -111,8 +117,13 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, > bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, > nls_cp); > bcc_ptr += 2 * bytes_ret; >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) >+ bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, >+ 32, nls_cp); >+#else > bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, > 32, nls_cp); >+#endif > bcc_ptr += 2 * bytes_ret; > bcc_ptr += 2; /* trailing null */ > >@@ -144,13 +155,11 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, > > /* copy domain */ > >- if(ses->domainName == NULL) { >- strcpy(bcc_ptr, "CIFS_LINUX_DOM"); >- bcc_ptr += 14; /* strlen(CIFS_LINUX_DOM) */ >- } else { >+ if(ses->domainName != NULL) { > strncpy(bcc_ptr, ses->domainName, 256); > bcc_ptr += strnlen(ses->domainName, 256); >- } >+ } /* else we will send a null domain name >+ so the server will default to its own domain */ > *bcc_ptr = 0; > bcc_ptr++; > >@@ -158,8 +167,13 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, > > strcpy(bcc_ptr, "Linux version "); > bcc_ptr += strlen("Linux version "); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) >+ strcpy(bcc_ptr, utsname()->release); >+ bcc_ptr += strlen(utsname()->release) + 1; >+#else > strcpy(bcc_ptr, system_utsname.release); > bcc_ptr += strlen(system_utsname.release) + 1; >+#endif > > strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); > bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; >@@ -179,11 +193,14 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf > cFYI(1,("bleft %d",bleft)); > > >- /* word align, if bytes remaining is not even */ >- if(bleft % 2) { >- bleft--; >- data++; >- } >+ /* SMB header is unaligned, so cifs servers word align start of >+ Unicode strings */ >+ data++; >+ bleft--; /* Windows servers do not always double null terminate >+ their final Unicode string - in which case we >+ now will not attempt to decode the byte of junk >+ which follows it */ >+ > words_left = bleft / 2; > > /* save off server operating system */ >@@ -268,6 +285,10 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo > ses->serverOS = kzalloc(len + 1, GFP_KERNEL); > if(ses->serverOS) > strncpy(ses->serverOS, bcc_ptr, len); >+ if(strncmp(ses->serverOS, "OS/2",4) == 0) { >+ cFYI(1,("OS/2 server")); >+ ses->flags |= CIFS_SES_OS2; >+ } > > bcc_ptr += len + 1; > bleft -= len + 1; >@@ -290,16 +311,11 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo > if(len > bleft) > return rc; > >- if(ses->serverDomain) >- kfree(ses->serverDomain); >- >- ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); >- if(ses->serverOS) >- strncpy(ses->serverOS, bcc_ptr, len); >- >- bcc_ptr += len + 1; >- bleft -= len + 1; >- >+ /* No domain field in LANMAN case. Domain is >+ returned by old servers in the SMB negprot response */ >+ /* BB For newer servers which do not support Unicode, >+ but thus do return domain here we could add parsing >+ for it later, but it is not very important */ > cFYI(1,("ascii: bytes left %d",bleft)); > > return rc; >@@ -366,6 +382,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, > str_area = kmalloc(2000, GFP_KERNEL); > bcc_ptr = str_area; > >+ ses->flags &= ~CIFS_SES_LANMAN; >+ > if(type == LANMAN) { > #ifdef CONFIG_CIFS_WEAK_PW_HASH > char lnm_session_key[CIFS_SESS_KEY_SIZE]; >@@ -377,7 +395,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, > /* and copy into bcc */ > > calc_lanman_hash(ses, lnm_session_key); >- >+ ses->flags |= CIFS_SES_LANMAN; > /* #ifdef CONFIG_CIFS_DEBUG2 > cifs_dump_mem("cryptkey: ",ses->server->cryptKey, > CIFS_SESS_KEY_SIZE); >diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c >index efaa044..13e9b83 100644 >--- a/fs/cifs/smbdes.c >+++ b/fs/cifs/smbdes.c >@@ -196,7 +196,7 @@ dohash(char *out, char *in, char *key, int forw) > char c[28]; > char d[28]; > char *cd; >- char ki[16][48]; >+ char (*ki)[48]; > char *pd1; > char l[32], r[32]; > char *rl; >@@ -206,6 +206,12 @@ dohash(char *out, char *in, char *key, int forw) > if(pk1 == NULL) > return; > >+ ki = kmalloc(16*48, GFP_KERNEL); >+ if(ki == NULL) { >+ kfree(pk1); >+ return; >+ } >+ > cd = pk1 + 56; > pd1= cd + 56; > rl = pd1 + 64; >@@ -243,6 +249,7 @@ dohash(char *out, char *in, char *key, int forw) > er = kmalloc(48+48+32+32+32, GFP_KERNEL); > if(er == NULL) { > kfree(pk1); >+ kfree(ki); > return; > } > erk = er+48; >@@ -290,6 +297,7 @@ dohash(char *out, char *in, char *key, int forw) > > permute(out, rl, perm6, 64); > kfree(pk1); >+ kfree(ki); > } > > static void >diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h >index cd41c67..212c3c2 100644 >--- a/fs/cifs/smberr.h >+++ b/fs/cifs/smberr.h >@@ -95,6 +95,7 @@ > #define ERRinvlevel 124 > #define ERRdirnotempty 145 > #define ERRnotlocked 158 >+#define ERRcancelviolation 173 > #define ERRalreadyexists 183 > #define ERRbadpipe 230 > #define ERRpipebusy 231 >diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c >index 62c1db3..4c4b2b3 100644 >--- a/fs/cifs/transport.c >+++ b/fs/cifs/transport.c >@@ -27,17 +27,23 @@ > #include <linux/delay.h> > #include <asm/uaccess.h> > #include <asm/processor.h> >-#include <linux/mempool.h> > #include "cifspdu.h" > #include "cifsglob.h" >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) >+#include <linux/mempool.h> >+#else >+extern kmem_cache_t *cifs_mid_cachep; >+#endif > #include "cifsproto.h" > #include "cifs_debug.h" >- >+ >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > extern mempool_t *cifs_mid_poolp; >+#endif > extern kmem_cache_t *cifs_oplock_cachep; > > static struct mid_q_entry * >-AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) >+AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) > { > struct mid_q_entry *temp; > >@@ -49,9 +55,16 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) > cERROR(1, ("Null TCP session in AllocMidQEntry")); > return NULL; > } >- >+ >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp, > SLAB_KERNEL | SLAB_NOFS); >+#else >+ temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep, >+ SLAB_KERNEL); >+ >+#endif >+ > if (temp == NULL) > return temp; > else { >@@ -106,7 +119,11 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) > } > } > #endif >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > mempool_free(midEntry, cifs_mid_poolp); >+#else >+ kmem_cache_free(cifs_mid_cachep, midEntry); >+#endif > } > > struct oplock_q_entry * >@@ -222,6 +239,10 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, > rc = 0; > } > >+ /* Don't want to modify the buffer as a >+ side effect of this call. */ >+ smb_buffer->smb_buf_length = smb_buf_length; >+ > return rc; > } > >@@ -236,6 +257,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, > unsigned int len = iov[0].iov_len; > unsigned int total_len; > int first_vec = 0; >+ unsigned int smb_buf_length = smb_buffer->smb_buf_length; > #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8) > mm_segment_t temp_fs; > #endif >@@ -292,7 +314,12 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, > break; > > if (rc >= total_len) { >- WARN_ON(rc > total_len); >+ if(rc > total_len) { >+ cERROR(1,("unexpected length received")); >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 19) >+ dump_stack(); >+#endif >+ } > break; > } > if(rc == 0) { >@@ -328,36 +355,15 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, > } else > rc = 0; > >+ /* Don't want to modify the buffer as a >+ side effect of this call. */ >+ smb_buffer->smb_buf_length = smb_buf_length; >+ > return rc; > } > >-int >-SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, >- struct kvec *iov, int n_vec, int * pRespBufType /* ret */, >- const int long_op) >+static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) > { >- int rc = 0; >- unsigned int receive_len; >- unsigned long timeout; >- struct mid_q_entry *midQ; >- struct smb_hdr *in_buf = iov[0].iov_base; >- >- *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ >- >- if ((ses == NULL) || (ses->server == NULL)) { >- cifs_small_buf_release(in_buf); >- cERROR(1,("Null session")); >- return -EIO; >- } >- >- if(ses->server->tcpStatus == CifsExiting) { >- cifs_small_buf_release(in_buf); >- 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 */ > if(long_op == -1) { > /* oplock breaks must not be held up */ > atomic_inc(&ses->server->inFlight); >@@ -380,53 +386,140 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, > } else { > if(ses->server->tcpStatus == CifsExiting) { > spin_unlock(&GlobalMid_Lock); >- cifs_small_buf_release(in_buf); > return -ENOENT; > } > >- /* can not count locking commands against total since >- they are allowed to block on server */ >+ /* can not count locking commands against total since >+ they are allowed to block on server */ > >- if(long_op < 3) { > /* update # of requests on the wire to server */ >+ if (long_op < 3) > atomic_inc(&ses->server->inFlight); >- } > spin_unlock(&GlobalMid_Lock); > break; > } > } > } >- /* make sure that we sign in the same order that we send on this socket >- and avoid races inside tcp sendmsg code that could cause corruption >- of smb data */ >- >- down(&ses->server->tcpSem); >+ return 0; >+} > >+static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, >+ struct mid_q_entry **ppmidQ) >+{ > if (ses->server->tcpStatus == CifsExiting) { >- rc = -ENOENT; >- goto out_unlock2; >+ return -ENOENT; > } else if (ses->server->tcpStatus == CifsNeedReconnect) { > cFYI(1,("tcp session dead - return to caller to retry")); >- rc = -EAGAIN; >- goto out_unlock2; >+ return -EAGAIN; > } else if (ses->status != CifsGood) { > /* check if SMB session is bad because we are setting it up */ > if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && > (in_buf->Command != SMB_COM_NEGOTIATE)) { >- rc = -EAGAIN; >- goto out_unlock2; >+ return -EAGAIN; > } /* else ok - we are setting up session */ > } >- midQ = AllocMidQEntry(in_buf, ses); >- if (midQ == NULL) { >+ *ppmidQ = AllocMidQEntry(in_buf, ses); >+ if (*ppmidQ == NULL) { >+ return -ENOMEM; >+ } >+ return 0; >+} >+ >+static int wait_for_response(struct cifsSesInfo *ses, >+ struct mid_q_entry *midQ, >+ unsigned long timeout, >+ unsigned long time_to_wait) >+{ >+ unsigned long curr_timeout; >+ >+ for (;;) { >+ curr_timeout = timeout + jiffies; >+ wait_event(ses->server->response_q, >+ (!(midQ->midState == MID_REQUEST_SUBMITTED)) || >+ time_after(jiffies, curr_timeout) || >+ ((ses->server->tcpStatus != CifsGood) && >+ (ses->server->tcpStatus != CifsNew))); >+ >+ if (time_after(jiffies, curr_timeout) && >+ (midQ->midState == MID_REQUEST_SUBMITTED) && >+ ((ses->server->tcpStatus == CifsGood) || >+ (ses->server->tcpStatus == CifsNew))) { >+ >+ unsigned long lrt; >+ >+ /* We timed out. Is the server still >+ sending replies ? */ >+ spin_lock(&GlobalMid_Lock); >+ lrt = ses->server->lstrp; >+ spin_unlock(&GlobalMid_Lock); >+ >+ /* Calculate time_to_wait past last receive time. >+ Although we prefer not to time out if the >+ server is still responding - we will time >+ out if the server takes more than 15 (or 45 >+ or 180) seconds to respond to this request >+ and has not responded to any request from >+ other threads on the client within 10 seconds */ >+ lrt += time_to_wait; >+ if (time_after(jiffies, lrt)) { >+ /* No replies for time_to_wait. */ >+ cERROR(1,("server not responding")); >+ return -1; >+ } >+ } else { >+ return 0; >+ } >+ } >+} >+ >+int >+SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, >+ struct kvec *iov, int n_vec, int * pRespBufType /* ret */, >+ const int long_op) >+{ >+ int rc = 0; >+ unsigned int receive_len; >+ unsigned long timeout; >+ struct mid_q_entry *midQ; >+ struct smb_hdr *in_buf = iov[0].iov_base; >+ >+ *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ >+ >+ if ((ses == NULL) || (ses->server == NULL)) { >+ cifs_small_buf_release(in_buf); >+ cERROR(1,("Null session")); >+ return -EIO; >+ } >+ >+ if(ses->server->tcpStatus == CifsExiting) { >+ cifs_small_buf_release(in_buf); >+ 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 */ >+ >+ rc = wait_for_free_request(ses, long_op); >+ if (rc) { >+ cifs_small_buf_release(in_buf); >+ return rc; >+ } >+ >+ /* make sure that we sign in the same order that we send on this socket >+ and avoid races inside tcp sendmsg code that could cause corruption >+ of smb data */ >+ >+ down(&ses->server->tcpSem); >+ >+ rc = allocate_mid(ses, in_buf, &midQ); >+ if (rc) { > up(&ses->server->tcpSem); > cifs_small_buf_release(in_buf); >- /* If not lock req, update # of requests on wire to server */ >- if(long_op < 3) { >- atomic_dec(&ses->server->inFlight); >- wake_up(&ses->server->request_q); >- } >- return -ENOMEM; >+ /* Update # of requests on wire to server */ >+ atomic_dec(&ses->server->inFlight); >+ wake_up(&ses->server->request_q); >+ return rc; > } > > rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); >@@ -441,88 +534,33 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, > atomic_dec(&ses->server->inSend); > midQ->when_sent = jiffies; > #endif >- if(rc < 0) { >- DeleteMidQEntry(midQ); >- up(&ses->server->tcpSem); >- cifs_small_buf_release(in_buf); >- /* If not lock req, update # of requests on wire to server */ >- if(long_op < 3) { >- atomic_dec(&ses->server->inFlight); >- wake_up(&ses->server->request_q); >- } >- return rc; >- } else { >- up(&ses->server->tcpSem); >- cifs_small_buf_release(in_buf); >- } >+ >+ up(&ses->server->tcpSem); >+ cifs_small_buf_release(in_buf); >+ >+ if(rc < 0) >+ goto out; > > if (long_op == -1) >- goto cifs_no_response_exit2; >+ goto out; > else if (long_op == 2) /* writes past end of file can take loong time */ > timeout = 180 * HZ; > else if (long_op == 1) > timeout = 45 * HZ; /* should be greater than > servers oplock break timeout (about 43 seconds) */ >- else if (long_op > 2) { >- timeout = MAX_SCHEDULE_TIMEOUT; >- } else >+ else > timeout = 15 * HZ; >+ > /* wait for 15 seconds or until woken up due to response arriving or > due to last connection to this server being unmounted */ > if (signal_pending(current)) { > /* if signal pending do not hold up user for full smb timeout >- but we still give response a change to complete */ >+ but we still give response a chance to complete */ > timeout = 2 * HZ; > } > > /* No user interrupts in wait - wreaks havoc with performance */ >- if(timeout != MAX_SCHEDULE_TIMEOUT) { >- unsigned long curr_timeout; >- >- for (;;) { >- curr_timeout = timeout + jiffies; >- wait_event(ses->server->response_q, >- (!(midQ->midState == MID_REQUEST_SUBMITTED)) || >- time_after(jiffies, curr_timeout) || >- ((ses->server->tcpStatus != CifsGood) && >- (ses->server->tcpStatus != CifsNew))); >- >- if (time_after(jiffies, curr_timeout) && >- (midQ->midState == MID_REQUEST_SUBMITTED) && >- ((ses->server->tcpStatus == CifsGood) || >- (ses->server->tcpStatus == CifsNew))) { >- >- unsigned long lrt; >- >- /* We timed out. Is the server still >- sending replies ? */ >- spin_lock(&GlobalMid_Lock); >- lrt = ses->server->lstrp; >- spin_unlock(&GlobalMid_Lock); >- >- /* Calculate 10 seconds past last receive time. >- Although we prefer not to time out if the >- server is still responding - we will time >- out if the server takes more than 15 (or 45 >- or 180) seconds to respond to this request >- and has not responded to any request from >- other threads on the client within 10 seconds */ >- lrt += (10 * HZ); >- if (time_after(jiffies, lrt)) { >- /* No replies for 10 seconds. */ >- cERROR(1,("server not responding")); >- break; >- } >- } else { >- break; >- } >- } >- } else { >- wait_event(ses->server->response_q, >- (!(midQ->midState == MID_REQUEST_SUBMITTED)) || >- ((ses->server->tcpStatus != CifsGood) && >- (ses->server->tcpStatus != CifsNew))); >- } >+ wait_for_response(ses, midQ, timeout, 10 * HZ); > > spin_lock(&GlobalMid_Lock); > if (midQ->resp_buf) { >@@ -550,11 +588,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, > } > spin_unlock(&GlobalMid_Lock); > DeleteMidQEntry(midQ); >- /* If not lock req, update # of requests on wire to server */ >- if(long_op < 3) { >- atomic_dec(&ses->server->inFlight); >- wake_up(&ses->server->request_q); >- } >+ /* Update # of requests on wire to server */ >+ atomic_dec(&ses->server->inFlight); >+ wake_up(&ses->server->request_q); > return rc; > } > >@@ -605,24 +641,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, > cFYI(1,("Bad MID state?")); > } > } >-cifs_no_response_exit2: >- DeleteMidQEntry(midQ); > >- if(long_op < 3) { >- atomic_dec(&ses->server->inFlight); >- wake_up(&ses->server->request_q); >- } >- >- return rc; >- >-out_unlock2: >- up(&ses->server->tcpSem); >- cifs_small_buf_release(in_buf); >- /* If not lock req, update # of requests on wire to server */ >- if(long_op < 3) { >- atomic_dec(&ses->server->inFlight); >- wake_up(&ses->server->request_q); >- } >+out: >+ DeleteMidQEntry(midQ); >+ atomic_dec(&ses->server->inFlight); >+ wake_up(&ses->server->request_q); > > return rc; > } >@@ -652,85 +675,34 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, > /* 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 */ >- if(long_op == -1) { >- /* oplock breaks must not be held up */ >- atomic_inc(&ses->server->inFlight); >- } else { >- spin_lock(&GlobalMid_Lock); >- while(1) { >- if(atomic_read(&ses->server->inFlight) >= >- cifs_max_pending){ >- spin_unlock(&GlobalMid_Lock); >-#ifdef CONFIG_CIFS_STATS2 >- atomic_inc(&ses->server->num_waiters); >-#endif >- wait_event(ses->server->request_q, >- atomic_read(&ses->server->inFlight) >- < cifs_max_pending); >-#ifdef CONFIG_CIFS_STATS2 >- atomic_dec(&ses->server->num_waiters); >-#endif >- spin_lock(&GlobalMid_Lock); >- } else { >- if(ses->server->tcpStatus == CifsExiting) { >- spin_unlock(&GlobalMid_Lock); >- return -ENOENT; >- } > >- /* can not count locking commands against total since >- they are allowed to block on server */ >- >- if(long_op < 3) { >- /* update # of requests on the wire to server */ >- atomic_inc(&ses->server->inFlight); >- } >- spin_unlock(&GlobalMid_Lock); >- break; >- } >- } >- } >+ rc = wait_for_free_request(ses, long_op); >+ if (rc) >+ return rc; >+ > /* make sure that we sign in the same order that we send on this socket > and avoid races inside tcp sendmsg code that could cause corruption > of smb data */ > > down(&ses->server->tcpSem); > >- if (ses->server->tcpStatus == CifsExiting) { >- rc = -ENOENT; >- goto out_unlock; >- } else if (ses->server->tcpStatus == CifsNeedReconnect) { >- cFYI(1,("tcp session dead - return to caller to retry")); >- rc = -EAGAIN; >- goto out_unlock; >- } else if (ses->status != CifsGood) { >- /* check if SMB session is bad because we are setting it up */ >- if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && >- (in_buf->Command != SMB_COM_NEGOTIATE)) { >- rc = -EAGAIN; >- goto out_unlock; >- } /* else ok - we are setting up session */ >- } >- midQ = AllocMidQEntry(in_buf, ses); >- if (midQ == NULL) { >+ rc = allocate_mid(ses, in_buf, &midQ); >+ if (rc) { > up(&ses->server->tcpSem); >- /* If not lock req, update # of requests on wire to server */ >- if(long_op < 3) { >- atomic_dec(&ses->server->inFlight); >- wake_up(&ses->server->request_q); >- } >- return -ENOMEM; >+ /* Update # of requests on wire to server */ >+ atomic_dec(&ses->server->inFlight); >+ wake_up(&ses->server->request_q); >+ return rc; > } > > if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { >- up(&ses->server->tcpSem); > cERROR(1, ("Illegal length, greater than maximum frame, %d", > in_buf->smb_buf_length)); > DeleteMidQEntry(midQ); >- /* If not lock req, update # of requests on wire to server */ >- if(long_op < 3) { >- atomic_dec(&ses->server->inFlight); >- wake_up(&ses->server->request_q); >- } >+ up(&ses->server->tcpSem); >+ /* Update # of requests on wire to server */ >+ atomic_dec(&ses->server->inFlight); >+ wake_up(&ses->server->request_q); > return -EIO; > } > >@@ -746,78 +718,30 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, > atomic_dec(&ses->server->inSend); > midQ->when_sent = jiffies; > #endif >- if(rc < 0) { >- DeleteMidQEntry(midQ); >- up(&ses->server->tcpSem); >- /* If not lock req, update # of requests on wire to server */ >- if(long_op < 3) { >- atomic_dec(&ses->server->inFlight); >- wake_up(&ses->server->request_q); >- } >- return rc; >- } else >- up(&ses->server->tcpSem); >+ up(&ses->server->tcpSem); >+ >+ if(rc < 0) >+ goto out; >+ > if (long_op == -1) >- goto cifs_no_response_exit; >+ goto out; > else if (long_op == 2) /* writes past end of file can take loong time */ > timeout = 180 * HZ; > else if (long_op == 1) > timeout = 45 * HZ; /* should be greater than > servers oplock break timeout (about 43 seconds) */ >- else if (long_op > 2) { >- timeout = MAX_SCHEDULE_TIMEOUT; >- } else >+ else > timeout = 15 * HZ; > /* wait for 15 seconds or until woken up due to response arriving or > due to last connection to this server being unmounted */ > if (signal_pending(current)) { > /* if signal pending do not hold up user for full smb timeout >- but we still give response a change to complete */ >+ but we still give response a chance to complete */ > timeout = 2 * HZ; > } > > /* No user interrupts in wait - wreaks havoc with performance */ >- if(timeout != MAX_SCHEDULE_TIMEOUT) { >- unsigned long curr_timeout; >- >- for (;;) { >- curr_timeout = timeout + jiffies; >- wait_event(ses->server->response_q, >- (!(midQ->midState == MID_REQUEST_SUBMITTED)) || >- time_after(jiffies, curr_timeout) || >- ((ses->server->tcpStatus != CifsGood) && >- (ses->server->tcpStatus != CifsNew))); >- >- if (time_after(jiffies, curr_timeout) && >- (midQ->midState == MID_REQUEST_SUBMITTED) && >- ((ses->server->tcpStatus == CifsGood) || >- (ses->server->tcpStatus == CifsNew))) { >- >- unsigned long lrt; >- >- /* We timed out. Is the server still >- sending replies ? */ >- spin_lock(&GlobalMid_Lock); >- lrt = ses->server->lstrp; >- spin_unlock(&GlobalMid_Lock); >- >- /* Calculate 10 seconds past last receive time*/ >- lrt += (10 * HZ); >- if (time_after(jiffies, lrt)) { >- /* Server sent no reply in 10 seconds */ >- cERROR(1,("Server not responding")); >- break; >- } >- } else { >- break; >- } >- } >- } else { >- wait_event(ses->server->response_q, >- (!(midQ->midState == MID_REQUEST_SUBMITTED)) || >- ((ses->server->tcpStatus != CifsGood) && >- (ses->server->tcpStatus != CifsNew))); >- } >+ wait_for_response(ses, midQ, timeout, 10 * HZ); > > spin_lock(&GlobalMid_Lock); > if (midQ->resp_buf) { >@@ -845,11 +769,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, > } > spin_unlock(&GlobalMid_Lock); > DeleteMidQEntry(midQ); >- /* If not lock req, update # of requests on wire to server */ >- if(long_op < 3) { >- atomic_dec(&ses->server->inFlight); >- wake_up(&ses->server->request_q); >- } >+ /* Update # of requests on wire to server */ >+ atomic_dec(&ses->server->inFlight); >+ wake_up(&ses->server->request_q); > return rc; > } > >@@ -896,23 +818,252 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, > cERROR(1,("Bad MID state?")); > } > } >-cifs_no_response_exit: >+ >+out: > DeleteMidQEntry(midQ); >+ atomic_dec(&ses->server->inFlight); >+ wake_up(&ses->server->request_q); > >- if(long_op < 3) { >- atomic_dec(&ses->server->inFlight); >- wake_up(&ses->server->request_q); >- } >+ return rc; >+} > >+/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */ >+ >+static int >+send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf, >+ struct mid_q_entry *midQ) >+{ >+ int rc = 0; >+ struct cifsSesInfo *ses = tcon->ses; >+ __u16 mid = in_buf->Mid; >+ >+ header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0); >+ in_buf->Mid = mid; >+ down(&ses->server->tcpSem); >+ rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); >+ if (rc) { >+ up(&ses->server->tcpSem); >+ return rc; >+ } >+ rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, >+ (struct sockaddr *) &(ses->server->addr.sockAddr)); >+ up(&ses->server->tcpSem); > return rc; >+} >+ >+/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows >+ blocking lock to return. */ >+ >+static int >+send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon, >+ struct smb_hdr *in_buf, >+ struct smb_hdr *out_buf) >+{ >+ int bytes_returned; >+ struct cifsSesInfo *ses = tcon->ses; >+ LOCK_REQ *pSMB = (LOCK_REQ *)in_buf; >+ >+ /* We just modify the current in_buf to change >+ the type of lock from LOCKING_ANDX_SHARED_LOCK >+ or LOCKING_ANDX_EXCLUSIVE_LOCK to >+ LOCKING_ANDX_CANCEL_LOCK. */ >+ >+ pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES; >+ pSMB->Timeout = 0; >+ pSMB->hdr.Mid = GetNextMid(ses->server); >+ >+ return SendReceive(xid, ses, in_buf, out_buf, >+ &bytes_returned, 0); >+} >+ >+int >+SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, >+ struct smb_hdr *in_buf, struct smb_hdr *out_buf, >+ int *pbytes_returned) >+{ >+ int rc = 0; >+ int rstart = 0; >+ unsigned int receive_len; >+ struct mid_q_entry *midQ; >+ struct cifsSesInfo *ses; >+ >+ if (tcon == NULL || tcon->ses == NULL) { >+ cERROR(1,("Null smb session")); >+ return -EIO; >+ } >+ ses = tcon->ses; >+ >+ if(ses->server == NULL) { >+ cERROR(1,("Null tcp session")); >+ 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 */ >+ >+ rc = wait_for_free_request(ses, 3); >+ if (rc) >+ return rc; >+ >+ /* make sure that we sign in the same order that we send on this socket >+ and avoid races inside tcp sendmsg code that could cause corruption >+ of smb data */ >+ >+ down(&ses->server->tcpSem); >+ >+ rc = allocate_mid(ses, in_buf, &midQ); >+ if (rc) { >+ up(&ses->server->tcpSem); >+ return rc; >+ } >+ >+ if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { >+ up(&ses->server->tcpSem); >+ cERROR(1, ("Illegal length, greater than maximum frame, %d", >+ in_buf->smb_buf_length)); >+ DeleteMidQEntry(midQ); >+ return -EIO; >+ } > >-out_unlock: >+ rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); >+ >+ midQ->midState = MID_REQUEST_SUBMITTED; >+#ifdef CONFIG_CIFS_STATS2 >+ atomic_inc(&ses->server->inSend); >+#endif >+ rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, >+ (struct sockaddr *) &(ses->server->addr.sockAddr)); >+#ifdef CONFIG_CIFS_STATS2 >+ atomic_dec(&ses->server->inSend); >+ midQ->when_sent = jiffies; >+#endif > up(&ses->server->tcpSem); >- /* If not lock req, update # of requests on wire to server */ >- if(long_op < 3) { >- atomic_dec(&ses->server->inFlight); >- wake_up(&ses->server->request_q); >+ >+ if(rc < 0) { >+ DeleteMidQEntry(midQ); >+ return rc; >+ } >+ >+ /* Wait for a reply - allow signals to interrupt. */ >+ rc = wait_event_interruptible(ses->server->response_q, >+ (!(midQ->midState == MID_REQUEST_SUBMITTED)) || >+ ((ses->server->tcpStatus != CifsGood) && >+ (ses->server->tcpStatus != CifsNew))); >+ >+ /* Were we interrupted by a signal ? */ >+ if ((rc == -ERESTARTSYS) && >+ (midQ->midState == MID_REQUEST_SUBMITTED) && >+ ((ses->server->tcpStatus == CifsGood) || >+ (ses->server->tcpStatus == CifsNew))) { >+ >+ if (in_buf->Command == SMB_COM_TRANSACTION2) { >+ /* POSIX lock. We send a NT_CANCEL SMB to cause the >+ blocking lock to return. */ >+ >+ rc = send_nt_cancel(tcon, in_buf, midQ); >+ if (rc) { >+ DeleteMidQEntry(midQ); >+ return rc; >+ } >+ } else { >+ /* Windows lock. We send a LOCKINGX_CANCEL_LOCK >+ to cause the blocking lock to return. */ >+ >+ rc = send_lock_cancel(xid, tcon, in_buf, out_buf); >+ >+ /* If we get -ENOLCK back the lock may have >+ already been removed. Don't exit in this case. */ >+ if (rc && rc != -ENOLCK) { >+ DeleteMidQEntry(midQ); >+ return rc; >+ } >+ } >+ >+ /* Wait 5 seconds for the response. */ >+ if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ)==0) { >+ /* We got the response - restart system call. */ >+ rstart = 1; >+ } >+ } >+ >+ spin_lock(&GlobalMid_Lock); >+ if (midQ->resp_buf) { >+ spin_unlock(&GlobalMid_Lock); >+ receive_len = midQ->resp_buf->smb_buf_length; >+ } else { >+ cERROR(1,("No response for cmd %d mid %d", >+ midQ->command, midQ->mid)); >+ if(midQ->midState == MID_REQUEST_SUBMITTED) { >+ if(ses->server->tcpStatus == CifsExiting) >+ rc = -EHOSTDOWN; >+ else { >+ ses->server->tcpStatus = CifsNeedReconnect; >+ midQ->midState = MID_RETRY_NEEDED; >+ } >+ } >+ >+ if (rc != -EHOSTDOWN) { >+ if(midQ->midState == MID_RETRY_NEEDED) { >+ rc = -EAGAIN; >+ cFYI(1,("marking request for retry")); >+ } else { >+ rc = -EIO; >+ } >+ } >+ spin_unlock(&GlobalMid_Lock); >+ DeleteMidQEntry(midQ); >+ return rc; > } >+ >+ if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { >+ cERROR(1, ("Frame too large received. Length: %d Xid: %d", >+ receive_len, xid)); >+ rc = -EIO; >+ } else { /* rcvd frame is ok */ >+ >+ if (midQ->resp_buf && out_buf >+ && (midQ->midState == MID_RESPONSE_RECEIVED)) { >+ out_buf->smb_buf_length = receive_len; >+ memcpy((char *)out_buf + 4, >+ (char *)midQ->resp_buf + 4, >+ receive_len); >+ >+ dump_smb(out_buf, 92); >+ /* convert the length into a more usable form */ >+ if((receive_len > 24) && >+ (ses->server->secMode & (SECMODE_SIGN_REQUIRED | >+ SECMODE_SIGN_ENABLED))) { >+ rc = cifs_verify_signature(out_buf, >+ ses->server->mac_signing_key, >+ midQ->sequence_number+1); >+ if(rc) { >+ cERROR(1,("Unexpected SMB signature")); >+ /* BB FIXME add code to kill session */ >+ } >+ } >+ >+ *pbytes_returned = out_buf->smb_buf_length; >+ >+ /* BB special case reconnect tid and uid here? */ >+ rc = map_smb_to_linux_error(out_buf); > >+ /* convert ByteCount if necessary */ >+ if (receive_len >= >+ sizeof (struct smb_hdr) - >+ 4 /* do not count RFC1001 header */ + >+ (2 * out_buf->WordCount) + 2 /* bcc */ ) >+ BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); >+ } else { >+ rc = -EIO; >+ cERROR(1,("Bad MID state?")); >+ } >+ } >+ DeleteMidQEntry(midQ); >+ if (rstart && rc == -EACCES) >+ return -ERESTARTSYS; > return rc; > } >diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c >index 7754d64..2734a92 100644 >--- a/fs/cifs/xattr.c >+++ b/fs/cifs/xattr.c >@@ -20,7 +20,10 @@ > */ > > #include <linux/fs.h> >+#include <linux/version.h> >+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) > #include <linux/posix_acl_xattr.h> >+#endif > #include "cifsfs.h" > #include "cifspdu.h" > #include "cifsglob.h" >@@ -269,7 +272,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, > rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, > ea_value, buf_size, > ACL_TYPE_ACCESS); >- CIFSSMBClose(xid, pTcon, fid) >+ CIFSSMBClose(xid, pTcon, fid); > } > } */ /* BB enable after fixing up return data */ > >@@ -330,11 +333,15 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) > sb = direntry->d_inode->i_sb; > if(sb == NULL) > return -EIO; >- xid = GetXid(); > > cifs_sb = CIFS_SB(sb); > pTcon = cifs_sb->tcon; > >+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) >+ return -EOPNOTSUPP; >+ >+ xid = GetXid(); >+ > full_path = build_path_from_dentry(direntry); > if(full_path == NULL) { > FreeXid(xid); >-- >1.5.0.6 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 239339
:
157310
|
157311
|
157313
|
158846
|
158848
|
158849