diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/cifs/cifs_spnego.c | 35 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 84 | ||||
| -rw-r--r-- | fs/cifs/dns_resolve.c | 74 | ||||
| -rw-r--r-- | fs/cifs/file.c | 130 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 644 | ||||
| -rw-r--r-- | fs/cifs/misc.c | 6 | ||||
| -rw-r--r-- | fs/cifs/readdir.c | 128 | ||||
| -rw-r--r-- | fs/cifs/sess.c | 4 | ||||
| -rw-r--r-- | fs/cifs/transport.c | 3 |
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 */ |
| 75 | struct key * | 92 | struct key * |
| 76 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | 93 | cifs_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 *); |
| 42 | extern struct dentry *cifs_lookup(struct inode *, struct dentry *, | 42 | extern struct dentry *cifs_lookup(struct inode *, struct dentry *, |
| 43 | struct nameidata *); | 43 | struct nameidata *); |
| 44 | extern int cifs_unlink(struct inode *, struct dentry *); | 44 | extern int cifs_unlink(struct inode *dir, struct dentry *dentry); |
| 45 | extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); | 45 | extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); |
| 46 | extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t); | 46 | extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t); |
| 47 | extern int cifs_mkdir(struct inode *, struct dentry *, int); | 47 | extern 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, | |||
| 179 | extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, | 179 | extern 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); |
| 182 | extern int CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon, | ||
| 183 | bool delete_file, __u16 fid, __u32 pid_of_opener); | ||
| 182 | #if 0 | 184 | #if 0 |
| 183 | extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, | 185 | extern 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); |
| 231 | extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, | 233 | extern 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); |
| 235 | extern int CIFSCreateHardLink(const int xid, | 237 | extern 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 | ||
| 2019 | int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, | 2019 | int 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 | ||
| 4904 | int | ||
| 4905 | CIFSSMBSetFileDisposition(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 | ||
| 4880 | int | 4960 | int |
| 4881 | CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon, | 4961 | CIFSSMBSetPathInfo(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 | ||
| 32 | static 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 | */ | ||
| 37 | static int | ||
| 38 | is_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 | |||
| 60 | static int | ||
| 61 | dns_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 | */ | ||
| 70 | static 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 | ||
| 149 | skip_upcall: | 159 | skip_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 | ||
| 917 | static ssize_t cifs_write(struct file *file, const char *write_data, | 917 | static 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) | |||
| 1065 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | 1065 | struct 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); |
| 1081 | refind_writable: | 1082 | refind_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 | ||
| 1450 | static int cifs_commit_write(struct file *file, struct page *page, | 1458 | static 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 | ||
| 2038 | static int cifs_prepare_write(struct file *file, struct page *page, | 2049 | static 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 | ||
| 668 | int cifs_unlink(struct inode *inode, struct dentry *direntry) | 668 | static int |
| 669 | cifs_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 | |||
| 756 | set_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); | ||
| 765 | out: | ||
| 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 | */ | ||
| 774 | static int | ||
| 775 | cifs_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 | |||
| 828 | out_close: | ||
| 829 | CIFSSMBClose(xid, tcon, netfid); | ||
| 830 | out: | ||
| 831 | return rc; | ||
| 832 | } | ||
| 833 | |||
| 834 | int 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, | 870 | retry_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 | |||
| 711 | psx_del_no_retry: | 874 | psx_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 | |||
| 911 | out_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 | ||
| 870 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | 966 | int 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 | ||
| 1204 | static int | ||
| 1205 | cifs_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 | |||
| 1099 | int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, | 1244 | int 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 */ | ||
| 1325 | unlink_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 | ||
| 1209 | cifs_rename_exit: | 1337 | cifs_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 | ||
| 1509 | static int | 1638 | static int |
| 1510 | cifs_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 | |||
| 1594 | set_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); | ||
| 1600 | out: | ||
| 1601 | return rc; | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | static int | ||
| 1605 | cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | 1639 | cifs_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 | ||
| 643 | static 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 | ||
| 922 | static 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 | ||
| 986 | int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | 988 | int 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 | ||
| 626 | ssetup_exit: | 626 | ssetup_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 { |
