Commit 6f060189 authored by Steve French's avatar Steve French

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

into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs
parents efe00e6a 05a46cc8
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 Version 1.17
------------ ------------
Update number of blocks in file so du command is happier (in Linux a fake Update number of blocks in file so du command is happier (in Linux a fake
......
...@@ -97,7 +97,9 @@ Linux: ...@@ -97,7 +97,9 @@ Linux:
case sensitive = yes case sensitive = yes
delete readonly = 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" Some administrators also change the "map archive" and the "create mask"
parameters from their default values. Creating special devices (mknod) remotely parameters from their default values. Creating special devices (mknod) remotely
may require specifying a mkdev function to Samba. For more information on these 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 ...@@ -268,11 +270,12 @@ Misc /proc/fs/cifs Flags and Debug Info
======================================= =======================================
Informational pseudo-files: Informational pseudo-files:
DebugData Displays information about active CIFS sessions DebugData Displays information about active CIFS sessions
as well as per share statistics (if CONFIG_CIFS_STATS and shares.
is enabled in the kernel configuration).
SimultaneousOps Counter which holds maximum number of SimultaneousOps Counter which holds maximum number of
simultaneous outstanding SMB/CIFS requests. 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: Configuration pseudo-files:
MultiuserMount If set to one, more than one CIFS session to MultiuserMount If set to one, more than one CIFS session to
......
...@@ -80,27 +80,13 @@ symlink text beginning with slash ...@@ -80,27 +80,13 @@ symlink text beginning with slash
but recognizes them but recognizes them
3) create of new files to FAT partitions on Windows servers can 3) create of new files to FAT partitions on Windows servers can
succeed but still return access denied (appears to be Windows 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. NTFS partitions do not have this problem.
4) debug connectation lock test case 10 which fails against 4) debug connectation lock test case 10 which fails against
Samba (may be unmappable due to POSIX to Windows lock model Samba (may be unmappable due to POSIX to Windows lock model
differences but worth investigating). Also debug Samba to differences but worth investigating). Also debug Samba to
see why lock test case 7 takes longer to complete to Samba see why lock test case 7 takes longer to complete to Samba
than to Windows. 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 Misc testing to do
================== ==================
......
...@@ -190,26 +190,26 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, ...@@ -190,26 +190,26 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
length = sprintf(buf, length = sprintf(buf,
"Currently Allocated structures\nCIFS Sessions: %d\n", "Resources in use\nCIFS Session: %d\n",
sesInfoAllocCount.counter); sesInfoAllocCount.counter);
buf += length; buf += length;
item_length = item_length =
sprintf(buf,"Shares (unique mount targets): %d\n", sprintf(buf,"Share (unique mount targets): %d\n",
tconInfoAllocCount.counter); tconInfoAllocCount.counter);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
item_length = item_length =
sprintf(buf,"Allocated SMB Request/Response Buffers: %d\n", sprintf(buf,"SMB Request/Response Buffer: %d\n",
bufAllocCount.counter); bufAllocCount.counter);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
item_length = item_length =
sprintf(buf,"Active Operations (MIDs in use): %d\n", sprintf(buf,"Operations (MIDs): %d\n",
midCount.counter); midCount.counter);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
item_length = sprintf(buf, item_length = sprintf(buf,
"%d sessions and %d shares reconnected after failure\n", "\n%d session %d share reconnects\n",
tcpSesReconnectCount.counter,tconInfoReconnectCount.counter); tcpSesReconnectCount.counter,tconInfoReconnectCount.counter);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
...@@ -400,7 +400,7 @@ cifsFYI_read(char *page, char **start, off_t off, int count, ...@@ -400,7 +400,7 @@ cifsFYI_read(char *page, char **start, off_t off, int count,
return len; return len;
} }
static int static int
cifsFYI_write(struct file *file, const char *buffer, cifsFYI_write(struct file *file, const char __user *buffer,
unsigned long count, void *data) unsigned long count, void *data)
{ {
char c; char c;
...@@ -439,7 +439,7 @@ oplockEnabled_read(char *page, char **start, off_t off, ...@@ -439,7 +439,7 @@ oplockEnabled_read(char *page, char **start, off_t off,
return len; return len;
} }
static int static int
oplockEnabled_write(struct file *file, const char *buffer, oplockEnabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data) unsigned long count, void *data)
{ {
char c; char c;
...@@ -479,7 +479,7 @@ quotaEnabled_read(char *page, char **start, off_t off, ...@@ -479,7 +479,7 @@ quotaEnabled_read(char *page, char **start, off_t off,
return len; return len;
} }
static int static int
quotaEnabled_write(struct file *file, const char *buffer, quotaEnabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data) unsigned long count, void *data)
{ {
char c; char c;
...@@ -519,7 +519,7 @@ linuxExtensionsEnabled_read(char *page, char **start, off_t off, ...@@ -519,7 +519,7 @@ linuxExtensionsEnabled_read(char *page, char **start, off_t off,
return len; return len;
} }
static int static int
linuxExtensionsEnabled_write(struct file *file, const char *buffer, linuxExtensionsEnabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data) unsigned long count, void *data)
{ {
char c; char c;
...@@ -559,7 +559,7 @@ lookupFlag_read(char *page, char **start, off_t off, ...@@ -559,7 +559,7 @@ lookupFlag_read(char *page, char **start, off_t off,
return len; return len;
} }
static int static int
lookupFlag_write(struct file *file, const char *buffer, lookupFlag_write(struct file *file, const char __user *buffer,
unsigned long count, void *data) unsigned long count, void *data)
{ {
char c; char c;
...@@ -597,7 +597,7 @@ traceSMB_read(char *page, char **start, off_t off, int count, ...@@ -597,7 +597,7 @@ traceSMB_read(char *page, char **start, off_t off, int count,
return len; return len;
} }
static int static int
traceSMB_write(struct file *file, const char *buffer, traceSMB_write(struct file *file, const char __user *buffer,
unsigned long count, void *data) unsigned long count, void *data)
{ {
char c; char c;
...@@ -636,7 +636,7 @@ multiuser_mount_read(char *page, char **start, off_t off, ...@@ -636,7 +636,7 @@ multiuser_mount_read(char *page, char **start, off_t off,
return len; return len;
} }
static int 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) unsigned long count, void *data)
{ {
char c; char c;
...@@ -675,7 +675,7 @@ extended_security_read(char *page, char **start, off_t off, ...@@ -675,7 +675,7 @@ extended_security_read(char *page, char **start, off_t off,
return len; return len;
} }
static int 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) unsigned long count, void *data)
{ {
char c; char c;
...@@ -714,7 +714,7 @@ ntlmv2_enabled_read(char *page, char **start, off_t off, ...@@ -714,7 +714,7 @@ ntlmv2_enabled_read(char *page, char **start, off_t off,
return len; return len;
} }
static int 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) unsigned long count, void *data)
{ {
char c; char c;
...@@ -753,7 +753,7 @@ packet_signing_enabled_read(char *page, char **start, off_t off, ...@@ -753,7 +753,7 @@ packet_signing_enabled_read(char *page, char **start, off_t off,
return len; return len;
} }
static int 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) unsigned long count, void *data)
{ {
char c; char c;
......
...@@ -426,7 +426,7 @@ cifs_get_sb(struct file_system_type *fs_type, ...@@ -426,7 +426,7 @@ cifs_get_sb(struct file_system_type *fs_type,
} }
static ssize_t 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) loff_t * poffset)
{ {
if(file == NULL) if(file == NULL)
...@@ -455,7 +455,7 @@ cifs_read_wrapper(struct file * file, char *read_data, size_t read_size, ...@@ -455,7 +455,7 @@ cifs_read_wrapper(struct file * file, char *read_data, size_t read_size,
} }
static ssize_t 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) size_t write_size, loff_t * poffset)
{ {
ssize_t written; ssize_t written;
......
...@@ -85,7 +85,7 @@ extern struct dentry_operations cifs_dentry_ops; ...@@ -85,7 +85,7 @@ extern struct dentry_operations cifs_dentry_ops;
/* Functions related to symlinks */ /* Functions related to symlinks */
extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd); 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, extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
const char *symname); const char *symname);
extern int cifs_removexattr(struct dentry *, const char *); extern int cifs_removexattr(struct dentry *, const char *);
...@@ -93,5 +93,5 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *, ...@@ -93,5 +93,5 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
size_t, int); size_t, int);
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, 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 */ #endif /* _CIFSFS_H */
...@@ -1046,9 +1046,12 @@ typedef union smb_com_transaction2 { ...@@ -1046,9 +1046,12 @@ typedef union smb_com_transaction2 {
/* PathInfo/FileInfo infolevels */ /* PathInfo/FileInfo infolevels */
#define SMB_INFO_STANDARD 1 #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_INFO_IS_NAME_VALID 6
#define SMB_QUERY_FILE_BASIC_INFO 0x101 #define SMB_QUERY_FILE_BASIC_INFO 0x101
#define SMB_QUERY_FILE_STANDARD_INFO 0x102 #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_NAME_INFO 0x104
#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105 #define SMB_QUERY_FILE_ALLOCATION_INFO 0x105
#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106 #define SMB_QUERY_FILE_END_OF_FILEINFO 0x106
...@@ -1687,16 +1690,17 @@ struct gealist { ...@@ -1687,16 +1690,17 @@ struct gealist {
}; };
struct fea { struct fea {
unsigned char fEA; unsigned char EA_flags;
unsigned char cbName; __u8 name_len;
unsigned short cbValue; __u16 value_len;
char szName[1]; char szName[1];
/* optionally followed by value */
}; };
/* flags for _FEA.fEA */ /* flags for _FEA.fEA */
#define FEA_NEEDEA 0x80 /* need EA bit */ #define FEA_NEEDEA 0x80 /* need EA bit */
struct fealist { struct fealist {
unsigned long cbList; unsigned long list_len;
struct fea list[1]; struct fea list[1];
}; };
......
...@@ -247,4 +247,8 @@ extern int CIFSSMBCopy(int xid, ...@@ -247,4 +247,8 @@ extern int CIFSSMBCopy(int xid,
extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
const int notify_subdirs,const __u16 netfid,__u32 filter, const int notify_subdirs,const __u16 netfid,__u32 filter,
const struct nls_table *nls_codepage); 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 */ #endif /* _CIFSPROTO_H */
...@@ -1596,6 +1596,8 @@ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, ...@@ -1596,6 +1596,8 @@ CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
} else { /* decode response */ } else { /* decode response */
pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
/* BB also check enough total bytes returned */ /* 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)) if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512))
rc = -EIO; /* bad smb */ rc = -EIO; /* bad smb */
else if (pFindData){ else if (pFindData){
...@@ -2879,3 +2881,88 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, ...@@ -2879,3 +2881,88 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
goto NotifyRetry; */ goto NotifyRetry; */
return rc; 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
rc = -ENOMEM;
}
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) ...@@ -128,7 +128,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
} }
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
/* do not want to be sending data on a socket we are freeing */
down(&server->tcpSem);
if(server->ssocket) { if(server->ssocket) {
cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state, cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
server->ssocket->flags)); server->ssocket->flags));
...@@ -154,7 +155,7 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -154,7 +155,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
} }
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
up(&server->tcpSem);
while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
{ {
...@@ -279,7 +280,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -279,7 +280,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
length = sock_recvmsg(csocket, &smb_msg, 4, 0); length = sock_recvmsg(csocket, &smb_msg, 4, 0);
cFYI(0,("Received 4 byte keep alive packet")); cFYI(0,("Received 4 byte keep alive packet"));
} else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) { } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
iov.iov_base = smb_buffer; iov.iov_base = smb_buffer;
iov.iov_len = 4; iov.iov_len = 4;
length = sock_recvmsg(csocket, &smb_msg, 4, 0); length = sock_recvmsg(csocket, &smb_msg, 4, 0);
cFYI(1,("Good RFC 1002 session rsp")); cFYI(1,("Good RFC 1002 session rsp"));
...@@ -1559,7 +1560,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -1559,7 +1560,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr += bcc_ptr +=
pSMBr->resp.SecurityBlobLength; pSMBr->resp.SecurityBlobLength;
if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
if ((long) (bcc_ptr) % 2) { if ((long) (bcc_ptr) % 2) {
remaining_words = remaining_words =
(BCC(smb_buffer_response) (BCC(smb_buffer_response)
...@@ -1812,7 +1813,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -1812,7 +1813,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pSMBr->resp.SecurityBlobLength)); pSMBr->resp.SecurityBlobLength));
} }
if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
if ((long) (bcc_ptr) % 2) { if ((long) (bcc_ptr) % 2) {
remaining_words = remaining_words =
(BCC(smb_buffer_response) (BCC(smb_buffer_response)
...@@ -2123,7 +2124,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2123,7 +2124,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
ses->server->secMode |= ses->server->secMode |=
SECMODE_SIGN_ENABLED; SECMODE_SIGN_ENABLED;
if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
if ((long) (bcc_ptr) % 2) { if ((long) (bcc_ptr) % 2) {
remaining_words = remaining_words =
(BCC(smb_buffer_response) (BCC(smb_buffer_response)
...@@ -2519,7 +2520,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2519,7 +2520,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
cFYI(1, cFYI(1,
("NTLMSSP response to Authenticate ")); ("NTLMSSP response to Authenticate "));
if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
if ((long) (bcc_ptr) % 2) { if ((long) (bcc_ptr) % 2) {
remaining_words = remaining_words =
(BCC(smb_buffer_response) (BCC(smb_buffer_response)
...@@ -2718,7 +2719,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2718,7 +2719,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
/* skip service field (NB: this field is always ASCII) */ /* skip service field (NB: this field is always ASCII) */
bcc_ptr += length + 1; bcc_ptr += length + 1;
strncpy(tcon->treeName, tree, MAX_TREE_SIZE); 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); length = UniStrnlen((wchar_t *) bcc_ptr, 512);
if (((long) bcc_ptr + (2 * length)) - if (((long) bcc_ptr + (2 * length)) -
(long) pByteArea(smb_buffer_response) <= (long) pByteArea(smb_buffer_response) <=
......
...@@ -143,6 +143,10 @@ cifs_open(struct inode *inode, struct file *file) ...@@ -143,6 +143,10 @@ cifs_open(struct inode *inode, struct file *file)
/* Also refresh inode by passing in file_info buf returned by SMBOpen /* Also refresh inode by passing in file_info buf returned by SMBOpen
and calling get_inode_info with returned buf (at least and calling get_inode_info with returned buf (at least
helps non-Unix server case */ 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); buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
if(buf==0) { if(buf==0) {
if (full_path) if (full_path)
...@@ -263,7 +267,7 @@ static int cifs_relock_file(struct cifsFileInfo * cifsFile) ...@@ -263,7 +267,7 @@ static int cifs_relock_file(struct cifsFileInfo * cifsFile)
return rc; 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 rc = -EACCES;
int xid, oplock; int xid, oplock;
...@@ -275,7 +279,6 @@ static int cifs_reopen_file(struct inode *inode, struct file *file) ...@@ -275,7 +279,6 @@ static int cifs_reopen_file(struct inode *inode, struct file *file)
int desiredAccess = 0x20197; int desiredAccess = 0x20197;
int disposition = FILE_OPEN; int disposition = FILE_OPEN;
__u16 netfid; __u16 netfid;
FILE_ALL_INFO * buf = NULL;
if(inode == NULL) if(inode == NULL)
return -EBADF; return -EBADF;
...@@ -328,21 +331,23 @@ and we can never tell if the caller already has the rename_sem */ ...@@ -328,21 +331,23 @@ and we can never tell if the caller already has the rename_sem */
else else
oplock = FALSE; 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 /* buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
and calling get_inode_info with returned buf (at least
helps non-Unix server case */
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
if(buf==0) { if(buf==0) {
up(&pCifsFile->fh_sem); up(&pCifsFile->fh_sem);
if (full_path) if (full_path)
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }*/
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, 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) { if (rc) {
up(&pCifsFile->fh_sem); up(&pCifsFile->fh_sem);
cFYI(1, ("cifs_open returned 0x%x ", rc)); 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 */ ...@@ -353,13 +358,25 @@ and we can never tell if the caller already has the rename_sem */
up(&pCifsFile->fh_sem); up(&pCifsFile->fh_sem);
pCifsInode = CIFS_I(inode); pCifsInode = CIFS_I(inode);
if(pCifsInode) { if(pCifsInode) {
if (pTcon->ses->capabilities & CAP_UNIX) if(can_flush) {
rc = cifs_get_inode_info_unix(&inode, 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); full_path, inode->i_sb);
else else
rc = cifs_get_inode_info(&inode, rc = cifs_get_inode_info(&inode,
full_path, buf, inode->i_sb); 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) { if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = TRUE; pCifsInode->clientCanCacheAll = TRUE;
pCifsInode->clientCanCacheRead = TRUE; pCifsInode->clientCanCacheRead = TRUE;
...@@ -375,8 +392,6 @@ and we can never tell if the caller already has the rename_sem */ ...@@ -375,8 +392,6 @@ and we can never tell if the caller already has the rename_sem */
} }
} }
if (buf)
kfree(buf);
if (full_path) if (full_path)
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
...@@ -612,7 +627,11 @@ cifs_write(struct file * file, const char *write_data, ...@@ -612,7 +627,11 @@ cifs_write(struct file * file, const char *write_data,
FreeXid(xid); FreeXid(xid);
return total_written; 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) if(rc != 0)
break; break;
} }
...@@ -968,7 +987,8 @@ cifs_read(struct file * file, char *read_data, size_t read_size, ...@@ -968,7 +987,8 @@ cifs_read(struct file * file, char *read_data, size_t read_size,
rc = -EAGAIN; rc = -EAGAIN;
while(rc == -EAGAIN) { while(rc == -EAGAIN) {
if ((open_file->invalidHandle) && (!open_file->closePend)) { 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) if(rc != 0)
break; break;
} }
...@@ -1123,7 +1143,8 @@ cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1123,7 +1143,8 @@ cifs_readpages(struct file *file, struct address_space *mapping,
rc = -EAGAIN; rc = -EAGAIN;
while(rc == -EAGAIN) { while(rc == -EAGAIN) {
if ((open_file->invalidHandle) && (!open_file->closePend)) { 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) if(rc != 0)
break; break;
} }
......
...@@ -568,9 +568,38 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry, ...@@ -568,9 +568,38 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
rc = CIFSSMBRename(xid, pTcon, fromName, toName, rc = CIFSSMBRename(xid, pTcon, fromName, toName,
cifs_sb_source->local_nls); cifs_sb_source->local_nls);
if(rc == -EEXIST) { if(rc == -EEXIST) {
cifs_unlink(target_inode, target_direntry); /* check if they are the same file
rc = CIFSSMBRename(xid, pTcon, fromName, toName, because rename of hardlinked files is a noop */
cifs_sb_source->local_nls); 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)) { if((rc == -EIO)||(rc == -EEXIST)) {
......
...@@ -210,7 +210,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) ...@@ -210,7 +210,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
} }
int 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; struct inode *inode = direntry->d_inode;
int rc = -EACCES; int rc = -EACCES;
......
...@@ -120,6 +120,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, ...@@ -120,6 +120,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
unsigned int smb_buf_length, struct sockaddr *sin) unsigned int smb_buf_length, struct sockaddr *sin)
{ {
int rc = 0; int rc = 0;
int i = 0;
struct msghdr smb_msg; struct msghdr smb_msg;
struct iovec iov; struct iovec iov;
mm_segment_t temp_fs; mm_segment_t temp_fs;
...@@ -151,6 +152,14 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, ...@@ -151,6 +152,14 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
while(iov.iov_len > 0) { while(iov.iov_len > 0) {
rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4); rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4);
if ((rc == -ENOSPC) || (rc == -EAGAIN)) { 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); set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ/2); schedule_timeout(HZ/2);
continue; continue;
...@@ -259,7 +268,17 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -259,7 +268,17 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
midQ->midState = MID_REQUEST_SUBMITTED; midQ->midState = MID_REQUEST_SUBMITTED;
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
(struct sockaddr *) &(ses->server->addr.sockAddr)); (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) if (long_op == -1)
goto cifs_no_response_exit; goto cifs_no_response_exit;
else if (long_op == 2) /* writes past end of file can take looooong time */ else if (long_op == 2) /* writes past end of file can take looooong time */
......
...@@ -20,37 +20,68 @@ ...@@ -20,37 +20,68 @@
*/ */
#include <linux/fs.h> #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 cifs_removexattr(struct dentry * direntry, const char * name)
{ {
int rc = -EOPNOTSUPP; int rc = -EOPNOTSUPP;
return rc; return rc;
} }
int cifs_setxattr(struct dentry * direntry, const char * name, int cifs_setxattr(struct dentry * direntry, const char * name,
const void * value, size_t size, int flags) const void * value, size_t size, int flags)
{ {
int rc = -EOPNOTSUPP; int rc = -EOPNOTSUPP;
return rc; return rc;
} }
ssize_t cifs_getxattr(struct dentry * direntry, const char * name, ssize_t cifs_getxattr(struct dentry * direntry, const char * name,
void * value, size_t size) void * value, size_t size)
{ {
ssize_t rc = -EOPNOTSUPP; ssize_t rc = -EOPNOTSUPP;
return rc; return rc;
} }
ssize_t cifs_listxattr(struct dentry * direntry, char * ea_data, size_t ea_size) 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 dosattributes as pseudo xattr */
/* return alt name if available as pseudo attr */ /* return alt name if available as pseudo attr */
/* if proc/fs/cifs/streamstoxattr is set then /* if proc/fs/cifs/streamstoxattr is set then
search server for EAs or streams to search server for EAs or streams to
returns as xattrs */ returns as xattrs */
rc = CIFSSMBQAllEAs(xid,pTcon,full_path,ea_data,ea_size,cifs_sb->local_nls);
return rc; 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