aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifs_spnego.c35
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/cifsproto.h4
-rw-r--r--fs/cifs/cifssmb.c84
-rw-r--r--fs/cifs/dns_resolve.c74
-rw-r--r--fs/cifs/file.c130
-rw-r--r--fs/cifs/inode.c644
-rw-r--r--fs/cifs/misc.c6
-rw-r--r--fs/cifs/readdir.c128
-rw-r--r--fs/cifs/sess.c4
-rw-r--r--fs/cifs/transport.c3
12 files changed, 632 insertions, 483 deletions
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
index 117ef4bba68e..fcee9298b620 100644
--- a/fs/cifs/cifs_spnego.c
+++ b/fs/cifs/cifs_spnego.c
@@ -66,11 +66,28 @@ struct key_type cifs_spnego_key_type = {
66 .describe = user_describe, 66 .describe = user_describe,
67}; 67};
68 68
69#define MAX_VER_STR_LEN 8 /* length of longest version string e.g. 69/* length of longest version string e.g. strlen("ver=0xFF") */
70 strlen("ver=0xFF") */ 70#define MAX_VER_STR_LEN 8
71#define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg 71
72 in future could have strlen(";sec=ntlmsspi") */ 72/* length of longest security mechanism name, eg in future could have
73#define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ 73 * strlen(";sec=ntlmsspi") */
74#define MAX_MECH_STR_LEN 13
75
76/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
77#define MAX_IPV6_ADDR_LEN 42
78
79/* strlen of "host=" */
80#define HOST_KEY_LEN 5
81
82/* strlen of ";ip4=" or ";ip6=" */
83#define IP_KEY_LEN 5
84
85/* strlen of ";uid=0x" */
86#define UID_KEY_LEN 7
87
88/* strlen of ";user=" */
89#define USER_KEY_LEN 6
90
74/* get a key struct with a SPNEGO security blob, suitable for session setup */ 91/* get a key struct with a SPNEGO security blob, suitable for session setup */
75struct key * 92struct key *
76cifs_get_spnego_key(struct cifsSesInfo *sesInfo) 93cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
@@ -84,11 +101,11 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
84 /* length of fields (with semicolons): ver=0xyz ip4=ipaddress 101 /* length of fields (with semicolons): ver=0xyz ip4=ipaddress
85 host=hostname sec=mechanism uid=0xFF user=username */ 102 host=hostname sec=mechanism uid=0xFF user=username */
86 desc_len = MAX_VER_STR_LEN + 103 desc_len = MAX_VER_STR_LEN +
87 6 /* len of "host=" */ + strlen(hostname) + 104 HOST_KEY_LEN + strlen(hostname) +
88 5 /* len of ";ipv4=" */ + MAX_IPV6_ADDR_LEN + 105 IP_KEY_LEN + MAX_IPV6_ADDR_LEN +
89 MAX_MECH_STR_LEN + 106 MAX_MECH_STR_LEN +
90 7 /* len of ";uid=0x" */ + (sizeof(uid_t) * 2) + 107 UID_KEY_LEN + (sizeof(uid_t) * 2) +
91 6 /* len of ";user=" */ + strlen(sesInfo->userName) + 1; 108 USER_KEY_LEN + strlen(sesInfo->userName) + 1;
92 109
93 spnego_key = ERR_PTR(-ENOMEM); 110 spnego_key = ERR_PTR(-ENOMEM);
94 description = kzalloc(desc_len, GFP_KERNEL); 111 description = kzalloc(desc_len, GFP_KERNEL);
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 135c965c4137..f7b4a5cd837b 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -41,7 +41,7 @@ extern int cifs_create(struct inode *, struct dentry *, int,
41 struct nameidata *); 41 struct nameidata *);
42extern struct dentry *cifs_lookup(struct inode *, struct dentry *, 42extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
43 struct nameidata *); 43 struct nameidata *);
44extern int cifs_unlink(struct inode *, struct dentry *); 44extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
45extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); 45extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
46extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t); 46extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t);
47extern int cifs_mkdir(struct inode *, struct dentry *, int); 47extern int cifs_mkdir(struct inode *, struct dentry *, int);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 8dfd6f24d488..0d22479d99b7 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -309,6 +309,7 @@ struct cifs_search_info {
309 __u32 resume_key; 309 __u32 resume_key;
310 char *ntwrk_buf_start; 310 char *ntwrk_buf_start;
311 char *srch_entries_start; 311 char *srch_entries_start;
312 char *last_entry;
312 char *presume_name; 313 char *presume_name;
313 unsigned int resume_name_len; 314 unsigned int resume_name_len;
314 bool endOfSearch:1; 315 bool endOfSearch:1;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index a729d083e6f4..0cff7fe986e8 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -179,6 +179,8 @@ extern int CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
179extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, 179extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
180 const FILE_BASIC_INFO *data, __u16 fid, 180 const FILE_BASIC_INFO *data, __u16 fid,
181 __u32 pid_of_opener); 181 __u32 pid_of_opener);
182extern int CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
183 bool delete_file, __u16 fid, __u32 pid_of_opener);
182#if 0 184#if 0
183extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, 185extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon,
184 char *fileName, __u16 dos_attributes, 186 char *fileName, __u16 dos_attributes,
@@ -229,7 +231,7 @@ extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
229 const struct nls_table *nls_codepage, 231 const struct nls_table *nls_codepage,
230 int remap_special_chars); 232 int remap_special_chars);
231extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, 233extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
232 int netfid, char *target_name, 234 int netfid, const char *target_name,
233 const struct nls_table *nls_codepage, 235 const struct nls_table *nls_codepage,
234 int remap_special_chars); 236 int remap_special_chars);
235extern int CIFSCreateHardLink(const int xid, 237extern int CIFSCreateHardLink(const int xid,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 994de7c90474..6f4ffe15d68d 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2017,7 +2017,7 @@ renameRetry:
2017} 2017}
2018 2018
2019int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, 2019int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2020 int netfid, char *target_name, 2020 int netfid, const char *target_name,
2021 const struct nls_table *nls_codepage, int remap) 2021 const struct nls_table *nls_codepage, int remap)
2022{ 2022{
2023 struct smb_com_transaction2_sfi_req *pSMB = NULL; 2023 struct smb_com_transaction2_sfi_req *pSMB = NULL;
@@ -2071,7 +2071,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
2071 remap); 2071 remap);
2072 } 2072 }
2073 rename_info->target_name_len = cpu_to_le32(2 * len_of_str); 2073 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2074 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2; 2074 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2075 byte_count += count; 2075 byte_count += count;
2076 pSMB->DataCount = cpu_to_le16(count); 2076 pSMB->DataCount = cpu_to_le16(count);
2077 pSMB->TotalDataCount = pSMB->DataCount; 2077 pSMB->TotalDataCount = pSMB->DataCount;
@@ -3614,6 +3614,8 @@ findFirstRetry:
3614 /* BB remember to free buffer if error BB */ 3614 /* BB remember to free buffer if error BB */
3615 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 3615 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3616 if (rc == 0) { 3616 if (rc == 0) {
3617 unsigned int lnoff;
3618
3617 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) 3619 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3618 psrch_inf->unicode = true; 3620 psrch_inf->unicode = true;
3619 else 3621 else
@@ -3636,6 +3638,17 @@ findFirstRetry:
3636 le16_to_cpu(parms->SearchCount); 3638 le16_to_cpu(parms->SearchCount);
3637 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + 3639 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3638 psrch_inf->entries_in_buffer; 3640 psrch_inf->entries_in_buffer;
3641 lnoff = le16_to_cpu(parms->LastNameOffset);
3642 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3643 lnoff) {
3644 cERROR(1, ("ignoring corrupt resume name"));
3645 psrch_inf->last_entry = NULL;
3646 return rc;
3647 }
3648
3649 psrch_inf->last_entry = psrch_inf->srch_entries_start +
3650 lnoff;
3651
3639 *pnetfid = parms->SearchHandle; 3652 *pnetfid = parms->SearchHandle;
3640 } else { 3653 } else {
3641 cifs_buf_release(pSMB); 3654 cifs_buf_release(pSMB);
@@ -3725,6 +3738,8 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3725 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 3738 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3726 3739
3727 if (rc == 0) { 3740 if (rc == 0) {
3741 unsigned int lnoff;
3742
3728 /* BB fixme add lock for file (srch_info) struct here */ 3743 /* BB fixme add lock for file (srch_info) struct here */
3729 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) 3744 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3730 psrch_inf->unicode = true; 3745 psrch_inf->unicode = true;
@@ -3751,6 +3766,16 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3751 le16_to_cpu(parms->SearchCount); 3766 le16_to_cpu(parms->SearchCount);
3752 psrch_inf->index_of_last_entry += 3767 psrch_inf->index_of_last_entry +=
3753 psrch_inf->entries_in_buffer; 3768 psrch_inf->entries_in_buffer;
3769 lnoff = le16_to_cpu(parms->LastNameOffset);
3770 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3771 lnoff) {
3772 cERROR(1, ("ignoring corrupt resume name"));
3773 psrch_inf->last_entry = NULL;
3774 return rc;
3775 } else
3776 psrch_inf->last_entry =
3777 psrch_inf->srch_entries_start + lnoff;
3778
3754/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d", 3779/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3755 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */ 3780 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3756 3781
@@ -4876,6 +4901,61 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4876 return rc; 4901 return rc;
4877} 4902}
4878 4903
4904int
4905CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4906 bool delete_file, __u16 fid, __u32 pid_of_opener)
4907{
4908 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4909 char *data_offset;
4910 int rc = 0;
4911 __u16 params, param_offset, offset, byte_count, count;
4912
4913 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4914 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4915
4916 if (rc)
4917 return rc;
4918
4919 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4920 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4921
4922 params = 6;
4923 pSMB->MaxSetupCount = 0;
4924 pSMB->Reserved = 0;
4925 pSMB->Flags = 0;
4926 pSMB->Timeout = 0;
4927 pSMB->Reserved2 = 0;
4928 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4929 offset = param_offset + params;
4930
4931 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4932
4933 count = 1;
4934 pSMB->MaxParameterCount = cpu_to_le16(2);
4935 /* BB find max SMB PDU from sess */
4936 pSMB->MaxDataCount = cpu_to_le16(1000);
4937 pSMB->SetupCount = 1;
4938 pSMB->Reserved3 = 0;
4939 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4940 byte_count = 3 /* pad */ + params + count;
4941 pSMB->DataCount = cpu_to_le16(count);
4942 pSMB->ParameterCount = cpu_to_le16(params);
4943 pSMB->TotalDataCount = pSMB->DataCount;
4944 pSMB->TotalParameterCount = pSMB->ParameterCount;
4945 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4946 pSMB->DataOffset = cpu_to_le16(offset);
4947 pSMB->Fid = fid;
4948 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4949 pSMB->Reserved4 = 0;
4950 pSMB->hdr.smb_buf_length += byte_count;
4951 pSMB->ByteCount = cpu_to_le16(byte_count);
4952 *data_offset = delete_file ? 1 : 0;
4953 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4954 if (rc)
4955 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4956
4957 return rc;
4958}
4879 4959
4880int 4960int
4881CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon, 4961CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index a2e0673e1b08..1e0c1bd8f2e4 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -29,19 +29,55 @@
29#include "cifsproto.h" 29#include "cifsproto.h"
30#include "cifs_debug.h" 30#include "cifs_debug.h"
31 31
32static int dns_resolver_instantiate(struct key *key, const void *data, 32/* Checks if supplied name is IP address
33 * returns:
34 * 1 - name is IP
35 * 0 - name is not IP
36 */
37static int
38is_ip(const char *name)
39{
40 int rc;
41 struct sockaddr_in sin_server;
42 struct sockaddr_in6 sin_server6;
43
44 rc = cifs_inet_pton(AF_INET, name,
45 &sin_server.sin_addr.s_addr);
46
47 if (rc <= 0) {
48 /* not ipv4 address, try ipv6 */
49 rc = cifs_inet_pton(AF_INET6, name,
50 &sin_server6.sin6_addr.in6_u);
51 if (rc > 0)
52 return 1;
53 } else {
54 return 1;
55 }
56 /* we failed translating address */
57 return 0;
58}
59
60static int
61dns_resolver_instantiate(struct key *key, const void *data,
33 size_t datalen) 62 size_t datalen)
34{ 63{
35 int rc = 0; 64 int rc = 0;
36 char *ip; 65 char *ip;
37 66
38 ip = kmalloc(datalen+1, GFP_KERNEL); 67 ip = kmalloc(datalen + 1, GFP_KERNEL);
39 if (!ip) 68 if (!ip)
40 return -ENOMEM; 69 return -ENOMEM;
41 70
42 memcpy(ip, data, datalen); 71 memcpy(ip, data, datalen);
43 ip[datalen] = '\0'; 72 ip[datalen] = '\0';
44 73
74 /* make sure this looks like an address */
75 if (!is_ip((const char *) ip)) {
76 kfree(ip);
77 return -EINVAL;
78 }
79
80 key->type_data.x[0] = datalen;
45 rcu_assign_pointer(key->payload.data, ip); 81 rcu_assign_pointer(key->payload.data, ip);
46 82
47 return rc; 83 return rc;
@@ -62,33 +98,6 @@ struct key_type key_type_dns_resolver = {
62 .match = user_match, 98 .match = user_match,
63}; 99};
64 100
65/* Checks if supplied name is IP address
66 * returns:
67 * 1 - name is IP
68 * 0 - name is not IP
69 */
70static int is_ip(const char *name)
71{
72 int rc;
73 struct sockaddr_in sin_server;
74 struct sockaddr_in6 sin_server6;
75
76 rc = cifs_inet_pton(AF_INET, name,
77 &sin_server.sin_addr.s_addr);
78
79 if (rc <= 0) {
80 /* not ipv4 address, try ipv6 */
81 rc = cifs_inet_pton(AF_INET6, name,
82 &sin_server6.sin6_addr.in6_u);
83 if (rc > 0)
84 return 1;
85 } else {
86 return 1;
87 }
88 /* we failed translating address */
89 return 0;
90}
91
92/* Resolves server name to ip address. 101/* Resolves server name to ip address.
93 * input: 102 * input:
94 * unc - server UNC 103 * unc - server UNC
@@ -140,6 +149,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
140 149
141 rkey = request_key(&key_type_dns_resolver, name, ""); 150 rkey = request_key(&key_type_dns_resolver, name, "");
142 if (!IS_ERR(rkey)) { 151 if (!IS_ERR(rkey)) {
152 len = rkey->type_data.x[0];
143 data = rkey->payload.data; 153 data = rkey->payload.data;
144 } else { 154 } else {
145 cERROR(1, ("%s: unable to resolve: %s", __func__, name)); 155 cERROR(1, ("%s: unable to resolve: %s", __func__, name));
@@ -148,11 +158,9 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
148 158
149skip_upcall: 159skip_upcall:
150 if (data) { 160 if (data) {
151 len = strlen(data); 161 *ip_addr = kmalloc(len + 1, GFP_KERNEL);
152 *ip_addr = kmalloc(len+1, GFP_KERNEL);
153 if (*ip_addr) { 162 if (*ip_addr) {
154 memcpy(*ip_addr, data, len); 163 memcpy(*ip_addr, data, len + 1);
155 (*ip_addr)[len] = '\0';
156 if (!IS_ERR(rkey)) 164 if (!IS_ERR(rkey))
157 cFYI(1, ("%s: resolved: %s to %s", __func__, 165 cFYI(1, ("%s: resolved: %s to %s", __func__,
158 name, 166 name,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index cbefe1f1f9fe..c4a8a0605125 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -107,7 +107,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
107 107
108 /* want handles we can use to read with first 108 /* want handles we can use to read with first
109 in the list so we do not have to walk the 109 in the list so we do not have to walk the
110 list to search for one in prepare_write */ 110 list to search for one in write_begin */
111 if ((file->f_flags & O_ACCMODE) == O_WRONLY) { 111 if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
112 list_add_tail(&pCifsFile->flist, 112 list_add_tail(&pCifsFile->flist,
113 &pCifsInode->openFileList); 113 &pCifsInode->openFileList);
@@ -915,7 +915,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
915} 915}
916 916
917static ssize_t cifs_write(struct file *file, const char *write_data, 917static ssize_t cifs_write(struct file *file, const char *write_data,
918 size_t write_size, loff_t *poffset) 918 size_t write_size, loff_t *poffset)
919{ 919{
920 int rc = 0; 920 int rc = 0;
921 unsigned int bytes_written = 0; 921 unsigned int bytes_written = 0;
@@ -1065,6 +1065,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
1065struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) 1065struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
1066{ 1066{
1067 struct cifsFileInfo *open_file; 1067 struct cifsFileInfo *open_file;
1068 bool any_available = false;
1068 int rc; 1069 int rc;
1069 1070
1070 /* Having a null inode here (because mapping->host was set to zero by 1071 /* Having a null inode here (because mapping->host was set to zero by
@@ -1080,8 +1081,10 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
1080 read_lock(&GlobalSMBSeslock); 1081 read_lock(&GlobalSMBSeslock);
1081refind_writable: 1082refind_writable:
1082 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { 1083 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
1083 if (open_file->closePend) 1084 if (open_file->closePend ||
1085 (!any_available && open_file->pid != current->tgid))
1084 continue; 1086 continue;
1087
1085 if (open_file->pfile && 1088 if (open_file->pfile &&
1086 ((open_file->pfile->f_flags & O_RDWR) || 1089 ((open_file->pfile->f_flags & O_RDWR) ||
1087 (open_file->pfile->f_flags & O_WRONLY))) { 1090 (open_file->pfile->f_flags & O_WRONLY))) {
@@ -1131,6 +1134,11 @@ refind_writable:
1131 of the loop here. */ 1134 of the loop here. */
1132 } 1135 }
1133 } 1136 }
1137 /* couldn't find useable FH with same pid, try any available */
1138 if (!any_available) {
1139 any_available = true;
1140 goto refind_writable;
1141 }
1134 read_unlock(&GlobalSMBSeslock); 1142 read_unlock(&GlobalSMBSeslock);
1135 return NULL; 1143 return NULL;
1136} 1144}
@@ -1447,49 +1455,52 @@ static int cifs_writepage(struct page *page, struct writeback_control *wbc)
1447 return rc; 1455 return rc;
1448} 1456}
1449 1457
1450static int cifs_commit_write(struct file *file, struct page *page, 1458static int cifs_write_end(struct file *file, struct address_space *mapping,
1451 unsigned offset, unsigned to) 1459 loff_t pos, unsigned len, unsigned copied,
1460 struct page *page, void *fsdata)
1452{ 1461{
1453 int xid; 1462 int rc;
1454 int rc = 0; 1463 struct inode *inode = mapping->host;
1455 struct inode *inode = page->mapping->host;
1456 loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
1457 char *page_data;
1458 1464
1459 xid = GetXid(); 1465 cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
1460 cFYI(1, ("commit write for page %p up to position %lld for %d", 1466 page, pos, copied));
1461 page, position, to)); 1467
1462 spin_lock(&inode->i_lock); 1468 if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
1463 if (position > inode->i_size) 1469 SetPageUptodate(page);
1464 i_size_write(inode, position);
1465 1470
1466 spin_unlock(&inode->i_lock);
1467 if (!PageUptodate(page)) { 1471 if (!PageUptodate(page)) {
1468 position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; 1472 char *page_data;
1469 /* can not rely on (or let) writepage write this data */ 1473 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
1470 if (to < offset) { 1474 int xid;
1471 cFYI(1, ("Illegal offsets, can not copy from %d to %d", 1475
1472 offset, to)); 1476 xid = GetXid();
1473 FreeXid(xid);
1474 return rc;
1475 }
1476 /* this is probably better than directly calling 1477 /* this is probably better than directly calling
1477 partialpage_write since in this function the file handle is 1478 partialpage_write since in this function the file handle is
1478 known which we might as well leverage */ 1479 known which we might as well leverage */
1479 /* BB check if anything else missing out of ppw 1480 /* BB check if anything else missing out of ppw
1480 such as updating last write time */ 1481 such as updating last write time */
1481 page_data = kmap(page); 1482 page_data = kmap(page);
1482 rc = cifs_write(file, page_data + offset, to-offset, 1483 rc = cifs_write(file, page_data + offset, copied, &pos);
1483 &position); 1484 /* if (rc < 0) should we set writebehind rc? */
1484 if (rc > 0)
1485 rc = 0;
1486 /* else if (rc < 0) should we set writebehind rc? */
1487 kunmap(page); 1485 kunmap(page);
1486
1487 FreeXid(xid);
1488 } else { 1488 } else {
1489 rc = copied;
1490 pos += copied;
1489 set_page_dirty(page); 1491 set_page_dirty(page);
1490 } 1492 }
1491 1493
1492 FreeXid(xid); 1494 if (rc > 0) {
1495 spin_lock(&inode->i_lock);
1496 if (pos > inode->i_size)
1497 i_size_write(inode, pos);
1498 spin_unlock(&inode->i_lock);
1499 }
1500
1501 unlock_page(page);
1502 page_cache_release(page);
1503
1493 return rc; 1504 return rc;
1494} 1505}
1495 1506
@@ -2035,49 +2046,44 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
2035 return true; 2046 return true;
2036} 2047}
2037 2048
2038static int cifs_prepare_write(struct file *file, struct page *page, 2049static int cifs_write_begin(struct file *file, struct address_space *mapping,
2039 unsigned from, unsigned to) 2050 loff_t pos, unsigned len, unsigned flags,
2051 struct page **pagep, void **fsdata)
2040{ 2052{
2041 int rc = 0; 2053 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
2042 loff_t i_size; 2054 loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
2043 loff_t offset;
2044 2055
2045 cFYI(1, ("prepare write for page %p from %d to %d", page, from, to)); 2056 cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
2046 if (PageUptodate(page)) 2057
2058 *pagep = __grab_cache_page(mapping, index);
2059 if (!*pagep)
2060 return -ENOMEM;
2061
2062 if (PageUptodate(*pagep))
2047 return 0; 2063 return 0;
2048 2064
2049 /* If we are writing a full page it will be up to date, 2065 /* If we are writing a full page it will be up to date,
2050 no need to read from the server */ 2066 no need to read from the server */
2051 if ((to == PAGE_CACHE_SIZE) && (from == 0)) { 2067 if (len == PAGE_CACHE_SIZE && flags & AOP_FLAG_UNINTERRUPTIBLE)
2052 SetPageUptodate(page);
2053 return 0; 2068 return 0;
2054 }
2055 2069
2056 offset = (loff_t)page->index << PAGE_CACHE_SHIFT; 2070 if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
2057 i_size = i_size_read(page->mapping->host); 2071 int rc;
2058 2072
2059 if ((offset >= i_size) ||
2060 ((from == 0) && (offset + to) >= i_size)) {
2061 /*
2062 * We don't need to read data beyond the end of the file.
2063 * zero it, and set the page uptodate
2064 */
2065 simple_prepare_write(file, page, from, to);
2066 SetPageUptodate(page);
2067 } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
2068 /* might as well read a page, it is fast enough */ 2073 /* might as well read a page, it is fast enough */
2069 rc = cifs_readpage_worker(file, page, &offset); 2074 rc = cifs_readpage_worker(file, *pagep, &offset);
2075
2076 /* we do not need to pass errors back
2077 e.g. if we do not have read access to the file
2078 because cifs_write_end will attempt synchronous writes
2079 -- shaggy */
2070 } else { 2080 } else {
2071 /* we could try using another file handle if there is one - 2081 /* we could try using another file handle if there is one -
2072 but how would we lock it to prevent close of that handle 2082 but how would we lock it to prevent close of that handle
2073 racing with this read? In any case 2083 racing with this read? In any case
2074 this will be written out by commit_write so is fine */ 2084 this will be written out by write_end so is fine */
2075 } 2085 }
2076 2086
2077 /* we do not need to pass errors back
2078 e.g. if we do not have read access to the file
2079 because cifs_commit_write will do the right thing. -- shaggy */
2080
2081 return 0; 2087 return 0;
2082} 2088}
2083 2089
@@ -2086,8 +2092,8 @@ const struct address_space_operations cifs_addr_ops = {
2086 .readpages = cifs_readpages, 2092 .readpages = cifs_readpages,
2087 .writepage = cifs_writepage, 2093 .writepage = cifs_writepage,
2088 .writepages = cifs_writepages, 2094 .writepages = cifs_writepages,
2089 .prepare_write = cifs_prepare_write, 2095 .write_begin = cifs_write_begin,
2090 .commit_write = cifs_commit_write, 2096 .write_end = cifs_write_end,
2091 .set_page_dirty = __set_page_dirty_nobuffers, 2097 .set_page_dirty = __set_page_dirty_nobuffers,
2092 /* .sync_page = cifs_sync_page, */ 2098 /* .sync_page = cifs_sync_page, */
2093 /* .direct_IO = */ 2099 /* .direct_IO = */
@@ -2102,8 +2108,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
2102 .readpage = cifs_readpage, 2108 .readpage = cifs_readpage,
2103 .writepage = cifs_writepage, 2109 .writepage = cifs_writepage,
2104 .writepages = cifs_writepages, 2110 .writepages = cifs_writepages,
2105 .prepare_write = cifs_prepare_write, 2111 .write_begin = cifs_write_begin,
2106 .commit_write = cifs_commit_write, 2112 .write_end = cifs_write_end,
2107 .set_page_dirty = __set_page_dirty_nobuffers, 2113 .set_page_dirty = __set_page_dirty_nobuffers,
2108 /* .sync_page = cifs_sync_page, */ 2114 /* .sync_page = cifs_sync_page, */
2109 /* .direct_IO = */ 2115 /* .direct_IO = */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 9c548f110102..a8c833345fc9 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -665,40 +665,201 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
665 return inode; 665 return inode;
666} 666}
667 667
668int cifs_unlink(struct inode *inode, struct dentry *direntry) 668static int
669cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
670 char *full_path, __u32 dosattr)
671{
672 int rc;
673 int oplock = 0;
674 __u16 netfid;
675 __u32 netpid;
676 bool set_time = false;
677 struct cifsFileInfo *open_file;
678 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
679 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
680 struct cifsTconInfo *pTcon = cifs_sb->tcon;
681 FILE_BASIC_INFO info_buf;
682
683 if (attrs->ia_valid & ATTR_ATIME) {
684 set_time = true;
685 info_buf.LastAccessTime =
686 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
687 } else
688 info_buf.LastAccessTime = 0;
689
690 if (attrs->ia_valid & ATTR_MTIME) {
691 set_time = true;
692 info_buf.LastWriteTime =
693 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
694 } else
695 info_buf.LastWriteTime = 0;
696
697 /*
698 * Samba throws this field away, but windows may actually use it.
699 * Do not set ctime unless other time stamps are changed explicitly
700 * (i.e. by utimes()) since we would then have a mix of client and
701 * server times.
702 */
703 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
704 cFYI(1, ("CIFS - CTIME changed"));
705 info_buf.ChangeTime =
706 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
707 } else
708 info_buf.ChangeTime = 0;
709
710 info_buf.CreationTime = 0; /* don't change */
711 info_buf.Attributes = cpu_to_le32(dosattr);
712
713 /*
714 * If the file is already open for write, just use that fileid
715 */
716 open_file = find_writable_file(cifsInode);
717 if (open_file) {
718 netfid = open_file->netfid;
719 netpid = open_file->pid;
720 goto set_via_filehandle;
721 }
722
723 /*
724 * NT4 apparently returns success on this call, but it doesn't
725 * really work.
726 */
727 if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
728 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
729 &info_buf, cifs_sb->local_nls,
730 cifs_sb->mnt_cifs_flags &
731 CIFS_MOUNT_MAP_SPECIAL_CHR);
732 if (rc == 0) {
733 cifsInode->cifsAttrs = dosattr;
734 goto out;
735 } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
736 goto out;
737 }
738
739 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
740 "times not supported by this server"));
741 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
742 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
743 CREATE_NOT_DIR, &netfid, &oplock,
744 NULL, cifs_sb->local_nls,
745 cifs_sb->mnt_cifs_flags &
746 CIFS_MOUNT_MAP_SPECIAL_CHR);
747
748 if (rc != 0) {
749 if (rc == -EIO)
750 rc = -EINVAL;
751 goto out;
752 }
753
754 netpid = current->tgid;
755
756set_via_filehandle:
757 rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
758 if (!rc)
759 cifsInode->cifsAttrs = dosattr;
760
761 if (open_file == NULL)
762 CIFSSMBClose(xid, pTcon, netfid);
763 else
764 atomic_dec(&open_file->wrtPending);
765out:
766 return rc;
767}
768
769/*
770 * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
771 * and rename it to a random name that hopefully won't conflict with
772 * anything else.
773 */
774static int
775cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid)
776{
777 int oplock = 0;
778 int rc;
779 __u16 netfid;
780 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
781 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
782 struct cifsTconInfo *tcon = cifs_sb->tcon;
783 __u32 dosattr;
784 FILE_BASIC_INFO *info_buf;
785
786 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
787 DELETE|FILE_WRITE_ATTRIBUTES,
788 CREATE_NOT_DIR|CREATE_DELETE_ON_CLOSE,
789 &netfid, &oplock, NULL, cifs_sb->local_nls,
790 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
791 if (rc != 0)
792 goto out;
793
794 /* set ATTR_HIDDEN and clear ATTR_READONLY */
795 cifsInode = CIFS_I(inode);
796 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
797 if (dosattr == 0)
798 dosattr |= ATTR_NORMAL;
799 dosattr |= ATTR_HIDDEN;
800
801 info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
802 if (info_buf == NULL) {
803 rc = -ENOMEM;
804 goto out_close;
805 }
806 info_buf->Attributes = cpu_to_le32(dosattr);
807 rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, current->tgid);
808 kfree(info_buf);
809 if (rc != 0)
810 goto out_close;
811 cifsInode->cifsAttrs = dosattr;
812
813 /* silly-rename the file */
814 CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
815 cifs_sb->mnt_cifs_flags &
816 CIFS_MOUNT_MAP_SPECIAL_CHR);
817
818 /* set DELETE_ON_CLOSE */
819 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid);
820
821 /*
822 * some samba versions return -ENOENT when we try to set the file
823 * disposition here. Likely a samba bug, but work around it for now
824 */
825 if (rc == -ENOENT)
826 rc = 0;
827
828out_close:
829 CIFSSMBClose(xid, tcon, netfid);
830out:
831 return rc;
832}
833
834int cifs_unlink(struct inode *dir, struct dentry *dentry)
669{ 835{
670 int rc = 0; 836 int rc = 0;
671 int xid; 837 int xid;
672 struct cifs_sb_info *cifs_sb;
673 struct cifsTconInfo *pTcon;
674 char *full_path = NULL; 838 char *full_path = NULL;
675 struct cifsInodeInfo *cifsInode; 839 struct inode *inode = dentry->d_inode;
676 FILE_BASIC_INFO *pinfo_buf; 840 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
841 struct super_block *sb = dir->i_sb;
842 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
843 struct cifsTconInfo *tcon = cifs_sb->tcon;
844 struct iattr *attrs = NULL;
845 __u32 dosattr = 0, origattr = 0;
677 846
678 cFYI(1, ("cifs_unlink, inode = 0x%p", inode)); 847 cFYI(1, ("cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry));
679 848
680 xid = GetXid(); 849 xid = GetXid();
681 850
682 if (inode) 851 /* Unlink can be called from rename so we can not take the
683 cifs_sb = CIFS_SB(inode->i_sb); 852 * sb->s_vfs_rename_mutex here */
684 else 853 full_path = build_path_from_dentry(dentry);
685 cifs_sb = CIFS_SB(direntry->d_sb);
686 pTcon = cifs_sb->tcon;
687
688 /* Unlink can be called from rename so we can not grab the sem here
689 since we deadlock otherwise */
690/* mutex_lock(&direntry->d_sb->s_vfs_rename_mutex);*/
691 full_path = build_path_from_dentry(direntry);
692/* mutex_unlock(&direntry->d_sb->s_vfs_rename_mutex);*/
693 if (full_path == NULL) { 854 if (full_path == NULL) {
694 FreeXid(xid); 855 FreeXid(xid);
695 return -ENOMEM; 856 return -ENOMEM;
696 } 857 }
697 858
698 if ((pTcon->ses->capabilities & CAP_UNIX) && 859 if ((tcon->ses->capabilities & CAP_UNIX) &&
699 (CIFS_UNIX_POSIX_PATH_OPS_CAP & 860 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
700 le64_to_cpu(pTcon->fsUnixInfo.Capability))) { 861 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
701 rc = CIFSPOSIXDelFile(xid, pTcon, full_path, 862 rc = CIFSPOSIXDelFile(xid, tcon, full_path,
702 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls, 863 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
703 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 864 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
704 cFYI(1, ("posix del rc %d", rc)); 865 cFYI(1, ("posix del rc %d", rc));
@@ -706,125 +867,60 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
706 goto psx_del_no_retry; 867 goto psx_del_no_retry;
707 } 868 }
708 869
709 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls, 870retry_std_delete:
871 rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
710 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 872 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
873
711psx_del_no_retry: 874psx_del_no_retry:
712 if (!rc) { 875 if (!rc) {
713 if (direntry->d_inode) 876 if (inode)
714 drop_nlink(direntry->d_inode); 877 drop_nlink(inode);
715 } else if (rc == -ENOENT) { 878 } else if (rc == -ENOENT) {
716 d_drop(direntry); 879 d_drop(dentry);
717 } else if (rc == -ETXTBSY) { 880 } else if (rc == -ETXTBSY) {
718 int oplock = 0; 881 rc = cifs_rename_pending_delete(full_path, inode, xid);
719 __u16 netfid; 882 if (rc == 0)
720 883 drop_nlink(inode);
721 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, 884 } else if (rc == -EACCES && dosattr == 0) {
722 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, 885 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
723 &netfid, &oplock, NULL, cifs_sb->local_nls, 886 if (attrs == NULL) {
724 cifs_sb->mnt_cifs_flags & 887 rc = -ENOMEM;
725 CIFS_MOUNT_MAP_SPECIAL_CHR); 888 goto out_reval;
726 if (rc == 0) {
727 CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
728 cifs_sb->local_nls,
729 cifs_sb->mnt_cifs_flags &
730 CIFS_MOUNT_MAP_SPECIAL_CHR);
731 CIFSSMBClose(xid, pTcon, netfid);
732 if (direntry->d_inode)
733 drop_nlink(direntry->d_inode);
734 } 889 }
735 } else if (rc == -EACCES) {
736 /* try only if r/o attribute set in local lookup data? */
737 pinfo_buf = kzalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
738 if (pinfo_buf) {
739 /* ATTRS set to normal clears r/o bit */
740 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
741 if (!(pTcon->ses->flags & CIFS_SES_NT4))
742 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
743 pinfo_buf,
744 cifs_sb->local_nls,
745 cifs_sb->mnt_cifs_flags &
746 CIFS_MOUNT_MAP_SPECIAL_CHR);
747 else
748 rc = -EOPNOTSUPP;
749 890
750 if (rc == -EOPNOTSUPP) { 891 /* try to reset dos attributes */
751 int oplock = 0; 892 origattr = cifsInode->cifsAttrs;
752 __u16 netfid; 893 if (origattr == 0)
753 /* rc = CIFSSMBSetAttrLegacy(xid, pTcon, 894 origattr |= ATTR_NORMAL;
754 full_path, 895 dosattr = origattr & ~ATTR_READONLY;
755 (__u16)ATTR_NORMAL, 896 if (dosattr == 0)
756 cifs_sb->local_nls); 897 dosattr |= ATTR_NORMAL;
757 For some strange reason it seems that NT4 eats the 898 dosattr |= ATTR_HIDDEN;
758 old setattr call without actually setting the 899
759 attributes so on to the third attempted workaround 900 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
760 */ 901 if (rc != 0)
761 902 goto out_reval;
762 /* BB could scan to see if we already have it open 903
763 and pass in pid of opener to function */ 904 goto retry_std_delete;
764 rc = CIFSSMBOpen(xid, pTcon, full_path,
765 FILE_OPEN, SYNCHRONIZE |
766 FILE_WRITE_ATTRIBUTES, 0,
767 &netfid, &oplock, NULL,
768 cifs_sb->local_nls,
769 cifs_sb->mnt_cifs_flags &
770 CIFS_MOUNT_MAP_SPECIAL_CHR);
771 if (rc == 0) {
772 rc = CIFSSMBSetFileInfo(xid, pTcon,
773 pinfo_buf,
774 netfid,
775 current->tgid);
776 CIFSSMBClose(xid, pTcon, netfid);
777 }
778 }
779 kfree(pinfo_buf);
780 }
781 if (rc == 0) {
782 rc = CIFSSMBDelFile(xid, pTcon, full_path,
783 cifs_sb->local_nls,
784 cifs_sb->mnt_cifs_flags &
785 CIFS_MOUNT_MAP_SPECIAL_CHR);
786 if (!rc) {
787 if (direntry->d_inode)
788 drop_nlink(direntry->d_inode);
789 } else if (rc == -ETXTBSY) {
790 int oplock = 0;
791 __u16 netfid;
792
793 rc = CIFSSMBOpen(xid, pTcon, full_path,
794 FILE_OPEN, DELETE,
795 CREATE_NOT_DIR |
796 CREATE_DELETE_ON_CLOSE,
797 &netfid, &oplock, NULL,
798 cifs_sb->local_nls,
799 cifs_sb->mnt_cifs_flags &
800 CIFS_MOUNT_MAP_SPECIAL_CHR);
801 if (rc == 0) {
802 CIFSSMBRenameOpenFile(xid, pTcon,
803 netfid, NULL,
804 cifs_sb->local_nls,
805 cifs_sb->mnt_cifs_flags &
806 CIFS_MOUNT_MAP_SPECIAL_CHR);
807 CIFSSMBClose(xid, pTcon, netfid);
808 if (direntry->d_inode)
809 drop_nlink(direntry->d_inode);
810 }
811 /* BB if rc = -ETXTBUSY goto the rename logic BB */
812 }
813 }
814 }
815 if (direntry->d_inode) {
816 cifsInode = CIFS_I(direntry->d_inode);
817 cifsInode->time = 0; /* will force revalidate to get info
818 when needed */
819 direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
820 } 905 }
906
907 /* undo the setattr if we errored out and it's needed */
908 if (rc != 0 && dosattr != 0)
909 cifs_set_file_info(inode, attrs, xid, full_path, origattr);
910
911out_reval:
821 if (inode) { 912 if (inode) {
822 inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
823 cifsInode = CIFS_I(inode); 913 cifsInode = CIFS_I(inode);
824 cifsInode->time = 0; /* force revalidate of dir as well */ 914 cifsInode->time = 0; /* will force revalidate to get info
915 when needed */
916 inode->i_ctime = current_fs_time(sb);
825 } 917 }
918 dir->i_ctime = dir->i_mtime = current_fs_time(sb);
919 cifsInode = CIFS_I(dir);
920 CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
826 921
827 kfree(full_path); 922 kfree(full_path);
923 kfree(attrs);
828 FreeXid(xid); 924 FreeXid(xid);
829 return rc; 925 return rc;
830} 926}
@@ -869,7 +965,7 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
869 965
870int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) 966int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
871{ 967{
872 int rc = 0; 968 int rc = 0, tmprc;
873 int xid; 969 int xid;
874 struct cifs_sb_info *cifs_sb; 970 struct cifs_sb_info *cifs_sb;
875 struct cifsTconInfo *pTcon; 971 struct cifsTconInfo *pTcon;
@@ -931,6 +1027,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
931 kfree(pInfo); 1027 kfree(pInfo);
932 goto mkdir_get_info; 1028 goto mkdir_get_info;
933 } 1029 }
1030
934 /* Is an i_ino of zero legal? */ 1031 /* Is an i_ino of zero legal? */
935 /* Are there sanity checks we can use to ensure that 1032 /* Are there sanity checks we can use to ensure that
936 the server is really filling in that field? */ 1033 the server is really filling in that field? */
@@ -1019,12 +1116,20 @@ mkdir_get_info:
1019 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 1116 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1020 (mode & S_IWUGO) == 0) { 1117 (mode & S_IWUGO) == 0) {
1021 FILE_BASIC_INFO pInfo; 1118 FILE_BASIC_INFO pInfo;
1119 struct cifsInodeInfo *cifsInode;
1120 u32 dosattrs;
1121
1022 memset(&pInfo, 0, sizeof(pInfo)); 1122 memset(&pInfo, 0, sizeof(pInfo));
1023 pInfo.Attributes = cpu_to_le32(ATTR_READONLY); 1123 cifsInode = CIFS_I(newinode);
1024 CIFSSMBSetPathInfo(xid, pTcon, full_path, 1124 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
1025 &pInfo, cifs_sb->local_nls, 1125 pInfo.Attributes = cpu_to_le32(dosattrs);
1126 tmprc = CIFSSMBSetPathInfo(xid, pTcon,
1127 full_path, &pInfo,
1128 cifs_sb->local_nls,
1026 cifs_sb->mnt_cifs_flags & 1129 cifs_sb->mnt_cifs_flags &
1027 CIFS_MOUNT_MAP_SPECIAL_CHR); 1130 CIFS_MOUNT_MAP_SPECIAL_CHR);
1131 if (tmprc == 0)
1132 cifsInode->cifsAttrs = dosattrs;
1028 } 1133 }
1029 if (direntry->d_inode) { 1134 if (direntry->d_inode) {
1030 if (cifs_sb->mnt_cifs_flags & 1135 if (cifs_sb->mnt_cifs_flags &
@@ -1096,117 +1201,141 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1096 return rc; 1201 return rc;
1097} 1202}
1098 1203
1204static int
1205cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
1206 struct dentry *to_dentry, const char *toPath)
1207{
1208 struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
1209 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1210 __u16 srcfid;
1211 int oplock, rc;
1212
1213 /* try path-based rename first */
1214 rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
1215 cifs_sb->mnt_cifs_flags &
1216 CIFS_MOUNT_MAP_SPECIAL_CHR);
1217
1218 /*
1219 * don't bother with rename by filehandle unless file is busy and
1220 * source Note that cross directory moves do not work with
1221 * rename by filehandle to various Windows servers.
1222 */
1223 if (rc == 0 || rc != -ETXTBSY)
1224 return rc;
1225
1226 /* open the file to be renamed -- we need DELETE perms */
1227 rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
1228 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
1229 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1230 CIFS_MOUNT_MAP_SPECIAL_CHR);
1231
1232 if (rc == 0) {
1233 rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
1234 (const char *) to_dentry->d_name.name,
1235 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1236 CIFS_MOUNT_MAP_SPECIAL_CHR);
1237
1238 CIFSSMBClose(xid, pTcon, srcfid);
1239 }
1240
1241 return rc;
1242}
1243
1099int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, 1244int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
1100 struct inode *target_inode, struct dentry *target_direntry) 1245 struct inode *target_inode, struct dentry *target_direntry)
1101{ 1246{
1102 char *fromName; 1247 char *fromName = NULL;
1103 char *toName; 1248 char *toName = NULL;
1104 struct cifs_sb_info *cifs_sb_source; 1249 struct cifs_sb_info *cifs_sb_source;
1105 struct cifs_sb_info *cifs_sb_target; 1250 struct cifs_sb_info *cifs_sb_target;
1106 struct cifsTconInfo *pTcon; 1251 struct cifsTconInfo *pTcon;
1252 FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
1253 FILE_UNIX_BASIC_INFO *info_buf_target;
1107 int xid; 1254 int xid;
1108 int rc = 0; 1255 int rc;
1109
1110 xid = GetXid();
1111 1256
1112 cifs_sb_target = CIFS_SB(target_inode->i_sb); 1257 cifs_sb_target = CIFS_SB(target_inode->i_sb);
1113 cifs_sb_source = CIFS_SB(source_inode->i_sb); 1258 cifs_sb_source = CIFS_SB(source_inode->i_sb);
1114 pTcon = cifs_sb_source->tcon; 1259 pTcon = cifs_sb_source->tcon;
1115 1260
1261 xid = GetXid();
1262
1263 /*
1264 * BB: this might be allowed if same server, but different share.
1265 * Consider adding support for this
1266 */
1116 if (pTcon != cifs_sb_target->tcon) { 1267 if (pTcon != cifs_sb_target->tcon) {
1117 FreeXid(xid); 1268 rc = -EXDEV;
1118 return -EXDEV; /* BB actually could be allowed if same server, 1269 goto cifs_rename_exit;
1119 but different share.
1120 Might eventually add support for this */
1121 } 1270 }
1122 1271
1123 /* we already have the rename sem so we do not need to grab it again 1272 /*
1124 here to protect the path integrity */ 1273 * we already have the rename sem so we do not need to
1274 * grab it again here to protect the path integrity
1275 */
1125 fromName = build_path_from_dentry(source_direntry); 1276 fromName = build_path_from_dentry(source_direntry);
1277 if (fromName == NULL) {
1278 rc = -ENOMEM;
1279 goto cifs_rename_exit;
1280 }
1281
1126 toName = build_path_from_dentry(target_direntry); 1282 toName = build_path_from_dentry(target_direntry);
1127 if ((fromName == NULL) || (toName == NULL)) { 1283 if (toName == NULL) {
1128 rc = -ENOMEM; 1284 rc = -ENOMEM;
1129 goto cifs_rename_exit; 1285 goto cifs_rename_exit;
1130 } 1286 }
1131 1287
1132 rc = CIFSSMBRename(xid, pTcon, fromName, toName, 1288 rc = cifs_do_rename(xid, source_direntry, fromName,
1133 cifs_sb_source->local_nls, 1289 target_direntry, toName);
1134 cifs_sb_source->mnt_cifs_flags & 1290
1135 CIFS_MOUNT_MAP_SPECIAL_CHR);
1136 if (rc == -EEXIST) { 1291 if (rc == -EEXIST) {
1137 /* check if they are the same file because rename of hardlinked 1292 if (pTcon->unix_ext) {
1138 files is a noop */ 1293 /*
1139 FILE_UNIX_BASIC_INFO *info_buf_source; 1294 * Are src and dst hardlinks of same inode? We can
1140 FILE_UNIX_BASIC_INFO *info_buf_target; 1295 * only tell with unix extensions enabled
1141 1296 */
1142 info_buf_source = 1297 info_buf_source =
1143 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); 1298 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
1144 if (info_buf_source != NULL) { 1299 GFP_KERNEL);
1300 if (info_buf_source == NULL)
1301 goto unlink_target;
1302
1145 info_buf_target = info_buf_source + 1; 1303 info_buf_target = info_buf_source + 1;
1146 if (pTcon->unix_ext) 1304 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
1147 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, 1305 info_buf_source,
1148 info_buf_source, 1306 cifs_sb_source->local_nls,
1149 cifs_sb_source->local_nls, 1307 cifs_sb_source->mnt_cifs_flags &
1150 cifs_sb_source->mnt_cifs_flags &
1151 CIFS_MOUNT_MAP_SPECIAL_CHR); 1308 CIFS_MOUNT_MAP_SPECIAL_CHR);
1152 /* else rc is still EEXIST so will fall through to 1309 if (rc != 0)
1153 unlink the target and retry rename */ 1310 goto unlink_target;
1154 if (rc == 0) { 1311
1155 rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName, 1312 rc = CIFSSMBUnixQPathInfo(xid, pTcon,
1156 info_buf_target, 1313 toName, info_buf_target,
1157 cifs_sb_target->local_nls, 1314 cifs_sb_target->local_nls,
1158 /* remap based on source sb */ 1315 /* remap based on source sb */
1159 cifs_sb_source->mnt_cifs_flags & 1316 cifs_sb_source->mnt_cifs_flags &
1160 CIFS_MOUNT_MAP_SPECIAL_CHR);
1161 }
1162 if ((rc == 0) &&
1163 (info_buf_source->UniqueId ==
1164 info_buf_target->UniqueId)) {
1165 /* do not rename since the files are hardlinked which
1166 is a noop */
1167 } else {
1168 /* we either can not tell the files are hardlinked
1169 (as with Windows servers) or files are not
1170 hardlinked so delete the target manually before
1171 renaming to follow POSIX rather than Windows
1172 semantics */
1173 cifs_unlink(target_inode, target_direntry);
1174 rc = CIFSSMBRename(xid, pTcon, fromName,
1175 toName,
1176 cifs_sb_source->local_nls,
1177 cifs_sb_source->mnt_cifs_flags
1178 & CIFS_MOUNT_MAP_SPECIAL_CHR);
1179 }
1180 kfree(info_buf_source);
1181 } /* if we can not get memory just leave rc as EEXIST */
1182 }
1183
1184 if (rc)
1185 cFYI(1, ("rename rc %d", rc));
1186
1187 if ((rc == -EIO) || (rc == -EEXIST)) {
1188 int oplock = 0;
1189 __u16 netfid;
1190
1191 /* BB FIXME Is Generic Read correct for rename? */
1192 /* if renaming directory - we should not say CREATE_NOT_DIR,
1193 need to test renaming open directory, also GENERIC_READ
1194 might not right be right access to request */
1195 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
1196 CREATE_NOT_DIR, &netfid, &oplock, NULL,
1197 cifs_sb_source->local_nls,
1198 cifs_sb_source->mnt_cifs_flags &
1199 CIFS_MOUNT_MAP_SPECIAL_CHR);
1200 if (rc == 0) {
1201 rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
1202 cifs_sb_source->local_nls,
1203 cifs_sb_source->mnt_cifs_flags &
1204 CIFS_MOUNT_MAP_SPECIAL_CHR); 1317 CIFS_MOUNT_MAP_SPECIAL_CHR);
1205 CIFSSMBClose(xid, pTcon, netfid); 1318
1206 } 1319 if (rc == 0 && (info_buf_source->UniqueId ==
1320 info_buf_target->UniqueId))
1321 /* same file, POSIX says that this is a noop */
1322 goto cifs_rename_exit;
1323 } /* else ... BB we could add the same check for Windows by
1324 checking the UniqueId via FILE_INTERNAL_INFO */
1325unlink_target:
1326 /*
1327 * we either can not tell the files are hardlinked (as with
1328 * Windows servers) or files are not hardlinked. Delete the
1329 * target manually before renaming to follow POSIX rather than
1330 * Windows semantics
1331 */
1332 cifs_unlink(target_inode, target_direntry);
1333 rc = cifs_do_rename(xid, source_direntry, fromName,
1334 target_direntry, toName);
1207 } 1335 }
1208 1336
1209cifs_rename_exit: 1337cifs_rename_exit:
1338 kfree(info_buf_source);
1210 kfree(fromName); 1339 kfree(fromName);
1211 kfree(toName); 1340 kfree(toName);
1212 FreeXid(xid); 1341 FreeXid(xid);
@@ -1507,101 +1636,6 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
1507} 1636}
1508 1637
1509static int 1638static int
1510cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
1511 char *full_path, __u32 dosattr)
1512{
1513 int rc;
1514 int oplock = 0;
1515 __u16 netfid;
1516 __u32 netpid;
1517 bool set_time = false;
1518 struct cifsFileInfo *open_file;
1519 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1520 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1521 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1522 FILE_BASIC_INFO info_buf;
1523
1524 if (attrs->ia_valid & ATTR_ATIME) {
1525 set_time = true;
1526 info_buf.LastAccessTime =
1527 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1528 } else
1529 info_buf.LastAccessTime = 0;
1530
1531 if (attrs->ia_valid & ATTR_MTIME) {
1532 set_time = true;
1533 info_buf.LastWriteTime =
1534 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1535 } else
1536 info_buf.LastWriteTime = 0;
1537
1538 /*
1539 * Samba throws this field away, but windows may actually use it.
1540 * Do not set ctime unless other time stamps are changed explicitly
1541 * (i.e. by utimes()) since we would then have a mix of client and
1542 * server times.
1543 */
1544 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
1545 cFYI(1, ("CIFS - CTIME changed"));
1546 info_buf.ChangeTime =
1547 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1548 } else
1549 info_buf.ChangeTime = 0;
1550
1551 info_buf.CreationTime = 0; /* don't change */
1552 info_buf.Attributes = cpu_to_le32(dosattr);
1553
1554 /*
1555 * If the file is already open for write, just use that fileid
1556 */
1557 open_file = find_writable_file(cifsInode);
1558 if (open_file) {
1559 netfid = open_file->netfid;
1560 netpid = open_file->pid;
1561 goto set_via_filehandle;
1562 }
1563
1564 /*
1565 * NT4 apparently returns success on this call, but it doesn't
1566 * really work.
1567 */
1568 if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
1569 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
1570 &info_buf, cifs_sb->local_nls,
1571 cifs_sb->mnt_cifs_flags &
1572 CIFS_MOUNT_MAP_SPECIAL_CHR);
1573 if (rc != -EOPNOTSUPP && rc != -EINVAL)
1574 goto out;
1575 }
1576
1577 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1578 "times not supported by this server"));
1579 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1580 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1581 CREATE_NOT_DIR, &netfid, &oplock,
1582 NULL, cifs_sb->local_nls,
1583 cifs_sb->mnt_cifs_flags &
1584 CIFS_MOUNT_MAP_SPECIAL_CHR);
1585
1586 if (rc != 0) {
1587 if (rc == -EIO)
1588 rc = -EINVAL;
1589 goto out;
1590 }
1591
1592 netpid = current->tgid;
1593
1594set_via_filehandle:
1595 rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
1596 if (open_file == NULL)
1597 CIFSSMBClose(xid, pTcon, netfid);
1598 else
1599 atomic_dec(&open_file->wrtPending);
1600out:
1601 return rc;
1602}
1603
1604static int
1605cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) 1639cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
1606{ 1640{
1607 int rc; 1641 int rc;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 4b17f8fe3157..654d972a88f4 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -150,8 +150,7 @@ cifs_buf_get(void)
150 but it may be more efficient to always alloc same size 150 but it may be more efficient to always alloc same size
151 albeit slightly larger than necessary and maxbuffersize 151 albeit slightly larger than necessary and maxbuffersize
152 defaults to this and can not be bigger */ 152 defaults to this and can not be bigger */
153 ret_buf = (struct smb_hdr *) mempool_alloc(cifs_req_poolp, 153 ret_buf = mempool_alloc(cifs_req_poolp, GFP_NOFS);
154 GFP_KERNEL | GFP_NOFS);
155 154
156 /* clear the first few header bytes */ 155 /* clear the first few header bytes */
157 /* for most paths, more is cleared in header_assemble */ 156 /* for most paths, more is cleared in header_assemble */
@@ -188,8 +187,7 @@ cifs_small_buf_get(void)
188 but it may be more efficient to always alloc same size 187 but it may be more efficient to always alloc same size
189 albeit slightly larger than necessary and maxbuffersize 188 albeit slightly larger than necessary and maxbuffersize
190 defaults to this and can not be bigger */ 189 defaults to this and can not be bigger */
191 ret_buf = (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, 190 ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS);
192 GFP_KERNEL | GFP_NOFS);
193 if (ret_buf) { 191 if (ret_buf) {
194 /* No need to clear memory here, cleared in header assemble */ 192 /* No need to clear memory here, cleared in header assemble */
195 /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/ 193 /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 5f40ed3473f5..765adf12d54f 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -640,6 +640,70 @@ static int is_dir_changed(struct file *file)
640 640
641} 641}
642 642
643static int cifs_save_resume_key(const char *current_entry,
644 struct cifsFileInfo *cifsFile)
645{
646 int rc = 0;
647 unsigned int len = 0;
648 __u16 level;
649 char *filename;
650
651 if ((cifsFile == NULL) || (current_entry == NULL))
652 return -EINVAL;
653
654 level = cifsFile->srch_inf.info_level;
655
656 if (level == SMB_FIND_FILE_UNIX) {
657 FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
658
659 filename = &pFindData->FileName[0];
660 if (cifsFile->srch_inf.unicode) {
661 len = cifs_unicode_bytelen(filename);
662 } else {
663 /* BB should we make this strnlen of PATH_MAX? */
664 len = strnlen(filename, PATH_MAX);
665 }
666 cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
667 } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
668 FILE_DIRECTORY_INFO *pFindData =
669 (FILE_DIRECTORY_INFO *)current_entry;
670 filename = &pFindData->FileName[0];
671 len = le32_to_cpu(pFindData->FileNameLength);
672 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
673 } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
674 FILE_FULL_DIRECTORY_INFO *pFindData =
675 (FILE_FULL_DIRECTORY_INFO *)current_entry;
676 filename = &pFindData->FileName[0];
677 len = le32_to_cpu(pFindData->FileNameLength);
678 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
679 } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
680 SEARCH_ID_FULL_DIR_INFO *pFindData =
681 (SEARCH_ID_FULL_DIR_INFO *)current_entry;
682 filename = &pFindData->FileName[0];
683 len = le32_to_cpu(pFindData->FileNameLength);
684 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
685 } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
686 FILE_BOTH_DIRECTORY_INFO *pFindData =
687 (FILE_BOTH_DIRECTORY_INFO *)current_entry;
688 filename = &pFindData->FileName[0];
689 len = le32_to_cpu(pFindData->FileNameLength);
690 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
691 } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
692 FIND_FILE_STANDARD_INFO *pFindData =
693 (FIND_FILE_STANDARD_INFO *)current_entry;
694 filename = &pFindData->FileName[0];
695 /* one byte length, no name conversion */
696 len = (unsigned int)pFindData->FileNameLength;
697 cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
698 } else {
699 cFYI(1, ("Unknown findfirst level %d", level));
700 return -EINVAL;
701 }
702 cifsFile->srch_inf.resume_name_len = len;
703 cifsFile->srch_inf.presume_name = filename;
704 return rc;
705}
706
643/* find the corresponding entry in the search */ 707/* find the corresponding entry in the search */
644/* Note that the SMB server returns search entries for . and .. which 708/* Note that the SMB server returns search entries for . and .. which
645 complicates logic here if we choose to parse for them and we do not 709 complicates logic here if we choose to parse for them and we do not
@@ -703,6 +767,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
703 while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 767 while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
704 (rc == 0) && !cifsFile->srch_inf.endOfSearch) { 768 (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
705 cFYI(1, ("calling findnext2")); 769 cFYI(1, ("calling findnext2"));
770 cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
706 rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, 771 rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
707 &cifsFile->srch_inf); 772 &cifsFile->srch_inf);
708 if (rc) 773 if (rc)
@@ -919,69 +984,6 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
919 return rc; 984 return rc;
920} 985}
921 986
922static int cifs_save_resume_key(const char *current_entry,
923 struct cifsFileInfo *cifsFile)
924{
925 int rc = 0;
926 unsigned int len = 0;
927 __u16 level;
928 char *filename;
929
930 if ((cifsFile == NULL) || (current_entry == NULL))
931 return -EINVAL;
932
933 level = cifsFile->srch_inf.info_level;
934
935 if (level == SMB_FIND_FILE_UNIX) {
936 FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
937
938 filename = &pFindData->FileName[0];
939 if (cifsFile->srch_inf.unicode) {
940 len = cifs_unicode_bytelen(filename);
941 } else {
942 /* BB should we make this strnlen of PATH_MAX? */
943 len = strnlen(filename, PATH_MAX);
944 }
945 cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
946 } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
947 FILE_DIRECTORY_INFO *pFindData =
948 (FILE_DIRECTORY_INFO *)current_entry;
949 filename = &pFindData->FileName[0];
950 len = le32_to_cpu(pFindData->FileNameLength);
951 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
952 } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
953 FILE_FULL_DIRECTORY_INFO *pFindData =
954 (FILE_FULL_DIRECTORY_INFO *)current_entry;
955 filename = &pFindData->FileName[0];
956 len = le32_to_cpu(pFindData->FileNameLength);
957 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
958 } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
959 SEARCH_ID_FULL_DIR_INFO *pFindData =
960 (SEARCH_ID_FULL_DIR_INFO *)current_entry;
961 filename = &pFindData->FileName[0];
962 len = le32_to_cpu(pFindData->FileNameLength);
963 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
964 } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
965 FILE_BOTH_DIRECTORY_INFO *pFindData =
966 (FILE_BOTH_DIRECTORY_INFO *)current_entry;
967 filename = &pFindData->FileName[0];
968 len = le32_to_cpu(pFindData->FileNameLength);
969 cifsFile->srch_inf.resume_key = pFindData->FileIndex;
970 } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
971 FIND_FILE_STANDARD_INFO *pFindData =
972 (FIND_FILE_STANDARD_INFO *)current_entry;
973 filename = &pFindData->FileName[0];
974 /* one byte length, no name conversion */
975 len = (unsigned int)pFindData->FileNameLength;
976 cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
977 } else {
978 cFYI(1, ("Unknown findfirst level %d", level));
979 return -EINVAL;
980 }
981 cifsFile->srch_inf.resume_name_len = len;
982 cifsFile->srch_inf.presume_name = filename;
983 return rc;
984}
985 987
986int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) 988int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
987{ 989{
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 252fdc0567f1..2851d5da0c8c 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -624,8 +624,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
624 ses, nls_cp); 624 ses, nls_cp);
625 625
626ssetup_exit: 626ssetup_exit:
627 if (spnego_key) 627 if (spnego_key) {
628 key_revoke(spnego_key);
628 key_put(spnego_key); 629 key_put(spnego_key);
630 }
629 kfree(str_area); 631 kfree(str_area);
630 if (resp_buf_type == CIFS_SMALL_BUFFER) { 632 if (resp_buf_type == CIFS_SMALL_BUFFER) {
631 cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base)); 633 cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base));
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index e286db9f5ee2..bf0e6d8e382a 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -50,8 +50,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
50 return NULL; 50 return NULL;
51 } 51 }
52 52
53 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp, 53 temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
54 GFP_KERNEL | GFP_NOFS);
55 if (temp == NULL) 54 if (temp == NULL)
56 return temp; 55 return temp;
57 else { 56 else {