/*
* fs/cifs/misc.c
*
- * Copyright (C) International Business Machines Corp., 2002,2003
+ * Copyright (C) International Business Machines Corp., 2002,2004
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
#include <linux/slab.h>
#include <linux/ctype.h>
+#include <linux/mempool.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "smberr.h"
#include "nterr.h"
-extern kmem_cache_t *cifs_req_cachep;
+extern mempool_t *cifs_sm_req_poolp;
+extern mempool_t *cifs_req_poolp;
extern struct task_struct * oplockThread;
__u16 GlobalMid; /* multiplex id - rotating counter */
ret_buf->tidStatus = CifsNew;
INIT_LIST_HEAD(&ret_buf->openFileList);
init_MUTEX(&ret_buf->tconSem);
+#ifdef CONFIG_CIFS_STATS
+ spin_lock_init(&ret_buf->stat_lock);
+#endif
write_unlock(&GlobalSMBSeslock);
}
return ret_buf;
struct smb_hdr *
cifs_buf_get(void)
{
- struct smb_hdr *ret_buf = 0;
+ struct smb_hdr *ret_buf = NULL;
/* We could use negotiated size instead of max_msgsize -
but it may be more efficient to always alloc same size
albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */
ret_buf =
- (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL | SLAB_NOFS);
+ (struct smb_hdr *) mempool_alloc(cifs_req_poolp, SLAB_KERNEL | SLAB_NOFS);
/* clear the first few header bytes */
+ /* for most paths, more is cleared in header_assemble */
if (ret_buf) {
- memset(ret_buf, 0, sizeof (struct smb_hdr));
+ memset(ret_buf, 0, sizeof(struct smb_hdr) + 3);
atomic_inc(&bufAllocCount);
}
{
if (buf_to_free == NULL) {
- cFYI(1, ("Null buffer passed to cifs_buf_release"));
+ /* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/
return;
}
- kmem_cache_free(cifs_req_cachep, buf_to_free);
+ mempool_free(buf_to_free,cifs_req_poolp);
atomic_dec(&bufAllocCount);
return;
}
+struct smb_hdr *
+cifs_small_buf_get(void)
+{
+ struct smb_hdr *ret_buf = NULL;
+
+/* We could use negotiated size instead of max_msgsize -
+ but it may be more efficient to always alloc same size
+ albeit slightly larger than necessary and maxbuffersize
+ defaults to this and can not be bigger */
+ ret_buf =
+ (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, SLAB_KERNEL | SLAB_NOFS);
+ if (ret_buf) {
+ /* No need to clear memory here, cleared in header assemble */
+ /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
+ atomic_inc(&smBufAllocCount);
+ }
+ return ret_buf;
+}
+
+void
+cifs_small_buf_release(void *buf_to_free)
+{
+
+ if (buf_to_free == NULL) {
+ cFYI(1, ("Null buffer passed to cifs_small_buf_release"));
+ return;
+ }
+ mempool_free(buf_to_free,cifs_sm_req_poolp);
+
+ atomic_dec(&smBufAllocCount);
+ return;
+}
+
void
header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
const struct cifsTconInfo *treeCon, int word_count
- /* length of fixed section (word count) in two byte units */
- )
+ /* length of fixed section (word count) in two byte units */)
{
- int i;
- __u32 tmp;
struct list_head* temp_item;
struct cifsSesInfo * ses;
char *temp = (char *) buffer;
- for (i = 0; i < MAX_CIFS_HDR_SIZE; i++) {
- temp[i] = 0; /* BB is this needed ?? */
- }
+ memset(temp,0,MAX_CIFS_HDR_SIZE);
buffer->smb_buf_length =
(2 * word_count) + sizeof (struct smb_hdr) -
buffer->Command = smb_command;
buffer->Flags = 0x00; /* case sensitive */
buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
- tmp = cpu_to_le32(current->tgid);
- buffer->Pid = tmp & 0xFFFF;
- tmp >>= 16;
- buffer->PidHigh = tmp & 0xFFFF;
+ buffer->Pid = cpu_to_le16((__u16)current->tgid);
+ buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
spin_lock(&GlobalMid_Lock);
GlobalMid++;
buffer->Mid = GlobalMid;
}
if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
buffer->Flags2 |= SMBFLG2_DFS;
- if(treeCon->ses->server)
+ if((treeCon->ses) && (treeCon->ses->server))
if(treeCon->ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
{
/* Make sure that this really is an SMB, that it is a response,
and that the message ids match */
- if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
+ if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
(mid == smb->Mid)) {
if(smb->Flags & SMBFLG_RESPONSE)
return 0;
cERROR(1, ("Rcvd Request not response "));
}
} else { /* bad signature or mid */
- if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff))
+ if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
cERROR(1,
("Bad protocol string signature header %x ",
*(unsigned int *) smb->Protocol));
int
checkSMB(struct smb_hdr *smb, __u16 mid, int length)
{
+ __u32 len = be32_to_cpu(smb->smb_buf_length);
cFYI(0,
("Entering checkSMB with Length: %x, smb_buf_length: %x ",
- length, ntohl(smb->smb_buf_length)));
- if (((unsigned int)length < 2 + sizeof (struct smb_hdr))
- || (ntohl(smb->smb_buf_length) >
- CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)) {
+ length, len));
+ if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
+ (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
cERROR(1, ("Length less than 2 + sizeof smb_hdr "));
if (((unsigned int)length >= sizeof (struct smb_hdr) - 1)
return 0; /* some error cases do not return wct and bcc */
}
- if (ntohl(smb->smb_buf_length) >
- CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)
+ if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
cERROR(1,
- ("smb_buf_length greater than CIFS_MAX_MSGSIZE ... "));
+ ("smb_buf_length greater than MaxBufSize"));
cERROR(1,
("bad smb detected. Illegal length. The mid=%d",
smb->Mid));
if (checkSMBhdr(smb, mid))
return 1;
- if ((4 + ntohl(smb->smb_buf_length) != smbCalcSize(smb))
- || (4 + ntohl(smb->smb_buf_length) != (unsigned int)length)) {
+ if ((4 + len != smbCalcSize(smb))
+ || (4 + len != (unsigned int)length)) {
return 0;
} else {
cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
struct cifsTconInfo *tcon;
struct cifsFileInfo *netfile;
- /* could add check for smb response flag 0x80 */
- cFYI(1,("Checking for oplock break"));
+ cFYI(1,("Checking for oplock break or dnotify response"));
+ if((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
+ (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
+ struct smb_com_transaction_change_notify_rsp * pSMBr =
+ (struct smb_com_transaction_change_notify_rsp *)buf;
+ struct file_notify_information * pnotify;
+ __u32 data_offset = 0;
+ if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
+ data_offset = le32_to_cpu(pSMBr->DataOffset);
+
+ pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol
+ + data_offset);
+ cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName,
+ pnotify->Action)); /* BB removeme BB */
+ /* cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */
+ return TRUE;
+ }
+ if(pSMBr->hdr.Status.CifsError) {
+ cFYI(1,("notify err 0x%d",pSMBr->hdr.Status.CifsError));
+ return TRUE;
+ }
+ return FALSE;
+ }
if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
return FALSE;
if(pSMB->hdr.Flags & SMBFLG_RESPONSE) {
list_for_each(tmp, &GlobalTreeConnectionList) {
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
if (tcon->tid == buf->Tid) {
+#ifdef CONFIG_CIFS_STATS
+ atomic_inc(&tcon->num_oplock_brks);
+#endif
list_for_each(tmp1,&tcon->openFileList){
netfile = list_entry(tmp1,struct cifsFileInfo,tlist);
if(pSMB->Fid == netfile->netfid) {