Commit e6ab7d05 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 e11ed9c5 3ca54671
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
------------
Fix oops in get dfs referral (triggered when null path sent in to
......
......@@ -185,6 +185,8 @@ static read_proc_t cifsFYI_read;
static write_proc_t cifsFYI_write;
static read_proc_t oplockEnabled_read;
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 write_proc_t traceSMB_write;
static read_proc_t multiuser_mount_read;
......@@ -243,6 +245,12 @@ cifs_proc_init(void)
if (pde)
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 =
create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
ntlmv2_enabled_read, 0);
......@@ -353,6 +361,44 @@ oplockEnabled_write(struct file *file, const char *buffer,
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
traceSMB_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
......
......@@ -48,11 +48,13 @@ int cifsFYI = 0;
int cifsERROR = 1;
int traceSMB = 0;
unsigned int oplockEnabled = 0;
unsigned int lookupCacheEnabled = 1;
unsigned int multiuser_mount = 0;
unsigned int extended_security = 0;
unsigned int ntlmv2_support = 0;
unsigned int sign_CIFS_PDUs = 0;
unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE;
struct task_struct * oplockThread = NULL;
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
char *);
......@@ -175,6 +177,7 @@ static int cifs_permission(struct inode * inode, int mask)
static kmem_cache_t *cifs_inode_cachep;
kmem_cache_t *cifs_req_cachep;
kmem_cache_t *cifs_mid_cachep;
kmem_cache_t *cifs_oplock_cachep;
static struct inode *
cifs_alloc_inode(struct super_block *sb)
......@@ -390,10 +393,17 @@ int
cifs_init_mids(void)
{
cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids",
sizeof (struct mid_q_entry), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
sizeof (struct mid_q_entry), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (cifs_mid_cachep == NULL)
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;
}
......@@ -404,6 +414,49 @@ cifs_destroy_mids(void)
if (kmem_cache_destroy(cifs_mid_cachep))
printk(KERN_WARNING
"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
......@@ -416,7 +469,7 @@ init_cifs(void)
INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */
INIT_LIST_HEAD(&GlobalSMBSessionList);
INIT_LIST_HEAD(&GlobalTreeConnectionList);
INIT_LIST_HEAD(&GlobalOplock_Q);
/*
* Initialize Global counters
*/
......@@ -437,9 +490,11 @@ init_cifs(void)
rc = cifs_init_request_bufs();
if (!rc) {
rc = register_filesystem(&cifs_fs_type);
if (!rc)
return rc; /* Success */
else
if (!rc) {
kernel_thread(cifs_oplock_thread, NULL,
CLONE_FS | CLONE_FILES | CLONE_VM);
return rc; /* Success */
} else
cifs_destroy_request_bufs();
}
cifs_destroy_mids();
......@@ -459,10 +514,12 @@ exit_cifs(void)
#if CONFIG_PROC_FS
cifs_proc_clean();
#endif
unregister_filesystem(&cifs_fs_type);
unregister_filesystem(&cifs_fs_type);
cifs_destroy_inodecache();
cifs_destroy_mids();
cifs_destroy_request_bufs();
if(oplockThread)
send_sig(SIGKILL, oplockThread, 1);
}
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
......
......@@ -199,14 +199,18 @@ struct cifsLockInfo {
struct cifsFileInfo {
struct list_head tlist; /* pointer to next fid owned by tcon */
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 */
__u16 netfid; /* file id from remote */
/* BB add lock scope info here if needed */ ;
/* 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 closePend:1; /* file is marked to close */
int emptyDir:1;
char * search_resume_name;
unsigned int resume_name_length;
__u32 resume_key;
};
/*
......@@ -221,7 +225,8 @@ struct cifsInodeInfo {
atomic_t inUse; /* num concurrent users (local openers cifs) of file*/
unsigned long time; /* jiffies of last update/check of inode */
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;
};
......@@ -251,14 +256,20 @@ struct mid_q_entry {
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_REQUEST_ALLOCATED 1
#define MID_REQUEST_SUBMITTED 2
#define MID_RESPONSE_RECEIVED 4
struct servers_not_supported { /* @z4a */
struct servers_not_supported *next1; /* @z4a */
char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* @z4a */
struct servers_not_supported { /* @z4a */
struct servers_not_supported *next1; /* @z4a */
char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* @z4a */
/* Server Names in SMB protocol are 15 chars + X'20' */
/* in 16th byte... @z4a */
};
......@@ -301,6 +312,8 @@ GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
GLOBAL_EXTERN struct list_head GlobalOplock_Q;
/*
* Global transaction id (XID) information
*/
......@@ -327,6 +340,7 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
have the uid/password or Kerberos credential
or equivalent for current user */
GLOBAL_EXTERN unsigned int oplockEnabled;
GLOBAL_EXTERN unsigned int lookupCacheEnabled;
GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */
GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */
......
......@@ -38,6 +38,7 @@
#define SMB_COM_WRITE_ANDX 0x2F
#define SMB_COM_TRANSACTION2 0x32
#define SMB_COM_TRANSACTION2_SECONDARY 0x33
#define SMB_COM_FIND_CLOSE2 0x34
#define SMB_COM_TREE_DISCONNECT 0x71
#define SMB_COM_NEGOTIATE 0x72
#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
typedef struct smb_com_close_req {
struct smb_hdr hdr; /* wct = 3 */
__u16 FileID; /* target file attributes */
__u16 FileID;
__u32 LastWriteTime; /* should be zero */
__u16 ByteCount; /* 0 */
} CLOSE_REQ;
......@@ -594,6 +595,12 @@ typedef struct smb_com_close_rsp {
__u16 ByteCount; /* bct = 0 */
} CLOSE_RSP;
typedef struct smb_com_findclose_req {
struct smb_hdr hdr; /* wct = 1 */
__u16 FileID;
__u16 ByteCount; /* 0 */
} FINDCLOSE_REQ;
/* OpenFlags */
#define REQ_OPLOCK 0x00000002
#define REQ_BATCHOPLOCK 0x00000004
......@@ -1152,7 +1159,7 @@ typedef struct smb_com_transaction2_fnext_req {
__u16 InformationLevel;
__u32 ResumeKey;
__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;
typedef struct smb_com_transaction2_fnext_rsp {
......@@ -1509,7 +1516,7 @@ typedef struct {
__u32 ExtFileAttributes;
__u32 FileNameLength;
char FileName[1];
} FILE_DIRECTORY_INFO; /* level 257 FF response data area */
} FILE_DIRECTORY_INFO; /* level 257 FF response data area */
struct gea {
unsigned char cbName;
......
......@@ -57,6 +57,8 @@ extern void header_assemble(struct smb_hdr *, char /* command */ ,
const struct cifsTconInfo *, int
/* 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 u64 cifs_UnixTimeToNT(struct timespec);
extern void RevUcode_to_Ucode(char *revUnicode, char *UnicodeName);
......@@ -104,9 +106,13 @@ extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
FILE_DIRECTORY_INFO * findData,
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);
extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
const __u16 search_handle);
extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_ALL_INFO * findData,
......
......@@ -1449,7 +1449,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
ATTR_DIRECTORY);
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 */
if (tcon->ses->capabilities & CAP_UNIX) {
......@@ -1496,9 +1496,9 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
int
CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
FILE_DIRECTORY_INFO * findData,
T2_FNEXT_RSP_PARMS * findParms, const __u16 searchHandle,
__u32 resumeKey, int *pUnicodeFlag, int *pUnixFlag)
FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms,
const __u16 searchHandle, char * resume_file_name, int name_len,
__u32 resume_key, int *pUnicodeFlag, int *pUnixFlag)
{
/* level 257 SMB_ */
TRANSACTION2_FNEXT_REQ *pSMB = NULL;
......@@ -1508,6 +1508,9 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
int bytes_returned;
cFYI(1, ("In FindNext"));
if(resume_file_name == NULL) {
return -EIO;
}
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
......@@ -1530,9 +1533,6 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
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 */
findParms->SearchCount = 0; /* set to zero in case of error */
pSMB->SearchCount =
......@@ -1546,10 +1546,19 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
*pUnixFlag = FALSE;
}
pSMB->ResumeKey = resumeKey; /* always kept as le */
pSMB->ResumeKey = resume_key;
pSMB->SearchFlags =
cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
CIFS_SEARCH_CONTINUE_FROM_LAST);
cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
/* 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->ByteCount = cpu_to_le16(pSMB->ByteCount);
......@@ -1585,6 +1594,33 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
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
CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName,
......
......@@ -850,8 +850,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
init_waitqueue_head(&srvTcp->response_q);
INIT_LIST_HEAD(&srvTcp->pending_mid_q);
srvTcp->tcpStatus = CifsGood;
kernel_thread((void *) (void *)
cifs_demultiplex_thread, srvTcp,
kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
CLONE_FS | CLONE_FILES | CLONE_VM);
}
}
......
This diff is collapsed.
......@@ -450,10 +450,10 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
cifs_sb_source = CIFS_SB(source_inode->i_sb);
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
different share. Might eventually add support for this */
FreeXid(xid);
}
fromName = build_path_from_dentry(source_direntry);
......@@ -471,7 +471,7 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
if (toName)
kfree(toName);
FreeXid(xid);
FreeXid(xid);
return rc;
}
......@@ -500,15 +500,15 @@ cifs_revalidate(struct dentry *direntry)
if (time_before(jiffies, cifsInode->time + HZ)) {
if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
(direntry->d_inode->i_nlink == 1)) {
if (full_path)
kfree(full_path);
FreeXid(xid);
return rc;
} else {
cFYI(1,("Have to revalidate file due to hardlinks"));
}
(direntry->d_inode->i_nlink == 1) ||
(lookupCacheEnabled == 0)) {
if (full_path)
kfree(full_path);
FreeXid(xid);
return rc;
} else {
cFYI(1,("Have to revalidate file due to hardlinks"));
}
}
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
......
......@@ -82,7 +82,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
int rc = -EACCES;
int xid;
char *full_path = NULL;
char target_path[257];
char * target_path;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
......@@ -91,7 +91,11 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
cifs_sb = CIFS_SB(inode->i_sb);
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 */
/* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1); */
......@@ -99,7 +103,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
if (pTcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
target_path,
sizeof (target_path) - 1,
PATH_MAX-1,
cifs_sb->local_nls);
else {
/* rc = CIFSSMBQueryReparseLinkInfo */
......@@ -109,11 +113,13 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
/* BB Should we be using page symlink ops here? */
if (rc == 0) {
target_path[256] = 0;
target_path[PATH_MAX-1] = 0;
rc = vfs_follow_link(nd, target_path);
}
/* else EACCESS */
if (target_path)
kfree(target_path);
if (full_path)
kfree(full_path);
FreeXid(xid);
......@@ -180,7 +186,8 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
char *full_path = NULL;
char tmpbuffer[256];
char * tmpbuffer;
int len;
__u16 fid;
xid = GetXid();
......@@ -190,20 +197,28 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
cFYI(1,
("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
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 */
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
tmpbuffer,
sizeof (tmpbuffer) - 1,
cifs_sb->local_nls);
tmpbuffer,
len - 1,
cifs_sb->local_nls);
else {
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
OPEN_REPARSE_POINT,&fid, &oplock, cifs_sb->local_nls);
if(!rc) {
rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
tmpbuffer,
sizeof(tmpbuffer) - 1,
len - 1,
fid,
cifs_sb->local_nls);
if(CIFSSMBClose(xid, pTcon, fid)) {
......@@ -216,15 +231,15 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
/* BB Should we be using page ops here? */
/* BB null terminate returned string in pBuffer? BB */
if (buflen > sizeof (tmpbuffer))
buflen = sizeof (tmpbuffer);
if (rc == 0) {
rc = vfs_readlink(direntry, pBuffer, buflen, tmpbuffer);
rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer);
cFYI(1,
("vfs_readlink called from cifs_readlink returned %d",
rc));
}
if (tmpbuffer)
kfree(tmpbuffer);
if (full_path)
kfree(full_path);
FreeXid(xid);
......
......@@ -27,6 +27,7 @@
#include "cifs_debug.h"
extern kmem_cache_t *cifs_req_cachep;
extern struct task_struct * oplockThread;
__u16 GlobalMid; /* multiplex id - rotating counter */
......@@ -336,6 +337,7 @@ is_valid_oplock_break(struct smb_hdr *buf)
list_for_each(tmp1,&tcon->openFileList){
netfile = list_entry(tmp1,struct cifsFileInfo,tlist);
if(pSMB->Fid == netfile->netfid) {
struct cifsInodeInfo *pCifsInode;
/* BB Add following logic:
2) look up inode from tcon->openFileList->file->f_dentry->d_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)
6) send oplock break response to server */
read_unlock(&GlobalSMBSeslock);
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;
}
}
......
......@@ -32,6 +32,7 @@
#include "cifs_debug.h"
extern kmem_cache_t *cifs_mid_cachep;
extern kmem_cache_t *cifs_oplock_cachep;
struct mid_q_entry *
AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
......@@ -95,6 +96,39 @@ DeleteMidQEntry(struct mid_q_entry *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
smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
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