From 9b6763e0aacf245b58687a372816a0a4aabf2b1e Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Mon, 21 Feb 2011 23:56:59 -0600 Subject: cifs: Remove unused inode number while fetching root inode ino is unused in function cifs_root_iget(). Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifsfs.h | 2 +- fs/cifs/inode.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5c412b33cd7c..0742c269ef12 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -163,7 +163,7 @@ cifs_read_super(struct super_block *sb, void *data, sb->s_bdi = &cifs_sb->bdi; sb->s_blocksize = CIFS_MAX_MSGSIZE; sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ - inode = cifs_root_iget(sb, ROOT_I); + inode = cifs_root_iget(sb); if (IS_ERR(inode)) { rc = PTR_ERR(inode); diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index a9371b6578c0..f191244f266e 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -47,7 +47,7 @@ extern void cifs_sb_deactive(struct super_block *sb); /* Functions related to inodes */ extern const struct inode_operations cifs_dir_inode_ops; -extern struct inode *cifs_root_iget(struct super_block *, unsigned long); +extern struct inode *cifs_root_iget(struct super_block *); extern int cifs_create(struct inode *, struct dentry *, int, struct nameidata *); extern struct dentry *cifs_lookup(struct inode *, struct dentry *, diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8852470b4fbb..196ef6078029 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -878,7 +878,7 @@ retry_iget5_locked: } /* gets root inode */ -struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) +struct inode *cifs_root_iget(struct super_block *sb) { int xid; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); -- cgit v1.2.3-59-g8ed1b From 0eff0e26777430bcfee1ef47bd90250858ada431 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 24 Feb 2011 05:39:23 +0000 Subject: Remove unused CIFSSMBNotify worker function The CIFSSMBNotify worker is unused, pending changes to allow it to be called via inotify, so move it into its own experimental config option so it does not get built in, until the necessary VFS support is fixed. It used to be used in dnotify, but according to Jeff, inotify needs minor changes before we can reenable this. CC: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 4 +- fs/cifs/cifsglob.h | 2 + fs/cifs/cifsproto.h | 10 ++-- fs/cifs/cifssmb.c | 169 +++++++++++++++++++++++++++++----------------------- 4 files changed, 105 insertions(+), 80 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0742c269ef12..b45d38b89116 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -981,10 +981,10 @@ init_cifs(void) int rc = 0; cifs_proc_init(); INIT_LIST_HEAD(&cifs_tcp_ses_list); -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ INIT_LIST_HEAD(&GlobalDnotifyReqList); INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); -#endif +#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ /* * Initialize Global counters */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a5d1106fcbde..6e211b67b273 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -780,10 +780,12 @@ GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock; */ GLOBAL_EXTERN spinlock_t cifs_file_list_lock; +#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ /* Outstanding dir notify requests */ GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* DirNotify response queue */ GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; +#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ /* * Global transaction id (XID) information diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 8096f27ad9a8..34bbd5cf46d0 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -386,6 +386,12 @@ extern int calc_seckey(struct cifsSesInfo *); extern void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ +#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ +extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, + const int notify_subdirs, const __u16 netfid, + __u32 filter, struct file *file, int multishot, + const struct nls_table *nls_codepage); +#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ extern int CIFSSMBCopy(int xid, struct cifsTconInfo *source_tcon, const char *fromName, @@ -393,10 +399,6 @@ extern int CIFSSMBCopy(int xid, const char *toName, const int flags, const struct nls_table *nls_codepage, int remap_special_chars); -extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, - const int notify_subdirs, const __u16 netfid, - __u32 filter, struct file *file, int multishot, - const struct nls_table *nls_codepage); extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, const unsigned char *ea_name, char *EAData, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index df959bae6728..5630282f2821 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -5418,79 +5418,6 @@ setPermsRetry: return rc; } -int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, - const int notify_subdirs, const __u16 netfid, - __u32 filter, struct file *pfile, int multishot, - const struct nls_table *nls_codepage) -{ - int rc = 0; - struct smb_com_transaction_change_notify_req *pSMB = NULL; - struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL; - struct dir_notify_req *dnotify_req; - int bytes_returned; - - cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid); - rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; - - pSMB->TotalParameterCount = 0 ; - pSMB->TotalDataCount = 0; - pSMB->MaxParameterCount = cpu_to_le32(2); - /* BB find exact data count max from sess structure BB */ - pSMB->MaxDataCount = 0; /* same in little endian or be */ -/* BB VERIFY verify which is correct for above BB */ - pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); - - pSMB->MaxSetupCount = 4; - pSMB->Reserved = 0; - pSMB->ParameterOffset = 0; - pSMB->DataCount = 0; - pSMB->DataOffset = 0; - pSMB->SetupCount = 4; /* single byte does not need le conversion */ - pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); - pSMB->ParameterCount = pSMB->TotalParameterCount; - if (notify_subdirs) - pSMB->WatchTree = 1; /* one byte - no le conversion needed */ - pSMB->Reserved2 = 0; - pSMB->CompletionFilter = cpu_to_le32(filter); - pSMB->Fid = netfid; /* file handle always le */ - pSMB->ByteCount = 0; - - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *)pSMBr, &bytes_returned, - CIFS_ASYNC_OP); - if (rc) { - cFYI(1, "Error in Notify = %d", rc); - } else { - /* Add file to outstanding requests */ - /* BB change to kmem cache alloc */ - dnotify_req = kmalloc( - sizeof(struct dir_notify_req), - GFP_KERNEL); - if (dnotify_req) { - dnotify_req->Pid = pSMB->hdr.Pid; - dnotify_req->PidHigh = pSMB->hdr.PidHigh; - dnotify_req->Mid = pSMB->hdr.Mid; - dnotify_req->Tid = pSMB->hdr.Tid; - dnotify_req->Uid = pSMB->hdr.Uid; - dnotify_req->netfid = netfid; - dnotify_req->pfile = pfile; - dnotify_req->filter = filter; - dnotify_req->multishot = multishot; - spin_lock(&GlobalMid_Lock); - list_add_tail(&dnotify_req->lhead, - &GlobalDnotifyReqList); - spin_unlock(&GlobalMid_Lock); - } else - rc = -ENOMEM; - } - cifs_buf_release(pSMB); - return rc; -} - #ifdef CONFIG_CIFS_XATTR /* * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common @@ -5787,5 +5714,99 @@ SetEARetry: return rc; } - #endif + +#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */ +/* + * Years ago the kernel added a "dnotify" function for Samba server, + * to allow network clients (such as Windows) to display updated + * lists of files in directory listings automatically when + * files are added by one user when another user has the + * same directory open on their desktop. The Linux cifs kernel + * client hooked into the kernel side of this interface for + * the same reason, but ironically when the VFS moved from + * "dnotify" to "inotify" it became harder to plug in Linux + * network file system clients (the most obvious use case + * for notify interfaces is when multiple users can update + * the contents of the same directory - exactly what network + * file systems can do) although the server (Samba) could + * still use it. For the short term we leave the worker + * function ifdeffed out (below) until inotify is fixed + * in the VFS to make it easier to plug in network file + * system clients. If inotify turns out to be permanently + * incompatible for network fs clients, we could instead simply + * expose this config flag by adding a future cifs (and smb2) notify ioctl. + */ +int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, + const int notify_subdirs, const __u16 netfid, + __u32 filter, struct file *pfile, int multishot, + const struct nls_table *nls_codepage) +{ + int rc = 0; + struct smb_com_transaction_change_notify_req *pSMB = NULL; + struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL; + struct dir_notify_req *dnotify_req; + int bytes_returned; + + cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid); + rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 0 ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le32(2); + /* BB find exact data count max from sess structure BB */ + pSMB->MaxDataCount = 0; /* same in little endian or be */ +/* BB VERIFY verify which is correct for above BB */ + pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - + MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + + pSMB->MaxSetupCount = 4; + pSMB->Reserved = 0; + pSMB->ParameterOffset = 0; + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 4; /* single byte does not need le conversion */ + pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); + pSMB->ParameterCount = pSMB->TotalParameterCount; + if (notify_subdirs) + pSMB->WatchTree = 1; /* one byte - no le conversion needed */ + pSMB->Reserved2 = 0; + pSMB->CompletionFilter = cpu_to_le32(filter); + pSMB->Fid = netfid; /* file handle always le */ + pSMB->ByteCount = 0; + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *)pSMBr, &bytes_returned, + CIFS_ASYNC_OP); + if (rc) { + cFYI(1, "Error in Notify = %d", rc); + } else { + /* Add file to outstanding requests */ + /* BB change to kmem cache alloc */ + dnotify_req = kmalloc( + sizeof(struct dir_notify_req), + GFP_KERNEL); + if (dnotify_req) { + dnotify_req->Pid = pSMB->hdr.Pid; + dnotify_req->PidHigh = pSMB->hdr.PidHigh; + dnotify_req->Mid = pSMB->hdr.Mid; + dnotify_req->Tid = pSMB->hdr.Tid; + dnotify_req->Uid = pSMB->hdr.Uid; + dnotify_req->netfid = netfid; + dnotify_req->pfile = pfile; + dnotify_req->filter = filter; + dnotify_req->multishot = multishot; + spin_lock(&GlobalMid_Lock); + list_add_tail(&dnotify_req->lhead, + &GlobalDnotifyReqList); + spin_unlock(&GlobalMid_Lock); + } else + rc = -ENOMEM; + } + cifs_buf_release(pSMB); + return rc; +} +#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ -- cgit v1.2.3-59-g8ed1b From c52a95545c7f8060aa4e83deca16e3414ce73000 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 24 Feb 2011 06:16:22 +0000 Subject: Don't compile in unused reparse point symlink code Recent Windows versions now create symlinks more frequently and they do use this "reparse point" symlink mechanism. We can of course do symlinks nicely to Samba and other servers which support the CIFS Unix Extensions and we can also do SFU symlinks and "client only" "MF" symlinks optionally, but for recent Windows we currently can not handle the common "reparse point" symlinks fully, removing the caller for this. We will need to extend and reenable this "reparse point" worker code in cifs and fix cifs_symlink to call this. In the interim this code has been moved to its own config option so it is not compiled in by default until cifs_symlink fixed up (and tested) to use this. CC: Jeff Layton Signed-off-by: Steve French --- fs/cifs/README | 12 ------------ fs/cifs/cifsproto.h | 3 ++- fs/cifs/cifssmb.c | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/fs/cifs/README b/fs/cifs/README index 74ab165fc646..4a3ca0e5ca24 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -704,18 +704,6 @@ the start of smb requests and responses can be enabled via: echo 1 > /proc/fs/cifs/traceSMB -Two other experimental features are under development. To test these -requires enabling CONFIG_CIFS_EXPERIMENTAL - - cifsacl support needed to retrieve approximated mode bits based on - the contents on the CIFS ACL. - - lease support: cifs will check the oplock state before calling into - the vfs to see if we can grant a lease on a file. - - DNOTIFY fcntl: needed for support of directory change - notification and perhaps later for file leases) - Per share (per client mount) statistics are available in /proc/fs/cifs/Stats if the kernel was configured with cifs statistics enabled. The statistics represent the number of successful (ie non-zero return code from the server) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 34bbd5cf46d0..da7a4923783f 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -304,12 +304,13 @@ extern int CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char **syminfo, const struct nls_table *nls_codepage); +#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL extern int CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char *symlinkinfo, const int buflen, __u16 fid, const struct nls_table *nls_codepage); - +#endif /* temporarily unused until cifs_symlink fixed */ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const char *fileName, const int disposition, const int access_flags, const int omode, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 5630282f2821..ae5e451a0d08 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2516,7 +2516,17 @@ querySymLinkRetry: return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL +/* + * Recent Windows versions now create symlinks more frequently + * and they use the "reparse point" mechanism below. We can of course + * do symlinks nicely to Samba and other servers which support the + * CIFS Unix Extensions and we can also do SFU symlinks and "client only" + * "MF" symlinks optionally, but for recent Windows we really need to + * reenable the code below and fix the cifs_symlink callers to handle this. + * In the interim this code has been moved to its own config option so + * it is not compiled in by default until callers fixed up and more tested. + */ int CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, @@ -2618,7 +2628,7 @@ qreparse_out: return rc; } -#endif /* CIFS_EXPERIMENTAL */ +#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */ #ifdef CONFIG_CIFS_POSIX -- cgit v1.2.3-59-g8ed1b From fd62cb7e7411f1f5ca774145665316d3612fed9a Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Thu, 24 Feb 2011 22:15:02 -0800 Subject: fs:cifs:connect.c remove one to many l's in the word. The patch below removes an extra "l" in the word. Signed-off-by: Justin P. Mattock Signed-off-by: Steve French --- fs/cifs/connect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 277262a8e82f..68b7dbf24b92 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -735,7 +735,7 @@ multi_t2_fnd: sock_release(csocket); server->ssocket = NULL; } - /* buffer usuallly freed in free_mid - need to free it here on exit */ + /* buffer usually freed in free_mid - need to free it here on exit */ cifs_buf_release(bigbuf); if (smallbuf) /* no sense logging a debug message if NULL */ cifs_small_buf_release(smallbuf); -- cgit v1.2.3-59-g8ed1b From 34c87901e113799a45423fdac29c7478c889a95d Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 1 Mar 2011 05:02:57 +0000 Subject: Shrink stack space usage in cifs_construct_tcon We were reserving MAX_USERNAME (now 256) on stack for something which only needs to fit about 24 bytes ie string krb50x + printf version of uid Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 3 ++- fs/cifs/connect.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 6e211b67b273..108a1e99aa9f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -274,7 +274,8 @@ struct cifsSesInfo { int capabilities; char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for TCP names - will ipv6 and sctp addresses fit? */ - char *user_name; + char *user_name; /* must not be null except during init of sess + and after mount option parsing we fill it */ char *domainName; char *password; struct session_key auth_key; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 68b7dbf24b92..8d72acbd5c13 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3258,7 +3258,9 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) struct cifsSesInfo *ses; struct cifsTconInfo *tcon = NULL; struct smb_vol *vol_info; - char username[MAX_USERNAME_SIZE + 1]; + char username[28]; /* big enough for "krb50x" + hex of ULONG_MAX 6+16 */ + /* We used to have this as MAX_USERNAME which is */ + /* way too big now (256 instead of 32) */ vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL); if (vol_info == NULL) { -- cgit v1.2.3-59-g8ed1b From b34cb85cc2d84c487afe2baa2d3c04d8b677bbd0 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 24 Feb 2011 17:58:00 +0000 Subject: Introduce SMB2 Kconfig option SMB2 is the followon to the CIFS (and SMB) protocols and the default for Windows since Windows Vista, and also now implemented by various non-Windows servers. SMB2 is more secure, has various performance advantages, including larger i/o sizes, flow control, better caching model and more. SMB2 also resolves some scalability limits in the cifs protocol and adds many new features while being much simpler (only a few dozen commands instead of hundreds) and since the protocol is clearer it is also more consistently implemented across servers and thus easier to optimize. After much discussion with Jeff Layton, Jeremy Allison and others at Connectathon, we decided to move the smb2 code from a distinct .ko and fstype into distinct C files that optionally build in cifs.ko. As a result the Kconfig gets simpler. To avoid destabilizing cifs, the smb2 code is going to be moved into its own experimental CONFIG_CIFS_SMB2 ifdef as it is merged and rereviewed. The changes to stable cifs (builds with the smb2 ifdef off) are expected to be fairly small. Reviewed-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/Kconfig | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 7cb0f7f847e4..2a492aad40d1 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -152,6 +152,26 @@ config CIFS_ACL Allows to fetch CIFS/NTFS ACL from the server. The DACL blob is handed over to the application/caller. +config CIFS_SMB2 + bool "SMB2 network file system support (EXPERIMENTAL)" + depends on EXPERIMENTAL && INET && BROKEN + select NLS + select KEYS + select FSCACHE + select DNS_RESOLVER + + help + This enables experimental support for the SMB2 (Server Message Block + version 2) protocol. The SMB2 protocol is the successor to the + popular CIFS and SMB network file sharing protocols. SMB2 is the + native file sharing mechanism for recent versions of Windows + operating systems (since Vista). SMB2 enablement will eventually + allow users better performance, security and features, than would be + possible with cifs. Note that smb2 mount options also are simpler + (compared to cifs) due to protocol improvements. + + Unless you are a developer or tester, say N. + config CIFS_EXPERIMENTAL bool "CIFS Experimental Features (EXPERIMENTAL)" depends on CIFS && EXPERIMENTAL -- cgit v1.2.3-59-g8ed1b From 257208736acc694def83627fa0de2892490a5d42 Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Fri, 25 Feb 2011 10:48:55 -0600 Subject: cifs: cleanup: Rename and remove config flags Remove config flag CIFS_EXPERIMENTAL. Do export operations under new config flag CIFS_NFSD_EXPORT Signed-off-by: Shirish Pargaonkar Reviewed-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/Kconfig | 14 +++----------- fs/cifs/cifsfs.c | 4 ++-- fs/cifs/cifsfs.h | 4 ++-- fs/cifs/cifssmb.c | 4 ---- fs/cifs/export.c | 4 ++-- 5 files changed, 9 insertions(+), 21 deletions(-) diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 2a492aad40d1..7c584be27fdf 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -172,16 +172,8 @@ config CIFS_SMB2 Unless you are a developer or tester, say N. -config CIFS_EXPERIMENTAL - bool "CIFS Experimental Features (EXPERIMENTAL)" +config CIFS_NFSD_EXPORT + bool "Allow nfsd to export CIFS file system (EXPERIMENTAL)" depends on CIFS && EXPERIMENTAL help - Enables cifs features under testing. These features are - experimental and currently include DFS support and directory - change notification ie fcntl(F_DNOTIFY), as well as the upcall - mechanism which will be used for Kerberos session negotiation - and uid remapping. Some of these features also may depend on - setting a value of 1 to the pseudo-file /proc/fs/cifs/Experimental - (which is disabled by default). See the file fs/cifs/README - for more details. If unsure, say N. - + Allows NFS server to export a CIFS mounted share (nfsd over cifs) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index b45d38b89116..30fc505b7ef1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -184,12 +184,12 @@ cifs_read_super(struct super_block *sb, void *data, else sb->s_d_op = &cifs_dentry_ops; -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CIFS_NFSD_EXPORT if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { cFYI(1, "export ops supported"); sb->s_export_op = &cifs_export_ops; } -#endif /* EXPERIMENTAL */ +#endif /* CIFS_NFSD_EXPORT */ return 0; diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index f191244f266e..371d021815b1 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -123,9 +123,9 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CIFS_NFSD_EXPORT extern const struct export_operations cifs_export_ops; -#endif /* EXPERIMENTAL */ +#endif /* CIFS_NFSD_EXPORT */ #define CIFS_VERSION "1.71" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index ae5e451a0d08..e6374dda3c6a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -541,10 +541,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->secType = RawNTLMSSP; else if (secFlags & CIFSSEC_MAY_LANMAN) server->secType = LANMAN; -/* #ifdef CONFIG_CIFS_EXPERIMENTAL - else if (secFlags & CIFSSEC_MAY_PLNTXT) - server->secType = ?? -#endif */ else { rc = -EOPNOTSUPP; cERROR(1, "Invalid security type"); diff --git a/fs/cifs/export.c b/fs/cifs/export.c index 993f82045bf6..55d87ac52000 100644 --- a/fs/cifs/export.c +++ b/fs/cifs/export.c @@ -45,7 +45,7 @@ #include "cifs_debug.h" #include "cifsfs.h" -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CIFS_NFSD_EXPORT static struct dentry *cifs_get_parent(struct dentry *dentry) { /* BB need to add code here eventually to enable export via NFSD */ @@ -63,5 +63,5 @@ const struct export_operations cifs_export_ops = { .encode_fs = */ }; -#endif /* EXPERIMENTAL */ +#endif /* CIFS_NFSD_EXPORT */ -- cgit v1.2.3-59-g8ed1b From 43988d76851077d2945080665e3c4e2e636d700a Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 19 Apr 2011 18:23:31 +0000 Subject: [CIFS] Use ecb des kernel crypto APIs instead of local cifs functions (repost) Using kernel crypto APIs for DES encryption during LM and NT hash generation instead of local functions within cifs. Source file smbdes.c is deleted sans four functions, one of which uses ecb des functionality provided by kernel crypto APIs. Remove function SMBOWFencrypt. Add return codes to various functions such as calc_lanman_hash, SMBencrypt, and SMBNTencrypt. Includes fix noticed by Dan Carpenter. Signed-off-by: Shirish Pargaonkar CC: Dan Carpenter Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/Kconfig | 1 + fs/cifs/Makefile | 2 +- fs/cifs/cifsencrypt.c | 10 +- fs/cifs/cifsproto.h | 7 +- fs/cifs/sess.c | 2 +- fs/cifs/smbdes.c | 418 -------------------------------------------------- fs/cifs/smbencrypt.c | 124 ++++++++++++--- 7 files changed, 109 insertions(+), 455 deletions(-) delete mode 100644 fs/cifs/smbdes.c diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 7c584be27fdf..75c47cd8d086 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -7,6 +7,7 @@ config CIFS select CRYPTO_MD5 select CRYPTO_HMAC select CRYPTO_ARC4 + select CRYPTO_DES help This is the client VFS module for the Common Internet File System (CIFS) protocol which is the successor to the Server Message Block diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index d87558448e3d..005d524c3a4a 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_CIFS) += cifs.o cifs-y := 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 \ + link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \ cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ readdir.o ioctl.o sess.o export.o diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index d1a016be73ba..e7c59314894f 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -268,10 +268,11 @@ int setup_ntlm_response(struct cifsSesInfo *ses) } #ifdef CONFIG_CIFS_WEAK_PW_HASH -void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, +int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key) { int i; + int rc; char password_with_pad[CIFS_ENCPWD_SIZE]; memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); @@ -282,7 +283,7 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE); memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); - return; + return 0; } /* calculate old style session key */ @@ -299,10 +300,9 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, for (i = 0; i < CIFS_ENCPWD_SIZE; i++) password_with_pad[i] = toupper(password_with_pad[i]); - SMBencrypt(password_with_pad, cryptkey, lnm_session_key); + rc = SMBencrypt(password_with_pad, cryptkey, lnm_session_key); - /* clear password before we return/free memory */ - memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); + return rc; } #endif /* CIFS_WEAK_PW_HASH */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index da7a4923783f..e94526949677 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -384,7 +384,7 @@ extern void cifs_crypto_shash_release(struct TCP_Server_Info *); extern int calc_seckey(struct cifsSesInfo *); #ifdef CONFIG_CIFS_WEAK_PW_HASH -extern void calc_lanman_hash(const char *password, const char *cryptkey, +extern int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ @@ -430,9 +430,6 @@ extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb, int xid); extern int mdfour(unsigned char *, unsigned char *, int); extern int E_md4hash(const unsigned char *passwd, unsigned char *p16); -extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, - unsigned char *p24); -extern void E_P16(unsigned char *p14, unsigned char *p16); -extern void E_P24(unsigned char *p21, const unsigned char *c8, +extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 645114ad0a10..b6ff84af81a4 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -656,7 +656,7 @@ ssetup_ntlmssp_authenticate: * to use challenge/response method (i.e. Password bit is 1). */ - calc_lanman_hash(ses->password, ses->server->cryptkey, + rc = calc_lanman_hash(ses->password, ses->server->cryptkey, ses->server->secMode & SECMODE_PW_ENCRYPT ? true : false, lnm_session_key); diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c deleted file mode 100644 index 04721485925d..000000000000 --- a/fs/cifs/smbdes.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - - a partial implementation of DES designed for use in the - SMB authentication protocol - - Copyright (C) Andrew Tridgell 1998 - Modified by Steve French (sfrench@us.ibm.com) 2002,2004 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* NOTES: - - This code makes no attempt to be fast! In fact, it is a very - slow implementation - - This code is NOT a complete DES implementation. It implements only - the minimum necessary for SMB authentication, as used by all SMB - products (including every copy of Microsoft Windows95 ever sold) - - In particular, it can only do a unchained forward DES pass. This - means it is not possible to use this code for encryption/decryption - of data, instead it is only useful as a "hash" algorithm. - - There is no entry point into this code that allows normal DES operation. - - I believe this means that this code does not come under ITAR - regulations but this is NOT a legal opinion. If you are concerned - about the applicability of ITAR regulations to this code then you - should confirm it for yourself (and maybe let me know if you come - up with a different answer to the one above) -*/ -#include -#define uchar unsigned char - -static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9, - 1, 58, 50, 42, 34, 26, 18, - 10, 2, 59, 51, 43, 35, 27, - 19, 11, 3, 60, 52, 44, 36, - 63, 55, 47, 39, 31, 23, 15, - 7, 62, 54, 46, 38, 30, 22, - 14, 6, 61, 53, 45, 37, 29, - 21, 13, 5, 28, 20, 12, 4 -}; - -static uchar perm2[48] = { 14, 17, 11, 24, 1, 5, - 3, 28, 15, 6, 21, 10, - 23, 19, 12, 4, 26, 8, - 16, 7, 27, 20, 13, 2, - 41, 52, 31, 37, 47, 55, - 30, 40, 51, 45, 33, 48, - 44, 49, 39, 56, 34, 53, - 46, 42, 50, 36, 29, 32 -}; - -static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2, - 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6, - 64, 56, 48, 40, 32, 24, 16, 8, - 57, 49, 41, 33, 25, 17, 9, 1, - 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, - 63, 55, 47, 39, 31, 23, 15, 7 -}; - -static uchar perm4[48] = { 32, 1, 2, 3, 4, 5, - 4, 5, 6, 7, 8, 9, - 8, 9, 10, 11, 12, 13, - 12, 13, 14, 15, 16, 17, - 16, 17, 18, 19, 20, 21, - 20, 21, 22, 23, 24, 25, - 24, 25, 26, 27, 28, 29, - 28, 29, 30, 31, 32, 1 -}; - -static uchar perm5[32] = { 16, 7, 20, 21, - 29, 12, 28, 17, - 1, 15, 23, 26, - 5, 18, 31, 10, - 2, 8, 24, 14, - 32, 27, 3, 9, - 19, 13, 30, 6, - 22, 11, 4, 25 -}; - -static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32, - 39, 7, 47, 15, 55, 23, 63, 31, - 38, 6, 46, 14, 54, 22, 62, 30, - 37, 5, 45, 13, 53, 21, 61, 29, - 36, 4, 44, 12, 52, 20, 60, 28, - 35, 3, 43, 11, 51, 19, 59, 27, - 34, 2, 42, 10, 50, 18, 58, 26, - 33, 1, 41, 9, 49, 17, 57, 25 -}; - -static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; - -static uchar sbox[8][4][16] = { - {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, - {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, - {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, - {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13} }, - - {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, - {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, - {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, - {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9} }, - - {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, - {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, - {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, - {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12} }, - - {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, - {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, - {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, - {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14} }, - - {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, - {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, - {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, - {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3} }, - - {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, - {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, - {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, - {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13} }, - - {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, - {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, - {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, - {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12} }, - - {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, - {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, - {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, - {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11} } -}; - -static void -permute(char *out, char *in, uchar *p, int n) -{ - int i; - for (i = 0; i < n; i++) - out[i] = in[p[i] - 1]; -} - -static void -lshift(char *d, int count, int n) -{ - char out[64]; - int i; - for (i = 0; i < n; i++) - out[i] = d[(i + count) % n]; - for (i = 0; i < n; i++) - d[i] = out[i]; -} - -static void -concat(char *out, char *in1, char *in2, int l1, int l2) -{ - while (l1--) - *out++ = *in1++; - while (l2--) - *out++ = *in2++; -} - -static void -xor(char *out, char *in1, char *in2, int n) -{ - int i; - for (i = 0; i < n; i++) - out[i] = in1[i] ^ in2[i]; -} - -static void -dohash(char *out, char *in, char *key, int forw) -{ - int i, j, k; - char *pk1; - char c[28]; - char d[28]; - char *cd; - char (*ki)[48]; - char *pd1; - char l[32], r[32]; - char *rl; - - /* Have to reduce stack usage */ - pk1 = kmalloc(56+56+64+64, GFP_KERNEL); - 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; - - permute(pk1, key, perm1, 56); - - for (i = 0; i < 28; i++) - c[i] = pk1[i]; - for (i = 0; i < 28; i++) - d[i] = pk1[i + 28]; - - for (i = 0; i < 16; i++) { - lshift(c, sc[i], 28); - lshift(d, sc[i], 28); - - concat(cd, c, d, 28, 28); - permute(ki[i], cd, perm2, 48); - } - - permute(pd1, in, perm3, 64); - - for (j = 0; j < 32; j++) { - l[j] = pd1[j]; - r[j] = pd1[j + 32]; - } - - for (i = 0; i < 16; i++) { - char *er; /* er[48] */ - char *erk; /* erk[48] */ - char b[8][6]; - char *cb; /* cb[32] */ - char *pcb; /* pcb[32] */ - char *r2; /* r2[32] */ - - er = kmalloc(48+48+32+32+32, GFP_KERNEL); - if (er == NULL) { - kfree(pk1); - kfree(ki); - return; - } - erk = er+48; - cb = erk+48; - pcb = cb+32; - r2 = pcb+32; - - permute(er, r, perm4, 48); - - xor(erk, er, ki[forw ? i : 15 - i], 48); - - for (j = 0; j < 8; j++) - for (k = 0; k < 6; k++) - b[j][k] = erk[j * 6 + k]; - - for (j = 0; j < 8; j++) { - int m, n; - m = (b[j][0] << 1) | b[j][5]; - - n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << - 1) | b[j][4]; - - for (k = 0; k < 4; k++) - b[j][k] = - (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0; - } - - for (j = 0; j < 8; j++) - for (k = 0; k < 4; k++) - cb[j * 4 + k] = b[j][k]; - permute(pcb, cb, perm5, 32); - - xor(r2, l, pcb, 32); - - for (j = 0; j < 32; j++) - l[j] = r[j]; - - for (j = 0; j < 32; j++) - r[j] = r2[j]; - - kfree(er); - } - - concat(rl, r, l, 32, 32); - - permute(out, rl, perm6, 64); - kfree(pk1); - kfree(ki); -} - -static void -str_to_key(unsigned char *str, unsigned char *key) -{ - int i; - - key[0] = str[0] >> 1; - key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); - key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); - key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); - key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); - key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); - key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); - key[7] = str[6] & 0x7F; - for (i = 0; i < 8; i++) - key[i] = (key[i] << 1); -} - -static void -smbhash(unsigned char *out, const unsigned char *in, unsigned char *key, - int forw) -{ - int i; - char *outb; /* outb[64] */ - char *inb; /* inb[64] */ - char *keyb; /* keyb[64] */ - unsigned char key2[8]; - - outb = kmalloc(64 * 3, GFP_KERNEL); - if (outb == NULL) - return; - - inb = outb + 64; - keyb = inb + 64; - - str_to_key(key, key2); - - for (i = 0; i < 64; i++) { - inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; - keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; - outb[i] = 0; - } - - dohash(outb, inb, keyb, forw); - - for (i = 0; i < 8; i++) - out[i] = 0; - - for (i = 0; i < 64; i++) { - if (outb[i]) - out[i / 8] |= (1 << (7 - (i % 8))); - } - kfree(outb); -} - -void -E_P16(unsigned char *p14, unsigned char *p16) -{ - unsigned char sp8[8] = - { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; - smbhash(p16, sp8, p14, 1); - smbhash(p16 + 8, sp8, p14 + 7, 1); -} - -void -E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) -{ - smbhash(p24, c8, p21, 1); - smbhash(p24 + 8, c8, p21 + 7, 1); - smbhash(p24 + 16, c8, p21 + 14, 1); -} - -#if 0 /* currently unused */ -static void -D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) -{ - smbhash(out, in, p14, 0); - smbhash(out + 8, in + 8, p14 + 7, 0); -} - -static void -E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) -{ - smbhash(out, in, p14, 1); - smbhash(out + 8, in + 8, p14 + 7, 1); -} -/* these routines are currently unneeded, but may be - needed later */ -void -cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key) -{ - unsigned char buf[8]; - - smbhash(buf, in, key, 1); - smbhash(out, buf, key + 9, 1); -} - -void -cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key) -{ - unsigned char buf[8]; - static unsigned char key2[8]; - - smbhash(buf, in, key, 1); - key2[0] = key[7]; - smbhash(out, buf, key2, 1); -} - -void -cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, int forw) -{ - static unsigned char key2[8]; - - smbhash(out, in, key, forw); - key2[0] = key[7]; - smbhash(out + 8, in + 8, key2, forw); -} -#endif /* unneeded routines */ diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index b5041c849981..1525d5e662b6 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -47,6 +47,88 @@ #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) +static void +str_to_key(unsigned char *str, unsigned char *key) +{ + int i; + + key[0] = str[0] >> 1; + key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); + key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); + key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); + key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); + key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); + key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); + key[7] = str[6] & 0x7F; + for (i = 0; i < 8; i++) + key[i] = (key[i] << 1); +} + +static int +smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) +{ + int rc; + unsigned char key2[8]; + struct crypto_blkcipher *tfm_des; + struct scatterlist sgin, sgout; + struct blkcipher_desc desc; + + str_to_key(key, key2); + + tfm_des = crypto_alloc_blkcipher("ecb(des)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm_des)) { + rc = PTR_ERR(tfm_des); + cERROR(1, "could not allocate des crypto API\n"); + goto smbhash_err; + } + + desc.tfm = tfm_des; + + crypto_blkcipher_setkey(tfm_des, key2, 8); + + sg_init_one(&sgin, in, 8); + sg_init_one(&sgout, out, 8); + + rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, 8); + if (rc) { + cERROR(1, "could not encrypt crypt key rc: %d\n", rc); + crypto_free_blkcipher(tfm_des); + goto smbhash_err; + } + +smbhash_err: + return rc; +} + +static int +E_P16(unsigned char *p14, unsigned char *p16) +{ + int rc; + unsigned char sp8[8] = + { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; + + rc = smbhash(p16, sp8, p14); + if (rc) + return rc; + rc = smbhash(p16 + 8, sp8, p14 + 7); + return rc; +} + +static int +E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) +{ + int rc; + + rc = smbhash(p24, c8, p21); + if (rc) + return rc; + rc = smbhash(p24 + 8, c8, p21 + 7); + if (rc) + return rc; + rc = smbhash(p24 + 16, c8, p21 + 14); + return rc; +} + /* produce a md4 message digest from data of length n bytes */ int mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) @@ -87,40 +169,30 @@ mdfour_err: return rc; } -/* Does the des encryption from the NT or LM MD4 hash. */ -static void -SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8, - unsigned char p24[24]) -{ - unsigned char p21[21]; - - memset(p21, '\0', 21); - - memcpy(p21, passwd, 16); - E_P24(p21, c8, p24); -} - /* This implements the X/Open SMB password encryption It takes a password, a 8 byte "crypt key" and puts 24 bytes of encrypted password into p24 */ /* Note that password must be uppercased and null terminated */ -void +int SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) { - unsigned char p14[15], p21[21]; + int rc; + unsigned char p14[14], p16[16], p21[21]; - memset(p21, '\0', 21); memset(p14, '\0', 14); - strncpy((char *) p14, (char *) passwd, 14); + memset(p16, '\0', 16); + memset(p21, '\0', 21); -/* strupper((char *)p14); *//* BB at least uppercase the easy range */ - E_P16(p14, p21); + memcpy(p14, passwd, 14); + rc = E_P16(p14, p16); + if (rc) + return rc; - SMBOWFencrypt(p21, c8, p24); + memcpy(p21, p16, 16); + rc = E_P24(p21, c8, p24); - memset(p14, 0, 15); - memset(p21, 0, 21); + return rc; } /* Routines for Windows NT MD4 Hash functions. */ @@ -279,16 +351,18 @@ int SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) { int rc; - unsigned char p21[21]; + unsigned char p16[16], p21[21]; + memset(p16, '\0', 16); memset(p21, '\0', 21); - rc = E_md4hash(passwd, p21); + rc = E_md4hash(passwd, p16); if (rc) { cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc); return rc; } - SMBOWFencrypt(p21, c8, p24); + memcpy(p21, p16, 16); + rc = E_P24(p21, c8, p24); return rc; } -- cgit v1.2.3-59-g8ed1b From b73b9a4ba753dfd7d304ee6ee4685b827524c533 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 19 Apr 2011 18:27:10 +0000 Subject: [CIFS] Allow to set extended attribute cifs_acl (try #2) Allow setting cifs_acl on the server. Pass on to the server the ACL blob generated by an application. cifs is just a pass-through, it does not monitor or inspect the contents of the blob, server decides whether to enforce/apply the ACL blob composed by an application. If setting of ACL is succeessful, mark the inode for revalidation. Signed-off-by: Shirish Pargaonkar Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 2 +- fs/cifs/cifsproto.h | 2 ++ fs/cifs/xattr.c | 20 ++++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index beeebf194234..a0d11eab14e5 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -688,7 +688,7 @@ out: } /* Set an ACL on the server */ -static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, +int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, struct inode *inode, const char *path) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e94526949677..0e4e057e2891 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -143,6 +143,8 @@ extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, extern int mode_to_cifs_acl(struct inode *inode, const char *path, __u64); extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, const char *, u32 *); +extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, + const char *); extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, const char *); diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index eae2a1491608..912995e013ec 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -112,6 +112,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, struct cifsTconInfo *pTcon; struct super_block *sb; char *full_path; + struct cifs_ntsd *pacl; if (direntry == NULL) return -EIO; @@ -166,6 +167,25 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, (__u16)value_size, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, + strlen(CIFS_XATTR_CIFS_ACL)) == 0) { + pacl = kmalloc(value_size, GFP_KERNEL); + if (!pacl) { + cFYI(1, "%s: Can't allocate memory for ACL", + __func__); + rc = -ENOMEM; + } else { +#ifdef CONFIG_CIFS_ACL + memcpy(pacl, ea_value, value_size); + rc = set_cifs_acl(pacl, value_size, + direntry->d_inode, full_path); + if (rc == 0) /* force revalidate of the inode */ + CIFS_I(direntry->d_inode)->time = 0; + kfree(pacl); +#else + cFYI(1, "Set CIFS ACL not supported yet"); +#endif /* CONFIG_CIFS_ACL */ + } } else { int temp; temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, -- cgit v1.2.3-59-g8ed1b From 4358b5678b27ffe81391d84ce150df8e81010f6a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 29 Mar 2011 09:33:31 -0400 Subject: VFS: trivial: fix comment on s_maxbytes value warning check I originally intended to remove this warning in 2.6.34, but it's not in a high performance codepath and might help us to catch bugs later. Let's keep it, but fix the comment to allay confusion about its removal. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/super.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/super.c b/fs/super.c index 8a06881b1920..c04f7e0b7ed2 100644 --- a/fs/super.c +++ b/fs/super.c @@ -948,8 +948,7 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data) * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE * but s_maxbytes was an unsigned long long for many releases. Throw * this warning for a little while to try and catch filesystems that - * violate this rule. This warning should be either removed or - * converted to a BUG() in 2.6.34. + * violate this rule. */ WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to " "negative value (%lld)\n", type->name, sb->s_maxbytes); -- cgit v1.2.3-59-g8ed1b From fd5707e1b44560d18b47d552c1871ea0bfc46688 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 31 Mar 2011 17:22:07 -0400 Subject: cifs: fix comment in validate_t2 The comment about checking the bcc is in the wrong place. Also make it match kernel coding style. Reported-and-acked-by: David Howells Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index e6374dda3c6a..64dad47641a1 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -339,12 +339,13 @@ static int validate_t2(struct smb_t2_rsp *pSMB) get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024) goto vt2_err; - /* check that bcc is at least as big as parms + data */ - /* check that bcc is less than negotiated smb buffer */ total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount); if (total_size >= 512) goto vt2_err; + /* check that bcc is at least as big as parms + data, and that it is + * less than negotiated smb buffer + */ total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount); if (total_size > get_bcc(&pSMB->hdr) || total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) -- cgit v1.2.3-59-g8ed1b From 257fb1f15d72f89dad2d72fa467c189f2d7fdd71 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Wed, 16 Mar 2011 01:55:32 +0300 Subject: CIFS: Use invalidate_inode_pages2 instead of invalidate_remote_inode (try #4) Use invalidate_inode_pages2 that don't leave pages even if shrink_page_list() has a temp ref on them. It prevents a data coherency problem when cifs_invalidate_mapping didn't invalidate pages but the client thinks that a data from the cache is uptodate according to an oplock level (exclusive or II). Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/inode.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 196ef6078029..fbe7d5858563 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1691,12 +1691,18 @@ cifs_invalidate_mapping(struct inode *inode) cifs_i->invalid_mapping = false; - /* write back any cached data */ if (inode->i_mapping && inode->i_mapping->nrpages != 0) { + /* write back any cached data */ rc = filemap_write_and_wait(inode->i_mapping); mapping_set_error(inode->i_mapping, rc); + rc = invalidate_inode_pages2(inode->i_mapping); + if (rc) { + cERROR(1, "%s: could not invalidate inode %p", __func__, + inode); + cifs_i->invalid_mapping = true; + } } - invalidate_remote_inode(inode); + cifs_fscache_reset_inode_cookie(inode); } -- cgit v1.2.3-59-g8ed1b From 1cb06d0b50536af177b2f2f7cab25546f3731d3e Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 24 Feb 2011 18:07:19 +0000 Subject: Introduce smb2 mounts as vers=2 As with Linux nfs client, which uses "nfsvers=" or "vers=" to indicate which protocol to use for mount, specifying "vers=smb2" or "vers=2" will force an smb2 mount. When vers is not specified cifs is used ie "vers=cifs" or "vers=1" We can eventually autonegotiate down from smb2 to cifs when smb2 is stable enough to make it the default, but this is for the future. At that time we could also implement a "maxprotocol" mount option as smbclient and Samba have today, but that would be premature until smb2 is stable. Intially the smb2 Kconfig option will depend on "BROKEN" until the merge is complete, and then be "EXPERIMENTAL" When it is no longer experimental we can consider changing the default protocol to attempt first. Reviewed-by: Jeff Layton Reviewed-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/connect.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8d72acbd5c13..acd1e3c887e1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -102,6 +102,7 @@ struct smb_vol { bool fsc:1; /* enable fscache */ bool mfsymlinks:1; /* use Minshall+French Symlinks */ bool multiuser:1; + bool use_smb2:1; /* force smb2 use on mount instead of cifs */ unsigned int rsize; unsigned int wsize; bool sockopt_tcp_nodelay:1; @@ -1038,6 +1039,22 @@ cifs_parse_mount_options(char *options, const char *devname, cERROR(1, "bad security option: %s", value); return 1; } + } else if (strnicmp(data, "vers", 3) == 0) { + if (!value || !*value) { + cERROR(1, "no protocol version specified" + " after vers= mount option"); + } else if ((strnicmp(value, "cifs", 4) == 0) || + (strnicmp(value, "1", 1) == 0)) { + /* this is the default */ + continue; + } else if ((strnicmp(value, "smb2", 4) == 0) || + (strnicmp(value, "2", 1) == 0)) { +#ifdef CONFIG_CIFS_SMB2 + vol->use_smb2 = true; +#else + cERROR(1, "smb2 support not enabled"); +#endif /* CONFIG_CIFS_SMB2 */ + } } else if ((strnicmp(data, "unc", 3) == 0) || (strnicmp(data, "target", 6) == 0) || (strnicmp(data, "path", 4) == 0)) { -- cgit v1.2.3-59-g8ed1b From 9ad1506b42c828dff0b9d8f3914e1f837734e91c Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Fri, 8 Apr 2011 05:29:10 +0400 Subject: CIFS: Add launder_page operation (try #3) Add this let us drop filemap_write_and_wait from cifs_invalidate_mapping and simplify the code to properly process invalidate logic. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/file.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index faf59529e847..00b466e667ab 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1420,9 +1420,10 @@ retry_write: return rc; } -static int cifs_writepage(struct page *page, struct writeback_control *wbc) +static int +cifs_writepage_locked(struct page *page, struct writeback_control *wbc) { - int rc = -EFAULT; + int rc; int xid; xid = GetXid(); @@ -1442,15 +1443,29 @@ static int cifs_writepage(struct page *page, struct writeback_control *wbc) * to fail to update with the state of the page correctly. */ set_page_writeback(page); +retry_write: rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE); - SetPageUptodate(page); /* BB add check for error and Clearuptodate? */ - unlock_page(page); + if (rc == -EAGAIN && wbc->sync_mode == WB_SYNC_ALL) + goto retry_write; + else if (rc == -EAGAIN) + redirty_page_for_writepage(wbc, page); + else if (rc != 0) + SetPageError(page); + else + SetPageUptodate(page); end_page_writeback(page); page_cache_release(page); FreeXid(xid); return rc; } +static int cifs_writepage(struct page *page, struct writeback_control *wbc) +{ + int rc = cifs_writepage_locked(page, wbc); + unlock_page(page); + return rc; +} + static int cifs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) @@ -2415,6 +2430,27 @@ static void cifs_invalidate_page(struct page *page, unsigned long offset) cifs_fscache_invalidate_page(page, &cifsi->vfs_inode); } +static int cifs_launder_page(struct page *page) +{ + int rc = 0; + loff_t range_start = page_offset(page); + loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 0, + .range_start = range_start, + .range_end = range_end, + }; + + cFYI(1, "Launder page: %p", page); + + if (clear_page_dirty_for_io(page)) + rc = cifs_writepage_locked(page, &wbc); + + cifs_fscache_invalidate_page(page, page->mapping->host); + return rc; +} + void cifs_oplock_break(struct work_struct *work) { struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, @@ -2486,7 +2522,7 @@ const struct address_space_operations cifs_addr_ops = { .set_page_dirty = __set_page_dirty_nobuffers, .releasepage = cifs_release_page, .invalidatepage = cifs_invalidate_page, - /* .direct_IO = */ + .launder_page = cifs_launder_page, }; /* @@ -2503,5 +2539,5 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { .set_page_dirty = __set_page_dirty_nobuffers, .releasepage = cifs_release_page, .invalidatepage = cifs_invalidate_page, - /* .direct_IO = */ + .launder_page = cifs_launder_page, }; -- cgit v1.2.3-59-g8ed1b From 4d79dba0e00749fa40de8ef13a9b85ce57a1603b Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Wed, 27 Apr 2011 23:34:35 -0500 Subject: cifs: Add idmap key and related data structures and functions (try #17 repost) Define (global) data structures to store ids, uids and gids, to which a SID maps. There are two separate trees, one for SID/uid and another one for SID/gid. A new type of key, cifs_idmap_key_type, is used. Keys are instantiated and searched using credential of the root by overriding and restoring the credentials of the caller requesting the key. Id mapping functions are invoked under config option of cifs acl. Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/cifsfs.c | 29 ++++++++--- fs/cifs/cifsglob.h | 5 ++ fs/cifs/cifsproto.h | 3 ++ 4 files changed, 167 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index a0d11eab14e5..061fc3afd841 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -23,6 +23,10 @@ #include #include +#include +#include +#include +#include #include "cifspdu.h" #include "cifsglob.h" #include "cifsacl.h" @@ -50,6 +54,140 @@ static const struct cifs_sid sid_authusers = { /* group users */ static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; +static const struct cred *root_cred; + +/* + * Run idmap cache shrinker. + */ +static int +cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) +{ + /* Use a pruning scheme in a subsequent patch instead */ + cifs_destroy_idmaptrees(); + return 0; +} + +static struct shrinker cifs_shrinker = { + .shrink = cifs_idmap_shrinker, + .seeks = DEFAULT_SEEKS, +}; + +static int +cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen) +{ + char *payload; + + payload = kmalloc(datalen, GFP_KERNEL); + if (!payload) + return -ENOMEM; + + memcpy(payload, data, datalen); + key->payload.data = payload; + return 0; +} + +static inline void +cifs_idmap_key_destroy(struct key *key) +{ + kfree(key->payload.data); +} + +static +struct key_type cifs_idmap_key_type = { + .name = "cifs.cifs_idmap", + .instantiate = cifs_idmap_key_instantiate, + .destroy = cifs_idmap_key_destroy, + .describe = user_describe, + .match = user_match, +}; + +int +init_cifs_idmap(void) +{ + struct cred *cred; + struct key *keyring; + int ret; + + cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name); + + /* create an override credential set with a special thread keyring in + * which requests are cached + * + * this is used to prevent malicious redirections from being installed + * with add_key(). + */ + cred = prepare_kernel_cred(NULL); + if (!cred) + return -ENOMEM; + + keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred, + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ, + KEY_ALLOC_NOT_IN_QUOTA); + if (IS_ERR(keyring)) { + ret = PTR_ERR(keyring); + goto failed_put_cred; + } + + ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); + if (ret < 0) + goto failed_put_key; + + ret = register_key_type(&cifs_idmap_key_type); + if (ret < 0) + goto failed_put_key; + + /* instruct request_key() to use this special keyring as a cache for + * the results it looks up */ + cred->thread_keyring = keyring; + cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; + root_cred = cred; + + spin_lock_init(&siduidlock); + uidtree = RB_ROOT; + spin_lock_init(&sidgidlock); + gidtree = RB_ROOT; + + register_shrinker(&cifs_shrinker); + + cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring)); + return 0; + +failed_put_key: + key_put(keyring); +failed_put_cred: + put_cred(cred); + return ret; +} + +void +exit_cifs_idmap(void) +{ + key_revoke(root_cred->thread_keyring); + unregister_key_type(&cifs_idmap_key_type); + put_cred(root_cred); + unregister_shrinker(&cifs_shrinker); + cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name); +} + +void +cifs_destroy_idmaptrees(void) +{ + struct rb_root *root; + struct rb_node *node; + + root = &uidtree; + spin_lock(&siduidlock); + while ((node = rb_first(root))) + rb_erase(node, root); + spin_unlock(&siduidlock); + + root = &gidtree; + spin_lock(&sidgidlock); + while ((node = rb_first(root))) + rb_erase(node, root); + spin_unlock(&sidgidlock); +} int match_sid(struct cifs_sid *ctsid) { diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 30fc505b7ef1..6c1d738418f1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1033,22 +1033,31 @@ init_cifs(void) if (rc) goto out_destroy_mids; - rc = register_filesystem(&cifs_fs_type); - if (rc) - goto out_destroy_request_bufs; #ifdef CONFIG_CIFS_UPCALL rc = register_key_type(&cifs_spnego_key_type); if (rc) - goto out_unregister_filesystem; -#endif + goto out_destroy_request_bufs; +#endif /* CONFIG_CIFS_UPCALL */ + +#ifdef CONFIG_CIFS_ACL + rc = init_cifs_idmap(); + if (rc) + goto out_destroy_request_bufs; +#endif /* CONFIG_CIFS_ACL */ + + rc = register_filesystem(&cifs_fs_type); + if (rc) + goto out_destroy_request_bufs; return 0; +out_destroy_request_bufs: +#ifdef CONFIG_CIFS_ACL + exit_cifs_idmap(); +#endif #ifdef CONFIG_CIFS_UPCALL -out_unregister_filesystem: - unregister_filesystem(&cifs_fs_type); + unregister_key_type(&cifs_spnego_key_type); #endif -out_destroy_request_bufs: cifs_destroy_request_bufs(); out_destroy_mids: cifs_destroy_mids(); @@ -1070,6 +1079,10 @@ exit_cifs(void) #ifdef CONFIG_CIFS_DFS_UPCALL cifs_dfs_release_automount_timer(); #endif +#ifdef CONFIG_CIFS_ACL + cifs_destroy_idmaptrees(); + exit_cifs_idmap(); +#endif #ifdef CONFIG_CIFS_UPCALL unregister_key_type(&cifs_spnego_key_type); #endif diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 108a1e99aa9f..76b4517e74b0 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -833,6 +833,11 @@ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ /* reconnect after this many failed echo attempts */ GLOBAL_EXTERN unsigned short echo_retries; +GLOBAL_EXTERN struct rb_root uidtree; +GLOBAL_EXTERN struct rb_root gidtree; +GLOBAL_EXTERN spinlock_t siduidlock; +GLOBAL_EXTERN spinlock_t sidgidlock; + void cifs_oplock_break(struct work_struct *work); void cifs_oplock_break_get(struct cifsFileInfo *cfile); void cifs_oplock_break_put(struct cifsFileInfo *cfile); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0e4e057e2891..7c1ed01d03f8 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -53,6 +53,9 @@ do { \ cFYI(1, "CIFS VFS: leaving %s (xid = %d) rc = %d", \ __func__, curr_xid, (int)rc); \ } while (0) +extern int init_cifs_idmap(void); +extern void exit_cifs_idmap(void); +extern void cifs_destroy_idmaptrees(void); extern char *build_path_from_dentry(struct dentry *); extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, struct cifsTconInfo *tcon); -- cgit v1.2.3-59-g8ed1b From 9409ae58e0759d010b347e7b19ebc90ab5d4b98f Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Fri, 22 Apr 2011 12:09:36 -0500 Subject: cifs: Invoke id mapping functions (try #17 repost) rb tree search and insertion routines. A SID which needs to be mapped, is looked up in one of the rb trees depending on whether SID is either owner or group SID. If found in the tree, a (mapped) id from that node is assigned to uid or gid as appropriate. If unmapped, an upcall is attempted to map the SID to an id. If upcall is successful, node is marked as mapped. If upcall fails, node stays marked as unmapped and a mapping is attempted again only after an arbitrary time period has passed. To map a SID, which can be either a Owner SID or a Group SID, key description starts with the string "os" or "gs" followed by SID converted to a string. Without "os" or "gs", cifs.upcall does not know whether SID needs to be mapped to either an uid or a gid. Nodes in rb tree have fields to prevent multiple upcalls for a SID. Searching, adding, and removing nodes is done within global locks. Whenever a node is either found or inserted in a tree, a reference is taken on that node. Shrinker routine prunes a node if it has expired but does not prune an expired node if its refcount is not zero (i.e. sid/id of that node is_being/will_be accessed). Thus a node, if its SID needs to be mapped by making an upcall, can safely stay and its fields accessed without shrinker pruning it. A reference (refcount) is put on the node without holding the spinlock but a reference is get on the node by holding the spinlock. Every time an existing mapped node is accessed or mapping is attempted, its timestamp is updated to prevent it from getting erased or a to prevent multiple unnecessary repeat mapping retries respectively. For now, cifs.upcall is only used to map a SID to an id (uid or gid) but it would be used to obtain an SID for an id. Signed-off-by: Shirish Pargaonkar Reviewed-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 325 ++++++++++++++++++++++++++++++++++++++++++++++++++---- fs/cifs/cifsacl.h | 24 ++++ 2 files changed, 325 insertions(+), 24 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 061fc3afd841..a4aa0f0af5c3 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -54,7 +54,33 @@ static const struct cifs_sid sid_authusers = { /* group users */ static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; -static const struct cred *root_cred; +const struct cred *root_cred; + +static void +shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem, + int *nr_del) +{ + struct rb_node *node; + struct rb_node *tmp; + struct cifs_sid_id *psidid; + + node = rb_first(root); + while (node) { + tmp = node; + node = rb_next(tmp); + psidid = rb_entry(tmp, struct cifs_sid_id, rbnode); + if (nr_to_scan == 0 || *nr_del == nr_to_scan) + ++(*nr_rem); + else { + if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE) + && psidid->refcount == 0) { + rb_erase(tmp, root); + ++(*nr_del); + } else + ++(*nr_rem); + } + } +} /* * Run idmap cache shrinker. @@ -62,9 +88,21 @@ static const struct cred *root_cred; static int cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) { - /* Use a pruning scheme in a subsequent patch instead */ - cifs_destroy_idmaptrees(); - return 0; + int nr_del = 0; + int nr_rem = 0; + struct rb_root *root; + + root = &uidtree; + spin_lock(&siduidlock); + shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); + spin_unlock(&siduidlock); + + root = &gidtree; + spin_lock(&sidgidlock); + shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); + spin_unlock(&sidgidlock); + + return nr_rem; } static struct shrinker cifs_shrinker = { @@ -92,7 +130,6 @@ cifs_idmap_key_destroy(struct key *key) kfree(key->payload.data); } -static struct key_type cifs_idmap_key_type = { .name = "cifs.cifs_idmap", .instantiate = cifs_idmap_key_instantiate, @@ -101,6 +138,220 @@ struct key_type cifs_idmap_key_type = { .match = user_match, }; +static void +sid_to_str(struct cifs_sid *sidptr, char *sidstr) +{ + int i; + unsigned long saval; + char *strptr; + + strptr = sidstr; + + sprintf(strptr, "%s", "S"); + strptr = sidstr + strlen(sidstr); + + sprintf(strptr, "-%d", sidptr->revision); + strptr = sidstr + strlen(sidstr); + + for (i = 0; i < 6; ++i) { + if (sidptr->authority[i]) { + sprintf(strptr, "-%d", sidptr->authority[i]); + strptr = sidstr + strlen(sidstr); + } + } + + for (i = 0; i < sidptr->num_subauth; ++i) { + saval = le32_to_cpu(sidptr->sub_auth[i]); + sprintf(strptr, "-%ld", saval); + strptr = sidstr + strlen(sidstr); + } +} + +static void +id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr, + struct cifs_sid_id **psidid, char *typestr) +{ + int rc; + char *strptr; + struct rb_node *node = root->rb_node; + struct rb_node *parent = NULL; + struct rb_node **linkto = &(root->rb_node); + struct cifs_sid_id *lsidid; + + while (node) { + lsidid = rb_entry(node, struct cifs_sid_id, rbnode); + parent = node; + rc = compare_sids(sidptr, &((lsidid)->sid)); + if (rc > 0) { + linkto = &(node->rb_left); + node = node->rb_left; + } else if (rc < 0) { + linkto = &(node->rb_right); + node = node->rb_right; + } + } + + memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid)); + (*psidid)->time = jiffies - (SID_MAP_RETRY + 1); + (*psidid)->refcount = 0; + + sprintf((*psidid)->sidstr, "%s", typestr); + strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr); + sid_to_str(&(*psidid)->sid, strptr); + + clear_bit(SID_ID_PENDING, &(*psidid)->state); + clear_bit(SID_ID_MAPPED, &(*psidid)->state); + + rb_link_node(&(*psidid)->rbnode, parent, linkto); + rb_insert_color(&(*psidid)->rbnode, root); +} + +static struct cifs_sid_id * +id_rb_search(struct rb_root *root, struct cifs_sid *sidptr) +{ + int rc; + struct rb_node *node = root->rb_node; + struct rb_node *parent = NULL; + struct rb_node **linkto = &(root->rb_node); + struct cifs_sid_id *lsidid; + + while (node) { + lsidid = rb_entry(node, struct cifs_sid_id, rbnode); + parent = node; + rc = compare_sids(sidptr, &((lsidid)->sid)); + if (rc > 0) { + linkto = &(node->rb_left); + node = node->rb_left; + } else if (rc < 0) { + linkto = &(node->rb_right); + node = node->rb_right; + } else /* node found */ + return lsidid; + } + + return NULL; +} + +static int +sidid_pending_wait(void *unused) +{ + schedule(); + return signal_pending(current) ? -ERESTARTSYS : 0; +} + +static int +sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, + struct cifs_fattr *fattr, uint sidtype) +{ + int rc; + unsigned long cid; + struct key *idkey; + const struct cred *saved_cred; + struct cifs_sid_id *psidid, *npsidid; + struct rb_root *cidtree; + spinlock_t *cidlock; + + if (sidtype == SIDOWNER) { + cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */ + cidlock = &siduidlock; + cidtree = &uidtree; + } else if (sidtype == SIDGROUP) { + cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */ + cidlock = &sidgidlock; + cidtree = &gidtree; + } else + return -ENOENT; + + spin_lock(cidlock); + psidid = id_rb_search(cidtree, psid); + + if (!psidid) { /* node does not exist, allocate one & attempt adding */ + spin_unlock(cidlock); + npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL); + if (!npsidid) + return -ENOMEM; + + npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL); + if (!npsidid->sidstr) { + kfree(npsidid); + return -ENOMEM; + } + + spin_lock(cidlock); + psidid = id_rb_search(cidtree, psid); + if (psidid) { /* node happened to get inserted meanwhile */ + ++psidid->refcount; + spin_unlock(cidlock); + kfree(npsidid->sidstr); + kfree(npsidid); + } else { + psidid = npsidid; + id_rb_insert(cidtree, psid, &psidid, + sidtype == SIDOWNER ? "os:" : "gs:"); + ++psidid->refcount; + spin_unlock(cidlock); + } + } else { + ++psidid->refcount; + spin_unlock(cidlock); + } + + /* + * If we are here, it is safe to access psidid and its fields + * since a reference was taken earlier while holding the spinlock. + * A reference on the node is put without holding the spinlock + * and it is OK to do so in this case, shrinker will not erase + * this node until all references are put and we do not access + * any fields of the node after a reference is put . + */ + if (test_bit(SID_ID_MAPPED, &psidid->state)) { + cid = psidid->id; + psidid->time = jiffies; /* update ts for accessing */ + goto sid_to_id_out; + } + + if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) + goto sid_to_id_out; + + if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) { + saved_cred = override_creds(root_cred); + idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, ""); + if (IS_ERR(idkey)) + cFYI(1, "%s: Can't map SID to an id", __func__); + else { + cid = *(unsigned long *)idkey->payload.value; + psidid->id = cid; + set_bit(SID_ID_MAPPED, &psidid->state); + key_put(idkey); + kfree(psidid->sidstr); + } + revert_creds(saved_cred); + psidid->time = jiffies; /* update ts for accessing */ + clear_bit(SID_ID_PENDING, &psidid->state); + wake_up_bit(&psidid->state, SID_ID_PENDING); + } else { + rc = wait_on_bit(&psidid->state, SID_ID_PENDING, + sidid_pending_wait, TASK_INTERRUPTIBLE); + if (rc) { + cFYI(1, "%s: sidid_pending_wait interrupted %d", + __func__, rc); + --psidid->refcount; /* decremented without spinlock */ + return rc; + } + if (test_bit(SID_ID_MAPPED, &psidid->state)) + cid = psidid->id; + } + +sid_to_id_out: + --psidid->refcount; /* decremented without spinlock */ + if (sidtype == SIDOWNER) + fattr->cf_uid = cid; + else + fattr->cf_gid = cid; + + return 0; +} + int init_cifs_idmap(void) { @@ -242,16 +493,24 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) int num_subauth, num_sat, num_saw; if ((!ctsid) || (!cwsid)) - return 0; + return 1; /* compare the revision */ - if (ctsid->revision != cwsid->revision) - return 0; + if (ctsid->revision != cwsid->revision) { + if (ctsid->revision > cwsid->revision) + return 1; + else + return -1; + } /* compare all of the six auth values */ for (i = 0; i < 6; ++i) { - if (ctsid->authority[i] != cwsid->authority[i]) - return 0; + if (ctsid->authority[i] != cwsid->authority[i]) { + if (ctsid->authority[i] > cwsid->authority[i]) + return 1; + else + return -1; + } } /* compare all of the subauth values if any */ @@ -260,12 +519,16 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) num_subauth = num_sat < num_saw ? num_sat : num_saw; if (num_subauth) { for (i = 0; i < num_subauth; ++i) { - if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) - return 0; + if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { + if (ctsid->sub_auth[i] > cwsid->sub_auth[i]) + return 1; + else + return -1; + } } } - return 1; /* sids compare/match */ + return 0; /* sids compare/match */ } @@ -520,22 +783,22 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, #ifdef CONFIG_CIFS_DEBUG2 dump_ace(ppace[i], end_of_acl); #endif - if (compare_sids(&(ppace[i]->sid), pownersid)) + if (compare_sids(&(ppace[i]->sid), pownersid) == 0) access_flags_to_mode(ppace[i]->access_req, ppace[i]->type, &fattr->cf_mode, &user_mask); - if (compare_sids(&(ppace[i]->sid), pgrpsid)) + if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0) access_flags_to_mode(ppace[i]->access_req, ppace[i]->type, &fattr->cf_mode, &group_mask); - if (compare_sids(&(ppace[i]->sid), &sid_everyone)) + if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0) access_flags_to_mode(ppace[i]->access_req, ppace[i]->type, &fattr->cf_mode, &other_mask); - if (compare_sids(&(ppace[i]->sid), &sid_authusers)) + if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0) access_flags_to_mode(ppace[i]->access_req, ppace[i]->type, &fattr->cf_mode, @@ -613,10 +876,10 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) /* Convert CIFS ACL to POSIX form */ -static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, - struct cifs_fattr *fattr) +static int parse_sec_desc(struct cifs_sb_info *cifs_sb, + struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr) { - int rc; + int rc = 0; struct cifs_sid *owner_sid_ptr, *group_sid_ptr; struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ char *end_of_acl = ((char *)pntsd) + acl_len; @@ -638,12 +901,26 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, le32_to_cpu(pntsd->sacloffset), dacloffset); /* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */ rc = parse_sid(owner_sid_ptr, end_of_acl); - if (rc) + if (rc) { + cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc); return rc; + } + rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER); + if (rc) { + cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc); + return rc; + } rc = parse_sid(group_sid_ptr, end_of_acl); - if (rc) + if (rc) { + cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc); return rc; + } + rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP); + if (rc) { + cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc); + return rc; + } if (dacloffset) parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, @@ -658,7 +935,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, sizeof(struct cifs_sid)); */ - return 0; + return rc; } @@ -865,7 +1142,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, rc = PTR_ERR(pntsd); cERROR(1, "%s: error %d getting sec desc", __func__, rc); } else { - rc = parse_sec_desc(pntsd, acllen, fattr); + rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr); kfree(pntsd); if (rc) cERROR(1, "parse sec desc failed rc = %d", rc); diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index c4ae7d036563..757cf5aec3ee 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -39,6 +39,15 @@ #define ACCESS_ALLOWED 0 #define ACCESS_DENIED 1 +#define SIDOWNER 1 +#define SIDGROUP 2 +#define SIDLEN 150 /* S- 1 revision- 6 authorities- max 5 sub authorities */ + +#define SID_ID_MAPPED 0 +#define SID_ID_PENDING 1 +#define SID_MAP_EXPIRE (3600 * HZ) /* map entry expires after one hour */ +#define SID_MAP_RETRY (300 * HZ) /* wait 5 minutes for next attempt to map */ + struct cifs_ntsd { __le16 revision; /* revision level */ __le16 type; @@ -74,6 +83,21 @@ struct cifs_wksid { char sidname[SIDNAMELENGTH]; } __attribute__((packed)); +struct cifs_sid_id { + unsigned int refcount; /* increment with spinlock, decrement without */ + unsigned long id; + unsigned long time; + unsigned long state; + char *sidstr; + struct rb_node rbnode; + struct cifs_sid sid; +}; + +#ifdef __KERNEL__ +extern struct key_type cifs_idmap_key_type; +extern const struct cred *root_cred; +#endif /* KERNEL */ + extern int match_sid(struct cifs_sid *); extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *); -- cgit v1.2.3-59-g8ed1b From be8e3b0044a68e1f1002c432f6b40d290cf0701d Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 29 Apr 2011 05:40:20 +0000 Subject: consistently use smb_buf_length as be32 for cifs (try 3) There is one big endian field in the cifs protocol, the RFC1001 length, which cifs code (unlike in the smb2 code) had been handling as u32 until the last possible moment, when it was converted to be32 (its native form) before sending on the wire. To remove the last sparse endian warning, and to make this consistent with the smb2 implementation (which always treats the fields in their native size and endianness), convert all uses of smb_buf_length to be32. This version incorporates Christoph's comment about using be32_add_cpu, and fixes a typo in the second version of the patch. Signed-off-by: Steve French Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 2 +- fs/cifs/cifspdu.h | 6 +-- fs/cifs/cifssmb.c | 123 ++++++++++++++++++++++++++------------------------ fs/cifs/connect.c | 12 ++--- fs/cifs/misc.c | 8 ++-- fs/cifs/sess.c | 5 +- fs/cifs/transport.c | 47 +++++++++---------- 7 files changed, 102 insertions(+), 101 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index e7c59314894f..45c3f78c8f81 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -60,7 +60,7 @@ static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, server->session_key.response, server->session_key.len); crypto_shash_update(&server->secmech.sdescmd5->shash, - cifs_pdu->Protocol, cifs_pdu->smb_buf_length); + cifs_pdu->Protocol, be32_to_cpu(cifs_pdu->smb_buf_length)); rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index b5c8cc5d7a7f..eac95e26d696 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -397,9 +397,9 @@ #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ struct smb_hdr { - __u32 smb_buf_length; /* big endian on wire *//* BB length is only two - or three bytes - with one or two byte type preceding it that are - zero - we could mask the type byte off just in case BB */ + __be32 smb_buf_length; /* BB length is only two (rarely three) bytes, + with one or two byte "type" preceding it that will be + zero - we could mask the type byte off */ __u8 Protocol[4]; __u8 Command; union { diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 64dad47641a1..88004094ebd1 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -358,6 +358,13 @@ vt2_err: return -EINVAL; } +static inline void inc_rfc1001_len(void *pSMB, int count) +{ + struct smb_hdr *hdr = (struct smb_hdr *)pSMB; + + be32_add_cpu(&hdr->smb_buf_length, count); +} + int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) { @@ -410,7 +417,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) count += strlen(protocols[i].name) + 1; /* null at end of source and target buffers anyway */ } - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, @@ -731,7 +738,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server) put_unaligned_le16(1, &smb->EchoCount); put_bcc_le(1, &smb->hdr); smb->Data[0] = 'a'; - smb->hdr.smb_buf_length += 3; + inc_rfc1001_len(smb, 3); rc = cifs_call_async(server, (struct smb_hdr *)smb, cifs_echo_callback, server); @@ -849,7 +856,7 @@ PsxDelete: pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -895,7 +902,7 @@ DelFileRetry: pSMB->SearchAttributes = cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -939,7 +946,7 @@ RmDirRetry: } pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -982,7 +989,7 @@ MkDirRetry: } pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -1060,7 +1067,7 @@ PsxCreat: pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -1225,7 +1232,7 @@ OldOpenRetry: pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); count += name_len; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); /* long_op set to 1 to allow for oplock break timeouts */ @@ -1338,7 +1345,7 @@ openRetry: SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY; count += name_len; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); /* long_op set to 1 to allow for oplock break timeouts */ @@ -1423,7 +1430,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, } iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, &resp_buf_type, CIFS_LOG_ERROR); cifs_stats_inc(&tcon->num_reads); @@ -1557,7 +1564,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); if (wct == 14) pSMB->ByteCount = cpu_to_le16(byte_count); @@ -1641,11 +1648,12 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); pSMB->DataLengthHigh = cpu_to_le16(count >> 16); - smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ + /* header + 1 byte pad */ + smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1; if (wct == 14) - pSMB->hdr.smb_buf_length += count+1; + inc_rfc1001_len(pSMB, count + 1); else /* wct == 12 */ - pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ + inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */ if (wct == 14) pSMB->ByteCount = cpu_to_le16(count + 1); else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ { @@ -1745,7 +1753,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, /* oplock break */ count = 0; } - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); if (waitFlag) { @@ -1836,14 +1844,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, pSMB->Fid = smb_file_id; pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); if (waitFlag) { rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned); } else { iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, &resp_buf_type, timeout); pSMB = NULL; /* request buf already freed by SendReceive2. Do @@ -2009,7 +2017,7 @@ renameRetry: } count = 1 /* 1st signature byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -2089,7 +2097,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -2156,7 +2164,7 @@ copyRetry: } count = 1 /* 1st signature byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -2246,7 +2254,7 @@ createSymLinkRetry: pSMB->DataOffset = cpu_to_le16(offset); pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -2332,7 +2340,7 @@ createHardLinkRetry: pSMB->DataOffset = cpu_to_le16(offset); pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -2403,7 +2411,7 @@ winCreateHardLinkRetry: } count = 1 /* string type byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -2474,7 +2482,7 @@ querySymLinkRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -2821,7 +2829,7 @@ queryAclRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -2915,7 +2923,7 @@ setAclRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -2973,7 +2981,7 @@ GetExtAttrRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS); pSMB->Pad = 0; pSMB->Fid = netfid; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->t2.ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -3131,9 +3139,9 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP | CIFS_ACL_DACL); pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */ - pSMB->hdr.smb_buf_length += 11; + inc_rfc1001_len(pSMB, 11); iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0); @@ -3242,10 +3250,9 @@ setCifsAclRetry: memcpy((char *) &pSMBr->hdr.Protocol + data_offset, (char *) pntsd, acllen); - pSMB->hdr.smb_buf_length += (byte_count + data_count); - + inc_rfc1001_len(pSMB, byte_count + data_count); } else - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -3296,7 +3303,7 @@ QInfRetry: } pSMB->BufferFormat = 0x04; name_len++; /* account for buffer type byte */ - pSMB->hdr.smb_buf_length += (__u16) name_len; + inc_rfc1001_len(pSMB, (__u16)name_len); pSMB->ByteCount = cpu_to_le16(name_len); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -3371,7 +3378,7 @@ QFileInfoRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); pSMB->Pad = 0; pSMB->Fid = netfid; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -3458,7 +3465,7 @@ QPathInfoRetry: else pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -3539,7 +3546,7 @@ UnixQFileInfoRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pSMB->Pad = 0; pSMB->Fid = netfid; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -3624,7 +3631,7 @@ UnixQPathInfoRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -3738,7 +3745,7 @@ findFirstRetry: /* BB what should we set StorageType to? Does it matter? BB */ pSMB->SearchStorageType = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -3867,7 +3874,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, byte_count = params + 1 /* pad */ ; pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4029,7 +4036,7 @@ GetInodeNumberRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4253,7 +4260,7 @@ getDFSRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->MaxReferralLevel = cpu_to_le16(3); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, @@ -4327,7 +4334,7 @@ oldQFSInfoRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4406,7 +4413,7 @@ QFSInfoRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4486,7 +4493,7 @@ QFSAttributeRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4557,7 +4564,7 @@ QFSDeviceRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4626,7 +4633,7 @@ QFSUnixRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4709,7 +4716,7 @@ SETFSUnixRetry: pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); pSMB->ClientUnixCap = cpu_to_le64(cap); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4771,7 +4778,7 @@ QFSPosixRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4897,7 +4904,7 @@ SetEOFRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); parm_data->FileSize = cpu_to_le64(size); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4976,7 +4983,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); } pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); if (rc) { @@ -5044,7 +5051,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, else pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); @@ -5103,7 +5110,7 @@ CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon, pSMB->Fid = fid; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); *data_offset = delete_file ? 1 : 0; rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); @@ -5176,7 +5183,7 @@ SetTimesRetry: else pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -5228,7 +5235,7 @@ SetAttrLgcyRetry: } pSMB->attr = cpu_to_le16(dos_attrs); pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -5333,7 +5340,7 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, pSMB->Fid = fid; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); cifs_fill_unix_set_info(data_offset, args); @@ -5409,7 +5416,7 @@ setPermsRetry: pSMB->TotalDataCount = pSMB->DataCount; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); cifs_fill_unix_set_info(data_offset, args); @@ -5494,7 +5501,7 @@ QAllEAsRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -5707,7 +5714,7 @@ SetEARetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index acd1e3c887e1..5d331cdd0b27 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -324,12 +324,12 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) return -EPROTO; put_bcc_le(byte_count, pTargetSMB); - byte_count = pTargetSMB->smb_buf_length; + byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); byte_count += total_in_buf2; /* don't allow buffer to overflow */ if (byte_count > CIFSMaxBufSize) return -ENOBUFS; - pTargetSMB->smb_buf_length = byte_count; + pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); @@ -496,8 +496,7 @@ incomplete_rcv: /* Note that FC 1001 length is big endian on the wire, but we convert it here so it is always manipulated as host byte order */ - pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length); - smb_buffer->smb_buf_length = pdu_length; + pdu_length = be32_to_cpu(smb_buffer->smb_buf_length); cFYI(1, "rfc1002 length 0x%x", pdu_length+4); @@ -2297,7 +2296,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) smb_buf = (struct smb_hdr *)ses_init_buf; /* sizeof RFC1002_SESSION_REQUEST with no scope */ - smb_buf->smb_buf_length = 0x81000044; + smb_buf->smb_buf_length = cpu_to_be32(0x81000044); rc = smb_send(server, smb_buf, 0x44); kfree(ses_init_buf); /* @@ -3100,7 +3099,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr += strlen("?????"); bcc_ptr += 1; count = bcc_ptr - &pSMB->Password[0]; - pSMB->hdr.smb_buf_length += count; + pSMB->hdr.smb_buf_length = cpu_to_be32(be32_to_cpu( + pSMB->hdr.smb_buf_length) + count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 0c684ae4c071..533f863067e5 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -304,12 +304,10 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */ - buffer->smb_buf_length = + buffer->smb_buf_length = cpu_to_be32( (2 * word_count) + sizeof(struct smb_hdr) - 4 /* RFC 1001 length field does not count */ + - 2 /* for bcc field itself */ ; - /* Note that this is the only network field that has to be converted - to big endian and it is done just before we send it */ + 2 /* for bcc field itself */) ; buffer->Protocol[0] = 0xFF; buffer->Protocol[1] = 'S'; @@ -424,7 +422,7 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid) int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) { - __u32 len = smb->smb_buf_length; + __u32 len = be32_to_cpu(smb->smb_buf_length); __u32 clc_len; /* calculated length */ cFYI(0, "checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len); diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index b6ff84af81a4..1daadade4d3c 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -621,7 +621,7 @@ ssetup_ntlmssp_authenticate: and rest of bcc area. This allows us to avoid a large buffer 17K allocation */ iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = smb_buf->smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(smb_buf->smb_buf_length) + 4; /* setting this here allows the code at the end of the function to free the request buffer if there's an error */ @@ -859,7 +859,8 @@ ssetup_ntlmssp_authenticate: iov[2].iov_len = (long) bcc_ptr - (long) str_area; count = iov[1].iov_len + iov[2].iov_len; - smb_buf->smb_buf_length += count; + smb_buf->smb_buf_length = + cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count); put_bcc_le(count, smb_buf); diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 46d8756f2b24..19df0e5af122 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -129,7 +129,7 @@ smb_sendv(struct TCP_Server_Info *server, 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; + unsigned int smb_buf_length = be32_to_cpu(smb_buffer->smb_buf_length); struct socket *ssocket = server->ssocket; if (ssocket == NULL) @@ -144,17 +144,10 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) else smb_msg.msg_flags = MSG_NOSIGNAL; - /* smb header is converted in header_assemble. bcc and rest of SMB word - area, and byte area if necessary, is converted to littleendian in - cifssmb.c and RFC1001 len is converted to bigendian in smb_send - Flags2 is converted in SendReceive */ - - total_len = 0; for (i = 0; i < n_vec; i++) total_len += iov[i].iov_len; - smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); cFYI(1, "Sending smb: total_len %d", total_len); dump_smb(smb_buffer, len); @@ -243,7 +236,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) /* Don't want to modify the buffer as a side effect of this call. */ - smb_buffer->smb_buf_length = smb_buf_length; + smb_buffer->smb_buf_length = cpu_to_be32(smb_buf_length); return rc; } @@ -387,7 +380,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf, #ifdef CONFIG_CIFS_STATS2 atomic_inc(&server->inSend); #endif - rc = smb_send(server, in_buf, in_buf->smb_buf_length); + rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&server->inSend); mid->when_sent = jiffies; @@ -422,7 +415,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, int resp_buf_type; iov[0].iov_base = (char *)in_buf; - iov[0].iov_len = in_buf->smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(in_buf->smb_buf_length) + 4; flags |= CIFS_NO_RESP; rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags); cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc); @@ -488,7 +481,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, int rc = 0; /* -4 for RFC1001 length and +2 for BCC field */ - in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4 + 2; + in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2); in_buf->Command = SMB_COM_NT_CANCEL; in_buf->WordCount = 0; put_bcc_le(0, in_buf); @@ -499,7 +492,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, mutex_unlock(&server->srv_mutex); return rc; } - rc = smb_send(server, in_buf, in_buf->smb_buf_length); + rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); mutex_unlock(&server->srv_mutex); cFYI(1, "issued NT_CANCEL for mid %u, rc = %d", @@ -612,7 +605,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, return rc; } - receive_len = midQ->resp_buf->smb_buf_length; + receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, "Frame too large received. Length: %d Xid: %d", @@ -698,9 +691,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, to the same server. We may make this configurable later or use ses->maxReq */ - if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { + if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize + + MAX_CIFS_HDR_SIZE - 4) { cERROR(1, "Illegal length, greater than maximum frame, %d", - in_buf->smb_buf_length); + be32_to_cpu(in_buf->smb_buf_length)); return -EIO; } @@ -733,7 +727,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif - rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); + rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; @@ -768,7 +762,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, return rc; } - receive_len = midQ->resp_buf->smb_buf_length; + receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, "Frame too large received. Length: %d Xid: %d", @@ -781,7 +775,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, if (midQ->resp_buf && out_buf && (midQ->midState == MID_RESPONSE_RECEIVED)) { - out_buf->smb_buf_length = receive_len; + out_buf->smb_buf_length = cpu_to_be32(receive_len); memcpy((char *)out_buf + 4, (char *)midQ->resp_buf + 4, receive_len); @@ -800,7 +794,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, } } - *pbytes_returned = out_buf->smb_buf_length; + *pbytes_returned = be32_to_cpu(out_buf->smb_buf_length); /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); @@ -877,9 +871,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, to the same server. We may make this configurable later or use ses->maxReq */ - if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { + if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize + + MAX_CIFS_HDR_SIZE - 4) { cERROR(1, "Illegal length, greater than maximum frame, %d", - in_buf->smb_buf_length); + be32_to_cpu(in_buf->smb_buf_length)); return -EIO; } @@ -910,7 +905,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif - rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); + rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; @@ -977,7 +972,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, if (rc != 0) return rc; - receive_len = midQ->resp_buf->smb_buf_length; + receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, "Frame too large received. Length: %d Xid: %d", receive_len, xid); @@ -993,7 +988,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, goto out; } - out_buf->smb_buf_length = receive_len; + out_buf->smb_buf_length = cpu_to_be32(receive_len); memcpy((char *)out_buf + 4, (char *)midQ->resp_buf + 4, receive_len); @@ -1012,7 +1007,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, } } - *pbytes_returned = out_buf->smb_buf_length; + *pbytes_returned = be32_to_cpu(out_buf->smb_buf_length); /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); -- cgit v1.2.3-59-g8ed1b From 0b81c1c405c063f3ecea66c2f5e9c3aefc5359c8 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 10 Mar 2011 10:11:05 +0300 Subject: CIFS: directio read/write cleanups Recently introduced strictcache mode brought a new code that can be efficiently used by directio part. That's let us add vectored operations and break unnecessary cifs_user_read and cifs_user_write. Signed-off-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 18 +++++----- fs/cifs/cifsfs.h | 8 ++--- fs/cifs/file.c | 103 ++----------------------------------------------------- 3 files changed, 16 insertions(+), 113 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 6c1d738418f1..f736d8a2e771 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -760,10 +760,11 @@ const struct file_operations cifs_file_strict_ops = { }; const struct file_operations cifs_file_direct_ops = { - /* no aio, no readv - - BB reevaluate whether they can be done with directio, no cache */ - .read = cifs_user_read, - .write = cifs_user_write, + /* BB reevaluate whether they can be done with directio, no cache */ + .read = do_sync_read, + .write = do_sync_write, + .aio_read = cifs_user_readv, + .aio_write = cifs_user_writev, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, @@ -815,10 +816,11 @@ const struct file_operations cifs_file_strict_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, - .write = cifs_user_write, + /* BB reevaluate whether they can be done with directio, no cache */ + .read = do_sync_read, + .write = do_sync_write, + .aio_read = cifs_user_readv, + .aio_write = cifs_user_writev, .open = cifs_open, .release = cifs_close, .fsync = cifs_fsync, diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 371d021815b1..bb64313fd750 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -80,12 +80,12 @@ extern const struct file_operations cifs_file_strict_nobrl_ops; 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); -extern ssize_t cifs_user_read(struct file *file, char __user *read_data, - size_t read_size, loff_t *poffset); +extern ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos); extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); -extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, - size_t write_size, loff_t *poffset); +extern ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos); extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); extern int cifs_lock(struct file *, int, struct file_lock *); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 00b466e667ab..0aeaaf7bf153 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -857,95 +857,6 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, cifsi->server_eof = end_of_write; } -ssize_t cifs_user_write(struct file *file, const char __user *write_data, - size_t write_size, loff_t *poffset) -{ - struct inode *inode = file->f_path.dentry->d_inode; - int rc = 0; - unsigned int bytes_written = 0; - unsigned int total_written; - struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; - int xid; - struct cifsFileInfo *open_file; - struct cifsInodeInfo *cifsi = CIFS_I(inode); - - cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - - /* cFYI(1, " write %d bytes to offset %lld of %s", write_size, - *poffset, file->f_path.dentry->d_name.name); */ - - if (file->private_data == NULL) - return -EBADF; - - open_file = file->private_data; - pTcon = tlink_tcon(open_file->tlink); - - rc = generic_write_checks(file, poffset, &write_size, 0); - if (rc) - return rc; - - xid = GetXid(); - - for (total_written = 0; write_size > total_written; - total_written += bytes_written) { - rc = -EAGAIN; - while (rc == -EAGAIN) { - if (file->private_data == NULL) { - /* file has been closed on us */ - FreeXid(xid); - /* if we have gotten here we have written some data - and blocked, and the file has been freed on us while - we blocked so return what we managed to write */ - return total_written; - } - if (open_file->invalidHandle) { - /* we could deadlock if we called - filemap_fdatawait from here so tell - reopen_file not to flush data to server - now */ - rc = cifs_reopen_file(open_file, false); - if (rc != 0) - break; - } - - rc = CIFSSMBWrite(xid, pTcon, - open_file->netfid, - min_t(const int, cifs_sb->wsize, - write_size - total_written), - *poffset, &bytes_written, - NULL, write_data + total_written, 0); - } - if (rc || (bytes_written == 0)) { - if (total_written) - break; - else { - FreeXid(xid); - return rc; - } - } else { - cifs_update_eof(cifsi, *poffset, bytes_written); - *poffset += bytes_written; - } - } - - cifs_stats_bytes_written(pTcon, total_written); - -/* Do not update local mtime - server will set its actual value on write - * inode->i_ctime = inode->i_mtime = - * current_fs_time(inode->i_sb);*/ - if (total_written > 0) { - spin_lock(&inode->i_lock); - if (*poffset > inode->i_size) - i_size_write(inode, *poffset); - spin_unlock(&inode->i_lock); - } - mark_inode_dirty_sync(inode); - - FreeXid(xid); - return total_written; -} - static ssize_t cifs_write(struct cifsFileInfo *open_file, const char *write_data, size_t write_size, loff_t *poffset) @@ -1741,7 +1652,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, return total_written; } -static ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, +ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { ssize_t written; @@ -1864,17 +1775,7 @@ cifs_iovec_read(struct file *file, const struct iovec *iov, return total_read; } -ssize_t cifs_user_read(struct file *file, char __user *read_data, - size_t read_size, loff_t *poffset) -{ - struct iovec iov; - iov.iov_base = read_data; - iov.iov_len = read_size; - - return cifs_iovec_read(file, &iov, 1, poffset); -} - -static ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, +ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { ssize_t read; -- cgit v1.2.3-59-g8ed1b From 6feb9891da4f8b04ffca69c00eb56bb7c1b64dc4 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 7 Apr 2011 18:18:11 +0400 Subject: CIFS: Simplify invalidate part (try #5) Simplify many places when we call cifs_revalidate/invalidate to make it do what it exactly needs. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 33 +++++++++++----- fs/cifs/cifsfs.h | 4 +- fs/cifs/file.c | 16 ++++++-- fs/cifs/inode.c | 117 +++++++++++++++++++++++++++++++++++-------------------- 4 files changed, 113 insertions(+), 57 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f736d8a2e771..0f6a54f14eff 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -618,16 +618,29 @@ 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 == SEEK_END) { - 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 */ - CIFS_I(file->f_path.dentry->d_inode)->time = 0; - - retval = cifs_revalidate_file(file); - if (retval < 0) - return (loff_t)retval; + int rc; + struct inode *inode = file->f_path.dentry->d_inode; + + /* + * We need to be sure that all dirty pages are written and the + * server has the newest file length. + */ + if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && + inode->i_mapping->nrpages != 0) { + rc = filemap_fdatawait(inode->i_mapping); + mapping_set_error(inode->i_mapping, rc); + return rc; + } + /* + * 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. + */ + CIFS_I(inode)->time = 0; + + rc = cifs_revalidate_file_attr(file); + if (rc < 0) + return (loff_t)rc; } return generic_file_llseek_unlocked(file, offset, origin); } diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index bb64313fd750..d304584408d1 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -59,9 +59,11 @@ 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_file_attr(struct file *filp); +extern int cifs_revalidate_dentry_attr(struct dentry *); extern int cifs_revalidate_file(struct file *filp); extern int cifs_revalidate_dentry(struct dentry *); -extern void cifs_invalidate_mapping(struct inode *inode); +extern int cifs_invalidate_mapping(struct inode *inode); extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int cifs_setattr(struct dentry *, struct iattr *); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 0aeaaf7bf153..c672afef0c09 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1445,8 +1445,13 @@ int cifs_strict_fsync(struct file *file, int datasync) cFYI(1, "Sync file - name: %s datasync: 0x%x", file->f_path.dentry->d_name.name, datasync); - if (!CIFS_I(inode)->clientCanCacheRead) - cifs_invalidate_mapping(inode); + if (!CIFS_I(inode)->clientCanCacheRead) { + rc = cifs_invalidate_mapping(inode); + if (rc) { + cFYI(1, "rc: %d during invalidate phase", rc); + rc = 0; /* don't care about it in fsync */ + } + } tcon = tlink_tcon(smbfile->tlink); if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) @@ -1903,8 +1908,11 @@ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) xid = GetXid(); - if (!CIFS_I(inode)->clientCanCacheRead) - cifs_invalidate_mapping(inode); + if (!CIFS_I(inode)->clientCanCacheRead) { + rc = cifs_invalidate_mapping(inode); + if (rc) + return rc; + } rc = generic_file_mmap(file, vma); if (rc == 0) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index fbe7d5858563..0cc7eddb077f 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1683,18 +1683,15 @@ cifs_inode_needs_reval(struct inode *inode) /* * Zap the cache. Called when invalid_mapping flag is set. */ -void +int cifs_invalidate_mapping(struct inode *inode) { - int rc; + int rc = 0; struct cifsInodeInfo *cifs_i = CIFS_I(inode); cifs_i->invalid_mapping = false; if (inode->i_mapping && inode->i_mapping->nrpages != 0) { - /* write back any cached data */ - rc = filemap_write_and_wait(inode->i_mapping); - mapping_set_error(inode->i_mapping, rc); rc = invalidate_inode_pages2(inode->i_mapping); if (rc) { cERROR(1, "%s: could not invalidate inode %p", __func__, @@ -1704,56 +1701,52 @@ cifs_invalidate_mapping(struct inode *inode) } cifs_fscache_reset_inode_cookie(inode); + return rc; } -int cifs_revalidate_file(struct file *filp) +int cifs_revalidate_file_attr(struct file *filp) { int rc = 0; struct inode *inode = filp->f_path.dentry->d_inode; struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; if (!cifs_inode_needs_reval(inode)) - goto check_inval; + return rc; if (tlink_tcon(cfile->tlink)->unix_ext) rc = cifs_get_file_info_unix(filp); else rc = cifs_get_file_info(filp); -check_inval: - if (CIFS_I(inode)->invalid_mapping) - cifs_invalidate_mapping(inode); - return rc; } -/* revalidate a dentry's inode attributes */ -int cifs_revalidate_dentry(struct dentry *dentry) +int cifs_revalidate_dentry_attr(struct dentry *dentry) { int xid; int rc = 0; - char *full_path = NULL; struct inode *inode = dentry->d_inode; struct super_block *sb = dentry->d_sb; + char *full_path = NULL; if (inode == NULL) return -ENOENT; - xid = GetXid(); - if (!cifs_inode_needs_reval(inode)) - goto check_inval; + return rc; + + xid = GetXid(); /* can not safely grab the rename sem here if rename calls revalidate since that would deadlock */ full_path = build_path_from_dentry(dentry); if (full_path == NULL) { rc = -ENOMEM; - goto check_inval; + goto out; } - cFYI(1, "Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " - "jiffies %ld", full_path, inode, inode->i_count.counter, + cFYI(1, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time " + "%ld jiffies %ld", full_path, inode, inode->i_count.counter, dentry, dentry->d_time, jiffies); if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) @@ -1762,41 +1755,81 @@ int cifs_revalidate_dentry(struct dentry *dentry) rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid, NULL); -check_inval: - if (CIFS_I(inode)->invalid_mapping) - cifs_invalidate_mapping(inode); - +out: kfree(full_path); FreeXid(xid); return rc; } +int cifs_revalidate_file(struct file *filp) +{ + int rc; + struct inode *inode = filp->f_path.dentry->d_inode; + + rc = cifs_revalidate_file_attr(filp); + if (rc) + return rc; + + if (CIFS_I(inode)->invalid_mapping) + rc = cifs_invalidate_mapping(inode); + return rc; +} + +/* revalidate a dentry's inode attributes */ +int cifs_revalidate_dentry(struct dentry *dentry) +{ + int rc; + struct inode *inode = dentry->d_inode; + + rc = cifs_revalidate_dentry_attr(dentry); + if (rc) + return rc; + + if (CIFS_I(inode)->invalid_mapping) + rc = cifs_invalidate_mapping(inode); + return rc; +} + int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); - int err = cifs_revalidate_dentry(dentry); + struct inode *inode = dentry->d_inode; + int rc; - if (!err) { - generic_fillattr(dentry->d_inode, stat); - stat->blksize = CIFS_MAX_MSGSIZE; - stat->ino = CIFS_I(dentry->d_inode)->uniqueid; + /* + * We need to be sure that all dirty pages are written and the server + * has actual ctime, mtime and file length. + */ + if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && + inode->i_mapping->nrpages != 0) { + rc = filemap_fdatawait(inode->i_mapping); + mapping_set_error(inode->i_mapping, rc); + return rc; + } - /* - * If on a multiuser mount without unix extensions, and the - * admin hasn't overridden them, set the ownership to the - * fsuid/fsgid of the current process. - */ - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && - !tcon->unix_ext) { - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) - stat->uid = current_fsuid(); - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) - stat->gid = current_fsgid(); - } + rc = cifs_revalidate_dentry_attr(dentry); + if (rc) + return rc; + + generic_fillattr(inode, stat); + stat->blksize = CIFS_MAX_MSGSIZE; + stat->ino = CIFS_I(inode)->uniqueid; + + /* + * If on a multiuser mount without unix extensions, and the admin hasn't + * overridden them, set the ownership to the fsuid/fsgid of the current + * process. + */ + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && + !tcon->unix_ext) { + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) + stat->uid = current_fsuid(); + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) + stat->gid = current_fsgid(); } - return err; + return rc; } static int cifs_truncate_page(struct address_space *mapping, loff_t from) -- cgit v1.2.3-59-g8ed1b From 0e6e37a7a81f370d9aafafdf88aca13977f6fb5f Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 4 May 2011 08:08:19 -0400 Subject: cifs: fix some unused variable warnings in id_rb_search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fs/cifs/cifsacl.c: In function ‘id_rb_search’: fs/cifs/cifsacl.c:215:19: warning: variable ‘linkto’ set but not used [-Wunused-but-set-variable] fs/cifs/cifsacl.c:214:18: warning: variable ‘parent’ set but not used [-Wunused-but-set-variable] Reviewed-by: Shirish Pargaonkar Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index a4aa0f0af5c3..bfb5ba5a271b 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -211,19 +211,14 @@ id_rb_search(struct rb_root *root, struct cifs_sid *sidptr) { int rc; struct rb_node *node = root->rb_node; - struct rb_node *parent = NULL; - struct rb_node **linkto = &(root->rb_node); struct cifs_sid_id *lsidid; while (node) { lsidid = rb_entry(node, struct cifs_sid_id, rbnode); - parent = node; rc = compare_sids(sidptr, &((lsidid)->sid)); if (rc > 0) { - linkto = &(node->rb_left); node = node->rb_left; } else if (rc < 0) { - linkto = &(node->rb_right); node = node->rb_right; } else /* node found */ return lsidid; -- cgit v1.2.3-59-g8ed1b From 820a803ffac3ef591e597bc107f8e289a823a29c Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 4 May 2011 08:05:26 -0400 Subject: cifs: keep BCC in little-endian format This is the same patch as originally posted, just with some merge conflicts fixed up... Currently, the ByteCount is usually converted to host-endian on receive. This is confusing however, as we need to keep two sets of routines for accessing it, and keep track of when to use each routine. Munging received packets like this also limits when the signature can be calulated. Simplify the code by keeping the received ByteCount in little-endian format. This allows us to eliminate a set of routines for accessing it and we can now drop the *_le suffixes from the accessor functions since that's now implied. While we're at it, switch all of the places that read the ByteCount directly to use the get_bcc inline which should also clean up some unaligned accesses. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 2 +- fs/cifs/cifspdu.h | 22 ++----------------- fs/cifs/cifsproto.h | 1 - fs/cifs/cifssmb.c | 62 +++++++++++++++++++++++++++------------------------- fs/cifs/connect.c | 4 ++-- fs/cifs/misc.c | 4 ++-- fs/cifs/netmisc.c | 7 ------ fs/cifs/sess.c | 2 +- fs/cifs/transport.c | 19 +--------------- 9 files changed, 41 insertions(+), 82 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 30d01bc90855..18f4272d9047 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -63,7 +63,7 @@ void cifs_dump_detail(struct smb_hdr *smb) cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d", smb->Command, smb->Status.CifsError, smb->Flags, smb->Flags2, smb->Mid, smb->Pid); - cERROR(1, "smb buf %p len %d", smb, smbCalcSize_LE(smb)); + cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb)); } diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index eac95e26d696..291d735abaac 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -435,36 +435,18 @@ struct smb_hdr { /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ #define pByteArea(smb_var) (BCC(smb_var) + 2) -/* get the converted ByteCount for a SMB packet and return it */ -static inline __u16 -get_bcc(struct smb_hdr *hdr) -{ - __u16 *bc_ptr = (__u16 *)BCC(hdr); - - return get_unaligned(bc_ptr); -} - /* get the unconverted ByteCount for a SMB packet and return it */ static inline __u16 -get_bcc_le(struct smb_hdr *hdr) +get_bcc(struct smb_hdr *hdr) { __le16 *bc_ptr = (__le16 *)BCC(hdr); return get_unaligned_le16(bc_ptr); } -/* set the ByteCount for a SMB packet in host-byte order */ -static inline void -put_bcc(__u16 count, struct smb_hdr *hdr) -{ - __u16 *bc_ptr = (__u16 *)BCC(hdr); - - put_unaligned(count, bc_ptr); -} - /* set the ByteCount for a SMB packet in little-endian */ static inline void -put_bcc_le(__u16 count, struct smb_hdr *hdr) +put_bcc(__u16 count, struct smb_hdr *hdr) { __le16 *bc_ptr = (__le16 *)BCC(hdr); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7c1ed01d03f8..136d2f2febcc 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -93,7 +93,6 @@ extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); extern unsigned int smbCalcSize(struct smb_hdr *ptr); -extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, struct TCP_Server_Info *server); extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 88004094ebd1..83df937b814e 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -582,7 +582,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && (server->capabilities & CAP_EXTENDED_SECURITY)) { - count = pSMBr->ByteCount; + count = get_bcc(&pSMBr->hdr); if (count < 16) { rc = -EIO; goto neg_err_exit; @@ -736,7 +736,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server) smb->hdr.Tid = 0xffff; smb->hdr.WordCount = 1; put_unaligned_le16(1, &smb->EchoCount); - put_bcc_le(1, &smb->hdr); + put_bcc(1, &smb->hdr); smb->Data[0] = 'a'; inc_rfc1001_len(smb, 3); @@ -1079,7 +1079,7 @@ PsxCreat: cFYI(1, "copying inode info"); rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) { + if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) { rc = -EIO; /* bad smb */ goto psx_create_err; } @@ -1100,7 +1100,7 @@ PsxCreat: pRetData->Type = cpu_to_le32(-1); /* unknown */ cFYI(DBG2, "unknown type"); } else { - if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP) + if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP) + sizeof(FILE_UNIX_BASIC_INFO)) { cERROR(1, "Open response data too small"); pRetData->Type = cpu_to_le32(-1); @@ -1867,7 +1867,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, __u16 data_count; rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) { + if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) { rc = -EIO; /* bad smb */ goto plk_err_exit; } @@ -2494,7 +2494,7 @@ querySymLinkRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); /* BB also check enough total bytes returned */ - if (rc || (pSMBr->ByteCount < 2)) + if (rc || get_bcc(&pSMBr->hdr) < 2) rc = -EIO; else { bool is_unicode; @@ -2576,14 +2576,14 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, } else { /* decode response */ __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); __u32 data_count = le32_to_cpu(pSMBr->DataCount); - if ((pSMBr->ByteCount < 2) || (data_offset > 512)) { - /* BB also check enough total bytes returned */ + if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { + /* BB also check enough total bytes returned */ rc = -EIO; /* bad smb */ goto qreparse_out; } if (data_count && (data_count < 2048)) { char *end_of_smb = 2 /* sizeof byte count */ + - pSMBr->ByteCount + (char *)&pSMBr->ByteCount; + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; struct reparse_data *reparse_buf = (struct reparse_data *) @@ -2841,8 +2841,8 @@ queryAclRetry: /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 2)) /* BB also check enough total bytes returned */ + if (rc || get_bcc(&pSMBr->hdr) < 2) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -2991,8 +2991,8 @@ GetExtAttrRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 2)) /* BB also check enough total bytes returned */ + if (rc || get_bcc(&pSMBr->hdr) < 2) /* If rc should we check for EOPNOSUPP and disable the srvino flag? or in caller? */ rc = -EIO; /* bad smb */ @@ -3067,6 +3067,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, char *end_of_smb; __u32 data_count, data_offset, parm_count, parm_offset; struct smb_com_ntransact_rsp *pSMBr; + u16 bcc; *pdatalen = 0; *pparmlen = 0; @@ -3076,8 +3077,8 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, pSMBr = (struct smb_com_ntransact_rsp *)buf; - /* ByteCount was converted from little endian in SendReceive */ - end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + + bcc = get_bcc(&pSMBr->hdr); + end_of_smb = 2 /* sizeof byte count */ + bcc + (char *)&pSMBr->ByteCount; data_offset = le32_to_cpu(pSMBr->DataOffset); @@ -3103,7 +3104,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr); return -EINVAL; - } else if (parm_count + data_count > pSMBr->ByteCount) { + } else if (parm_count + data_count > bcc) { cFYI(1, "parm count and data count larger than SMB"); return -EINVAL; } @@ -3389,7 +3390,7 @@ QFileInfoRetry: if (rc) /* BB add auto retry on EOPNOTSUPP? */ rc = -EIO; - else if (pSMBr->ByteCount < 40) + else if (get_bcc(&pSMBr->hdr) < 40) rc = -EIO; /* bad smb */ else if (pFindData) { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -3477,9 +3478,9 @@ QPathInfoRetry: if (rc) /* BB add auto retry on EOPNOTSUPP? */ rc = -EIO; - else if (!legacy && (pSMBr->ByteCount < 40)) + else if (!legacy && get_bcc(&pSMBr->hdr) < 40) rc = -EIO; /* bad smb */ - else if (legacy && (pSMBr->ByteCount < 24)) + else if (legacy && get_bcc(&pSMBr->hdr) < 24) rc = -EIO; /* 24 or 26 expected but we do not read last field */ else if (pFindData) { @@ -3555,7 +3556,7 @@ UnixQFileInfoRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { + if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n" "Unix Extensions can be disabled on mount " "by specifying the nosfu mount option."); @@ -3641,7 +3642,7 @@ UnixQPathInfoRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { + if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n" "Unix Extensions can be disabled on mount " "by specifying the nosfu mount option."); @@ -4046,8 +4047,8 @@ GetInodeNumberRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 2)) /* BB also check enough total bytes returned */ + if (rc || get_bcc(&pSMBr->hdr) < 2) /* If rc should we check for EOPNOSUPP and disable the srvino flag? or in caller? */ rc = -EIO; /* bad smb */ @@ -4272,13 +4273,13 @@ getDFSRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); /* BB Also check if enough total bytes returned? */ - if (rc || (pSMBr->ByteCount < 17)) { + if (rc || get_bcc(&pSMBr->hdr) < 17) { rc = -EIO; /* bad smb */ goto GetDFSRefExit; } cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d", - pSMBr->ByteCount, + get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset)); /* parse returned result into more usable form */ @@ -4344,12 +4345,12 @@ oldQFSInfoRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 18)) + if (rc || get_bcc(&pSMBr->hdr) < 18) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); cFYI(1, "qfsinf resp BCC: %d Offset %d", - pSMBr->ByteCount, data_offset); + get_bcc(&pSMBr->hdr), data_offset); response_data = (FILE_SYSTEM_ALLOC_INFO *) (((char *) &pSMBr->hdr.Protocol) + data_offset); @@ -4423,7 +4424,7 @@ QFSInfoRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 24)) + if (rc || get_bcc(&pSMBr->hdr) < 24) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -4503,7 +4504,7 @@ QFSAttributeRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 13)) { + if (rc || get_bcc(&pSMBr->hdr) < 13) { /* BB also check if enough bytes returned */ rc = -EIO; /* bad smb */ } else { @@ -4574,7 +4575,8 @@ QFSDeviceRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO))) + if (rc || get_bcc(&pSMBr->hdr) < + sizeof(FILE_SYSTEM_DEVICE_INFO)) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -4643,7 +4645,7 @@ QFSUnixRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 13)) { + if (rc || get_bcc(&pSMBr->hdr) < 13) { rc = -EIO; /* bad smb */ } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -4788,7 +4790,7 @@ QFSPosixRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 13)) { + if (rc || get_bcc(&pSMBr->hdr) < 13) { rc = -EIO; /* bad smb */ } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -5517,7 +5519,7 @@ QAllEAsRetry: of these trans2 responses */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 4)) { + if (rc || get_bcc(&pSMBr->hdr) < 4) { rc = -EIO; /* bad smb */ goto QAllEAsOut; } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5d331cdd0b27..2b511991187a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -317,12 +317,12 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount); /* fix up the BCC */ - byte_count = get_bcc_le(pTargetSMB); + byte_count = get_bcc(pTargetSMB); byte_count += total_in_buf2; /* is the result too big for the field? */ if (byte_count > USHRT_MAX) return -EPROTO; - put_bcc_le(byte_count, pTargetSMB); + put_bcc(byte_count, pTargetSMB); byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); byte_count += total_in_buf2; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 533f863067e5..907531ac5888 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -462,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) if (check_smb_hdr(smb, mid)) return 1; - clc_len = smbCalcSize_LE(smb); + clc_len = smbCalcSize(smb); if (4 + len != length) { cERROR(1, "Length read does not match RFC1001 length %d", @@ -519,7 +519,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) (struct smb_com_transaction_change_notify_rsp *)buf; struct file_notify_information *pnotify; __u32 data_offset = 0; - if (get_bcc_le(buf) > sizeof(struct file_notify_information)) { + if (get_bcc(buf) > sizeof(struct file_notify_information)) { data_offset = le32_to_cpu(pSMBr->DataOffset); pnotify = (struct file_notify_information *) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 79f641eeda30..79b71c2c7c9d 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -919,13 +919,6 @@ smbCalcSize(struct smb_hdr *ptr) 2 /* size of the bcc field */ + get_bcc(ptr)); } -unsigned int -smbCalcSize_LE(struct smb_hdr *ptr) -{ - return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + - 2 /* size of the bcc field */ + get_bcc_le(ptr)); -} - /* The following are taken from fs/ntfs/util.c */ #define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000) diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 1daadade4d3c..7dd462100378 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -862,7 +862,7 @@ ssetup_ntlmssp_authenticate: smb_buf->smb_buf_length = cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count); - put_bcc_le(count, smb_buf); + put_bcc(count, smb_buf); rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, CIFS_LOG_ERROR); diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 19df0e5af122..f2513fb8c391 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -484,7 +484,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2); in_buf->Command = SMB_COM_NT_CANCEL; in_buf->WordCount = 0; - put_bcc_le(0, in_buf); + put_bcc(0, in_buf); mutex_lock(&server->srv_mutex); rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); @@ -644,11 +644,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, rc = map_smb_to_linux_error(midQ->resp_buf, flags & CIFS_LOG_ERROR); - /* convert ByteCount if necessary */ - if (receive_len >= sizeof(struct smb_hdr) - 4 - /* do not count RFC1001 header */ + - (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) - put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); if ((flags & CIFS_NO_RESP) == 0) midQ->resp_buf = NULL; /* mark it so buf will not be freed by @@ -798,12 +793,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); - - /* convert ByteCount if necessary */ - if (receive_len >= sizeof(struct smb_hdr) - 4 - /* do not count RFC1001 header */ + - (2 * out_buf->WordCount) + 2 /* bcc */ ) - put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); } else { rc = -EIO; cERROR(1, "Bad MID state?"); @@ -1012,12 +1001,6 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); - /* convert ByteCount if necessary */ - if (receive_len >= sizeof(struct smb_hdr) - 4 - /* do not count RFC1001 header */ + - (2 * out_buf->WordCount) + 2 /* bcc */ ) - put_bcc(get_bcc_le(out_buf), out_buf); - out: delete_mid(midQ); if (rstart && rc == -EACCES) -- cgit v1.2.3-59-g8ed1b From 460458ce8ec195a1902f0c742b76880fbd01dd96 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 31 Mar 2011 21:18:15 -0400 Subject: cifs: turn BCC into a static inlined function It's a bad idea to have macro functions that reference variables more than once, as the arguments could have side effects. Turn BCC() into a static inlined function instead. While we're at it, make it return a void * to discourage anyone from dereferencing it as-is. Reported-and-acked-by: David Howells Signed-off-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifspdu.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 291d735abaac..de3aa285de03 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -428,9 +428,12 @@ struct smb_hdr { __u8 WordCount; } __attribute__((packed)); -/* given a pointer to an smb_hdr retrieve a char pointer to the byte count */ -#define BCC(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + \ - (2 * (smb_var)->WordCount)) +/* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */ +static inline void * +BCC(struct smb_hdr *smb) +{ + return (void *)smb + sizeof(*smb) + 2 * smb->WordCount; +} /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ #define pByteArea(smb_var) (BCC(smb_var) + 2) -- cgit v1.2.3-59-g8ed1b From dd61394586dbd9387fe53b325c6807f61734cf89 Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:30 +0000 Subject: cifs: Extract DFS referral expansion logic to separate function The logic behind the expansion of DFS referrals is now extracted from cifs_mount into a new static function, expand_dfs_referral. This will reduce duplicate code in upcoming commits. Reviewed-by: Jeff Layton Signed-off-by: Sean Finney Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/connect.c | 105 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 36 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2b511991187a..b6c6a3629b07 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2745,6 +2745,57 @@ build_unc_path_to_root(const struct smb_vol *volume_info, full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */ return full_path; } + +/* + * Perform a dfs referral query for a share and (optionally) prefix + * + * If a referral is found, mount_data will be set to point at a newly + * allocated string containing updated options for the submount. + * Otherwise it will be left untouched. + * + * Returns the rc from get_dfs_path to the caller, which can be used to + * determine whether there were referrals. + */ +static int +expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo, + struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb, + char **mount_data, int check_prefix) +{ + int rc; + unsigned int num_referrals = 0; + struct dfs_info3_param *referrals = NULL; + char *full_path = NULL, *ref_path = NULL, *mdata = NULL; + + full_path = build_unc_path_to_root(volume_info, cifs_sb); + if (IS_ERR(full_path)) + return PTR_ERR(full_path); + + /* For DFS paths, skip the first '\' of the UNC */ + ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1; + + rc = get_dfs_path(xid, pSesInfo , ref_path, cifs_sb->local_nls, + &num_referrals, &referrals, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + + if (!rc && num_referrals > 0) { + char *fake_devname = NULL; + + mdata = cifs_compose_mount_options(cifs_sb->mountdata, + full_path + 1, referrals, + &fake_devname); + + free_dfs_info_array(referrals, num_referrals); + kfree(fake_devname); + + if (IS_ERR(mdata)) { + rc = PTR_ERR(mdata); + mdata = NULL; + } + *mount_data = mdata; + } + kfree(full_path); + return rc; +} #endif int @@ -2761,10 +2812,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, char *mount_data = mount_data_global; struct tcon_link *tlink; #ifdef CONFIG_CIFS_DFS_UPCALL - struct dfs_info3_param *referrals = NULL; - unsigned int num_referrals = 0; int referral_walks_count = 0; try_mount_again: + + /* cleanup activities if we're chasing a referral */ + if (referral_walks_count) { + if (tcon) + cifs_put_tcon(tcon); + else if (pSesInfo) + cifs_put_smb_ses(pSesInfo); + + cleanup_volume_info(&volume_info); + FreeXid(xid); + } #endif rc = 0; tcon = NULL; @@ -2910,46 +2970,19 @@ remote_path_check: if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb)); - full_path = build_unc_path_to_root(volume_info, cifs_sb); - if (IS_ERR(full_path)) { - rc = PTR_ERR(full_path); - goto mount_fail_check; - } - cFYI(1, "Getting referral for: %s", full_path); - rc = get_dfs_path(xid, pSesInfo , full_path + 1, - cifs_sb->local_nls, &num_referrals, &referrals, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - if (!rc && num_referrals > 0) { - char *fake_devname = NULL; - - if (mount_data != mount_data_global) - kfree(mount_data); - - mount_data = cifs_compose_mount_options( - cifs_sb->mountdata, full_path + 1, - referrals, &fake_devname); - - free_dfs_info_array(referrals, num_referrals); - kfree(fake_devname); - kfree(full_path); - - if (IS_ERR(mount_data)) { - rc = PTR_ERR(mount_data); - mount_data = NULL; - goto mount_fail_check; - } + if (mount_data != mount_data_global) + kfree(mount_data); - if (tcon) - cifs_put_tcon(tcon); - else if (pSesInfo) - cifs_put_smb_ses(pSesInfo); + rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb, + &mount_data, true); - cleanup_volume_info(&volume_info); + if (!rc) { referral_walks_count++; - FreeXid(xid); goto try_mount_again; } + mount_data = NULL; + goto mount_fail_check; #else /* No DFS support, return error on mount */ rc = -EOPNOTSUPP; #endif -- cgit v1.2.3-59-g8ed1b From c1508ca23653245266e2e3ab69a8dad464f7a569 Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:31 +0000 Subject: cifs: Add support for mounting Windows 2008 DFS shares Windows 2008 CIFS servers do not always return PATH_NOT_COVERED when attempting to access a DFS share. Therefore, when checking for remote shares, unconditionally ask for a DFS referral for the UNC (w/out prepath) before continuing with previous behavior of attempting to access the UNC + prepath and checking for PATH_NOT_COVERED. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=31092 Reviewed-by: Jeff Layton Signed-off-by: Sean Finney Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/connect.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index b6c6a3629b07..c7ebeee38c67 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2937,6 +2937,24 @@ try_mount_again: (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); remote_path_check: +#ifdef CONFIG_CIFS_DFS_UPCALL + /* + * Perform an unconditional check for whether there are DFS + * referrals for this path without prefix, to provide support + * for DFS referrals from w2k8 servers which don't seem to respond + * with PATH_NOT_COVERED to requests that include the prefix. + * Chase the referral if found, otherwise continue normally. + */ + if (referral_walks_count == 0) { + int refrc = expand_dfs_referral(xid, pSesInfo, volume_info, + cifs_sb, &mount_data, false); + if (!refrc) { + referral_walks_count++; + goto try_mount_again; + } + } +#endif + /* check if a whole path (including prepath) is not remote */ if (!rc && tcon) { /* build_path_to_root works only when we have a valid tcon */ -- cgit v1.2.3-59-g8ed1b From b946845a9dc523c759cae2b6a0f6827486c3221a Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:32 +0000 Subject: cifs: cifs_parse_mount_options: do not tokenize mount options in-place To keep strings passed to cifs_parse_mount_options re-usable (which is needed to clean up the DFS referral handling), tokenize a copy of the mount options instead. If values are needed from this tokenized string, they too must be duplicated (previously, some options were copied and others duplicated). Since we are not on the critical path and any cleanup is relatively easy, the extra memory usage shouldn't be a problem (and it is a bit simpler than trying to implement something smarter). Reviewed-by: Jeff Layton Signed-off-by: Sean Finney Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/connect.c | 109 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 35 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c7ebeee38c67..20c60ddaa5a1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -818,10 +818,11 @@ extract_hostname(const char *unc) } static int -cifs_parse_mount_options(char *options, const char *devname, +cifs_parse_mount_options(const char *mountdata, const char *devname, struct smb_vol *vol) { char *value, *data, *end; + char *mountdata_copy, *options; unsigned int temp_len, i, j; char separator[2]; short int override_uid = -1; @@ -861,9 +862,14 @@ cifs_parse_mount_options(char *options, const char *devname, vol->actimeo = CIFS_DEF_ACTIMEO; - if (!options) - return 1; + if (!mountdata) + goto cifs_parse_mount_err; + + mountdata_copy = kstrndup(mountdata, PAGE_SIZE, GFP_KERNEL); + if (!mountdata_copy) + goto cifs_parse_mount_err; + options = mountdata_copy; end = options + strlen(options); if (strncmp(options, "sep=", 4) == 0) { if (options[4] != 0) { @@ -889,17 +895,22 @@ cifs_parse_mount_options(char *options, const char *devname, if (!value) { printk(KERN_WARNING "CIFS: invalid or missing username\n"); - return 1; /* needs_arg; */ + goto cifs_parse_mount_err; } else if (!*value) { /* null user, ie anonymous, authentication */ vol->nullauth = 1; } if (strnlen(value, MAX_USERNAME_SIZE) < MAX_USERNAME_SIZE) { - vol->username = value; + vol->username = kstrdup(value, GFP_KERNEL); + if (!vol->username) { + printk(KERN_WARNING "CIFS: no memory " + "for username\n"); + goto cifs_parse_mount_err; + } } else { printk(KERN_WARNING "CIFS: username too long\n"); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "pass", 4) == 0) { if (!value) { @@ -963,7 +974,7 @@ cifs_parse_mount_options(char *options, const char *devname, if (vol->password == NULL) { printk(KERN_WARNING "CIFS: no memory " "for password\n"); - return 1; + goto cifs_parse_mount_err; } for (i = 0, j = 0; i < temp_len; i++, j++) { vol->password[j] = value[i]; @@ -979,7 +990,7 @@ cifs_parse_mount_options(char *options, const char *devname, if (vol->password == NULL) { printk(KERN_WARNING "CIFS: no memory " "for password\n"); - return 1; + goto cifs_parse_mount_err; } strcpy(vol->password, value); } @@ -989,11 +1000,16 @@ cifs_parse_mount_options(char *options, const char *devname, vol->UNCip = NULL; } else if (strnlen(value, INET6_ADDRSTRLEN) < INET6_ADDRSTRLEN) { - vol->UNCip = value; + vol->UNCip = kstrdup(value, GFP_KERNEL); + if (!vol->UNCip) { + printk(KERN_WARNING "CIFS: no memory " + "for UNC IP\n"); + goto cifs_parse_mount_err; + } } else { printk(KERN_WARNING "CIFS: ip address " "too long\n"); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "sec", 3) == 0) { if (!value || !*value) { @@ -1006,7 +1022,7 @@ cifs_parse_mount_options(char *options, const char *devname, /* vol->secFlg |= CIFSSEC_MUST_SEAL | CIFSSEC_MAY_KRB5; */ cERROR(1, "Krb5 cifs privacy not supported"); - return 1; + goto cifs_parse_mount_err; } else if (strnicmp(value, "krb5", 4) == 0) { vol->secFlg |= CIFSSEC_MAY_KRB5; } else if (strnicmp(value, "ntlmsspi", 8) == 0) { @@ -1036,7 +1052,7 @@ cifs_parse_mount_options(char *options, const char *devname, vol->nullauth = 1; } else { cERROR(1, "bad security option: %s", value); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "vers", 3) == 0) { if (!value || !*value) { @@ -1060,12 +1076,12 @@ cifs_parse_mount_options(char *options, const char *devname, if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid path to " "network resource\n"); - return 1; /* needs_arg; */ + goto cifs_parse_mount_err; } if ((temp_len = strnlen(value, 300)) < 300) { vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); if (vol->UNC == NULL) - return 1; + goto cifs_parse_mount_err; strcpy(vol->UNC, value); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; @@ -1074,27 +1090,32 @@ cifs_parse_mount_options(char *options, const char *devname, printk(KERN_WARNING "CIFS: UNC Path does not begin " "with // or \\\\ \n"); - return 1; + goto cifs_parse_mount_err; } } else { printk(KERN_WARNING "CIFS: UNC name too long\n"); - return 1; + goto cifs_parse_mount_err; } } else if ((strnicmp(data, "domain", 3) == 0) || (strnicmp(data, "workgroup", 5) == 0)) { if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid domain name\n"); - return 1; /* needs_arg; */ + goto cifs_parse_mount_err; } /* BB are there cases in which a comma can be valid in a domain name and need special handling? */ if (strnlen(value, 256) < 256) { - vol->domainname = value; + vol->domainname = kstrdup(value, GFP_KERNEL); + if (!vol->domainname) { + printk(KERN_WARNING "CIFS: no memory " + "for domainname\n"); + goto cifs_parse_mount_err; + } cFYI(1, "Domain name set"); } else { printk(KERN_WARNING "CIFS: domain name too " "long\n"); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "srcaddr", 7) == 0) { vol->srcaddr.ss_family = AF_UNSPEC; @@ -1102,7 +1123,7 @@ cifs_parse_mount_options(char *options, const char *devname, if (!value || !*value) { printk(KERN_WARNING "CIFS: srcaddr value" " not specified.\n"); - return 1; /* needs_arg; */ + goto cifs_parse_mount_err; } i = cifs_convert_address((struct sockaddr *)&vol->srcaddr, value, strlen(value)); @@ -1110,20 +1131,20 @@ cifs_parse_mount_options(char *options, const char *devname, printk(KERN_WARNING "CIFS: Could not parse" " srcaddr: %s\n", value); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "prefixpath", 10) == 0) { if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid path prefix\n"); - return 1; /* needs_argument */ + goto cifs_parse_mount_err; } 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; + goto cifs_parse_mount_err; if (value[0] != '/') { vol->prepath[0] = '/'; strcpy(vol->prepath+1, value); @@ -1132,24 +1153,33 @@ cifs_parse_mount_options(char *options, const char *devname, cFYI(1, "prefix path %s", vol->prepath); } else { printk(KERN_WARNING "CIFS: prefix too long\n"); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "iocharset", 9) == 0) { if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid iocharset " "specified\n"); - return 1; /* needs_arg; */ + goto cifs_parse_mount_err; } if (strnlen(value, 65) < 65) { - if (strnicmp(value, "default", 7)) - vol->iocharset = value; + if (strnicmp(value, "default", 7)) { + vol->iocharset = kstrdup(value, + GFP_KERNEL); + + if (!vol->iocharset) { + printk(KERN_WARNING "CIFS: no " + "memory for" + "charset\n"); + goto cifs_parse_mount_err; + } + } /* if iocharset not set then load_nls_default is used by caller */ cFYI(1, "iocharset set to %s", value); } else { printk(KERN_WARNING "CIFS: iocharset name " "too long.\n"); - return 1; + goto cifs_parse_mount_err; } } else if (!strnicmp(data, "uid", 3) && value && *value) { vol->linux_uid = simple_strtoul(value, &value, 0); @@ -1262,7 +1292,7 @@ cifs_parse_mount_options(char *options, const char *devname, if (vol->actimeo > CIFS_MAX_ACTIMEO) { cERROR(1, "CIFS: attribute cache" "timeout too large"); - return 1; + goto cifs_parse_mount_err; } } } else if (strnicmp(data, "credentials", 4) == 0) { @@ -1406,7 +1436,7 @@ cifs_parse_mount_options(char *options, const char *devname, #ifndef CONFIG_CIFS_FSCACHE cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE" "kernel config option set"); - return 1; + goto cifs_parse_mount_err; #endif vol->fsc = true; } else if (strnicmp(data, "mfsymlinks", 10) == 0) { @@ -1421,12 +1451,12 @@ cifs_parse_mount_options(char *options, const char *devname, if (devname == NULL) { printk(KERN_WARNING "CIFS: Missing UNC name for mount " "target\n"); - return 1; + goto cifs_parse_mount_err; } if ((temp_len = strnlen(devname, 300)) < 300) { vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); if (vol->UNC == NULL) - return 1; + goto cifs_parse_mount_err; strcpy(vol->UNC, devname); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; @@ -1434,21 +1464,21 @@ cifs_parse_mount_options(char *options, const char *devname, } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { printk(KERN_WARNING "CIFS: UNC Path does not " "begin with // or \\\\ \n"); - return 1; + goto cifs_parse_mount_err; } value = strpbrk(vol->UNC+2, "/\\"); if (value) *value = '\\'; } else { printk(KERN_WARNING "CIFS: UNC name too long\n"); - return 1; + goto cifs_parse_mount_err; } } if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) { cERROR(1, "Multiuser mounts currently require krb5 " "authentication!"); - return 1; + goto cifs_parse_mount_err; } if (vol->UNCip == NULL) @@ -1466,7 +1496,12 @@ cifs_parse_mount_options(char *options, const char *devname, printk(KERN_NOTICE "CIFS: ignoring forcegid mount option " "specified with no gid= option.\n"); + kfree(mountdata_copy); return 0; + +cifs_parse_mount_err: + kfree(mountdata_copy); + return 1; } /** Returns true if srcaddr isn't specified and rhs isn't @@ -2707,8 +2742,12 @@ cleanup_volume_info(struct smb_vol **pvolume_info) return; volume_info = *pvolume_info; + kfree(volume_info->username); kzfree(volume_info->password); kfree(volume_info->UNC); + kfree(volume_info->UNCip); + kfree(volume_info->domainname); + kfree(volume_info->iocharset); kfree(volume_info->prepath); kfree(volume_info); *pvolume_info = NULL; -- cgit v1.2.3-59-g8ed1b From 046462abca2576cc1c71f501c148798fac4ea314 Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:33 +0000 Subject: cifs: Simplify handling of submount options in cifs_mount. With CONFIG_DFS_UPCALL enabled, maintain the submount options in cifs_sb->mountdata, simplifying the code just a bit as well as making corner-case allocation problems less likely. Reviewed-by: Jeff Layton Signed-off-by: Sean Finney Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/connect.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 20c60ddaa5a1..3e20831119a9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2788,9 +2788,9 @@ build_unc_path_to_root(const struct smb_vol *volume_info, /* * Perform a dfs referral query for a share and (optionally) prefix * - * If a referral is found, mount_data will be set to point at a newly - * allocated string containing updated options for the submount. - * Otherwise it will be left untouched. + * If a referral is found, cifs_sb->mountdata will be (re-)allocated + * to a string containing updated options for the submount. Otherwise it + * will be left untouched. * * Returns the rc from get_dfs_path to the caller, which can be used to * determine whether there were referrals. @@ -2798,7 +2798,7 @@ build_unc_path_to_root(const struct smb_vol *volume_info, static int expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo, struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb, - char **mount_data, int check_prefix) + int check_prefix) { int rc; unsigned int num_referrals = 0; @@ -2826,11 +2826,14 @@ expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo, free_dfs_info_array(referrals, num_referrals); kfree(fake_devname); + if (cifs_sb->mountdata != NULL) + kfree(cifs_sb->mountdata); + if (IS_ERR(mdata)) { rc = PTR_ERR(mdata); mdata = NULL; } - *mount_data = mdata; + cifs_sb->mountdata = mdata; } kfree(full_path); return rc; @@ -2853,6 +2856,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, #ifdef CONFIG_CIFS_DFS_UPCALL int referral_walks_count = 0; try_mount_again: + mount_data = cifs_sb->mountdata; /* cleanup activities if we're chasing a referral */ if (referral_walks_count) { @@ -2986,7 +2990,7 @@ remote_path_check: */ if (referral_walks_count == 0) { int refrc = expand_dfs_referral(xid, pSesInfo, volume_info, - cifs_sb, &mount_data, false); + cifs_sb, false); if (!refrc) { referral_walks_count++; goto try_mount_again; @@ -3028,17 +3032,13 @@ remote_path_check: convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb)); - if (mount_data != mount_data_global) - kfree(mount_data); - rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb, - &mount_data, true); + true); if (!rc) { referral_walks_count++; goto try_mount_again; } - mount_data = NULL; goto mount_fail_check; #else /* No DFS support, return error on mount */ rc = -EOPNOTSUPP; @@ -3072,8 +3072,6 @@ remote_path_check: mount_fail_check: /* on error free sesinfo and tcon struct if needed */ if (rc) { - if (mount_data != mount_data_global) - kfree(mount_data); /* If find_unc succeeded then rc == 0 so we can not end */ /* up accidentally freeing someone elses tcon struct */ if (tcon) -- cgit v1.2.3-59-g8ed1b From 5167f11ec962690ecf926fab00f1d0524cd78664 Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:34 +0000 Subject: cifs: Use kstrndup for cifs_sb->mountdata A relatively minor nit, but also clarified the "consensus" from the preceding comments that it is in fact better to try for the kstrdup early and cleanup while cleaning up is still a simple thing to do. Reviewed-By: Steve French Signed-off-by: Sean Finney Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0f6a54f14eff..bb39afcc6f38 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -129,24 +129,19 @@ cifs_read_super(struct super_block *sb, void *data, cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages; #ifdef CONFIG_CIFS_DFS_UPCALL - /* copy mount params to sb for use in submounts */ - /* BB: should we move this after the mount so we - * do not have to do the copy on failed mounts? - * BB: May be it is better to do simple copy before - * complex operation (mount), and in case of fail - * just exit instead of doing mount and attempting - * undo it if this copy fails?*/ + /* + * Copy mount params to sb for use in submounts. Better to do + * the copy here and deal with the error before cleanup gets + * complicated post-mount. + */ if (data) { - int len = strlen(data); - cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL); + cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL); if (cifs_sb->mountdata == NULL) { bdi_destroy(&cifs_sb->bdi); kfree(sb->s_fs_info); sb->s_fs_info = NULL; return -ENOMEM; } - strncpy(cifs_sb->mountdata, data, len + 1); - cifs_sb->mountdata[len] = '\0'; } #endif -- cgit v1.2.3-59-g8ed1b From f14bcf71d1b802f6042b6c70a0c37120e47a0876 Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:35 +0000 Subject: cifs: Unconditionally copy mount options to superblock info Previously mount options were copied and updated in the cifs_sb_info struct only when CONFIG_CIFS_DFS_UPCALL was enabled. Making this information generally available allows us to remove a number of ifdefs, extra function params, and temporary variables. Reviewed-by: Jeff Layton Signed-off-by: Sean Finney Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 4 +--- fs/cifs/cifsfs.c | 8 +------- fs/cifs/cifsproto.h | 2 +- fs/cifs/connect.c | 8 +++----- 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index ac51cd2d33ae..a9d5692e0c20 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -58,9 +58,7 @@ struct cifs_sb_info { unsigned int mnt_cifs_flags; int prepathlen; char *prepath; /* relative path under the share to mount to */ -#ifdef CONFIG_CIFS_DFS_UPCALL - char *mountdata; /* mount options received at mount time */ -#endif + char *mountdata; /* options received at mount time or via DFS refs */ struct backing_dev_info bdi; struct delayed_work prune_tlinks; }; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index bb39afcc6f38..2b8e47e5e533 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -128,7 +128,6 @@ cifs_read_super(struct super_block *sb, void *data, } cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages; -#ifdef CONFIG_CIFS_DFS_UPCALL /* * Copy mount params to sb for use in submounts. Better to do * the copy here and deal with the error before cleanup gets @@ -143,9 +142,8 @@ cifs_read_super(struct super_block *sb, void *data, return -ENOMEM; } } -#endif - rc = cifs_mount(sb, cifs_sb, data, devname); + rc = cifs_mount(sb, cifs_sb, devname); if (rc) { if (!silent) @@ -197,12 +195,10 @@ out_no_root: out_mount_failed: if (cifs_sb) { -#ifdef CONFIG_CIFS_DFS_UPCALL if (cifs_sb->mountdata) { kfree(cifs_sb->mountdata); cifs_sb->mountdata = NULL; } -#endif unload_nls(cifs_sb->local_nls); bdi_destroy(&cifs_sb->bdi); kfree(cifs_sb); @@ -226,12 +222,10 @@ cifs_put_super(struct super_block *sb) rc = cifs_umount(sb, cifs_sb); if (rc) cERROR(1, "cifs_umount failed with return code %d", rc); -#ifdef CONFIG_CIFS_DFS_UPCALL if (cifs_sb->mountdata) { kfree(cifs_sb->mountdata); cifs_sb->mountdata = NULL; } -#endif unload_nls(cifs_sb->local_nls); bdi_destroy(&cifs_sb->bdi); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 136d2f2febcc..a1c94d396afe 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -148,7 +148,7 @@ extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, const char *); -extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, +extern int cifs_mount(struct super_block *, struct cifs_sb_info *, const char *); extern int cifs_umount(struct super_block *, struct cifs_sb_info *); extern void cifs_dfs_release_automount_timer(void); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3e20831119a9..da284e3cb653 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2842,7 +2842,7 @@ expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo, int cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, - char *mount_data_global, const char *devname) + const char *devname) { int rc; int xid; @@ -2851,13 +2851,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, struct cifsTconInfo *tcon; struct TCP_Server_Info *srvTcp; char *full_path; - char *mount_data = mount_data_global; struct tcon_link *tlink; #ifdef CONFIG_CIFS_DFS_UPCALL int referral_walks_count = 0; try_mount_again: - mount_data = cifs_sb->mountdata; - /* cleanup activities if we're chasing a referral */ if (referral_walks_count) { if (tcon) @@ -2884,7 +2881,8 @@ try_mount_again: goto out; } - if (cifs_parse_mount_options(mount_data, devname, volume_info)) { + if (cifs_parse_mount_options(cifs_sb->mountdata, devname, + volume_info)) { rc = -EINVAL; goto out; } -- cgit v1.2.3-59-g8ed1b From c4aca0c09f80ca40dbcecb2370af9594fbe9051d Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Fri, 6 May 2011 02:35:00 -0500 Subject: cifs: Change key name to cifs.idmap, misc. clean-up Change idmap key name from cifs.cifs_idmap to cifs.idmap. Removed unused structure wksidarr and function match_sid(). Handle errors correctly in function init_cifs(). Signed-off-by: Shirish Pargaonkar Reviewed-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 59 +------------------------------------------------------ fs/cifs/cifsacl.h | 1 - fs/cifs/cifsfs.c | 8 +++++--- 3 files changed, 6 insertions(+), 62 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index bfb5ba5a271b..f3c6fb9942ac 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -33,18 +33,6 @@ #include "cifsproto.h" #include "cifs_debug.h" - -static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { - {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, - {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, - {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"}, - {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"}, - {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"}, - {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"}, - {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} } -; - - /* security id for everyone/world system group */ static const struct cifs_sid sid_everyone = { 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; @@ -131,7 +119,7 @@ cifs_idmap_key_destroy(struct key *key) } struct key_type cifs_idmap_key_type = { - .name = "cifs.cifs_idmap", + .name = "cifs.idmap", .instantiate = cifs_idmap_key_instantiate, .destroy = cifs_idmap_key_destroy, .describe = user_describe, @@ -435,51 +423,6 @@ cifs_destroy_idmaptrees(void) spin_unlock(&sidgidlock); } -int match_sid(struct cifs_sid *ctsid) -{ - int i, j; - int num_subauth, num_sat, num_saw; - struct cifs_sid *cwsid; - - if (!ctsid) - return -1; - - for (i = 0; i < NUM_WK_SIDS; ++i) { - cwsid = &(wksidarr[i].cifssid); - - /* compare the revision */ - if (ctsid->revision != cwsid->revision) - continue; - - /* compare all of the six auth values */ - for (j = 0; j < 6; ++j) { - if (ctsid->authority[j] != cwsid->authority[j]) - break; - } - if (j < 6) - continue; /* all of the auth values did not match */ - - /* compare all of the subauth values if any */ - num_sat = ctsid->num_subauth; - num_saw = cwsid->num_subauth; - num_subauth = num_sat < num_saw ? num_sat : num_saw; - if (num_subauth) { - for (j = 0; j < num_subauth; ++j) { - if (ctsid->sub_auth[j] != cwsid->sub_auth[j]) - break; - } - if (j < num_subauth) - continue; /* all sub_auth values do not match */ - } - - cFYI(1, "matching sid: %s\n", wksidarr[i].sidname); - return 0; /* sids compare/match */ - } - - cFYI(1, "No matching sid"); - return -1; -} - /* if the two SIDs (roughly equivalent to a UUID for a user or group) are the same returns 1, if they do not match returns 0 */ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 757cf5aec3ee..5c902c7ce524 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -98,7 +98,6 @@ extern struct key_type cifs_idmap_key_type; extern const struct cred *root_cred; #endif /* KERNEL */ -extern int match_sid(struct cifs_sid *); extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *); #endif /* _CIFSACL_H */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 2b8e47e5e533..ed92c7d36378 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1046,21 +1046,23 @@ init_cifs(void) #ifdef CONFIG_CIFS_ACL rc = init_cifs_idmap(); if (rc) - goto out_destroy_request_bufs; + goto out_register_key_type; #endif /* CONFIG_CIFS_ACL */ rc = register_filesystem(&cifs_fs_type); if (rc) - goto out_destroy_request_bufs; + goto out_init_cifs_idmap; return 0; -out_destroy_request_bufs: +out_init_cifs_idmap: #ifdef CONFIG_CIFS_ACL exit_cifs_idmap(); +out_register_key_type: #endif #ifdef CONFIG_CIFS_UPCALL unregister_key_type(&cifs_spnego_key_type); +out_destroy_request_bufs: #endif cifs_destroy_request_bufs(); out_destroy_mids: -- cgit v1.2.3-59-g8ed1b From 4e64fb33dea9c4cad0106760c49c7629d4c699a5 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 18 May 2011 18:08:28 +0000 Subject: [CIFS] Update cifs to version 1.72 Signed-off-by: Steve French --- fs/cifs/cifsfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index d304584408d1..64313f778ebf 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -129,5 +129,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); extern const struct export_operations cifs_export_ops; #endif /* CIFS_NFSD_EXPORT */ -#define CIFS_VERSION "1.71" +#define CIFS_VERSION "1.72" #endif /* _CIFSFS_H */ -- cgit v1.2.3-59-g8ed1b From ceec1e0fae6eecac876ec28cfb97786f87dfb1c6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 14 Mar 2011 19:01:59 +0000 Subject: [CIFS] Remove sparse warning Move extern for cifsConvertToUCS to different header to prevent following warning: CHECK fs/cifs/cifs_unicode.c fs/cifs/cifs_unicode.c:267:1: warning: symbol 'cifsConvertToUCS' was not declared. Should it be static? Signed-off-by: Steve French Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifs_unicode.h | 3 +++ fs/cifs/cifsproto.h | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index 644dd882a560..6d02fd560566 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h @@ -82,6 +82,9 @@ int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); char *cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, const struct nls_table *codepage); +extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, + const struct nls_table *cp, int mapChars); + #endif /* diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index a1c94d396afe..6e69e06a30b3 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -353,8 +353,6 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 *inode_number, const struct nls_table *nls_codepage, int remap_special_chars); -extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, - const struct nls_table *cp, int mapChars); extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, const __u16 netfid, const __u64 len, -- cgit v1.2.3-59-g8ed1b From 156ecb2d8b06589098f6ce3012e6a10fef07c416 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 20 May 2011 17:00:01 +0000 Subject: [CIFS] Fix to problem with getattr caused by invalidate simplification patch Fix to earlier "Simplify invalidate part (try #6)" patch That patch caused problems with connectathon test 5. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 6 ++++-- fs/cifs/inode.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ed92c7d36378..493b74ca5648 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -617,8 +617,10 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && inode->i_mapping->nrpages != 0) { rc = filemap_fdatawait(inode->i_mapping); - mapping_set_error(inode->i_mapping, rc); - return rc; + if (rc) { + mapping_set_error(inode->i_mapping, rc); + return rc; + } } /* * Some applications poll for the file length in this strange diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 0cc7eddb077f..de02ed5e25c2 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1805,8 +1805,10 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && inode->i_mapping->nrpages != 0) { rc = filemap_fdatawait(inode->i_mapping); - mapping_set_error(inode->i_mapping, rc); - return rc; + if (rc) { + mapping_set_error(inode->i_mapping, rc); + return rc; + } } rc = cifs_revalidate_dentry_attr(dentry); -- cgit v1.2.3-59-g8ed1b