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)
...@@ -390,10 +395,17 @@ int ...@@ -390,10 +395,17 @@ int
cifs_init_mids(void) cifs_init_mids(void)
{ {
cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids",
sizeof (struct mid_q_entry), 0, sizeof (struct mid_q_entry), 0,
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) {
return rc; /* Success */ kernel_thread(cifs_oplock_thread, NULL,
else CLONE_FS | CLONE_FILES | CLONE_VM);
return rc; /* Success */
} else
cifs_destroy_request_bufs(); cifs_destroy_request_bufs();
} }
cifs_destroy_mids(); cifs_destroy_mids();
...@@ -459,10 +516,12 @@ exit_cifs(void) ...@@ -459,10 +516,12 @@ exit_cifs(void)
#if CONFIG_PROC_FS #if CONFIG_PROC_FS
cifs_proc_clean(); cifs_proc_clean();
#endif #endif
unregister_filesystem(&cifs_fs_type); unregister_filesystem(&cifs_fs_type);
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,14 +199,18 @@ struct cifsLockInfo { ...@@ -199,14 +199,18 @@ 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 */ ;
/* 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;
char * search_resume_name;
unsigned int resume_name_length;
__u32 resume_key;
}; };
/* /*
...@@ -221,7 +225,8 @@ struct cifsInodeInfo { ...@@ -221,7 +225,8 @@ struct cifsInodeInfo {
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 */
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,14 +256,20 @@ struct mid_q_entry { ...@@ -251,14 +256,20 @@ 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
#define MID_RESPONSE_RECEIVED 4 #define MID_RESPONSE_RECEIVED 4
struct servers_not_supported { /* @z4a */ struct servers_not_supported { /* @z4a */
struct servers_not_supported *next1; /* @z4a */ struct servers_not_supported *next1; /* @z4a */
char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* @z4a */ char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* @z4a */
/* Server Names in SMB protocol are 15 chars + X'20' */ /* Server Names in SMB protocol are 15 chars + X'20' */
/* in 16th byte... @z4a */ /* in 16th byte... @z4a */
}; };
...@@ -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 {
...@@ -1509,7 +1516,7 @@ typedef struct { ...@@ -1509,7 +1516,7 @@ typedef struct {
__u32 ExtFileAttributes; __u32 ExtFileAttributes;
__u32 FileNameLength; __u32 FileNameLength;
char FileName[1]; char FileName[1];
} FILE_DIRECTORY_INFO; /* level 257 FF response data area */ } FILE_DIRECTORY_INFO; /* level 257 FF response data area */
struct gea { struct gea {
unsigned char cbName; unsigned char cbName;
......
...@@ -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);
} }
} }
......
This diff is collapsed.
...@@ -450,10 +450,10 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry, ...@@ -450,10 +450,10 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
cifs_sb_source = CIFS_SB(source_inode->i_sb); cifs_sb_source = CIFS_SB(source_inode->i_sb);
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);
...@@ -471,7 +471,7 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry, ...@@ -471,7 +471,7 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
if (toName) if (toName)
kfree(toName); kfree(toName);
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
...@@ -500,15 +500,15 @@ cifs_revalidate(struct dentry *direntry) ...@@ -500,15 +500,15 @@ 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) ||
if (full_path) (lookupCacheEnabled == 0)) {
kfree(full_path); if (full_path)
FreeXid(xid); kfree(full_path);
return rc; FreeXid(xid);
} else { return rc;
cFYI(1,("Have to revalidate file due to hardlinks")); } else {
} 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,20 +197,28 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -190,20 +197,28 @@ 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,
OPEN_REPARSE_POINT,&fid, &oplock, cifs_sb->local_nls); OPEN_REPARSE_POINT,&fid, &oplock, cifs_sb->local_nls);
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