Commit cc6bcfef authored by Linus Torvalds's avatar Linus Torvalds

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

into penguin.transmeta.com:/home/torvalds/v2.5/linux
parents 7196d9df 629d5ab8
...@@ -20,3 +20,9 @@ Patch Contributors ...@@ -20,3 +20,9 @@ Patch Contributors
Zwane Mwaikambo Zwane Mwaikambo
Andi Kleen Andi Kleen
Test case and Bug Report contributors
-------------------------------------
Thanks to those in the community who have submitted detailed bug reports
and debug of problems they have found: Jochen Dolze, David Blaine,
Rene Scharfe, Martin Josefsson and others.
Version 0.77
------------
Fix display of NTFS DFS junctions to display as symlinks.
They are the network equivalent. Fix oops in
cifs_partialpagewrite caused by missing spinlock protection
of openfile linked list. Allow writebehind caching errors to
be returned to the application at file close.
Version 0.76
------------
Clean up options displayed in /proc/mounts by show_options to
be more consistent with other filesystems.
Version 0.75 Version 0.75
------------ ------------
Fix delete of readonly file to Windows servers. Reflect Fix delete of readonly file to Windows servers. Reflect
......
...@@ -18,6 +18,8 @@ c) multi-user mounts - multiplexed sessionsetups over single vc ...@@ -18,6 +18,8 @@ c) multi-user mounts - multiplexed sessionsetups over single vc
d) Kerberos/SPNEGO session setup support - (started) d) Kerberos/SPNEGO session setup support - (started)
e) NTLMv2 authentication and MD5-HMAC signing SMB PDUs - (mostly implemented) e) NTLMv2 authentication and MD5-HMAC signing SMB PDUs - (mostly implemented)
signing necessary for some Windows 2003 servers in domain
controller mode.
f) oplock support (ie safe CIFS distributed file caching) is not quite complete. f) oplock support (ie safe CIFS distributed file caching) is not quite complete.
In addition Directory entry caching relies on a 1 second timer, rather than In addition Directory entry caching relies on a 1 second timer, rather than
...@@ -52,7 +54,8 @@ file opens on top of each other by incrementing reference count rather ...@@ -52,7 +54,8 @@ file opens on top of each other by incrementing reference count rather
than resending (helps reduce server resource utilization and avoid than resending (helps reduce server resource utilization and avoid
spurious oplock breaks). spurious oplock breaks).
KNOWN BUGS (updated March 7, 2003)
KNOWN BUGS (updated May 16, 2003)
==================================== ====================================
1) existing symbolic links (Windows reparse points) are recognized but 1) existing symbolic links (Windows reparse points) are recognized but
can not be created remotely. They are implemented for Samba and those that can not be created remotely. They are implemented for Samba and those that
...@@ -60,6 +63,11 @@ support the CIFS Unix extensions but Samba has a bug currently handling ...@@ -60,6 +63,11 @@ support the CIFS Unix extensions but Samba has a bug currently handling
symlink text beginning with slash symlink text beginning with slash
2) delete of file with read-only attribute set will fail (may be ok) 2) delete of file with read-only attribute set will fail (may be ok)
3) mount helper syntax not quite matching man page 3) mount helper syntax not quite matching man page
4) follow_link and readdir code does not follow dfs junctions
but recognizes them
5) create of new files to FAT partitions on Windows servers can
succeed but still return access denied (appears to be Windows
not client problem). NTFS partitions do not have this problem.
Misc testing to do Misc testing to do
================= =================
...@@ -68,6 +76,6 @@ types. ...@@ -68,6 +76,6 @@ types.
2) Run dbench 2) Run dbench
3) Finish FSX testing on SMP now that we workaround the Samba bug 3) Finish high stress fsx testing on SMP clients
4) Additional performance testing and optimization 4) Additional performance testing and optimization
...@@ -89,8 +89,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -89,8 +89,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
ses->serverOS, ses->serverNOS, ses->capabilities); ses->serverOS, ses->serverNOS, ses->capabilities);
buf += length; buf += length;
if(ses->server) if(ses->server)
buf += sprintf(buf, "\tLocal Users To Same Server: %d ", buf += sprintf(buf, "\tLocal Users To Same Server: %d ",
atomic_read(&ses->server->socketUseCount)); atomic_read(&ses->server->socketUseCount));
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
sprintf(buf, "\n"); sprintf(buf, "\n");
......
...@@ -22,7 +22,7 @@ struct cifs_sb_info { ...@@ -22,7 +22,7 @@ struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */ struct cifsTconInfo *tcon; /* primary mount */
struct list_head nested_tcon_q; struct list_head nested_tcon_q;
struct nls_table *local_nls; struct nls_table *local_nls;
unsigned int rsize; unsigned int rsize;
unsigned int wsize; unsigned int wsize;
}; };
#endif /* _CIFS_FS_SB_H */ #endif /* _CIFS_FS_SB_H */
...@@ -209,8 +209,8 @@ cifs_destroy_inode(struct inode *inode) ...@@ -209,8 +209,8 @@ cifs_destroy_inode(struct inode *inode)
/* /*
* cifs_show_options() is for displaying mount options in /proc/mounts. * cifs_show_options() is for displaying mount options in /proc/mounts.
* It tries to avoid showing settings that were not changed from their * Not all settable options are displayed but most of the important
* defaults. * ones are.
*/ */
static int static int
cifs_show_options(struct seq_file *s, struct vfsmount *m) cifs_show_options(struct seq_file *s, struct vfsmount *m)
...@@ -219,15 +219,19 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) ...@@ -219,15 +219,19 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
cifs_sb = CIFS_SB(m->mnt_sb); cifs_sb = CIFS_SB(m->mnt_sb);
if (cifs_sb) if (cifs_sb) {
if (cifs_sb->tcon) { if (cifs_sb->tcon) {
seq_printf(s, ", TARGET: %s ", cifs_sb->tcon->treeName); seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
seq_printf(s, "FS TYPE: %s ",
cifs_sb->tcon->nativeFileSystem);
if (cifs_sb->tcon->ses->userName) if (cifs_sb->tcon->ses->userName)
seq_printf(s, " USER: %s ", seq_printf(s, ",username=%s",
cifs_sb->tcon->ses->userName); cifs_sb->tcon->ses->userName);
if(cifs_sb->tcon->ses->domainName)
seq_printf(s, ",domain=%s",
cifs_sb->tcon->ses->domainName);
} }
seq_printf(s, ",rsize=%d",cifs_sb->rsize);
seq_printf(s, ",wsize=%d",cifs_sb->wsize);
}
return 0; return 0;
} }
...@@ -423,6 +427,7 @@ cifs_destroy_mids(void) ...@@ -423,6 +427,7 @@ cifs_destroy_mids(void)
static int cifs_oplock_thread(void * dummyarg) static int cifs_oplock_thread(void * dummyarg)
{ {
struct list_head * tmp; struct list_head * tmp;
struct list_head * tmp1;
struct oplock_q_entry * oplock_item; struct oplock_q_entry * oplock_item;
struct file * pfile; struct file * pfile;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
...@@ -438,9 +443,8 @@ static int cifs_oplock_thread(void * dummyarg) ...@@ -438,9 +443,8 @@ static int cifs_oplock_thread(void * dummyarg)
/* BB add missing code */ /* BB add missing code */
cFYI(1,("oplock thread woken up - flush inode")); /* BB remove */ cFYI(1,("oplock thread woken up - flush inode")); /* BB remove */
write_lock(&GlobalMid_Lock); write_lock(&GlobalMid_Lock);
list_for_each(tmp, &GlobalOplock_Q) { list_for_each_safe(tmp, tmp1, &GlobalOplock_Q) {
oplock_item = list_entry(tmp, struct oplock_item = list_entry(tmp, struct oplock_q_entry,
oplock_q_entry,
qhead); qhead);
if(oplock_item) { if(oplock_item) {
pTcon = oplock_item->tcon; pTcon = oplock_item->tcon;
...@@ -449,6 +453,9 @@ static int cifs_oplock_thread(void * dummyarg) ...@@ -449,6 +453,9 @@ static int cifs_oplock_thread(void * dummyarg)
DeleteOplockQEntry(oplock_item); DeleteOplockQEntry(oplock_item);
write_unlock(&GlobalMid_Lock); write_unlock(&GlobalMid_Lock);
rc = filemap_fdatawrite(pfile->f_dentry->d_inode->i_mapping); rc = filemap_fdatawrite(pfile->f_dentry->d_inode->i_mapping);
if(rc)
CIFS_I(pfile->f_dentry->d_inode)->write_behind_rc
= rc;
cFYI(1,("Oplock flush file %p rc %d",pfile,rc)); cFYI(1,("Oplock flush file %p rc %d",pfile,rc));
/* send oplock break */ /* send oplock break */
write_lock(&GlobalMid_Lock); write_lock(&GlobalMid_Lock);
......
...@@ -157,8 +157,8 @@ struct cifsSesInfo { ...@@ -157,8 +157,8 @@ struct cifsSesInfo {
int capabilities; int capabilities;
char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */
char userName[MAX_USERNAME_SIZE + 1]; char userName[MAX_USERNAME_SIZE + 1];
char domainName[MAX_USERNAME_SIZE + 1]; char domainName[MAX_USERNAME_SIZE + 1];
char password_with_pad[CIFS_ENCPWD_SIZE]; char password_with_pad[CIFS_ENCPWD_SIZE];
}; };
/* /*
...@@ -204,7 +204,7 @@ struct cifsFileInfo { ...@@ -204,7 +204,7 @@ struct cifsFileInfo {
__u16 netfid; /* file id from remote */ __u16 netfid; /* file id from remote */
/* BB add lock scope info here if needed */ ; /* BB add lock scope info here if needed */ ;
/* lock scope id (0 if none) */ /* lock scope id (0 if none) */
struct file * pfile; /* needed for writepage */ struct file * pfile; /* needed for writepage */
int endOfSearch:1; /* we have reached end of search */ int endOfSearch:1; /* we have reached end of search */
int closePend:1; /* file is marked to close */ int closePend:1; /* file is marked to close */
int emptyDir:1; int emptyDir:1;
...@@ -221,6 +221,7 @@ struct cifsInodeInfo { ...@@ -221,6 +221,7 @@ struct cifsInodeInfo {
struct list_head lockList; struct list_head lockList;
/* BB add in lists for dirty pages - i.e. write caching info for oplock */ /* BB add in lists for dirty pages - i.e. write caching info for oplock */
struct list_head openFileList; struct list_head openFileList;
int write_behind_rc;
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
atomic_t inUse; /* num concurrent users (local openers cifs) of file*/ atomic_t inUse; /* num concurrent users (local openers cifs) of file*/
unsigned long time; /* jiffies of last update/check of inode */ unsigned long time; /* jiffies of last update/check of inode */
......
...@@ -1263,6 +1263,7 @@ typedef struct dfs_referral_level_3 { ...@@ -1263,6 +1263,7 @@ typedef struct dfs_referral_level_3 {
__u16 ServerType; /* 0x0001 = CIFS server */ __u16 ServerType; /* 0x0001 = CIFS server */
__u16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */ __u16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */
__u16 TimeToLive; __u16 TimeToLive;
__u16 Proximity;
__u16 DfsPathOffset; __u16 DfsPathOffset;
__u16 DfsAlternatePathOffset; __u16 DfsAlternatePathOffset;
__u16 NetworkAddressOffset; __u16 NetworkAddressOffset;
......
...@@ -127,13 +127,15 @@ extern int CIFSSMBUnixQPathInfo(const int xid, ...@@ -127,13 +127,15 @@ extern int CIFSSMBUnixQPathInfo(const int xid,
extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName, const unsigned char *searchName,
unsigned char **targetUNCs, unsigned char **targetUNCs,
int *number_of_UNC_in_array, unsigned int *number_of_UNC_in_array,
const struct nls_table *nls_codepage); const struct nls_table *nls_codepage);
extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const char *old_path,
const struct nls_table *nls_codepage); const struct nls_table *nls_codepage);
extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const struct nls_table *nls_codepage,
unsigned int *pnum_referrals, unsigned char ** preferrals);
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
struct statfs *FSData, struct statfs *FSData,
const struct nls_table *nls_codepage); const struct nls_table *nls_codepage);
......
...@@ -1625,15 +1625,18 @@ int ...@@ -1625,15 +1625,18 @@ int
CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName, const unsigned char *searchName,
unsigned char **targetUNCs, unsigned char **targetUNCs,
int *number_of_UNC_in_array, unsigned int *number_of_UNC_in_array,
const struct nls_table *nls_codepage) const struct nls_table *nls_codepage)
{ {
/* TRANS2_GET_DFS_REFERRAL */ /* TRANS2_GET_DFS_REFERRAL */
TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
struct dfs_referral_level_3 * referrals = NULL;
int rc = 0; int rc = 0;
int bytes_returned; int bytes_returned;
int name_len; int name_len;
unsigned int i;
char * temp;
*number_of_UNC_in_array = 0; *number_of_UNC_in_array = 0;
*targetUNCs = NULL; *targetUNCs = NULL;
...@@ -1654,8 +1657,8 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, ...@@ -1654,8 +1657,8 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
if (ses->capabilities & CAP_DFS) { if (ses->capabilities & CAP_DFS) {
pSMB->hdr.Flags2 |= SMBFLG2_DFS; pSMB->hdr.Flags2 |= SMBFLG2_DFS;
} }
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
if (ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
...@@ -1701,6 +1704,76 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, ...@@ -1701,6 +1704,76 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
cFYI(1, ("Send error in GetDFSRefer = %d", rc)); cFYI(1, ("Send error in GetDFSRefer = %d", rc));
} else { /* decode response */ } else { /* decode response */
/* BB Add logic to parse referrals here */ /* BB Add logic to parse referrals here */
pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
cFYI(1,
("Decoding GetDFSRefer response. BCC: %d Offset %d",
pSMBr->ByteCount, pSMBr->DataOffset));
if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */
rc = -EIO; /* bad smb */
else {
referrals =
(struct dfs_referral_level_3 *)
(8 /* sizeof start of data block */ +
pSMBr->DataOffset +
(char *) &pSMBr->hdr.Protocol);
cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive));
/* BB This field is actually two bytes in from start of
data block so we could do safety check that DataBlock
begins at address of pSMBr->NumberOfReferrals */
*number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
/* BB Fix below so can return more than one referral */
if(*number_of_UNC_in_array > 1)
*number_of_UNC_in_array = 1;
/* get the length of the strings describing refs */
name_len = 0;
for(i=0;i<*number_of_UNC_in_array;i++) {
/* make sure that DfsPathOffset not past end */
referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset);
if(referrals->DfsPathOffset > pSMBr->DataCount) {
/* if invalid referral, stop here and do
not try to copy any more */
*number_of_UNC_in_array = i;
break;
}
temp = ((char *)referrals) + referrals->DfsPathOffset;
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount);
} else {
name_len += strnlen(temp,pSMBr->DataCount);
}
referrals++;
/* BB add check that referral pointer does not fall off end PDU */
}
/* BB add check for name_len bigger than bcc */
*targetUNCs =
kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
/* copy the ref strings */
referrals =
(struct dfs_referral_level_3 *)
(8 /* sizeof data hdr */ +
pSMBr->DataOffset +
(char *) &pSMBr->hdr.Protocol);
for(i=0;i<*number_of_UNC_in_array;i++) {
temp = ((char *)referrals) + referrals->DfsPathOffset;
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
cifs_strfromUCS_le(*targetUNCs,
(wchar_t *) temp, name_len, nls_codepage);
} else {
strncpy(*targetUNCs,temp,name_len);
}
/* BB update target_uncs pointers */
referrals++;
}
temp = *targetUNCs;
temp[name_len] = 0;
}
} }
if (pSMB) if (pSMB)
buf_release(pSMB); buf_release(pSMB);
......
...@@ -57,8 +57,8 @@ struct smb_vol { ...@@ -57,8 +57,8 @@ struct smb_vol {
mode_t file_mode; mode_t file_mode;
mode_t dir_mode; mode_t dir_mode;
int rw; int rw;
unsigned int rsize; unsigned int rsize;
unsigned int wsize; unsigned int wsize;
unsigned short int port; unsigned short int port;
}; };
...@@ -571,11 +571,32 @@ find_unc(__u32 new_target_ip_addr, char *uncName, char *userName) ...@@ -571,11 +571,32 @@ find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
int int
connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const struct nls_table *nls_codepage) const char *old_path, const struct nls_table *nls_codepage)
{
unsigned char *referrals = NULL;
unsigned int num_referrals;
int rc = 0;
rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
&num_referrals, &referrals);
/* BB Add in code to: if valid refrl, if not ip address contact
the helper that resolves tcp names, mount to it, try to
tcon to it unmount it if fail */
/* BB free memory for referrals string BB */
return rc;
}
int
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const struct nls_table *nls_codepage,
unsigned int *pnum_referrals, unsigned char ** preferrals)
{ {
char *temp_unc; char *temp_unc;
int rc = 0; int rc = 0;
int num_referrals = 0;
unsigned char *referrals = NULL; *pnum_referrals = 0;
if (pSesInfo->ipc_tid == 0) { if (pSesInfo->ipc_tid == 0) {
temp_unc = kmalloc(2 /* for slashes */ + temp_unc = kmalloc(2 /* for slashes */ +
...@@ -594,11 +615,10 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ...@@ -594,11 +615,10 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
kfree(temp_unc); kfree(temp_unc);
} }
if (rc == 0) if (rc == 0)
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &referrals, rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
&num_referrals, nls_codepage); pnum_referrals, nls_codepage);
return -ENODEV; /* BB remove and add return code processing */
return rc;
} }
int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info) int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info)
......
...@@ -110,10 +110,14 @@ cifs_open(struct inode *inode, struct file *file) ...@@ -110,10 +110,14 @@ cifs_open(struct inode *inode, struct file *file)
pCifsFile->netfid = netfid; pCifsFile->netfid = netfid;
pCifsFile->pid = current->pid; pCifsFile->pid = current->pid;
pCifsFile->pfile = file; /* needed for writepage */ pCifsFile->pfile = file; /* needed for writepage */
write_lock(&file->f_owner.lock);
write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist,&pTcon->openFileList); list_add(&pCifsFile->tlist,&pTcon->openFileList);
pCifsInode = CIFS_I(file->f_dentry->d_inode); pCifsInode = CIFS_I(file->f_dentry->d_inode);
if(pCifsInode->openFileList.next) if(pCifsInode->openFileList.next)
list_add(&pCifsFile->flist,&pCifsInode->openFileList); list_add(&pCifsFile->flist,&pCifsInode->openFileList);
write_unlock(&GlobalSMBSeslock);
write_unlock(&file->f_owner.lock);
if(file->f_flags & O_CREAT) { if(file->f_flags & O_CREAT) {
/* time to set mode which we can not set earlier due /* time to set mode which we can not set earlier due
to problems creating new read-only files */ to problems creating new read-only files */
...@@ -152,11 +156,13 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo) ...@@ -152,11 +156,13 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo)
{ {
int rc = 0; int rc = 0;
struct cifsFileInfo *open_file = NULL; struct cifsFileInfo *open_file = NULL;
struct file * file = NULL; struct file * file = NULL;
struct list_head *tmp; struct list_head *tmp;
struct list_head *tmp1;
/* list all files open on tree connection */ /* list all files open on tree connection */
list_for_each(tmp, &pTcon->openFileList) { read_lock(&GlobalSMBSeslock);
list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
open_file = list_entry(tmp,struct cifsFileInfo, flist); open_file = list_entry(tmp,struct cifsFileInfo, flist);
if(open_file) { if(open_file) {
if(open_file->search_resume_name) { if(open_file->search_resume_name) {
...@@ -166,7 +172,9 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo) ...@@ -166,7 +172,9 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo)
kfree(open_file); kfree(open_file);
if(file) { if(file) {
file->private_data = NULL; file->private_data = NULL;
read_unlock(&GlobalSMBSeslock);
rc = cifs_open(file->f_dentry->d_inode,file); rc = cifs_open(file->f_dentry->d_inode,file);
read_lock(&GlobalSMBSeslock);
if(rc) { if(rc) {
cFYI(1,("reconnecting file %s failed with %d", cFYI(1,("reconnecting file %s failed with %d",
file->f_dentry->d_name.name,rc)); file->f_dentry->d_name.name,rc));
...@@ -177,6 +185,7 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo) ...@@ -177,6 +185,7 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo)
} }
} }
} }
read_unlock(&GlobalSMBSeslock);
return rc; return rc;
} }
...@@ -195,9 +204,11 @@ cifs_close(struct inode *inode, struct file *file) ...@@ -195,9 +204,11 @@ cifs_close(struct inode *inode, struct file *file)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if (pSMBFile) { if (pSMBFile) {
write_lock(&file->f_owner.lock);
if(pSMBFile->flist.next) if(pSMBFile->flist.next)
list_del(&pSMBFile->flist); list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist); list_del(&pSMBFile->tlist);
write_unlock(&file->f_owner.lock);
rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid); rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid);
if(pSMBFile->search_resume_name) if(pSMBFile->search_resume_name)
kfree(pSMBFile->search_resume_name); kfree(pSMBFile->search_resume_name);
...@@ -206,6 +217,8 @@ cifs_close(struct inode *inode, struct file *file) ...@@ -206,6 +217,8 @@ cifs_close(struct inode *inode, struct file *file)
} else } else
rc = -EBADF; rc = -EBADF;
if((rc ==0) && CIFS_I(inode)->write_behind_rc)
rc = CIFS_I(inode)->write_behind_rc;
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
...@@ -407,6 +420,7 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) ...@@ -407,6 +420,7 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
struct cifsInodeInfo *cifsInode; struct cifsInodeInfo *cifsInode;
struct cifsFileInfo *open_file = NULL; struct cifsFileInfo *open_file = NULL;
struct list_head *tmp; struct list_head *tmp;
struct list_head *tmp1;
int xid; int xid;
xid = GetXid(); xid = GetXid();
...@@ -445,14 +459,17 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) ...@@ -445,14 +459,17 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
cifsInode = CIFS_I(mapping->host); cifsInode = CIFS_I(mapping->host);
list_for_each(tmp, &cifsInode->openFileList) { read_lock(&GlobalSMBSeslock);
list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {
open_file = list_entry(tmp,struct cifsFileInfo, flist); open_file = list_entry(tmp,struct cifsFileInfo, flist);
/* We could check if file is open for writing first */ /* We could check if file is open for writing first */
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))) {
read_unlock(&GlobalSMBSeslock);
bytes_written = cifs_write(open_file->pfile, write_data, bytes_written = cifs_write(open_file->pfile, write_data,
to-from, &offset); to-from, &offset);
read_lock(&GlobalSMBSeslock);
/* Does mm or vfs already set times? */ /* Does mm or vfs already set times? */
inode->i_atime = inode->i_mtime = CURRENT_TIME; inode->i_atime = inode->i_mtime = CURRENT_TIME;
if ((bytes_written > 0) && (offset)) { if ((bytes_written > 0) && (offset)) {
...@@ -462,6 +479,7 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) ...@@ -462,6 +479,7 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
} }
} }
} }
read_unlock(&GlobalSMBSeslock);
if(open_file == NULL) { if(open_file == NULL) {
cFYI(1,("No writeable filehandles for inode")); cFYI(1,("No writeable filehandles for inode"));
rc = -EIO; rc = -EIO;
...@@ -548,7 +566,8 @@ cifs_fsync(struct file *file, struct dentry *dentry, int datasync) ...@@ -548,7 +566,8 @@ cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
dentry->d_name.name, datasync)); dentry->d_name.name, datasync));
rc = filemap_fdatawrite(inode->i_mapping); rc = filemap_fdatawrite(inode->i_mapping);
if(rc == 0)
CIFS_I(inode)->write_behind_rc = 0;
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
...@@ -600,6 +619,9 @@ int cifs_flush(struct file *file) ...@@ -600,6 +619,9 @@ int cifs_flush(struct file *file)
/* filemapfdatawrite appears easier for the time being */ /* filemapfdatawrite appears easier for the time being */
rc = filemap_fdatawrite(inode->i_mapping); rc = filemap_fdatawrite(inode->i_mapping);
if(rc == 0) /* reset wb rc if we were able to write out dirty pages */
CIFS_I(inode)->write_behind_rc = 0;
cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc)); cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc));
return rc; return rc;
...@@ -678,12 +700,16 @@ static void cifs_copy_cache_pages(struct address_space *mapping, ...@@ -678,12 +700,16 @@ static void cifs_copy_cache_pages(struct address_space *mapping,
while (bytes_read > 0) { while (bytes_read > 0) {
if(list_empty(pages)) if(list_empty(pages))
break; break;
spin_lock(&mapping->page_lock);
page = list_entry(pages->prev, struct page, list); page = list_entry(pages->prev, struct page, list);
list_del(&page->list); list_del(&page->list);
spin_unlock(&mapping->page_lock);
if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
page_cache_release(page); page_cache_release(page);
cFYI(1,("Add page cache failed")); cFYI(1,("Add page cache failed"));
continue; continue;
} }
...@@ -739,12 +765,14 @@ cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -739,12 +765,14 @@ cifs_readpages(struct file *file, struct address_space *mapping,
pagevec_init(&lru_pvec, 0); pagevec_init(&lru_pvec, 0);
for(i = 0;i<num_pages;) { for(i = 0;i<num_pages;) {
spin_lock(&mapping->page_lock);
if(list_empty(page_list)) { if(list_empty(page_list)) {
break; break;
} }
page = list_entry(page_list->prev, struct page, list); page = list_entry(page_list->prev, struct page, list);
offset = (loff_t)page->index << PAGE_CACHE_SHIFT; offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
spin_unlock(&mapping->page_lock);
/* for reads over a certain size could initiate async read ahead */ /* for reads over a certain size could initiate async read ahead */
cFYI(0,("Read %d pages into cache at offset %ld ", cFYI(0,("Read %d pages into cache at offset %ld ",
...@@ -762,12 +790,15 @@ cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -762,12 +790,15 @@ cifs_readpages(struct file *file, struct address_space *mapping,
if ((rc < 0) || (smb_read_data == NULL)) { if ((rc < 0) || (smb_read_data == NULL)) {
cFYI(1,("Read error in readpages: %d",rc)); cFYI(1,("Read error in readpages: %d",rc));
/* clean up remaing pages off list */ /* clean up remaing pages off list */
spin_lock(&mapping->page_lock);
while (!list_empty(page_list) && (i < num_pages)) { while (!list_empty(page_list) && (i < num_pages)) {
page = list_entry(page_list->prev, struct page, list); page = list_entry(page_list->prev, struct page, list);
list_del(&page->list); list_del(&page->list);
} }
spin_unlock(&mapping->page_lock);
break; break;
} else if (bytes_read > 0){ } else if (bytes_read > 0) {
pSMBr = (struct smb_com_read_rsp *)smb_read_data; pSMBr = (struct smb_com_read_rsp *)smb_read_data;
cifs_copy_cache_pages(mapping, page_list, bytes_read, cifs_copy_cache_pages(mapping, page_list, bytes_read,
smb_read_data + 4 /* RFC1000 hdr */ + smb_read_data + 4 /* RFC1000 hdr */ +
...@@ -783,9 +814,9 @@ cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -783,9 +814,9 @@ cifs_readpages(struct file *file, struct address_space *mapping,
} }
if(smb_read_data) { if(smb_read_data) {
buf_release(smb_read_data); buf_release(smb_read_data);
smb_read_data = 0; smb_read_data = 0;
} }
bytes_read = 0; bytes_read = 0;
} }
pagevec_lru_add(&lru_pvec); pagevec_lru_add(&lru_pvec);
......
...@@ -53,10 +53,6 @@ cifs_get_inode_info_unix(struct inode **pinode, ...@@ -53,10 +53,6 @@ cifs_get_inode_info_unix(struct inode **pinode,
/* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */ /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
if (rc) { if (rc) {
if (rc == -EREMOTE) { if (rc == -EREMOTE) {
/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
&referrals,
&num_referrals,
cifs_sb->local_nls); */
tmp_path = tmp_path =
kmalloc(strnlen kmalloc(strnlen
(pTcon->treeName, (pTcon->treeName,
...@@ -180,11 +176,6 @@ cifs_get_inode_info(struct inode **pinode, ...@@ -180,11 +176,6 @@ cifs_get_inode_info(struct inode **pinode,
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) { if (rc) {
if (rc == -EREMOTE) { if (rc == -EREMOTE) {
/* BB add call to new func rc = GetDFSReferral(); */
/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
&referrals,
&num_referrals,
cifs_sb->local_nls); */
tmp_path = tmp_path =
kmalloc(strnlen kmalloc(strnlen
(pTcon->treeName, (pTcon->treeName,
......
...@@ -113,6 +113,9 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -113,6 +113,9 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
/* BB Should we be using page symlink ops here? */ /* BB Should we be using page symlink ops here? */
if (rc == 0) { if (rc == 0) {
/* BB Add special case check for Samba DFS symlinks */
target_path[PATH_MAX-1] = 0; target_path[PATH_MAX-1] = 0;
rc = vfs_follow_link(nd, target_path); rc = vfs_follow_link(nd, target_path);
} }
...@@ -186,7 +189,10 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -186,7 +189,10 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
char *full_path = NULL; char *full_path = NULL;
char *tmp_path = NULL;
char * tmpbuffer; char * tmpbuffer;
unsigned char * referrals = NULL;
int num_referrals = 0;
int len; int len;
__u16 fid; __u16 fid;
...@@ -206,6 +212,7 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -206,6 +212,7 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ /* BB add read reparse point symlink code and Unix extensions symlink code here BB */
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
...@@ -224,8 +231,36 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -224,8 +231,36 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
if(CIFSSMBClose(xid, pTcon, fid)) { if(CIFSSMBClose(xid, pTcon, fid)) {
cFYI(1,("Error closing junction point (open for ioctl)")); cFYI(1,("Error closing junction point (open for ioctl)"));
} }
} if(rc == -EIO) {
/* Query if DFS Junction */
tmp_path =
kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
GFP_KERNEL);
if (tmp_path) {
strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
strncat(tmp_path, full_path, MAX_PATHCONF);
rc = get_dfs_path(xid, pTcon->ses, tmp_path,
cifs_sb->local_nls, &num_referrals, &referrals);
cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc));
if((num_referrals == 0) && (rc == 0))
rc = -EACCES;
else {
cFYI(1,("num referral: %d",num_referrals));
if(referrals) {
cFYI(1,("referral string: %s ",referrals));
strncpy(tmpbuffer, referrals, len-1);
}
}
kfree(tmp_path);
if(referrals) {
kfree(referrals);
}
}
/* BB add code like else decode referrals then memcpy to
tmpbuffer and free referrals string array BB */
}
}
} }
/* BB Anything else to do to handle recursive links? */ /* BB Anything else to do to handle recursive links? */
/* BB Should we be using page ops here? */ /* BB Should we be using page ops here? */
...@@ -238,10 +273,12 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -238,10 +273,12 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
rc)); rc));
} }
if (tmpbuffer) if (tmpbuffer) {
kfree(tmpbuffer); kfree(tmpbuffer);
if (full_path) }
if (full_path) {
kfree(full_path); kfree(full_path);
}
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
...@@ -115,7 +115,7 @@ AllocOplockQEntry(struct file * file, struct cifsTconInfo * tcon) ...@@ -115,7 +115,7 @@ AllocOplockQEntry(struct file * file, struct cifsTconInfo * tcon)
list_add_tail(&temp->qhead, &GlobalOplock_Q); list_add_tail(&temp->qhead, &GlobalOplock_Q);
write_unlock(&GlobalMid_Lock); write_unlock(&GlobalMid_Lock);
} }
return temp; return temp;
} }
......
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