Commit 2dc51bdf authored by Steve French's avatar Steve French

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

into hostme.bitkeeper.com:/ua/repos/c/cifs/linux-2.5cifs
parents 7b87c44e 8d2ccdc9
Version 0.73
------------
unload nls if mount fails.
Version 0.72
------------
Add resume key support to search (readdir) code to workaround
Windows bug. Add /proc/fs/cifs/LookupCacheEnable which
allows disabling caching of attribute information for
lookups.
Version 0.71
------------
Add more oplock handling (distributed caching code). Remove
dead code. Remove excessive stack space utilization from
symlink routines.
Version 0.70 Version 0.70
------------ ------------
Fix oops in get dfs referral (triggered when null path sent in to Fix oops in get dfs referral (triggered when null path sent in to
......
...@@ -185,6 +185,8 @@ static read_proc_t cifsFYI_read; ...@@ -185,6 +185,8 @@ static read_proc_t cifsFYI_read;
static write_proc_t cifsFYI_write; static write_proc_t cifsFYI_write;
static read_proc_t oplockEnabled_read; static read_proc_t oplockEnabled_read;
static write_proc_t oplockEnabled_write; static write_proc_t oplockEnabled_write;
static read_proc_t lookupFlag_read;
static write_proc_t lookupFlag_write;
static read_proc_t traceSMB_read; static read_proc_t traceSMB_read;
static write_proc_t traceSMB_write; static write_proc_t traceSMB_write;
static read_proc_t multiuser_mount_read; static read_proc_t multiuser_mount_read;
...@@ -243,6 +245,12 @@ cifs_proc_init(void) ...@@ -243,6 +245,12 @@ cifs_proc_init(void)
if (pde) if (pde)
pde->write_proc = extended_security_write; pde->write_proc = extended_security_write;
pde =
create_proc_read_entry("LookupCacheEnable", 0, proc_fs_cifs,
lookupFlag_read, 0);
if (pde)
pde->write_proc = lookupFlag_write;
pde = pde =
create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
ntlmv2_enabled_read, 0); ntlmv2_enabled_read, 0);
...@@ -353,6 +361,44 @@ oplockEnabled_write(struct file *file, const char *buffer, ...@@ -353,6 +361,44 @@ oplockEnabled_write(struct file *file, const char *buffer,
return count; return count;
} }
static int
lookupFlag_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len;
len = sprintf(page, "%d\n", lookupCacheEnabled);
len -= off;
*start = page + off;
if (len > count)
len = count;
else
*eof = 1;
if (len < 0)
len = 0;
return len;
}
static int
lookupFlag_write(struct file *file, const char *buffer,
unsigned long count, void *data)
{
char c;
int rc;
rc = get_user(c, buffer);
if (rc)
return rc;
if (c == '0' || c == 'n' || c == 'N')
lookupCacheEnabled = 0;
else if (c == '1' || c == 'y' || c == 'Y')
lookupCacheEnabled = 1;
return count;
}
static int static int
traceSMB_read(char *page, char **start, off_t off, int count, traceSMB_read(char *page, char **start, off_t off, int count,
int *eof, void *data) int *eof, void *data)
......
...@@ -48,11 +48,13 @@ int cifsFYI = 0; ...@@ -48,11 +48,13 @@ int cifsFYI = 0;
int cifsERROR = 1; int cifsERROR = 1;
int traceSMB = 0; int traceSMB = 0;
unsigned int oplockEnabled = 0; unsigned int oplockEnabled = 0;
unsigned int lookupCacheEnabled = 1;
unsigned int multiuser_mount = 0; unsigned int multiuser_mount = 0;
unsigned int extended_security = 0; unsigned int extended_security = 0;
unsigned int ntlmv2_support = 0; unsigned int ntlmv2_support = 0;
unsigned int sign_CIFS_PDUs = 0; unsigned int sign_CIFS_PDUs = 0;
unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE; unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE;
struct task_struct * oplockThread = NULL;
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
char *); char *);
...@@ -107,6 +109,8 @@ cifs_read_super(struct super_block *sb, void *data, char *devname, int silent) ...@@ -107,6 +109,8 @@ cifs_read_super(struct super_block *sb, void *data, char *devname, int silent)
iput(inode); iput(inode);
out_mount_failed: out_mount_failed:
if(cifs_sb->local_nls)
unload_nls(cifs_sb->local_nls);
if(cifs_sb) if(cifs_sb)
kfree(cifs_sb); kfree(cifs_sb);
return -EINVAL; return -EINVAL;
...@@ -175,6 +179,7 @@ static int cifs_permission(struct inode * inode, int mask) ...@@ -175,6 +179,7 @@ static int cifs_permission(struct inode * inode, int mask)
static kmem_cache_t *cifs_inode_cachep; static kmem_cache_t *cifs_inode_cachep;
kmem_cache_t *cifs_req_cachep; kmem_cache_t *cifs_req_cachep;
kmem_cache_t *cifs_mid_cachep; kmem_cache_t *cifs_mid_cachep;
kmem_cache_t *cifs_oplock_cachep;
static struct inode * static struct inode *
cifs_alloc_inode(struct super_block *sb) cifs_alloc_inode(struct super_block *sb)
...@@ -394,6 +399,13 @@ cifs_init_mids(void) ...@@ -394,6 +399,13 @@ cifs_init_mids(void)
SLAB_HWCACHE_ALIGN, NULL, NULL); SLAB_HWCACHE_ALIGN, NULL, NULL);
if (cifs_mid_cachep == NULL) if (cifs_mid_cachep == NULL)
return -ENOMEM; return -ENOMEM;
cifs_oplock_cachep = kmem_cache_create("cifs_oplock_structs",
sizeof (struct oplock_q_entry), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (cifs_oplock_cachep == NULL) {
kmem_cache_destroy(cifs_mid_cachep);
return -ENOMEM;
}
return 0; return 0;
} }
...@@ -404,6 +416,49 @@ cifs_destroy_mids(void) ...@@ -404,6 +416,49 @@ cifs_destroy_mids(void)
if (kmem_cache_destroy(cifs_mid_cachep)) if (kmem_cache_destroy(cifs_mid_cachep))
printk(KERN_WARNING printk(KERN_WARNING
"cifs_destroy_mids: error not all structures were freed\n"); "cifs_destroy_mids: error not all structures were freed\n");
if (kmem_cache_destroy(cifs_oplock_cachep))
printk(KERN_WARNING
"error not all oplock structures were freed\n");}
static int cifs_oplock_thread(void * dummyarg)
{
struct list_head * tmp;
struct oplock_q_entry * oplock_item;
struct file * pfile;
struct cifsTconInfo *pTcon;
int rc;
daemonize("cifsoplockd");
allow_signal(SIGKILL);
oplockThread = current;
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(100*HZ);
/* BB add missing code */
cFYI(1,("oplock thread woken up - flush inode")); /* BB remove */
write_lock(&GlobalMid_Lock);
list_for_each(tmp, &GlobalOplock_Q) {
oplock_item = list_entry(tmp, struct
oplock_q_entry,
qhead);
if(oplock_item) {
pTcon = oplock_item->tcon;
pfile = oplock_item->file_to_flush;
cFYI(1,("process item on queue"));/* BB remove */
DeleteOplockQEntry(oplock_item);
write_unlock(&GlobalMid_Lock);
rc = filemap_fdatawrite(pfile->f_dentry->d_inode->i_mapping);
cFYI(1,("Oplock flush file %p rc %d",pfile,rc));
/* send oplock break */
write_lock(&GlobalMid_Lock);
} else
break;
cFYI(1,("next time through list")); /* BB remove */
}
write_unlock(&GlobalMid_Lock);
cFYI(1,("next time through while loop")); /* BB remove */
}
} }
static int __init static int __init
...@@ -416,7 +471,7 @@ init_cifs(void) ...@@ -416,7 +471,7 @@ init_cifs(void)
INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */ INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */
INIT_LIST_HEAD(&GlobalSMBSessionList); INIT_LIST_HEAD(&GlobalSMBSessionList);
INIT_LIST_HEAD(&GlobalTreeConnectionList); INIT_LIST_HEAD(&GlobalTreeConnectionList);
INIT_LIST_HEAD(&GlobalOplock_Q);
/* /*
* Initialize Global counters * Initialize Global counters
*/ */
...@@ -437,9 +492,11 @@ init_cifs(void) ...@@ -437,9 +492,11 @@ init_cifs(void)
rc = cifs_init_request_bufs(); rc = cifs_init_request_bufs();
if (!rc) { if (!rc) {
rc = register_filesystem(&cifs_fs_type); rc = register_filesystem(&cifs_fs_type);
if (!rc) if (!rc) {
kernel_thread(cifs_oplock_thread, NULL,
CLONE_FS | CLONE_FILES | CLONE_VM);
return rc; /* Success */ return rc; /* Success */
else } else
cifs_destroy_request_bufs(); cifs_destroy_request_bufs();
} }
cifs_destroy_mids(); cifs_destroy_mids();
...@@ -463,6 +520,8 @@ exit_cifs(void) ...@@ -463,6 +520,8 @@ exit_cifs(void)
cifs_destroy_inodecache(); cifs_destroy_inodecache();
cifs_destroy_mids(); cifs_destroy_mids();
cifs_destroy_request_bufs(); cifs_destroy_request_bufs();
if(oplockThread)
send_sig(SIGKILL, oplockThread, 1);
} }
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
......
...@@ -199,7 +199,7 @@ struct cifsLockInfo { ...@@ -199,7 +199,7 @@ struct cifsLockInfo {
struct cifsFileInfo { struct cifsFileInfo {
struct list_head tlist; /* pointer to next fid owned by tcon */ struct list_head tlist; /* pointer to next fid owned by tcon */
struct list_head flist; /* next fid (file instance) for this inode */ struct list_head flist; /* next fid (file instance) for this inode */
unsigned int uid; /* allows you to find which FileInfo structure */ unsigned int uid; /* allows finding which FileInfo structure */
__u32 pid; /* process id who opened file */ __u32 pid; /* process id who opened file */
__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 */ ;
...@@ -207,6 +207,10 @@ struct cifsFileInfo { ...@@ -207,6 +207,10 @@ struct cifsFileInfo {
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;
char * search_resume_name;
unsigned int resume_name_length;
__u32 resume_key;
}; };
/* /*
...@@ -222,6 +226,7 @@ struct cifsInodeInfo { ...@@ -222,6 +226,7 @@ struct cifsInodeInfo {
unsigned long time; /* jiffies of last update/check of inode */ unsigned long time; /* jiffies of last update/check of inode */
int clientCanCacheRead:1; /* read oplock */ int clientCanCacheRead:1; /* read oplock */
int clientCanCacheAll:1; /* read and writebehind oplock */ int clientCanCacheAll:1; /* read and writebehind oplock */
int oplockPending:1;
struct inode vfs_inode; struct inode vfs_inode;
}; };
...@@ -251,6 +256,12 @@ struct mid_q_entry { ...@@ -251,6 +256,12 @@ struct mid_q_entry {
int midState; /* wish this were enum but can not pass to wait_event */ int midState; /* wish this were enum but can not pass to wait_event */
}; };
struct oplock_q_entry {
struct list_head qhead;
struct file * file_to_flush;
struct cifsTconInfo * tcon;
};
#define MID_FREE 0 #define MID_FREE 0
#define MID_REQUEST_ALLOCATED 1 #define MID_REQUEST_ALLOCATED 1
#define MID_REQUEST_SUBMITTED 2 #define MID_REQUEST_SUBMITTED 2
...@@ -301,6 +312,8 @@ GLOBAL_EXTERN struct list_head GlobalSMBSessionList; ...@@ -301,6 +312,8 @@ GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
GLOBAL_EXTERN struct list_head GlobalOplock_Q;
/* /*
* Global transaction id (XID) information * Global transaction id (XID) information
*/ */
...@@ -327,6 +340,7 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions ...@@ -327,6 +340,7 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
have the uid/password or Kerberos credential have the uid/password or Kerberos credential
or equivalent for current user */ or equivalent for current user */
GLOBAL_EXTERN unsigned int oplockEnabled; GLOBAL_EXTERN unsigned int oplockEnabled;
GLOBAL_EXTERN unsigned int lookupCacheEnabled;
GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */ with more secure ntlmssp2 challenge/resp */
GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#define SMB_COM_WRITE_ANDX 0x2F #define SMB_COM_WRITE_ANDX 0x2F
#define SMB_COM_TRANSACTION2 0x32 #define SMB_COM_TRANSACTION2 0x32
#define SMB_COM_TRANSACTION2_SECONDARY 0x33 #define SMB_COM_TRANSACTION2_SECONDARY 0x33
#define SMB_COM_FIND_CLOSE2 0x34
#define SMB_COM_TREE_DISCONNECT 0x71 #define SMB_COM_TREE_DISCONNECT 0x71
#define SMB_COM_NEGOTIATE 0x72 #define SMB_COM_NEGOTIATE 0x72
#define SMB_COM_SESSION_SETUP_ANDX 0x73 #define SMB_COM_SESSION_SETUP_ANDX 0x73
...@@ -584,7 +585,7 @@ typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tre ...@@ -584,7 +585,7 @@ typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tre
typedef struct smb_com_close_req { typedef struct smb_com_close_req {
struct smb_hdr hdr; /* wct = 3 */ struct smb_hdr hdr; /* wct = 3 */
__u16 FileID; /* target file attributes */ __u16 FileID;
__u32 LastWriteTime; /* should be zero */ __u32 LastWriteTime; /* should be zero */
__u16 ByteCount; /* 0 */ __u16 ByteCount; /* 0 */
} CLOSE_REQ; } CLOSE_REQ;
...@@ -594,6 +595,12 @@ typedef struct smb_com_close_rsp { ...@@ -594,6 +595,12 @@ typedef struct smb_com_close_rsp {
__u16 ByteCount; /* bct = 0 */ __u16 ByteCount; /* bct = 0 */
} CLOSE_RSP; } CLOSE_RSP;
typedef struct smb_com_findclose_req {
struct smb_hdr hdr; /* wct = 1 */
__u16 FileID;
__u16 ByteCount; /* 0 */
} FINDCLOSE_REQ;
/* OpenFlags */ /* OpenFlags */
#define REQ_OPLOCK 0x00000002 #define REQ_OPLOCK 0x00000002
#define REQ_BATCHOPLOCK 0x00000004 #define REQ_BATCHOPLOCK 0x00000004
...@@ -1152,7 +1159,7 @@ typedef struct smb_com_transaction2_fnext_req { ...@@ -1152,7 +1159,7 @@ typedef struct smb_com_transaction2_fnext_req {
__u16 InformationLevel; __u16 InformationLevel;
__u32 ResumeKey; __u32 ResumeKey;
__u16 SearchFlags; __u16 SearchFlags;
char ResumeFileName[1]; /* will be null string actually since we set bit 3 - resume from previous ending place */ char ResumeFileName[1];
} TRANSACTION2_FNEXT_REQ; } TRANSACTION2_FNEXT_REQ;
typedef struct smb_com_transaction2_fnext_rsp { typedef struct smb_com_transaction2_fnext_rsp {
......
...@@ -57,6 +57,8 @@ extern void header_assemble(struct smb_hdr *, char /* command */ , ...@@ -57,6 +57,8 @@ extern void header_assemble(struct smb_hdr *, char /* command */ ,
const struct cifsTconInfo *, int const struct cifsTconInfo *, int
/* length of fixed section (word count) in two byte units */ /* length of fixed section (word count) in two byte units */
); );
struct oplock_q_entry * AllocOplockQEntry(struct file *,struct cifsTconInfo *);
void DeleteOplockQEntry(struct oplock_q_entry *);
extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
extern u64 cifs_UnixTimeToNT(struct timespec); extern u64 cifs_UnixTimeToNT(struct timespec);
extern void RevUcode_to_Ucode(char *revUnicode, char *UnicodeName); extern void RevUcode_to_Ucode(char *revUnicode, char *UnicodeName);
...@@ -104,9 +106,13 @@ extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, ...@@ -104,9 +106,13 @@ extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
FILE_DIRECTORY_INFO * findData, FILE_DIRECTORY_INFO * findData,
T2_FNEXT_RSP_PARMS * findParms, T2_FNEXT_RSP_PARMS * findParms,
const __u16 searchHandle, const __u32 resumeKey, const __u16 searchHandle, char * resume_name,
int name_length, __u32 resume_key,
int *UnicodeFlag, int *pUnixFlag); int *UnicodeFlag, int *pUnixFlag);
extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
const __u16 search_handle);
extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, const unsigned char *searchName,
FILE_ALL_INFO * findData, FILE_ALL_INFO * findData,
......
...@@ -1449,7 +1449,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, ...@@ -1449,7 +1449,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
ATTR_DIRECTORY); ATTR_DIRECTORY);
pSMB->SearchCount = cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); /* should this be shrunk even more ? */ pSMB->SearchCount = cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); /* should this be shrunk even more ? */
pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END); pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
/* test for Unix extensions */ /* test for Unix extensions */
if (tcon->ses->capabilities & CAP_UNIX) { if (tcon->ses->capabilities & CAP_UNIX) {
...@@ -1496,9 +1496,9 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, ...@@ -1496,9 +1496,9 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
int int
CIFSFindNext(const int xid, struct cifsTconInfo *tcon, CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
FILE_DIRECTORY_INFO * findData, FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms,
T2_FNEXT_RSP_PARMS * findParms, const __u16 searchHandle, const __u16 searchHandle, char * resume_file_name, int name_len,
__u32 resumeKey, int *pUnicodeFlag, int *pUnixFlag) __u32 resume_key, int *pUnicodeFlag, int *pUnixFlag)
{ {
/* level 257 SMB_ */ /* level 257 SMB_ */
TRANSACTION2_FNEXT_REQ *pSMB = NULL; TRANSACTION2_FNEXT_REQ *pSMB = NULL;
...@@ -1508,6 +1508,9 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon, ...@@ -1508,6 +1508,9 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
int bytes_returned; int bytes_returned;
cFYI(1, ("In FindNext")); cFYI(1, ("In FindNext"));
if(resume_file_name == NULL) {
return -EIO;
}
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr); (void **) &pSMBr);
if (rc) if (rc)
...@@ -1530,9 +1533,6 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon, ...@@ -1530,9 +1533,6 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB->SetupCount = 1; pSMB->SetupCount = 1;
pSMB->Reserved3 = 0; pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT); pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->SearchHandle = searchHandle; /* always kept as le */ pSMB->SearchHandle = searchHandle; /* always kept as le */
findParms->SearchCount = 0; /* set to zero in case of error */ findParms->SearchCount = 0; /* set to zero in case of error */
pSMB->SearchCount = pSMB->SearchCount =
...@@ -1546,10 +1546,19 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon, ...@@ -1546,10 +1546,19 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
*pUnixFlag = FALSE; *pUnixFlag = FALSE;
} }
pSMB->ResumeKey = resumeKey; /* always kept as le */ pSMB->ResumeKey = resume_key;
pSMB->SearchFlags = pSMB->SearchFlags =
cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
CIFS_SEARCH_CONTINUE_FROM_LAST); /* BB add check to make sure we do not cross end of smb */
if(name_len < CIFS_MAX_MSGSIZE) {
memcpy(pSMB->ResumeFileName, resume_file_name, name_len);
pSMB->ByteCount += name_len;
}
pSMB->TotalParameterCount += name_len;
pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
pSMB->ParameterCount = pSMB->TotalParameterCount;
/* BB improve error handling here */
pSMB->hdr.smb_buf_length += pSMB->ByteCount; pSMB->hdr.smb_buf_length += pSMB->ByteCount;
pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
...@@ -1585,6 +1594,33 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon, ...@@ -1585,6 +1594,33 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
return rc; return rc;
} }
int
CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
{
int rc = 0;
FINDCLOSE_REQ *pSMB = NULL;
CLOSE_RSP *pSMBr = NULL;
int bytes_returned;
cFYI(1, ("In CIFSSMBFindClose"));
rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
return rc;
pSMB->FileID = searchHandle;
pSMB->ByteCount = 0;
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cERROR(1, ("Send error in FindClose = %d", rc));
}
if (pSMB)
buf_release(pSMB);
return rc;
}
int int
CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName, const unsigned char *searchName,
......
...@@ -850,8 +850,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -850,8 +850,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
init_waitqueue_head(&srvTcp->response_q); init_waitqueue_head(&srvTcp->response_q);
INIT_LIST_HEAD(&srvTcp->pending_mid_q); INIT_LIST_HEAD(&srvTcp->pending_mid_q);
srvTcp->tcpStatus = CifsGood; srvTcp->tcpStatus = CifsGood;
kernel_thread((void *) (void *) kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
cifs_demultiplex_thread, srvTcp,
CLONE_FS | CLONE_FILES | CLONE_VM); CLONE_FS | CLONE_FILES | CLONE_VM);
} }
} }
......
...@@ -152,28 +152,31 @@ int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo) ...@@ -152,28 +152,31 @@ 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 list_head *tmp; struct list_head *tmp;
/* list all files open on tree connection */ /* list all files open on tree connection */
list_for_each(tmp, &pTcon->openFileList) { list_for_each(tmp, &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->pfile) { if(open_file->search_resume_name) {
if(open_file->pfile->private_data) { kfree(open_file->search_resume_name);
kfree(open_file->pfile->private_data);
} }
rc = cifs_open(open_file->pfile->f_dentry->d_inode, file = open_file->pfile;
open_file->pfile); kfree(open_file);
if(file) {
file->private_data = NULL;
rc = cifs_open(file->f_dentry->d_inode,file);
if(rc) { if(rc) {
cFYI(1,("reconnecting file %s failed with %d", cFYI(1,("reconnecting file %s failed with %d",
open_file->pfile->f_dentry->d_name.name,rc)); file->f_dentry->d_name.name,rc));
} else { } else {
cFYI(1,("reconnection of %s succeeded", cFYI(1,("reconnection of %s succeeded",
open_file->pfile->f_dentry->d_name.name)); file->f_dentry->d_name.name));
}
} }
} }
} }
return rc; return rc;
} }
...@@ -196,6 +199,8 @@ cifs_close(struct inode *inode, struct file *file) ...@@ -196,6 +199,8 @@ cifs_close(struct inode *inode, struct file *file)
list_del(&pSMBFile->flist); list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist); list_del(&pSMBFile->tlist);
rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid); rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid);
if(pSMBFile->search_resume_name)
kfree(pSMBFile->search_resume_name);
kfree(file->private_data); kfree(file->private_data);
file->private_data = NULL; file->private_data = NULL;
} else } else
...@@ -1055,6 +1060,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1055,6 +1060,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
int xid, i; int xid, i;
int Unicode = FALSE; int Unicode = FALSE;
int UnixSearch = FALSE; int UnixSearch = FALSE;
unsigned int bufsize;
__u16 searchHandle; __u16 searchHandle;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
...@@ -1065,14 +1071,19 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1065,14 +1071,19 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
T2_FFIRST_RSP_PARMS findParms; T2_FFIRST_RSP_PARMS findParms;
T2_FNEXT_RSP_PARMS findNextParms; T2_FNEXT_RSP_PARMS findNextParms;
FILE_DIRECTORY_INFO *pfindData; FILE_DIRECTORY_INFO *pfindData;
FILE_DIRECTORY_INFO *lastFindData;
FILE_UNIX_INFO *pfindDataUnix; FILE_UNIX_INFO *pfindDataUnix;
xid = GetXid(); xid = GetXid();
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
data = kmalloc(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE, bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE;
GFP_KERNEL); if(bufsize > CIFS_MAX_MSGSIZE) {
FreeXid(xid);
return -EIO;
}
data = kmalloc(bufsize, GFP_KERNEL);
pfindData = (FILE_DIRECTORY_INFO *) data; pfindData = (FILE_DIRECTORY_INFO *) data;
full_path = build_wildcard_path_from_dentry(file->f_dentry); full_path = build_wildcard_path_from_dentry(file->f_dentry);
...@@ -1081,8 +1092,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1081,8 +1092,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
switch ((int) file->f_pos) { switch ((int) file->f_pos) {
case 0: case 0:
if (filldir if (filldir(direntry, ".", 1, file->f_pos,
(direntry, ".", 1, file->f_pos,
file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
cERROR(1, ("Filldir for current dir failed ")); cERROR(1, ("Filldir for current dir failed "));
break; break;
...@@ -1090,8 +1100,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1090,8 +1100,7 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
file->f_pos++; file->f_pos++;
/* fallthrough */ /* fallthrough */
case 1: case 1:
if (filldir if (filldir(direntry, "..", 2, file->f_pos,
(direntry, "..", 2, file->f_pos,
file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
cERROR(1, ("Filldir for parent dir failed ")); cERROR(1, ("Filldir for parent dir failed "));
break; break;
...@@ -1099,18 +1108,27 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1099,18 +1108,27 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
file->f_pos++; file->f_pos++;
/* fallthrough */ /* fallthrough */
case 2: case 2:
/* do not reallocate search handle if rewind */ if (file->private_data != NULL) {
if(file->private_data == NULL) { cifsFile =
(struct cifsFileInfo *) file->private_data;
if (cifsFile->endOfSearch) {
if(cifsFile->emptyDir) {
cFYI(1, ("End of search, empty dir"));
rc = 0;
break;
}
} else
CIFSFindClose(xid, pTcon, cifsFile->netfid);
if(cifsFile->search_resume_name) {
kfree(cifsFile->search_resume_name);
cifsFile->search_resume_name = NULL;
}
}
rc = CIFSFindFirst(xid, pTcon, full_path, pfindData, rc = CIFSFindFirst(xid, pTcon, full_path, pfindData,
&findParms, cifs_sb->local_nls, &findParms, cifs_sb->local_nls,
&Unicode, &UnixSearch); &Unicode, &UnixSearch);
cFYI(1, cFYI(1, ("Count: %d End: %d ", findParms.SearchCount,
("Count: %d End: %d ", findParms.SearchCount,
findParms.EndofSearch)); findParms.EndofSearch));
} else {
cFYI(1,("Search rewinding on %s",full_path));
goto readdir_rewind;
}
if (rc == 0) { if (rc == 0) {
searchHandle = findParms.SearchHandle; searchHandle = findParms.SearchHandle;
...@@ -1118,25 +1136,79 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1118,25 +1136,79 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
file->private_data = file->private_data =
kmalloc(sizeof(struct cifsFileInfo), kmalloc(sizeof(struct cifsFileInfo),
GFP_KERNEL); GFP_KERNEL);
else {
/* BB close search handle */
cFYI(1,("Search rewinding on %s",full_path));
}
if (file->private_data) { if (file->private_data) {
memset(file->private_data, 0, memset(file->private_data, 0,
sizeof (struct cifsFileInfo)); sizeof (struct cifsFileInfo));
cifsFile = cifsFile =
(struct cifsFileInfo *) file->private_data; (struct cifsFileInfo *) file->private_data;
cifsFile->netfid = searchHandle; cifsFile->netfid = searchHandle;
} else {
rc = -ENOMEM;
break;
} }
renew_parental_timestamps(file->f_dentry); renew_parental_timestamps(file->f_dentry);
lastFindData =
(FILE_DIRECTORY_INFO *) ((char *) pfindData +
le32_to_cpu(findParms.LastNameOffset));
if((char *)lastFindData > (char *)pfindData + bufsize) {
cFYI(1,("last search entry past end of packet"));
rc = -EIO;
break;
}
/* Offset of resume key same for levels 257 and 514 */
cifsFile->resume_key = lastFindData->FileIndex;
if(UnixSearch == FALSE) {
cifsFile->resume_name_length =
le32_to_cpu(lastFindData->FileNameLength);
if(cifsFile->resume_name_length > bufsize - 64) {
cFYI(1,("Illegal resume file name length %d",
cifsFile->resume_name_length));
rc = -ENOMEM;
break;
}
cifsFile->search_resume_name =
kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
cFYI(1,("Last file: %s with name %d bytes long",
lastFindData->FileName,
cifsFile->resume_name_length));
memcpy(cifsFile->search_resume_name,
lastFindData->FileName,
cifsFile->resume_name_length);
} else {
pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
if (Unicode == TRUE) {
for(i=0;(pfindDataUnix->FileName[i]
| pfindDataUnix->FileName[i+1]);
i+=2) {
if(i > bufsize-64)
break;
}
cifsFile->resume_name_length = i + 2;
} else {
cifsFile->resume_name_length =
strnlen(pfindDataUnix->FileName,
bufsize-63);
}
if(cifsFile->resume_name_length > bufsize - 64) {
cFYI(1,("Illegal resume file name length %d",
cifsFile->resume_name_length));
rc = -ENOMEM;
break;
}
cifsFile->search_resume_name =
kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
cFYI(1,("Last file: %s with name %d bytes long",
lastFindData->FileName,
cifsFile->resume_name_length));
memcpy(cifsFile->search_resume_name,
lastFindData->FileName,
cifsFile->resume_name_length);
}
for (i = 2; i < findParms.SearchCount + 2; i++) { for (i = 2; i < findParms.SearchCount + 2; i++) {
if (UnixSearch == FALSE) { if (UnixSearch == FALSE) {
pfindData->FileNameLength = pfindData->FileNameLength =
le32_to_cpu(pfindData-> le32_to_cpu(pfindData->FileNameLength);
FileNameLength);
if (Unicode == TRUE) if (Unicode == TRUE)
pfindData->FileNameLength = pfindData->FileNameLength =
cifs_strfromUCS_le cifs_strfromUCS_le
...@@ -1166,10 +1238,9 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1166,10 +1238,9 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
if (Unicode == TRUE) if (Unicode == TRUE)
qstring.len = qstring.len =
cifs_strfromUCS_le cifs_strfromUCS_le
(pfindDataUnix-> (pfindDataUnix->FileName,
FileName, (wchar_t *) (wchar_t *)
pfindDataUnix-> pfindDataUnix->FileName,
FileName,
MAX_PATHCONF, MAX_PATHCONF,
cifs_sb->local_nls); cifs_sb->local_nls);
else else
...@@ -1193,21 +1264,26 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1193,21 +1264,26 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
file->f_pos++; file->f_pos++;
} }
} }
pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + le32_to_cpu(pfindData->NextEntryOffset)); /* works also for Unix find struct since this is the first field of both */ /* works also for Unix ff struct since first field of both */
pfindData =
(FILE_DIRECTORY_INFO *) ((char *) pfindData
+ le32_to_cpu(pfindData->NextEntryOffset));
/* BB also should check to make sure that pointer is not beyond the end of the SMB */ /* BB also should check to make sure that pointer is not beyond the end of the SMB */
/* if(pfindData > lastFindData) rc = -EIO; break; */
} /* end for loop */ } /* end for loop */
if ((findParms.EndofSearch != 0) && cifsFile) { if ((findParms.EndofSearch != 0) && cifsFile) {
cifsFile->endOfSearch = TRUE; cifsFile->endOfSearch = TRUE;
if(findParms.SearchCount == 2)
cifsFile->emptyDir = TRUE;
} }
} else { } else {
if (cifsFile) if (cifsFile)
cifsFile->endOfSearch = TRUE; cifsFile->endOfSearch = TRUE;
rc = 0; /* unless parent directory disappeared - do not return error here (eg Access Denied or no more files) */ /* unless parent directory gone do not return error */
rc = 0;
} }
break; break;
readdir_rewind:
default: default:
/* BB rewrite eventually to better handle rewind */
if (file->private_data == NULL) { if (file->private_data == NULL) {
rc = -EBADF; rc = -EBADF;
cFYI(1, cFYI(1,
...@@ -1222,43 +1298,96 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1222,43 +1298,96 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
} }
searchHandle = cifsFile->netfid; searchHandle = cifsFile->netfid;
rc = CIFSFindNext(xid, pTcon, pfindData, rc = CIFSFindNext(xid, pTcon, pfindData,
&findNextParms, searchHandle, 0, &findNextParms, searchHandle,
cifsFile->search_resume_name,
cifsFile->resume_name_length,
cifsFile->resume_key,
&Unicode, &UnixSearch); &Unicode, &UnixSearch);
cFYI(1, cFYI(1,("Count: %d End: %d ",
("Count: %d End: %d ",
findNextParms.SearchCount, findNextParms.SearchCount,
findNextParms.EndofSearch)); findNextParms.EndofSearch));
if ((rc == 0) && (findNextParms.SearchCount != 0)) { if ((rc == 0) && (findNextParms.SearchCount != 0)) {
/* BB save off resume key, key name and name length */
lastFindData =
(FILE_DIRECTORY_INFO *) ((char *) pfindData
+ le32_to_cpu(findNextParms.LastNameOffset));
if((char *)lastFindData > (char *)pfindData + bufsize) {
cFYI(1,("last search entry past end of packet"));
rc = -EIO;
break;
}
/* Offset of resume key same for levels 257 and 514 */
cifsFile->resume_key = lastFindData->FileIndex;
if(UnixSearch == FALSE) {
cifsFile->resume_name_length =
le32_to_cpu(lastFindData->FileNameLength);
if(cifsFile->resume_name_length > bufsize - 64) {
cFYI(1,("Illegal resume file name length %d",
cifsFile->resume_name_length));
rc = -ENOMEM;
break;
}
cifsFile->search_resume_name =
kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
cFYI(1,("Last file: %s with name %d bytes long",
lastFindData->FileName,
cifsFile->resume_name_length));
memcpy(cifsFile->search_resume_name,
lastFindData->FileName,
cifsFile->resume_name_length);
} else {
pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
if (Unicode == TRUE) {
for(i=0;(pfindDataUnix->FileName[i]
| pfindDataUnix->FileName[i+1]);
i+=2) {
if(i > bufsize-64)
break;
}
cifsFile->resume_name_length = i + 2;
} else {
cifsFile->resume_name_length =
strnlen(pfindDataUnix->
FileName,
MAX_PATHCONF);
}
if(cifsFile->resume_name_length > bufsize - 64) {
cFYI(1,("Illegal resume file name length %d",
cifsFile->resume_name_length));
rc = -ENOMEM;
break;
}
cifsFile->search_resume_name =
kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
cFYI(1,("fnext last file: %s with name %d bytes long",
lastFindData->FileName,
cifsFile->resume_name_length));
memcpy(cifsFile->search_resume_name,
lastFindData->FileName,
cifsFile->resume_name_length);
}
for (i = 0; i < findNextParms.SearchCount; i++) { for (i = 0; i < findNextParms.SearchCount; i++) {
pfindData->FileNameLength = pfindData->FileNameLength =
le32_to_cpu(pfindData-> le32_to_cpu(pfindData->
FileNameLength); FileNameLength);
if (UnixSearch == FALSE) { if (UnixSearch == FALSE) {
if (Unicode == TRUE) if (Unicode == TRUE)
pfindData-> pfindData->FileNameLength =
FileNameLength
=
cifs_strfromUCS_le cifs_strfromUCS_le
(pfindData-> (pfindData->FileName,
FileName,
(wchar_t *) (wchar_t *)
pfindData-> pfindData->FileName,
FileName, (pfindData->FileNameLength)/ 2,
(pfindData-> cifs_sb->local_nls);
FileNameLength)
/ 2,
cifs_sb->
local_nls);
qstring.len = qstring.len =
pfindData->FileNameLength; pfindData->FileNameLength;
if (((qstring.len != 1) if (((qstring.len != 1)
|| (pfindData-> || (pfindData->FileName[0] != '.'))
FileName[0] != '.'))
&& ((qstring.len != 2) && ((qstring.len != 2)
|| (pfindData-> || (pfindData->FileName[0] != '.')
FileName[0] != '.') || (pfindData->FileName[1] !=
|| (pfindData->
FileName[1] !=
'.'))) { '.'))) {
cifs_filldir cifs_filldir
(&qstring, (&qstring,
...@@ -1274,21 +1403,17 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1274,21 +1403,17 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
if (Unicode == TRUE) if (Unicode == TRUE)
qstring.len = qstring.len =
cifs_strfromUCS_le cifs_strfromUCS_le
(pfindDataUnix-> (pfindDataUnix->FileName,
FileName,
(wchar_t *) (wchar_t *)
pfindDataUnix-> pfindDataUnix->FileName,
FileName,
MAX_PATHCONF, MAX_PATHCONF,
cifs_sb-> cifs_sb->local_nls);
local_nls);
else else
qstring.len = qstring.len =
strnlen strnlen
(pfindDataUnix-> (pfindDataUnix->
FileName, FileName,
MAX_PATHCONF); MAX_PATHCONF);
if (((qstring.len != 1) if (((qstring.len != 1)
|| (pfindDataUnix-> || (pfindDataUnix->
FileName[0] != '.')) FileName[0] != '.'))
...@@ -1308,7 +1433,6 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1308,7 +1433,6 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
} }
pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + le32_to_cpu(pfindData->NextEntryOffset)); /* works also for Unix find struct since this is the first field of both */ pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + le32_to_cpu(pfindData->NextEntryOffset)); /* works also for Unix find struct since this is the first field of both */
/* BB also should check to make sure that pointer is not beyond the end of the SMB */ /* BB also should check to make sure that pointer is not beyond the end of the SMB */
} /* end for loop */ } /* end for loop */
if (findNextParms.EndofSearch != 0) { if (findNextParms.EndofSearch != 0) {
cifsFile->endOfSearch = TRUE; cifsFile->endOfSearch = TRUE;
...@@ -1319,7 +1443,6 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1319,7 +1443,6 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
} }
} }
} /* end switch */ } /* end switch */
if (data) if (data)
kfree(data); kfree(data);
if (full_path) if (full_path)
...@@ -1336,6 +1459,7 @@ struct address_space_operations cifs_addr_ops = { ...@@ -1336,6 +1459,7 @@ struct address_space_operations cifs_addr_ops = {
.prepare_write = simple_prepare_write, .prepare_write = simple_prepare_write,
.commit_write = cifs_commit_write, .commit_write = cifs_commit_write,
.sync_page = cifs_sync_page, .sync_page = cifs_sync_page,
/*.direct_IO = */
}; };
struct address_space_operations cifs_addr_ops_writethrough = { struct address_space_operations cifs_addr_ops_writethrough = {
...@@ -1345,6 +1469,7 @@ struct address_space_operations cifs_addr_ops_writethrough = { ...@@ -1345,6 +1469,7 @@ struct address_space_operations cifs_addr_ops_writethrough = {
.prepare_write = simple_prepare_write, .prepare_write = simple_prepare_write,
.commit_write = cifs_commit_write, .commit_write = cifs_commit_write,
.sync_page = cifs_sync_page, .sync_page = cifs_sync_page,
/*.direct_IO = */
}; };
struct address_space_operations cifs_addr_ops_nocache = { struct address_space_operations cifs_addr_ops_nocache = {
...@@ -1354,5 +1479,6 @@ struct address_space_operations cifs_addr_ops_nocache = { ...@@ -1354,5 +1479,6 @@ struct address_space_operations cifs_addr_ops_nocache = {
.prepare_write = simple_prepare_write, .prepare_write = simple_prepare_write,
.commit_write = cifs_commit_write, .commit_write = cifs_commit_write,
.sync_page = cifs_sync_page, .sync_page = cifs_sync_page,
/*.direct_IO = */
}; };
...@@ -451,9 +451,9 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry, ...@@ -451,9 +451,9 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
pTcon = cifs_sb_source->tcon; pTcon = cifs_sb_source->tcon;
if (pTcon != cifs_sb_target->tcon) { if (pTcon != cifs_sb_target->tcon) {
FreeXid(xid);
return -EXDEV; /* BB actually could be allowed if same server, but return -EXDEV; /* BB actually could be allowed if same server, but
different share. Might eventually add support for this */ different share. Might eventually add support for this */
FreeXid(xid);
} }
fromName = build_path_from_dentry(source_direntry); fromName = build_path_from_dentry(source_direntry);
...@@ -500,7 +500,8 @@ cifs_revalidate(struct dentry *direntry) ...@@ -500,7 +500,8 @@ cifs_revalidate(struct dentry *direntry)
if (time_before(jiffies, cifsInode->time + HZ)) { if (time_before(jiffies, cifsInode->time + HZ)) {
if((S_ISREG(direntry->d_inode->i_mode) == 0) || if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
(direntry->d_inode->i_nlink == 1)) { (direntry->d_inode->i_nlink == 1) ||
(lookupCacheEnabled == 0)) {
if (full_path) if (full_path)
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
...@@ -508,7 +509,6 @@ cifs_revalidate(struct dentry *direntry) ...@@ -508,7 +509,6 @@ cifs_revalidate(struct dentry *direntry)
} else { } else {
cFYI(1,("Have to revalidate file due to hardlinks")); cFYI(1,("Have to revalidate file due to hardlinks"));
} }
} }
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
......
...@@ -82,7 +82,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -82,7 +82,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
int rc = -EACCES; int rc = -EACCES;
int xid; int xid;
char *full_path = NULL; char *full_path = NULL;
char target_path[257]; char * target_path;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
...@@ -91,7 +91,11 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -91,7 +91,11 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
target_path = kmalloc(PATH_MAX, GFP_KERNEL);
if(target_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
/* can not call the following line due to EFAULT in vfs_readlink which is presumably expecting a user space buffer */ /* can not call the following line due to EFAULT in vfs_readlink which is presumably expecting a user space buffer */
/* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1); */ /* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1); */
...@@ -99,7 +103,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -99,7 +103,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
target_path, target_path,
sizeof (target_path) - 1, PATH_MAX-1,
cifs_sb->local_nls); cifs_sb->local_nls);
else { else {
/* rc = CIFSSMBQueryReparseLinkInfo */ /* rc = CIFSSMBQueryReparseLinkInfo */
...@@ -109,11 +113,13 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -109,11 +113,13 @@ 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) {
target_path[256] = 0; target_path[PATH_MAX-1] = 0;
rc = vfs_follow_link(nd, target_path); rc = vfs_follow_link(nd, target_path);
} }
/* else EACCESS */ /* else EACCESS */
if (target_path)
kfree(target_path);
if (full_path) if (full_path)
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
...@@ -180,7 +186,8 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -180,7 +186,8 @@ 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 tmpbuffer[256]; char * tmpbuffer;
int len;
__u16 fid; __u16 fid;
xid = GetXid(); xid = GetXid();
...@@ -190,12 +197,20 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -190,12 +197,20 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
cFYI(1, cFYI(1,
("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d", ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
full_path, inode, pBuffer, buflen)); full_path, inode, pBuffer, buflen));
if(buflen > PATH_MAX)
len = PATH_MAX;
else
len = buflen;
tmpbuffer = kmalloc(len,GFP_KERNEL);
if(tmpbuffer == NULL) {
FreeXid(xid);
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,
tmpbuffer, tmpbuffer,
sizeof (tmpbuffer) - 1, len - 1,
cifs_sb->local_nls); cifs_sb->local_nls);
else { else {
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
...@@ -203,7 +218,7 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -203,7 +218,7 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
if(!rc) { if(!rc) {
rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
tmpbuffer, tmpbuffer,
sizeof(tmpbuffer) - 1, len - 1,
fid, fid,
cifs_sb->local_nls); cifs_sb->local_nls);
if(CIFSSMBClose(xid, pTcon, fid)) { if(CIFSSMBClose(xid, pTcon, fid)) {
...@@ -216,15 +231,15 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -216,15 +231,15 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
/* BB Should we be using page ops here? */ /* BB Should we be using page ops here? */
/* BB null terminate returned string in pBuffer? BB */ /* BB null terminate returned string in pBuffer? BB */
if (buflen > sizeof (tmpbuffer))
buflen = sizeof (tmpbuffer);
if (rc == 0) { if (rc == 0) {
rc = vfs_readlink(direntry, pBuffer, buflen, tmpbuffer); rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer);
cFYI(1, cFYI(1,
("vfs_readlink called from cifs_readlink returned %d", ("vfs_readlink called from cifs_readlink returned %d",
rc)); rc));
} }
if (tmpbuffer)
kfree(tmpbuffer);
if (full_path) if (full_path)
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "cifs_debug.h" #include "cifs_debug.h"
extern kmem_cache_t *cifs_req_cachep; extern kmem_cache_t *cifs_req_cachep;
extern struct task_struct * oplockThread;
__u16 GlobalMid; /* multiplex id - rotating counter */ __u16 GlobalMid; /* multiplex id - rotating counter */
...@@ -336,6 +337,7 @@ is_valid_oplock_break(struct smb_hdr *buf) ...@@ -336,6 +337,7 @@ is_valid_oplock_break(struct smb_hdr *buf)
list_for_each(tmp1,&tcon->openFileList){ list_for_each(tmp1,&tcon->openFileList){
netfile = list_entry(tmp1,struct cifsFileInfo,tlist); netfile = list_entry(tmp1,struct cifsFileInfo,tlist);
if(pSMB->Fid == netfile->netfid) { if(pSMB->Fid == netfile->netfid) {
struct cifsInodeInfo *pCifsInode;
/* BB Add following logic: /* BB Add following logic:
2) look up inode from tcon->openFileList->file->f_dentry->d_inode 2) look up inode from tcon->openFileList->file->f_dentry->d_inode
3) flush dirty pages and cached byte range locks and mark inode 3) flush dirty pages and cached byte range locks and mark inode
...@@ -345,6 +347,15 @@ is_valid_oplock_break(struct smb_hdr *buf) ...@@ -345,6 +347,15 @@ is_valid_oplock_break(struct smb_hdr *buf)
6) send oplock break response to server */ 6) send oplock break response to server */
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
cFYI(1,("Matching file id, processing oplock break")); cFYI(1,("Matching file id, processing oplock break"));
pCifsInode =
CIFS_I(netfile->pfile->f_dentry->d_inode);
pCifsInode->clientCanCacheAll = FALSE;
if(pSMB->OplockLevel == 0)
pCifsInode->clientCanCacheRead = FALSE;
pCifsInode->oplockPending = TRUE;
AllocOplockQEntry(netfile->pfile, tcon);
cFYI(1,("about to wake up oplock thd"));
wake_up_process(oplockThread);
return TRUE; return TRUE;
} }
} }
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "cifs_debug.h" #include "cifs_debug.h"
extern kmem_cache_t *cifs_mid_cachep; extern kmem_cache_t *cifs_mid_cachep;
extern kmem_cache_t *cifs_oplock_cachep;
struct mid_q_entry * struct mid_q_entry *
AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
...@@ -95,6 +96,39 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) ...@@ -95,6 +96,39 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
kmem_cache_free(cifs_mid_cachep, midEntry); kmem_cache_free(cifs_mid_cachep, midEntry);
} }
struct oplock_q_entry *
AllocOplockQEntry(struct file * file, struct cifsTconInfo * tcon)
{
struct oplock_q_entry *temp;
if ((file == NULL) || (tcon == NULL)) {
cERROR(1, ("Null parms passed to AllocOplockQEntry"));
return NULL;
}
temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
SLAB_KERNEL);
if (temp == NULL)
return temp;
else {
temp->file_to_flush = file;
temp->tcon = tcon;
write_lock(&GlobalMid_Lock);
list_add_tail(&temp->qhead, &GlobalOplock_Q);
write_unlock(&GlobalMid_Lock);
}
return temp;
}
void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
{
/* BB add spinlock to protect midq for each session BB */
write_lock(&GlobalMid_Lock);
/* should we check if list empty first? */
list_del(&oplockEntry->qhead);
write_unlock(&GlobalMid_Lock);
kmem_cache_free(cifs_oplock_cachep, oplockEntry);
}
int int
smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, 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)
......
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