Commit 86ed5a93 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  [CIFS] Check that last search entry resume key is valid
  [CIFS] make sure we have the right resume info before calling CIFSFindNext
  [CIFS]  clean up error handling in cifs_unlink
  [CIFS] fix some settings of cifsAttrs after calling SetFileInfo and SetPathInfo
  cifs: explicitly revoke SPNEGO key after session setup
  cifs: Convert cifs to new aops.
  [CIFS] update DOS attributes in cifsInode if we successfully changed them
  cifs: remove NULL termination from rename target in CIFSSMBRenameOpenFIle
  cifs: work around samba returning -ENOENT on SetFileDisposition call
  cifs: fix inverted NULL check after kmalloc
  [CIFS] clean up upcall handling for dns_resolver keys
  [CIFS]  fix busy-file renames and refactor cifs_rename logic
  cifs: add function to set file disposition
  [CIFS] add constants for string lengths of keynames in SPNEGO upcall string
  cifs: move rename and delete-on-close logic into helper function
  cifs: have find_writeable_file prefer filehandles opened by same task
  cifs: don't use GFP_KERNEL with GFP_NOFS
  [CIFS] use common code for turning off ATTR_READONLY in cifs_unlink
  cifs: clean up variables in cifs_unlink
parents 835a1c09 b77d753c
...@@ -66,11 +66,28 @@ struct key_type cifs_spnego_key_type = { ...@@ -66,11 +66,28 @@ struct key_type cifs_spnego_key_type = {
.describe = user_describe, .describe = user_describe,
}; };
#define MAX_VER_STR_LEN 8 /* length of longest version string e.g. /* length of longest version string e.g. strlen("ver=0xFF") */
strlen("ver=0xFF") */ #define MAX_VER_STR_LEN 8
#define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg
in future could have strlen(";sec=ntlmsspi") */ /* length of longest security mechanism name, eg in future could have
#define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ * strlen(";sec=ntlmsspi") */
#define MAX_MECH_STR_LEN 13
/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
#define MAX_IPV6_ADDR_LEN 42
/* strlen of "host=" */
#define HOST_KEY_LEN 5
/* strlen of ";ip4=" or ";ip6=" */
#define IP_KEY_LEN 5
/* strlen of ";uid=0x" */
#define UID_KEY_LEN 7
/* strlen of ";user=" */
#define USER_KEY_LEN 6
/* get a key struct with a SPNEGO security blob, suitable for session setup */ /* get a key struct with a SPNEGO security blob, suitable for session setup */
struct key * struct key *
cifs_get_spnego_key(struct cifsSesInfo *sesInfo) cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
...@@ -84,11 +101,11 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) ...@@ -84,11 +101,11 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
/* length of fields (with semicolons): ver=0xyz ip4=ipaddress /* length of fields (with semicolons): ver=0xyz ip4=ipaddress
host=hostname sec=mechanism uid=0xFF user=username */ host=hostname sec=mechanism uid=0xFF user=username */
desc_len = MAX_VER_STR_LEN + desc_len = MAX_VER_STR_LEN +
6 /* len of "host=" */ + strlen(hostname) + HOST_KEY_LEN + strlen(hostname) +
5 /* len of ";ipv4=" */ + MAX_IPV6_ADDR_LEN + IP_KEY_LEN + MAX_IPV6_ADDR_LEN +
MAX_MECH_STR_LEN + MAX_MECH_STR_LEN +
7 /* len of ";uid=0x" */ + (sizeof(uid_t) * 2) + UID_KEY_LEN + (sizeof(uid_t) * 2) +
6 /* len of ";user=" */ + strlen(sesInfo->userName) + 1; USER_KEY_LEN + strlen(sesInfo->userName) + 1;
spnego_key = ERR_PTR(-ENOMEM); spnego_key = ERR_PTR(-ENOMEM);
description = kzalloc(desc_len, GFP_KERNEL); description = kzalloc(desc_len, GFP_KERNEL);
......
...@@ -41,7 +41,7 @@ extern int cifs_create(struct inode *, struct dentry *, int, ...@@ -41,7 +41,7 @@ extern int cifs_create(struct inode *, struct dentry *, int,
struct nameidata *); struct nameidata *);
extern struct dentry *cifs_lookup(struct inode *, struct dentry *, extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
struct nameidata *); struct nameidata *);
extern int cifs_unlink(struct inode *, struct dentry *); extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t); extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t);
extern int cifs_mkdir(struct inode *, struct dentry *, int); extern int cifs_mkdir(struct inode *, struct dentry *, int);
......
...@@ -309,6 +309,7 @@ struct cifs_search_info { ...@@ -309,6 +309,7 @@ struct cifs_search_info {
__u32 resume_key; __u32 resume_key;
char *ntwrk_buf_start; char *ntwrk_buf_start;
char *srch_entries_start; char *srch_entries_start;
char *last_entry;
char *presume_name; char *presume_name;
unsigned int resume_name_len; unsigned int resume_name_len;
bool endOfSearch:1; bool endOfSearch:1;
......
...@@ -179,6 +179,8 @@ extern int CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon, ...@@ -179,6 +179,8 @@ extern int CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
const FILE_BASIC_INFO *data, __u16 fid, const FILE_BASIC_INFO *data, __u16 fid,
__u32 pid_of_opener); __u32 pid_of_opener);
extern int CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
bool delete_file, __u16 fid, __u32 pid_of_opener);
#if 0 #if 0
extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon,
char *fileName, __u16 dos_attributes, char *fileName, __u16 dos_attributes,
...@@ -229,7 +231,7 @@ extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, ...@@ -229,7 +231,7 @@ extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
int netfid, char *target_name, int netfid, const char *target_name,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSCreateHardLink(const int xid, extern int CIFSCreateHardLink(const int xid,
......
...@@ -2017,7 +2017,7 @@ CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, ...@@ -2017,7 +2017,7 @@ CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
} }
int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
int netfid, char *target_name, int netfid, const char *target_name,
const struct nls_table *nls_codepage, int remap) const struct nls_table *nls_codepage, int remap)
{ {
struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_req *pSMB = NULL;
...@@ -2071,7 +2071,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, ...@@ -2071,7 +2071,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
remap); remap);
} }
rename_info->target_name_len = cpu_to_le32(2 * len_of_str); rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2; count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
byte_count += count; byte_count += count;
pSMB->DataCount = cpu_to_le16(count); pSMB->DataCount = cpu_to_le16(count);
pSMB->TotalDataCount = pSMB->DataCount; pSMB->TotalDataCount = pSMB->DataCount;
...@@ -3614,6 +3614,8 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, ...@@ -3614,6 +3614,8 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
/* BB remember to free buffer if error BB */ /* BB remember to free buffer if error BB */
rc = validate_t2((struct smb_t2_rsp *)pSMBr); rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc == 0) { if (rc == 0) {
unsigned int lnoff;
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
psrch_inf->unicode = true; psrch_inf->unicode = true;
else else
...@@ -3636,6 +3638,17 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, ...@@ -3636,6 +3638,17 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
le16_to_cpu(parms->SearchCount); le16_to_cpu(parms->SearchCount);
psrch_inf->index_of_last_entry = 2 /* skip . and .. */ + psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
psrch_inf->entries_in_buffer; psrch_inf->entries_in_buffer;
lnoff = le16_to_cpu(parms->LastNameOffset);
if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
lnoff) {
cERROR(1, ("ignoring corrupt resume name"));
psrch_inf->last_entry = NULL;
return rc;
}
psrch_inf->last_entry = psrch_inf->srch_entries_start +
lnoff;
*pnetfid = parms->SearchHandle; *pnetfid = parms->SearchHandle;
} else { } else {
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
...@@ -3725,6 +3738,8 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, ...@@ -3725,6 +3738,8 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
rc = validate_t2((struct smb_t2_rsp *)pSMBr); rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc == 0) { if (rc == 0) {
unsigned int lnoff;
/* BB fixme add lock for file (srch_info) struct here */ /* BB fixme add lock for file (srch_info) struct here */
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
psrch_inf->unicode = true; psrch_inf->unicode = true;
...@@ -3751,6 +3766,16 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, ...@@ -3751,6 +3766,16 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
le16_to_cpu(parms->SearchCount); le16_to_cpu(parms->SearchCount);
psrch_inf->index_of_last_entry += psrch_inf->index_of_last_entry +=
psrch_inf->entries_in_buffer; psrch_inf->entries_in_buffer;
lnoff = le16_to_cpu(parms->LastNameOffset);
if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
lnoff) {
cERROR(1, ("ignoring corrupt resume name"));
psrch_inf->last_entry = NULL;
return rc;
} else
psrch_inf->last_entry =
psrch_inf->srch_entries_start + lnoff;
/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d", /* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */ psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
...@@ -4876,6 +4901,61 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, ...@@ -4876,6 +4901,61 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
return rc; return rc;
} }
int
CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
bool delete_file, __u16 fid, __u32 pid_of_opener)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
char *data_offset;
int rc = 0;
__u16 params, param_offset, offset, byte_count, count;
cFYI(1, ("Set File Disposition (via SetFileInfo)"));
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
if (rc)
return rc;
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
params = 6;
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
offset = param_offset + params;
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
count = 1;
pSMB->MaxParameterCount = cpu_to_le16(2);
/* BB find max SMB PDU from sess */
pSMB->MaxDataCount = cpu_to_le16(1000);
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
byte_count = 3 /* pad */ + params + count;
pSMB->DataCount = cpu_to_le16(count);
pSMB->ParameterCount = cpu_to_le16(params);
pSMB->TotalDataCount = pSMB->DataCount;
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->ParameterOffset = cpu_to_le16(param_offset);
pSMB->DataOffset = cpu_to_le16(offset);
pSMB->Fid = fid;
pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
pSMB->Reserved4 = 0;
pSMB->hdr.smb_buf_length += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
*data_offset = delete_file ? 1 : 0;
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
if (rc)
cFYI(1, ("Send error in SetFileDisposition = %d", rc));
return rc;
}
int int
CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon, CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
......
...@@ -29,19 +29,55 @@ ...@@ -29,19 +29,55 @@
#include "cifsproto.h" #include "cifsproto.h"
#include "cifs_debug.h" #include "cifs_debug.h"
static int dns_resolver_instantiate(struct key *key, const void *data, /* Checks if supplied name is IP address
* returns:
* 1 - name is IP
* 0 - name is not IP
*/
static int
is_ip(const char *name)
{
int rc;
struct sockaddr_in sin_server;
struct sockaddr_in6 sin_server6;
rc = cifs_inet_pton(AF_INET, name,
&sin_server.sin_addr.s_addr);
if (rc <= 0) {
/* not ipv4 address, try ipv6 */
rc = cifs_inet_pton(AF_INET6, name,
&sin_server6.sin6_addr.in6_u);
if (rc > 0)
return 1;
} else {
return 1;
}
/* we failed translating address */
return 0;
}
static int
dns_resolver_instantiate(struct key *key, const void *data,
size_t datalen) size_t datalen)
{ {
int rc = 0; int rc = 0;
char *ip; char *ip;
ip = kmalloc(datalen+1, GFP_KERNEL); ip = kmalloc(datalen + 1, GFP_KERNEL);
if (!ip) if (!ip)
return -ENOMEM; return -ENOMEM;
memcpy(ip, data, datalen); memcpy(ip, data, datalen);
ip[datalen] = '\0'; ip[datalen] = '\0';
/* make sure this looks like an address */
if (!is_ip((const char *) ip)) {
kfree(ip);
return -EINVAL;
}
key->type_data.x[0] = datalen;
rcu_assign_pointer(key->payload.data, ip); rcu_assign_pointer(key->payload.data, ip);
return rc; return rc;
...@@ -62,33 +98,6 @@ struct key_type key_type_dns_resolver = { ...@@ -62,33 +98,6 @@ struct key_type key_type_dns_resolver = {
.match = user_match, .match = user_match,
}; };
/* Checks if supplied name is IP address
* returns:
* 1 - name is IP
* 0 - name is not IP
*/
static int is_ip(const char *name)
{
int rc;
struct sockaddr_in sin_server;
struct sockaddr_in6 sin_server6;
rc = cifs_inet_pton(AF_INET, name,
&sin_server.sin_addr.s_addr);
if (rc <= 0) {
/* not ipv4 address, try ipv6 */
rc = cifs_inet_pton(AF_INET6, name,
&sin_server6.sin6_addr.in6_u);
if (rc > 0)
return 1;
} else {
return 1;
}
/* we failed translating address */
return 0;
}
/* Resolves server name to ip address. /* Resolves server name to ip address.
* input: * input:
* unc - server UNC * unc - server UNC
...@@ -140,6 +149,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) ...@@ -140,6 +149,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
rkey = request_key(&key_type_dns_resolver, name, ""); rkey = request_key(&key_type_dns_resolver, name, "");
if (!IS_ERR(rkey)) { if (!IS_ERR(rkey)) {
len = rkey->type_data.x[0];
data = rkey->payload.data; data = rkey->payload.data;
} else { } else {
cERROR(1, ("%s: unable to resolve: %s", __func__, name)); 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,11 +158,9 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
skip_upcall: skip_upcall:
if (data) { if (data) {
len = strlen(data); *ip_addr = kmalloc(len + 1, GFP_KERNEL);
*ip_addr = kmalloc(len+1, GFP_KERNEL);
if (*ip_addr) { if (*ip_addr) {
memcpy(*ip_addr, data, len); memcpy(*ip_addr, data, len + 1);
(*ip_addr)[len] = '\0';
if (!IS_ERR(rkey)) if (!IS_ERR(rkey))
cFYI(1, ("%s: resolved: %s to %s", __func__, cFYI(1, ("%s: resolved: %s to %s", __func__,
name, name,
......
...@@ -107,7 +107,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, ...@@ -107,7 +107,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
/* want handles we can use to read with first /* want handles we can use to read with first
in the list so we do not have to walk the in the list so we do not have to walk the
list to search for one in prepare_write */ list to search for one in write_begin */
if ((file->f_flags & O_ACCMODE) == O_WRONLY) { if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
list_add_tail(&pCifsFile->flist, list_add_tail(&pCifsFile->flist,
&pCifsInode->openFileList); &pCifsInode->openFileList);
...@@ -915,7 +915,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -915,7 +915,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
} }
static ssize_t cifs_write(struct file *file, const char *write_data, static ssize_t cifs_write(struct file *file, const char *write_data,
size_t write_size, loff_t *poffset) size_t write_size, loff_t *poffset)
{ {
int rc = 0; int rc = 0;
unsigned int bytes_written = 0; unsigned int bytes_written = 0;
...@@ -1065,6 +1065,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) ...@@ -1065,6 +1065,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
{ {
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
bool any_available = false;
int rc; int rc;
/* Having a null inode here (because mapping->host was set to zero by /* 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,8 +1081,10 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
read_lock(&GlobalSMBSeslock); read_lock(&GlobalSMBSeslock);
refind_writable: refind_writable:
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
if (open_file->closePend) if (open_file->closePend ||
(!any_available && open_file->pid != current->tgid))
continue; continue;
if (open_file->pfile && if (open_file->pfile &&
((open_file->pfile->f_flags & O_RDWR) || ((open_file->pfile->f_flags & O_RDWR) ||
(open_file->pfile->f_flags & O_WRONLY))) { (open_file->pfile->f_flags & O_WRONLY))) {
...@@ -1131,6 +1134,11 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) ...@@ -1131,6 +1134,11 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
of the loop here. */ of the loop here. */
} }
} }
/* couldn't find useable FH with same pid, try any available */
if (!any_available) {
any_available = true;
goto refind_writable;
}
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
return NULL; return NULL;
} }
...@@ -1447,49 +1455,52 @@ static int cifs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -1447,49 +1455,52 @@ static int cifs_writepage(struct page *page, struct writeback_control *wbc)
return rc; return rc;
} }
static int cifs_commit_write(struct file *file, struct page *page, static int cifs_write_end(struct file *file, struct address_space *mapping,
unsigned offset, unsigned to) loff_t pos, unsigned len, unsigned copied,
struct page *page, void *fsdata)
{ {
int xid; int rc;
int rc = 0; struct inode *inode = mapping->host;
struct inode *inode = page->mapping->host;
loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
char *page_data;
xid = GetXid(); cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
cFYI(1, ("commit write for page %p up to position %lld for %d", page, pos, copied));
page, position, to));
spin_lock(&inode->i_lock); if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
if (position > inode->i_size) SetPageUptodate(page);
i_size_write(inode, position);
spin_unlock(&inode->i_lock);
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; char *page_data;
/* can not rely on (or let) writepage write this data */ unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
if (to < offset) { int xid;
cFYI(1, ("Illegal offsets, can not copy from %d to %d",
offset, to)); xid = GetXid();
FreeXid(xid);
return rc;
}
/* this is probably better than directly calling /* this is probably better than directly calling
partialpage_write since in this function the file handle is partialpage_write since in this function the file handle is
known which we might as well leverage */ known which we might as well leverage */
/* BB check if anything else missing out of ppw /* BB check if anything else missing out of ppw
such as updating last write time */ such as updating last write time */
page_data = kmap(page); page_data = kmap(page);
rc = cifs_write(file, page_data + offset, to-offset, rc = cifs_write(file, page_data + offset, copied, &pos);
&position); /* if (rc < 0) should we set writebehind rc? */
if (rc > 0)
rc = 0;
/* else if (rc < 0) should we set writebehind rc? */
kunmap(page); kunmap(page);
FreeXid(xid);
} else { } else {
rc = copied;
pos += copied;
set_page_dirty(page); set_page_dirty(page);
} }
FreeXid(xid); if (rc > 0) {
spin_lock(&inode->i_lock);
if (pos > inode->i_size)
i_size_write(inode, pos);
spin_unlock(&inode->i_lock);
}
unlock_page(page);
page_cache_release(page);
return rc; return rc;
} }
...@@ -2035,49 +2046,44 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file) ...@@ -2035,49 +2046,44 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
return true; return true;
} }
static int cifs_prepare_write(struct file *file, struct page *page, static int cifs_write_begin(struct file *file, struct address_space *mapping,
unsigned from, unsigned to) loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{ {
int rc = 0; pgoff_t index = pos >> PAGE_CACHE_SHIFT;
loff_t i_size; loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
loff_t offset;
cFYI(1, ("prepare write for page %p from %d to %d", page, from, to)); cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
if (PageUptodate(page))
*pagep = __grab_cache_page(mapping, index);
if (!*pagep)
return -ENOMEM;
if (PageUptodate(*pagep))
return 0; return 0;
/* If we are writing a full page it will be up to date, /* If we are writing a full page it will be up to date,
no need to read from the server */ no need to read from the server */
if ((to == PAGE_CACHE_SIZE) && (from == 0)) { if (len == PAGE_CACHE_SIZE && flags & AOP_FLAG_UNINTERRUPTIBLE)
SetPageUptodate(page);
return 0; return 0;
}
offset = (loff_t)page->index << PAGE_CACHE_SHIFT; if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
i_size = i_size_read(page->mapping->host); int rc;
if ((offset >= i_size) ||
((from == 0) && (offset + to) >= i_size)) {
/*
* We don't need to read data beyond the end of the file.
* zero it, and set the page uptodate
*/
simple_prepare_write(file, page, from, to);
SetPageUptodate(page);
} else if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
/* might as well read a page, it is fast enough */ /* might as well read a page, it is fast enough */
rc = cifs_readpage_worker(file, page, &offset); rc = cifs_readpage_worker(file, *pagep, &offset);
/* we do not need to pass errors back
e.g. if we do not have read access to the file
because cifs_write_end will attempt synchronous writes
-- shaggy */
} else { } else {
/* we could try using another file handle if there is one - /* we could try using another file handle if there is one -
but how would we lock it to prevent close of that handle but how would we lock it to prevent close of that handle
racing with this read? In any case racing with this read? In any case
this will be written out by commit_write so is fine */ this will be written out by write_end so is fine */
} }
/* we do not need to pass errors back
e.g. if we do not have read access to the file
because cifs_commit_write will do the right thing. -- shaggy */
return 0; return 0;
} }
...@@ -2086,8 +2092,8 @@ const struct address_space_operations cifs_addr_ops = { ...@@ -2086,8 +2092,8 @@ const struct address_space_operations cifs_addr_ops = {
.readpages = cifs_readpages, .readpages = cifs_readpages,
.writepage = cifs_writepage, .writepage = cifs_writepage,
.writepages = cifs_writepages, .writepages = cifs_writepages,
.prepare_write = cifs_prepare_write, .write_begin = cifs_write_begin,
.commit_write = cifs_commit_write, .write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers, .set_page_dirty = __set_page_dirty_nobuffers,
/* .sync_page = cifs_sync_page, */ /* .sync_page = cifs_sync_page, */
/* .direct_IO = */ /* .direct_IO = */
...@@ -2102,8 +2108,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { ...@@ -2102,8 +2108,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
.readpage = cifs_readpage, .readpage = cifs_readpage,
.writepage = cifs_writepage, .writepage = cifs_writepage,
.writepages = cifs_writepages, .writepages = cifs_writepages,
.prepare_write = cifs_prepare_write, .write_begin = cifs_write_begin,
.commit_write = cifs_commit_write, .write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers, .set_page_dirty = __set_page_dirty_nobuffers,
/* .sync_page = cifs_sync_page, */ /* .sync_page = cifs_sync_page, */
/* .direct_IO = */ /* .direct_IO = */
......
This diff is collapsed.
...@@ -150,8 +150,7 @@ cifs_buf_get(void) ...@@ -150,8 +150,7 @@ cifs_buf_get(void)
but it may be more efficient to always alloc same size but it may be more efficient to always alloc same size
albeit slightly larger than necessary and maxbuffersize albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */ defaults to this and can not be bigger */
ret_buf = (struct smb_hdr *) mempool_alloc(cifs_req_poolp, ret_buf = mempool_alloc(cifs_req_poolp, GFP_NOFS);
GFP_KERNEL | GFP_NOFS);
/* clear the first few header bytes */ /* clear the first few header bytes */
/* for most paths, more is cleared in header_assemble */ /* for most paths, more is cleared in header_assemble */
...@@ -188,8 +187,7 @@ cifs_small_buf_get(void) ...@@ -188,8 +187,7 @@ cifs_small_buf_get(void)
but it may be more efficient to always alloc same size but it may be more efficient to always alloc same size
albeit slightly larger than necessary and maxbuffersize albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */ defaults to this and can not be bigger */
ret_buf = (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS);
GFP_KERNEL | GFP_NOFS);
if (ret_buf) { if (ret_buf) {
/* No need to clear memory here, cleared in header assemble */ /* No need to clear memory here, cleared in header assemble */
/* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/ /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
......
...@@ -640,6 +640,70 @@ static int is_dir_changed(struct file *file) ...@@ -640,6 +640,70 @@ static int is_dir_changed(struct file *file)
} }
static int cifs_save_resume_key(const char *current_entry,
struct cifsFileInfo *cifsFile)
{
int rc = 0;
unsigned int len = 0;
__u16 level;
char *filename;
if ((cifsFile == NULL) || (current_entry == NULL))
return -EINVAL;
level = cifsFile->srch_inf.info_level;
if (level == SMB_FIND_FILE_UNIX) {
FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0];
if (cifsFile->srch_inf.unicode) {
len = cifs_unicode_bytelen(filename);
} else {
/* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, PATH_MAX);
}
cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
FILE_DIRECTORY_INFO *pFindData =
(FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
FILE_FULL_DIRECTORY_INFO *pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
SEARCH_ID_FULL_DIR_INFO *pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
FILE_BOTH_DIRECTORY_INFO *pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if (level == SMB_FIND_FILE_INFO_STANDARD) {
FIND_FILE_STANDARD_INFO *pFindData =
(FIND_FILE_STANDARD_INFO *)current_entry;
filename = &pFindData->FileName[0];
/* one byte length, no name conversion */
len = (unsigned int)pFindData->FileNameLength;
cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
} else {
cFYI(1, ("Unknown findfirst level %d", level));
return -EINVAL;
}
cifsFile->srch_inf.resume_name_len = len;
cifsFile->srch_inf.presume_name = filename;
return rc;
}
/* find the corresponding entry in the search */ /* find the corresponding entry in the search */
/* Note that the SMB server returns search entries for . and .. which /* Note that the SMB server returns search entries for . and .. which
complicates logic here if we choose to parse for them and we do not 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,6 +767,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
(rc == 0) && !cifsFile->srch_inf.endOfSearch) { (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
cFYI(1, ("calling findnext2")); cFYI(1, ("calling findnext2"));
cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
&cifsFile->srch_inf); &cifsFile->srch_inf);
if (rc) if (rc)
...@@ -919,69 +984,6 @@ static int cifs_filldir(char *pfindEntry, struct file *file, ...@@ -919,69 +984,6 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
return rc; return rc;
} }
static int cifs_save_resume_key(const char *current_entry,
struct cifsFileInfo *cifsFile)
{
int rc = 0;
unsigned int len = 0;
__u16 level;
char *filename;
if ((cifsFile == NULL) || (current_entry == NULL))
return -EINVAL;
level = cifsFile->srch_inf.info_level;
if (level == SMB_FIND_FILE_UNIX) {
FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0];
if (cifsFile->srch_inf.unicode) {
len = cifs_unicode_bytelen(filename);
} else {
/* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, PATH_MAX);
}
cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
FILE_DIRECTORY_INFO *pFindData =
(FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
FILE_FULL_DIRECTORY_INFO *pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
SEARCH_ID_FULL_DIR_INFO *pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
FILE_BOTH_DIRECTORY_INFO *pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if (level == SMB_FIND_FILE_INFO_STANDARD) {
FIND_FILE_STANDARD_INFO *pFindData =
(FIND_FILE_STANDARD_INFO *)current_entry;
filename = &pFindData->FileName[0];
/* one byte length, no name conversion */
len = (unsigned int)pFindData->FileNameLength;
cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
} else {
cFYI(1, ("Unknown findfirst level %d", level));
return -EINVAL;
}
cifsFile->srch_inf.resume_name_len = len;
cifsFile->srch_inf.presume_name = filename;
return rc;
}
int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
{ {
......
...@@ -624,8 +624,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -624,8 +624,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
ses, nls_cp); ses, nls_cp);
ssetup_exit: ssetup_exit:
if (spnego_key) if (spnego_key) {
key_revoke(spnego_key);
key_put(spnego_key); key_put(spnego_key);
}
kfree(str_area); kfree(str_area);
if (resp_buf_type == CIFS_SMALL_BUFFER) { if (resp_buf_type == CIFS_SMALL_BUFFER) {
cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base)); cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base));
......
...@@ -50,8 +50,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) ...@@ -50,8 +50,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
return NULL; return NULL;
} }
temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp, temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
GFP_KERNEL | GFP_NOFS);
if (temp == NULL) if (temp == NULL)
return temp; return temp;
else { else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment