Commit a63a10fe authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://cifs.bkbits.net/linux-2.5cifs

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 71279d2b 81a50e44
Version 1.18
------------
Do not rename hardlinked files (since that should be a noop). Flush
cached write behind data when reopening a file after session abend,
except when already in write. Grab per socket sem during reconnect
to avoid oops in sendmsg if overlapping with reconnect.
Version 1.17
------------
Update number of blocks in file so du command is happier (in Linux a fake
......
......@@ -97,7 +97,9 @@ Linux:
case sensitive = yes
delete readonly = yes
ea support = yes
Note that ea support is required for supporting Linux xattrs.
Some administrators also change the "map archive" and the "create mask"
parameters from their default values. Creating special devices (mknod) remotely
may require specifying a mkdev function to Samba. For more information on these
......@@ -268,11 +270,12 @@ Misc /proc/fs/cifs Flags and Debug Info
=======================================
Informational pseudo-files:
DebugData Displays information about active CIFS sessions
as well as per share statistics (if CONFIG_CIFS_STATS
is enabled in the kernel configuration).
and shares.
SimultaneousOps Counter which holds maximum number of
simultaneous outstanding SMB/CIFS requests.
Stats Lists summary resource usage information
Stats Lists summary resource usage information as well as per
share statistics, if CONFIG_CIFS_STATS in enabled
in the kernel configuration.
Configuration pseudo-files:
MultiuserMount If set to one, more than one CIFS session to
......
......@@ -80,27 +80,13 @@ symlink text beginning with slash
but recognizes them
3) create of new files to FAT partitions on Windows servers can
succeed but still return access denied (appears to be Windows
not client problem) and has not been reproduced recently.
server not cifs client problem) and has not been reproduced recently.
NTFS partitions do not have this problem.
4) debug connectation lock test case 10 which fails against
Samba (may be unmappable due to POSIX to Windows lock model
differences but worth investigating). Also debug Samba to
see why lock test case 7 takes longer to complete to Samba
than to Windows.
5) prepare_write does not initialize pages properly when partial
page writes begin in the middle of a page (pages can get zeroed).
6) Write caching done incorrectly when files are only opened
with write permission by the application.
7) Rename of files that are hardlinked does not work correctly e.g.
ln source target
mv source target
This should be no op since files are linked but in cifs it causes
the source file to go away. This may require implementation of
the cifs POSIX extensions (Unix Extensions version 2) for
it to be done correctly since Samba is failing the rename,
(rather than ignoring it) so the client not knowing they
are linked proceeds to delete the target and then retry the
move which succeeds this time (but the source is gone).
Misc testing to do
==================
......
......@@ -190,26 +190,26 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
struct cifsTconInfo *tcon;
length = sprintf(buf,
"Currently Allocated structures\nCIFS Sessions: %d\n",
"Resources in use\nCIFS Session: %d\n",
sesInfoAllocCount.counter);
buf += length;
item_length =
sprintf(buf,"Shares (unique mount targets): %d\n",
sprintf(buf,"Share (unique mount targets): %d\n",
tconInfoAllocCount.counter);
length += item_length;
buf += item_length;
item_length =
sprintf(buf,"Allocated SMB Request/Response Buffers: %d\n",
sprintf(buf,"SMB Request/Response Buffer: %d\n",
bufAllocCount.counter);
length += item_length;
buf += item_length;
item_length =
sprintf(buf,"Active Operations (MIDs in use): %d\n",
sprintf(buf,"Operations (MIDs): %d\n",
midCount.counter);
length += item_length;
buf += item_length;
item_length = sprintf(buf,
"%d sessions and %d shares reconnected after failure\n",
"\n%d session %d share reconnects\n",
tcpSesReconnectCount.counter,tconInfoReconnectCount.counter);
length += item_length;
buf += item_length;
......@@ -400,7 +400,7 @@ cifsFYI_read(char *page, char **start, off_t off, int count,
return len;
}
static int
cifsFYI_write(struct file *file, const char *buffer,
cifsFYI_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
......@@ -439,7 +439,7 @@ oplockEnabled_read(char *page, char **start, off_t off,
return len;
}
static int
oplockEnabled_write(struct file *file, const char *buffer,
oplockEnabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
......@@ -479,7 +479,7 @@ quotaEnabled_read(char *page, char **start, off_t off,
return len;
}
static int
quotaEnabled_write(struct file *file, const char *buffer,
quotaEnabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
......@@ -519,7 +519,7 @@ linuxExtensionsEnabled_read(char *page, char **start, off_t off,
return len;
}
static int
linuxExtensionsEnabled_write(struct file *file, const char *buffer,
linuxExtensionsEnabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
......@@ -559,7 +559,7 @@ lookupFlag_read(char *page, char **start, off_t off,
return len;
}
static int
lookupFlag_write(struct file *file, const char *buffer,
lookupFlag_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
......@@ -597,7 +597,7 @@ traceSMB_read(char *page, char **start, off_t off, int count,
return len;
}
static int
traceSMB_write(struct file *file, const char *buffer,
traceSMB_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
......@@ -636,7 +636,7 @@ multiuser_mount_read(char *page, char **start, off_t off,
return len;
}
static int
multiuser_mount_write(struct file *file, const char *buffer,
multiuser_mount_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
......@@ -675,7 +675,7 @@ extended_security_read(char *page, char **start, off_t off,
return len;
}
static int
extended_security_write(struct file *file, const char *buffer,
extended_security_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
......@@ -714,7 +714,7 @@ ntlmv2_enabled_read(char *page, char **start, off_t off,
return len;
}
static int
ntlmv2_enabled_write(struct file *file, const char *buffer,
ntlmv2_enabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
......@@ -753,7 +753,7 @@ packet_signing_enabled_read(char *page, char **start, off_t off,
return len;
}
static int
packet_signing_enabled_write(struct file *file, const char *buffer,
packet_signing_enabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
......
......@@ -426,7 +426,7 @@ cifs_get_sb(struct file_system_type *fs_type,
}
static ssize_t
cifs_read_wrapper(struct file * file, char *read_data, size_t read_size,
cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size,
loff_t * poffset)
{
if(file == NULL)
......@@ -455,7 +455,7 @@ cifs_read_wrapper(struct file * file, char *read_data, size_t read_size,
}
static ssize_t
cifs_write_wrapper(struct file * file, const char *write_data,
cifs_write_wrapper(struct file * file, const char __user *write_data,
size_t write_size, loff_t * poffset)
{
ssize_t written;
......
......@@ -85,7 +85,7 @@ extern struct dentry_operations cifs_dentry_ops;
/* Functions related to symlinks */
extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
extern int cifs_readlink(struct dentry *direntry, char *buffer, int buflen);
extern int cifs_readlink(struct dentry *direntry, char __user *buffer, int buflen);
extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
const char *symname);
extern int cifs_removexattr(struct dentry *, const char *);
......@@ -93,5 +93,5 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
size_t, int);
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
#define CIFS_VERSION "1.17"
#define CIFS_VERSION "1.18"
#endif /* _CIFSFS_H */
......@@ -1046,9 +1046,12 @@ typedef union smb_com_transaction2 {
/* PathInfo/FileInfo infolevels */
#define SMB_INFO_STANDARD 1
#define SMB_INFO_QUERY_EAS_FROM_LIST 3
#define SMB_INFO_QUERY_ALL_EAS 4
#define SMB_INFO_IS_NAME_VALID 6
#define SMB_QUERY_FILE_BASIC_INFO 0x101
#define SMB_QUERY_FILE_STANDARD_INFO 0x102
#define SMB_QUERY_FILE_EA_INFO 0x103
#define SMB_QUERY_FILE_NAME_INFO 0x104
#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105
#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106
......@@ -1687,16 +1690,17 @@ struct gealist {
};
struct fea {
unsigned char fEA;
unsigned char cbName;
unsigned short cbValue;
unsigned char EA_flags;
__u8 name_len;
__u16 value_len;
char szName[1];
/* optionally followed by value */
};
/* flags for _FEA.fEA */
#define FEA_NEEDEA 0x80 /* need EA bit */
struct fealist {
unsigned long cbList;
__u32 list_len;
struct fea list[1];
};
......
......@@ -247,4 +247,8 @@ extern int CIFSSMBCopy(int xid,
extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
const int notify_subdirs,const __u16 netfid,__u32 filter,
const struct nls_table *nls_codepage);
extern int CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
char * EAData, size_t size,
const struct nls_table *nls_codepage);
#endif /* _CIFSPROTO_H */
......@@ -1596,6 +1596,8 @@ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
} else { /* decode response */
pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
/* BB also check enough total bytes returned */
/* BB we need to improve the validity checking
of these trans2 responses */
if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512))
rc = -EIO; /* bad smb */
else if (pFindData){
......@@ -2879,3 +2881,101 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
goto NotifyRetry; */
return rc;
}
#ifdef CONFIG_CIFS_XATTR
int
CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
char * EAData, size_t size,
const struct nls_table *nls_codepage)
{
/* BB assumes one setup word */
TRANSACTION2_QPI_REQ *pSMB = NULL;
TRANSACTION2_QPI_RSP *pSMBr = NULL;
int rc = 0;
int bytes_returned;
int name_len;
cFYI(1, ("In Query All EAs path %s", searchName));
QAllEAsRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
/* find define for this maxpathcomponent */
, nls_codepage);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(searchName, 530);
name_len++; /* trailing null */
strncpy(pSMB->FileName, searchName, name_len);
}
pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ +
name_len /* includes null */ ;
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
pSMB->Reserved4 = 0;
pSMB->hdr.smb_buf_length += pSMB->ByteCount;
pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cFYI(1, ("Send error in QueryAllEAs = %d", rc));
} else { /* decode response */
pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
/* BB also check enough total bytes returned */
/* BB we need to improve the validity checking
of these trans2 responses */
if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512))
rc = -EIO; /* bad smb */
/* else if (pFindData){
memcpy((char *) pFindData,
(char *) &pSMBr->hdr.Protocol +
pSMBr->DataOffset, kl);
}*/ else {
/* check that length of list is not more than bcc */
/* check that each entry does not go beyond length
of list */
/* check that each element of each entry does not
go beyond end of list */
struct fealist * ea_response_data;
rc = 0;
/* validate_trans2_offsets() */
/* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/
ea_response_data = (struct fealist *)
(((char *) &pSMBr->hdr.Protocol) +
pSMBr->DataOffset);
cFYI(1,("ea length %d",ea_response_data->list_len));
}
}
if (pSMB)
cifs_buf_release(pSMB);
if (rc == -EAGAIN)
goto QAllEAsRetry;
return rc;
}
#endif
......@@ -128,7 +128,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
}
}
read_unlock(&GlobalSMBSeslock);
/* do not want to be sending data on a socket we are freeing */
down(&server->tcpSem);
if(server->ssocket) {
cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
server->ssocket->flags));
......@@ -154,7 +155,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
}
}
spin_unlock(&GlobalMid_Lock);
up(&server->tcpSem);
while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
{
......@@ -279,7 +280,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
length = sock_recvmsg(csocket, &smb_msg, 4, 0);
cFYI(0,("Received 4 byte keep alive packet"));
} else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
iov.iov_base = smb_buffer;
iov.iov_base = smb_buffer;
iov.iov_len = 4;
length = sock_recvmsg(csocket, &smb_msg, 4, 0);
cFYI(1,("Good RFC 1002 session rsp"));
......@@ -1559,7 +1560,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr +=
pSMBr->resp.SecurityBlobLength;
if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
if ((long) (bcc_ptr) % 2) {
remaining_words =
(BCC(smb_buffer_response)
......@@ -1812,7 +1813,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pSMBr->resp.SecurityBlobLength));
}
if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
if ((long) (bcc_ptr) % 2) {
remaining_words =
(BCC(smb_buffer_response)
......@@ -2123,7 +2124,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
ses->server->secMode |=
SECMODE_SIGN_ENABLED;
if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
if ((long) (bcc_ptr) % 2) {
remaining_words =
(BCC(smb_buffer_response)
......@@ -2519,7 +2520,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
cFYI(1,
("NTLMSSP response to Authenticate "));
if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
if ((long) (bcc_ptr) % 2) {
remaining_words =
(BCC(smb_buffer_response)
......@@ -2718,7 +2719,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
/* skip service field (NB: this field is always ASCII) */
bcc_ptr += length + 1;
strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
length = UniStrnlen((wchar_t *) bcc_ptr, 512);
if (((long) bcc_ptr + (2 * length)) -
(long) pByteArea(smb_buffer_response) <=
......
......@@ -143,6 +143,10 @@ cifs_open(struct inode *inode, struct file *file)
/* Also refresh inode by passing in file_info buf returned by SMBOpen
and calling get_inode_info with returned buf (at least
helps non-Unix server case */
/* BB we can not do this if this is the second open of a file
and the first handle has writebehind data, we might be
able to simply do a filemap_fdatawrite/filemap_fdatawait first */
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
if(buf==0) {
if (full_path)
......@@ -263,7 +267,7 @@ static int cifs_relock_file(struct cifsFileInfo * cifsFile)
return rc;
}
static int cifs_reopen_file(struct inode *inode, struct file *file)
static int cifs_reopen_file(struct inode *inode, struct file *file, int can_flush)
{
int rc = -EACCES;
int xid, oplock;
......@@ -275,7 +279,6 @@ static int cifs_reopen_file(struct inode *inode, struct file *file)
int desiredAccess = 0x20197;
int disposition = FILE_OPEN;
__u16 netfid;
FILE_ALL_INFO * buf = NULL;
if(inode == NULL)
return -EBADF;
......@@ -328,21 +331,23 @@ and we can never tell if the caller already has the rename_sem */
else
oplock = FALSE;
/* BB pass O_SYNC flag through on file attributes .. BB */
/* Can not refresh inode by passing in file_info buf to be returned
by SMBOpen and then calling get_inode_info with returned buf
since file might have write behind data that needs to be flushed
and server version of file size can be stale. If we
knew for sure that inode was not dirty locally we could do this */
/* Also refresh inode by passing in file_info buf returned by SMBOpen
and calling get_inode_info with returned buf (at least
helps non-Unix server case */
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
/* buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
if(buf==0) {
up(&pCifsFile->fh_sem);
if (full_path)
kfree(full_path);
FreeXid(xid);
return -ENOMEM;
}
}*/
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls);
CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls);
if (rc) {
up(&pCifsFile->fh_sem);
cFYI(1, ("cifs_open returned 0x%x ", rc));
......@@ -353,13 +358,25 @@ and we can never tell if the caller already has the rename_sem */
up(&pCifsFile->fh_sem);
pCifsInode = CIFS_I(inode);
if(pCifsInode) {
if (pTcon->ses->capabilities & CAP_UNIX)
rc = cifs_get_inode_info_unix(&inode,
if(can_flush) {
filemap_fdatawrite(inode->i_mapping);
filemap_fdatawait(inode->i_mapping);
/* temporarily disable caching while we
go to server to get inode info */
pCifsInode->clientCanCacheAll = FALSE;
pCifsInode->clientCanCacheRead = FALSE;
if (pTcon->ses->capabilities & CAP_UNIX)
rc = cifs_get_inode_info_unix(&inode,
full_path, inode->i_sb);
else
rc = cifs_get_inode_info(&inode,
full_path, buf, inode->i_sb);
else
rc = cifs_get_inode_info(&inode,
full_path, NULL, inode->i_sb);
} /* else we are writing out data to server already
and could deadlock if we tried to flush data, and
since we do not know if we have data that would
invalidate the current end of file on the server
we can not go to the server to get the new
inod info */
if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = TRUE;
pCifsInode->clientCanCacheRead = TRUE;
......@@ -375,8 +392,6 @@ and we can never tell if the caller already has the rename_sem */
}
}
if (buf)
kfree(buf);
if (full_path)
kfree(full_path);
FreeXid(xid);
......@@ -612,7 +627,11 @@ cifs_write(struct file * file, const char *write_data,
FreeXid(xid);
return total_written;
}
rc = cifs_reopen_file(file->f_dentry->d_inode,file);
/* we could deadlock if we called
filemap_fdatawait from here so tell
reopen_file not to flush data to server now */
rc = cifs_reopen_file(file->f_dentry->d_inode,
file,FALSE);
if(rc != 0)
break;
}
......@@ -829,7 +848,7 @@ cifs_commit_write(struct file *file, struct page *page, unsigned offset,
cFYI(1,(" SetEOF (commit write) rc = %d",rc));
}*/
}
if (!PageUptodate(page)) {
if (!PageUptodate(page)) {
position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
/* can not rely on (or let) writepage write this data */
if(to < offset) {
......@@ -968,7 +987,8 @@ cifs_read(struct file * file, char *read_data, size_t read_size,
rc = -EAGAIN;
while(rc == -EAGAIN) {
if ((open_file->invalidHandle) && (!open_file->closePend)) {
rc = cifs_reopen_file(file->f_dentry->d_inode,file);
rc = cifs_reopen_file(file->f_dentry->d_inode,
file,TRUE);
if(rc != 0)
break;
}
......@@ -1123,7 +1143,8 @@ cifs_readpages(struct file *file, struct address_space *mapping,
rc = -EAGAIN;
while(rc == -EAGAIN) {
if ((open_file->invalidHandle) && (!open_file->closePend)) {
rc = cifs_reopen_file(file->f_dentry->d_inode,file);
rc = cifs_reopen_file(file->f_dentry->d_inode,
file, TRUE);
if(rc != 0)
break;
}
......@@ -1263,6 +1284,49 @@ cifs_readpage(struct file *file, struct page *page)
return rc;
}
/* We do not want to update the file size from server for inodes
open for write - to avoid races with writepage extending
the file - in the future we could consider allowing
refreshing the inode only on increases in the file size
but this is tricky to do without racing with writebehind
page caching in the current Linux kernel design */
int is_size_safe_to_change(struct cifsInodeInfo * cifsInode)
{
struct list_head *tmp;
struct list_head *tmp1;
struct cifsFileInfo *open_file = NULL;
int rc = TRUE;
if(cifsInode == NULL)
return rc;
read_lock(&GlobalSMBSeslock);
list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {
open_file = list_entry(tmp,struct cifsFileInfo, flist);
if(open_file == NULL)
break;
if(open_file->closePend)
continue;
/* We check if file is open for writing,
BB we could supplement this with a check to see if file size
changes have been flushed to server - ie inode metadata dirty */
if((open_file->pfile) &&
((open_file->pfile->f_flags & O_RDWR) ||
(open_file->pfile->f_flags & O_WRONLY))) {
rc = FALSE;
break;
}
if(tmp->next == NULL) {
cFYI(1,("File instance %p removed",tmp));
break;
}
}
read_unlock(&GlobalSMBSeslock);
return rc;
}
void
fill_in_inode(struct inode *tmp_inode,
FILE_DIRECTORY_INFO * pfindData, int *pobject_type)
......@@ -1322,11 +1386,15 @@ fill_in_inode(struct inode *tmp_inode,
atomic_set(&cifsInfo->inUse,1);
}
i_size_write(tmp_inode,pfindData->EndOfFile);
if(is_size_safe_to_change(cifsInfo)) {
/* can not safely change the file size here if the
client is writing to it due to potential races */
i_size_write(tmp_inode,pfindData->EndOfFile);
/* 512 bytes (2**9) is the fake blocksize that must be used */
/* for this calculation, even though the reported blocksize is larger */
tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9;
tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9;
}
if (pfindData->AllocationSize < pfindData->EndOfFile)
cFYI(1, ("Possible sparse file: allocation size less than end of file "));
......@@ -1398,12 +1466,17 @@ unix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes);
pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
i_size_write(tmp_inode,pfindData->EndOfFile);
if(is_size_safe_to_change(cifsInfo)) {
/* can not safely change the file size here if the
client is writing to it due to potential races */
pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
i_size_write(tmp_inode,pfindData->EndOfFile);
/* 512 bytes (2**9) is the fake blocksize that must be used */
/* for this calculation, not the real blocksize */
tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9;
tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9;
}
if (S_ISREG(tmp_inode->i_mode)) {
cFYI(1, ("File inode"));
......@@ -1547,9 +1620,9 @@ cifs_filldir_unix(struct qstr *pqstring,
pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF);
construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
return -ENOMEM;
}
if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
return -ENOMEM;
}
unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type);
rc = filldir(direntry, pUnixFindData->FileName, pqstring->len,
......
......@@ -30,6 +30,8 @@
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
extern int is_size_safe_to_change(struct cifsInodeInfo *);
int
cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
......@@ -43,9 +45,6 @@ cifs_get_inode_info_unix(struct inode **pinode,
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
char *tmp_path;
/* BB add caching check so we do not go to server to overwrite inode info to cached file
where the local file sizes are correct and the server info is stale BB */
xid = GetXid();
pTcon = cifs_sb->tcon;
......@@ -125,7 +124,12 @@ cifs_get_inode_info_unix(struct inode **pinode,
inode->i_nlink = le64_to_cpu(findData.Nlinks);
findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes);
findData.EndOfFile = le64_to_cpu(findData.EndOfFile);
i_size_write(inode,findData.EndOfFile);
if(is_size_safe_to_change(cifsInfo)) {
/* can not safely change the file size here if the
client is writing to it due to potential races */
i_size_write(inode,findData.EndOfFile);
/* blksize needs to be multiple of two. So safer to default to blksize
and blkbits set in superblock so 2**blkbits and blksize will match */
/* inode->i_blksize =
......@@ -141,7 +145,8 @@ cifs_get_inode_info_unix(struct inode **pinode,
/* 512 bytes (2**9) is the fake blocksize that must be used */
/* for this calculation */
inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9;
inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9;
}
if (findData.NumOfBytes < findData.EndOfFile)
cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
......@@ -283,12 +288,18 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
inode->i_mode &= ~(S_IWUGO);
/* BB add code here - validate if device or weird share or device type? */
}
i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
if(is_size_safe_to_change(cifsInfo)) {
/* can not safely change the file size here if the
client is writing to it due to potential races */
i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
/* 512 bytes (2**9) is the fake blocksize that must be used */
/* for this calculation */
inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9;
inode->i_blocks = (512 - 1 + pfindData->AllocationSize)
>> 9;
}
pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
......@@ -568,9 +579,38 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
rc = CIFSSMBRename(xid, pTcon, fromName, toName,
cifs_sb_source->local_nls);
if(rc == -EEXIST) {
cifs_unlink(target_inode, target_direntry);
rc = CIFSSMBRename(xid, pTcon, fromName, toName,
cifs_sb_source->local_nls);
/* check if they are the same file
because rename of hardlinked files is a noop */
FILE_UNIX_BASIC_INFO * info_buf_source;
FILE_UNIX_BASIC_INFO * info_buf_target;
info_buf_source =
kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL);
if(info_buf_source != NULL) {
info_buf_target = info_buf_source+1;
rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
info_buf_source, cifs_sb_source->local_nls);
if(rc == 0) {
rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName,
info_buf_target,
cifs_sb_target->local_nls);
}
if((rc == 0) &&
(info_buf_source->UniqueId ==
info_buf_target->UniqueId)) {
/* do not rename since the files are hardlinked
which is a noop */
} else {
/* we either can not tell the files are hardlinked
(as with Windows servers) or files are not hardlinked
so delete the target manually before renaming to
follow POSIX rather than Windows semantics */
cifs_unlink(target_inode, target_direntry);
rc = CIFSSMBRename(xid, pTcon, fromName, toName,
cifs_sb_source->local_nls);
}
kfree(info_buf_source);
} /* if we can not get memory just leave rc as EEXIST */
}
if((rc == -EIO)||(rc == -EEXIST)) {
......
......@@ -210,7 +210,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
}
int
cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
{
struct inode *inode = direntry->d_inode;
int rc = -EACCES;
......
......@@ -120,6 +120,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
unsigned int smb_buf_length, struct sockaddr *sin)
{
int rc = 0;
int i = 0;
struct msghdr smb_msg;
struct iovec iov;
mm_segment_t temp_fs;
......@@ -151,6 +152,14 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
while(iov.iov_len > 0) {
rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4);
if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
i++;
if(i > 60) {
cERROR(1,
("sends on sock %p stuck for 30 seconds",
ssocket));
rc = -EAGAIN;
break;
}
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ/2);
continue;
......@@ -259,7 +268,17 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
midQ->midState = MID_REQUEST_SUBMITTED;
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
(struct sockaddr *) &(ses->server->addr.sockAddr));
up(&ses->server->tcpSem);
if(rc < 0) {
DeleteMidQEntry(midQ);
up(&ses->server->tcpSem);
/* If not lock req, update # of requests on wire to server */
if(long_op < 3) {
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
}
return rc;
} else
up(&ses->server->tcpSem);
if (long_op == -1)
goto cifs_no_response_exit;
else if (long_op == 2) /* writes past end of file can take looooong time */
......
......@@ -20,37 +20,68 @@
*/
#include <linux/fs.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
int cifs_removexattr(struct dentry * direntry, const char * name)
{
int rc = -EOPNOTSUPP;
return rc;
int rc = -EOPNOTSUPP;
return rc;
}
int cifs_setxattr(struct dentry * direntry, const char * name,
const void * value, size_t size, int flags)
{
int rc = -EOPNOTSUPP;
return rc;
int rc = -EOPNOTSUPP;
return rc;
}
ssize_t cifs_getxattr(struct dentry * direntry, const char * name,
void * value, size_t size)
{
ssize_t rc = -EOPNOTSUPP;
return rc;
ssize_t rc = -EOPNOTSUPP;
return rc;
}
ssize_t cifs_listxattr(struct dentry * direntry, char * ea_data, size_t ea_size)
{
ssize_t rc = -EOPNOTSUPP;
ssize_t rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR
int xid;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
struct super_block * sb;
char * full_path;
if(direntry == NULL)
return -EIO;
if(direntry->d_inode == NULL)
return -EIO;
sb = direntry->d_inode->i_sb;
if(sb == NULL)
return -EIO;
xid = GetXid();
cifs_sb = CIFS_SB(sb);
pTcon = cifs_sb->tcon;
down(&sb->s_vfs_rename_sem);
full_path = build_path_from_dentry(direntry);
up(&sb->s_vfs_rename_sem);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
/* return dosattributes as pseudo xattr */
/* return alt name if available as pseudo attr */
/* if proc/fs/cifs/streamstoxattr is set then
search server for EAs or streams to
returns as xattrs */
return rc;
rc = CIFSSMBQAllEAs(xid,pTcon,full_path,ea_data,ea_size,cifs_sb->local_nls);
FreeXid(xid);
#endif
return rc;
}
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