Hitoshi Mitake | 6 Oct 08:09 2009
Picon

Fw: [PATCH] Fixing to avoid invalid kfree() in cifs_get_tcp_session() of fs/cifs/connect.c


Hi,

Yesterday I posted this bug fix to LKML.
For confirmation, I forward this to linux-cifs-client too.

Picon
From: Hitoshi Mitake <mitake <at> dcl.info.waseda.ac.jp>
Subject: [PATCH] Fixing to avoid invalid kfree() in cifs_get_tcp_session() of fs/cifs/connect.c
Date: 2009-10-05 09:28:56 GMT

Hi,

I found a trivial bug in fs/cifs/connect.c .
The bug is caused by fail of extract_hostname()
when mounting cifs file system.

This is the situation when I noticed this bug.

% sudo mount -t cifs //192.168.10.208 mountpoint -o options...

Then my kernel says,

[ 1461.807776] ------------[ cut here ]------------
(Continue reading)

Jeff Layton | 6 Oct 13:05 2009
Picon

Re: Fw: [PATCH] Fixing to avoid invalid kfree() in cifs_get_tcp_session() of fs/cifs/connect.c

On Tue, 06 Oct 2009 15:09:47 +0900 (JST)
Hitoshi Mitake <mitake <at> dcl.info.waseda.ac.jp> wrote:

> From: Hitoshi Mitake <mitake <at> dcl.info.waseda.ac.jp>
> To: linux-cifs-client <at> lists.samba.org
> Subject: [linux-cifs-client] Fw: [PATCH] Fixing to avoid invalid kfree() in cifs_get_tcp_session()
of fs/cifs/connect.c
> Date: Tue, 06 Oct 2009 15:09:47 +0900 (JST)
> Sender: linux-cifs-client-bounces <at> lists.samba.org
> X-Mailer: Mew version 5.2 on Emacs 22.2 / Mule 5.0 (SAKAKI)
> 
> 
> Hi,
> 
> Yesterday I posted this bug fix to LKML.
> For confirmation, I forward this to linux-cifs-client too.
> 
> 
> From: Hitoshi Mitake <mitake <at> dcl.info.waseda.ac.jp>
> To: sfrench <at> us.ibm.com, linux-kernel <at> vger.kernel.org
> Subject: [PATCH] Fixing to avoid invalid kfree() in cifs_get_tcp_session() of fs/cifs/connect.c
> Date: Mon, 05 Oct 2009 18:28:56 +0900 (JST)
> X-Mailer: Mew version 5.2 on Emacs 22.2 / Mule 5.0 (SAKAKI)
> 
> 
> Hi,
> 
> I found a trivial bug in fs/cifs/connect.c .
> The bug is caused by fail of extract_hostname()
> when mounting cifs file system.
(Continue reading)

Steve French | 6 Oct 20:37 2009
Picon

Re: [PATCH] Fixing to avoid invalid kfree() in cifs_get_tcp_session() of fs/cifs/connect.c

> Hi,
>
> I found a trivial bug in fs/cifs/connect.c .
> The bug is caused by fail of extract_hostname()
> when mounting cifs file system.
>
> This is the situation when I noticed this bug.
>
> % sudo mount -t cifs //192.168.10.208 mountpoint -o options...
>
> Then my kernel says,
>
> [ 1461.807776] ------------[ cut here ]------------
> [ 1461.807781] kernel BUG at mm/slab.c:521!
> [ 1461.807784] invalid opcode: 0000 [#2] PREEMPT SMP
> [ 1461.807790] last sysfs file:
> /sys/devices/pci0000:00/0000:00:1e.0/0000:09:02.0/resource
> [ 1461.807793] CPU 0
> [ 1461.807796] Modules linked in: nls_iso8859_1 usbhid sbp2 uhci_hcd
> ehci_hcd i2c_i801 ohci1394 ieee1394 psmouse serio_raw pcspkr sky2 usbcore
> evdev
> [ 1461.807816] Pid: 3446, comm: mount Tainted: G      D 2.6.32-rc2-vanilla
> #1 System Product Name
> [ 1461.807820] RIP: 0010:[<ffffffff810b888e>]  [<ffffffff810b888e>]
> kfree+0x63/0x156
> [ 1461.807829] RSP: 0018:ffff8800b4f7fbb8  EFLAGS: 00010046
> [ 1461.807832] RAX: ffffea00033fff98 RBX: ffff8800afbae7e2 RCX:
> 0000000000000000
> [ 1461.807836] RDX: ffffea0000000000 RSI: 000000000000005c RDI:
> ffffffffffffffea
(Continue reading)

Suresh Jayaraman | 7 Oct 14:39 2009
Picon

Accessing CIFS DFS link for the first time

Hi all,

The first access to a DFS link fails with -EREMOTE on a 2.6.27 based
kernel (haven't tested on the recent one, but looking at the code it
appears that the code in question has not changed).

#mount -t cifs -o username=administrator, domain=foo.dom.com
\\\\<ipaddress>\\DFSROOT /mnt/
(mount succeeds)
#cd /mnt
#cd DFS-test/ 	(DFS-test is a dfs link)
# ls
returns -EREMOTE

Looking at the cFYI information and code, it looks like cifs_readdir()
doesn't follow dfs links. Is it not supported, yet?

Possible handle -EREMOTE from FindFirst() in initiate_cifs_search() and
calling cifs_dfs_follow_mountpoint() would help fixing this?

Are there more details involved that I'm missing?

Thanks,

--

-- 
Suresh Jayaraman
Steve French | 7 Oct 15:21 2009
Picon

Re: Accessing CIFS DFS link for the first time

On Wed, Oct 7, 2009 at 7:39 AM, Suresh Jayaraman <sjayaraman <at> suse.de> wrote:
> Hi all,
>
> The first access to a DFS link fails with -EREMOTE on a 2.6.27 based
> kernel (haven't tested on the recent one, but looking at the code it
> appears that the code in question has not changed).
>
> #mount -t cifs -o username=administrator, domain=foo.dom.com
> \\\\<ipaddress>\\DFSROOT /mnt/
> (mount succeeds)
> #cd /mnt
> #cd DFS-test/   (DFS-test is a dfs link)
> # ls
> returns -EREMOTE
>
> Looking at the cFYI information and code, it looks like cifs_readdir()
> doesn't follow dfs links. Is it not supported, yet?
>
> Possible handle -EREMOTE from FindFirst() in initiate_cifs_search() and
> calling cifs_dfs_follow_mountpoint() would help fixing this?

The lookup (QueryPathInfo) should get the EREMOTE before you even
get to readdir

> Are there more details involved that I'm missing?

--

-- 
Thanks,

Steve
(Continue reading)

Steve French | 15 Oct 19:32 2009
Picon

TCP_NODELAY and CORK - should they be added for network fs case?

Looking at calls to kernel_sendmsg, and thinking about why I only see
a few places that do TCP_NODELAY and TCP_CORK in kernel.

Looking at the cifs example.  cifs is trying to send packets which
vary from about 50-100 bytes for common calls (like lookup) to about
56K for file writes (can be larger if override wsize and max buffer
size via insmod parameter), and cifs always uses kernel_sendmsg.   For
the cifs case, sending individual SMB/CIFS requests to a particular
server (socket) are serialized, protected by a mutex, even if many
processes are writing to different remote files at one time.
Usually one kernel_sendmsg is all that is needed to send an SMB
request - does kernel_sendmsg implicitly "cork" the request so that
the SMB is not unnecessarily fragmented?  If the socket is full, and
only a few bytes are sent, multiple sendmsg's may be required to send
one smb - should cifs be doing a cork before the loop which calls
kernel_sendmsg in smb_sendv in fs/cifs/transport.c and uncork
afterward (since the server can't do much processing without getting
the whole SMB request except in one narrow case of receivefile on
certain write requests)?    Especially if we add code to allow setting
"TCP_NODELAY" ... to improve GigE performance

Are there any cases where we should be setting LOWDELAY instead for
this kind of socket?

--

-- 
Thanks,

Steve
Shirish Pargaonkar | 15 Oct 19:36 2009
Picon

[patch][0/3] Add support infrastructure for Named Pipe

Add Named Pipe support in cifs client. 
 
Since there are no equivalent kernel APIs for transactions, most of the SMBTrans
functions are implemented using ioctls which are handle based, like the
APIs used for Named Pipes.
 
A path based function, WaitNamedPipe is not implemented at this time.
Also not implemented support for multiple fragments in TransactNmPipe function.
 
 
Signed-off-by: Shirish Pargaonkar shirishpargaonkar <at> gmail.com
_______________________________________________
linux-cifs-client mailing list
linux-cifs-client <at> lists.samba.org
https://lists.samba.org/mailman/listinfo/linux-cifs-client
Shirish Pargaonkar | 15 Oct 19:40 2009
Picon

[patch][1/3] Data structures and defines for Named Pipes

Add data structures and defines (ioctl commands etc.) for Named Pipe
support in cifs

From 02cc49c80d125beac34cf82d312f5f221311dd62 Mon Sep 17 00:00:00 2001
From: Shirish Pargaonkar <shirishpargaonkar <at> gmail.com>
Date: Thu, 15 Oct 2009 08:14:44 -0500
Subject: [PATCH] Header file changes for Named Pipe support

---
 fs/cifs/cifsglob.h  |   48 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/cifspdu.h   |   45 +++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/cifsproto.h |   15 +++++++++++++++
 3 files changed, 108 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 5d0fde1..6ee9dae 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
 <at>  <at>  -612,6 +612,54  <at>  <at>  require use of the stronger protocol */
  *****************************************************************
  */

+/*
+ *****************************************************************
+ * Named Pipe data structures and ioctl commands
+ *****************************************************************
+ */
+
+#define MAXPIPENAMELEN 256
+#define MAXPEEKNMBUFSIZE 8192
+
+struct qnmp_info {
+	unsigned short outbuf;
+	unsigned short inbuf;
+	unsigned char maxinst;
+	unsigned char curinst;
+	unsigned char length;
+	char pipename[MAXPIPENAMELEN];
+};
+
+struct qnmp_hinfo {
+	unsigned short mode;
+};
+
+struct peeknmp_info {
+	unsigned int size;
+	unsigned short bavail;
+	unsigned short bremain;
+	unsigned short conntype;
+	char buffer[MAXPEEKNMBUFSIZE];
+};
+
+struct transnmp_info {
+	unsigned int wsize;
+	char sendbuf[MAXPEEKNMBUFSIZE];
+	unsigned rsize;
+	char recvbuf[MAXPEEKNMBUFSIZE];
+};
+
+#define CIFS_QUERYNMPIPE _IOR(0xCF, 0x3, struct qnmp_info)
+#define CIFS_PEEKNMPIPE _IOWR(0xCF, 0x4, struct peeknmp_info)
+#define CIFS_GETNMPIPEHANDSTATE _IOR(0xCF, 0x5, struct qnmp_hinfo)
+#define CIFS_SETNMPIPEHANDSTATE _IOW(0xCF, 0x6, struct qnmp_hinfo)
+#define CIFS_TRANSACTNMPIPE _IOWR(0xCF, 0x7, struct qnmp_hinfo)
+
+#define NONBLOCKINGNMPIPE 0x0008
+#define BLOCKINGNMPIPE 0x0004
+#define MESSAGENMREAD 0x0002
+#define BYTESTREAMNMREAD 0x0001
+
 #define UID_HASH (16)

 /*
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 2d07f89..df922dc 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
 <at>  <at>  -49,6 +49,7  <at>  <at> 
 #define SMB_COM_QUERY_INFORMATION     0x08 /* aka getattr */
 #define SMB_COM_SETATTR               0x09 /* trivial response */
 #define SMB_COM_LOCKING_ANDX          0x24 /* trivial response */
+#define SMB_COM_TRANSACTION           0x25
 #define SMB_COM_COPY                  0x29 /* trivial rsp, fail
filename ignrd*/
 #define SMB_COM_OPEN_ANDX             0x2D /* Legacy open for old servers */
 #define SMB_COM_READ_ANDX             0x2E
 <at>  <at>  -1269,6 +1270,50  <at>  <at>  typedef struct smb_com_ntransact_rsp {
 	/* parms and data follow */
 } __attribute__((packed)) NTRANSACT_RSP;

+typedef struct smb_com_transact_req {
+	struct smb_hdr hdr; /* wct >= 19 */
+	__le16 TotalParameterCount;
+	__le16 TotalDataCount;
+	__le16 MaxParameterCount;
+	__le16 MaxDataCount;
+	__u8 MaxSetupCount;
+	__u8 Reserved;
+	__u16 Flags;
+	__le32 Timeout;
+	__le16 Reserved1;
+	__le16 ParameterCount;
+	__le16 ParameterOffset;
+	__le16 DataCount;
+	__le16 DataOffset;
+	__u8 SetupCount;
+	__u8 Reserved2;
+	__le16 Function;
+	__le16 Fid;
+	__le16 ByteCount;
+	unsigned char pad[1];
+	unsigned char Name[1];
+	unsigned char Param[1];
+	unsigned char Data[1];
+} __attribute__((packed)) TRANS_REQ;
+
+typedef struct smb_com_transact_rsp {
+	struct smb_hdr hdr;     /* wct = 18 */
+	__u16 Reserved;
+	__le16 TotalParameterCount;
+	__le16 TotalDataCount;
+	__le16 ParameterCount;
+	__le16 ParameterOffset;
+	__le16 ParameterDisplacement;
+	__le16 DataCount;
+	__le16 DataOffset;
+	__le16 DataDisplacement;
+	__u8 SetupCount;   /* 0 */
+	__u16 ByteCount;
+	__u8 Reserved1;
+	/* __u8 Pad[3]; */
+	/* parms and data follow */
+} __attribute__((packed)) TRANS_RSP;
+
 typedef struct smb_com_transaction_ioctl_req {
 	struct smb_hdr hdr;	/* wct = 23 */
 	__u8 MaxSetupCount;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6928c24..21e553f 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
 <at>  <at>  -388,4 +388,19  <at>  <at>  extern int CIFSSMBSetPosixACL(const int xid,
struct cifsTconInfo *tcon,
 		const struct nls_table *nls_codepage, int remap_special_chars);
 extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
 			const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
+extern int CIFSSMBTransQNmPipe(const int, struct cifsTconInfo *,
+		 unsigned long, __u16, const struct nls_table *, int);
+extern int CIFSSMBTransSetNmPHState(const int, struct cifsTconInfo *,
+		unsigned long, __u16, const struct nls_table *, int);
+extern int CIFSSMBTranWaitNmPipe(const int, struct cifsTconInfo *,
+		 const unsigned char *, unsigned char *,
+		__u16, const struct nls_table *, int);
+extern int CIFSSMBTransPeekNmPipe(const int, struct cifsTconInfo *,
+		 unsigned long, __u16, const struct nls_table *, int);
+extern int CIFSSMBTransGetNmPHState(const int, struct cifsTconInfo *,
+		unsigned long, __u16, const struct nls_table *, int);
+extern int CIFSSMBTransNmPipe(const int, struct cifsTconInfo *,
+		unsigned char *, __u16, const struct nls_table *, int);
+extern int ChkNMPHmode(unsigned short);
+extern unsigned short SetNMPHmode(unsigned short, unsigned short);
 #endif			/* _CIFSPROTO_H */
--

-- 
1.5.2
Shirish Pargaonkar | 15 Oct 19:41 2009
Picon

[patch][2/3] SMBTrans functions for Named Pipes

SMB Trans commands (except WaitNamedPipe)

From d11c8d19f9e1bf5d3ed615a38ce99e97dfe0b7dd Mon Sep 17 00:00:00 2001
From: Shirish Pargaonkar <shirishpargaonkar <at> gmail.com>
Date: Thu, 15 Oct 2009 08:16:26 -0500
Subject: [PATCH] SMB Trans functions for Named Pipe support

---
 fs/cifs/cifssmb.c |  488 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 488 insertions(+), 0 deletions(-)

diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 941441d..9d6b77b 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
 <at>  <at>  -5675,4 +5675,492  <at>  <at>  SetEARetry:
 	return rc;
 }

+int
+CIFSSMBTransQNmPipe(const int xid, struct cifsTconInfo *tcon,
+		unsigned long arg, __u16 netfid,
+		const struct nls_table *nls_codepage, int remap)
+{
+	TRANS_REQ *pSMB = NULL;
+	TRANS_RSP *pSMBr = NULL;
+	int rc = 0;
+	int name_len, param_len;
+	int pad;
+	int bytes_returned = 0;
+	__u16 offset;
+	__u16 byte_count = 0;
+	char *fileName = "\\PIPE\\";
+	char *bcc_ptr;
+	struct qnmp_info qnmpipeinfo;
+
+	cFYI(1, ("In CIFSSMBTransQNmPipe"));
+qnmpiperetry:
+	rc = smb_init(SMB_COM_TRANSACTION, 16, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	offset = offsetof(TRANS_REQ, Name) - 4;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifsConvertToUCS((__le16 *) bcc_ptr, fileName,
+				     PATH_MAX, nls_codepage, remap);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(bcc_ptr, fileName, name_len);
+	}
+	byte_count += (1 + pad + name_len);
+
+	offset += name_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->ParameterCount = 2;
+	pSMB->TotalParameterCount = 2;
+	pSMB->ParameterOffset = offset;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	*bcc_ptr++ = 0x1;
+	*bcc_ptr = 0x0;
+	param_len = 2;
+	byte_count += (pad + param_len);
+
+	offset += param_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->DataOffset = 0;
+	pSMB->DataCount = 0;
+	pSMB->TotalDataCount = 0;
+
+	pSMB->MaxParameterCount = 0;
+	/* BB find max SMB PDU from sess */
+	pSMB->MaxDataCount = cpu_to_le16(4280);
+	pSMB->MaxSetupCount = 0;
+
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+
+	pSMB->SetupCount = 2;
+	pSMB->Function = cpu_to_le16(TRANS_QUERY_NMPIPE_INFO);
+	pSMB->Fid = cpu_to_le16(netfid);
+
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	pSMB->hdr.smb_buf_length += byte_count;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("CIFSSMBTransQNmPipe returned %d", rc));
+	} else {
+		offset = le16_to_cpu(pSMBr->DataOffset);
+		bcc_ptr = (char *)pSMBr + offset + 4;
+		qnmpipeinfo.outbuf = le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		qnmpipeinfo.inbuf = le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		qnmpipeinfo.maxinst = le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		qnmpipeinfo.curinst = *bcc_ptr;
+		bcc_ptr += 2;
+		qnmpipeinfo.length = *bcc_ptr;
+		bcc_ptr += 2;
+		if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+			rc = cifs_from_ucs2(qnmpipeinfo.pipename,
+				(__le16 *)bcc_ptr,
+				(int)qnmpipeinfo.length,
+				(int)(qnmpipeinfo.length - 2),
+				nls_codepage, 0);
+		} else
+			strncpy(qnmpipeinfo.pipename, bcc_ptr,
+				qnmpipeinfo.length);
+		memcpy((char *)arg, &qnmpipeinfo, sizeof(struct qnmp_info));
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto qnmpiperetry;
+
+	return rc;
+}
+
+int
+CIFSSMBTransSetNmPHState(const int xid, struct cifsTconInfo *tcon,
+		unsigned long arg, __u16 netfid,
+		const struct nls_table *nls_codepage, int remap)
+{
+	TRANS_REQ *pSMB = NULL;
+	TRANS_RSP *pSMBr = NULL;
+	int rc = 0;
+	int name_len, param_len;
+	int pad;
+	int bytes_returned = 0;
+	__u16 offset;
+	__u16 byte_count = 0;
+	char *fileName = "\\PIPE\\";
+	char *bcc_ptr;
+	unsigned short mode;
+
+	cFYI(1, ("In CIFSSMBTransSetNmPHandState"));
+setnmaphandstateretry:
+	rc = smb_init(SMB_COM_TRANSACTION, 16, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	offset = offsetof(TRANS_REQ, Name) - 4;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifsConvertToUCS((__le16 *) bcc_ptr, fileName,
+				     PATH_MAX, nls_codepage, remap);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(bcc_ptr, fileName, name_len);
+	}
+	byte_count += (1 + pad + name_len);
+
+	offset += name_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->ParameterCount = 2;
+	pSMB->TotalParameterCount = 2;
+	pSMB->ParameterOffset = offset;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	mode = (*(unsigned short *)(arg));
+	*(unsigned short *)bcc_ptr = cpu_to_le16(mode);
+	bcc_ptr += 2;
+	param_len = 2;
+	byte_count += (pad + param_len);
+
+	offset += param_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->DataOffset = 0;
+	pSMB->DataCount = 0;
+	pSMB->TotalDataCount = 0;
+
+	pSMB->MaxParameterCount = 0;
+	pSMB->MaxDataCount = 0;
+	pSMB->MaxSetupCount = 0;
+
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+
+	pSMB->SetupCount = 2;
+	pSMB->Function = cpu_to_le16(TRANS_SET_NMPIPE_STATE);
+	pSMB->Fid = cpu_to_le16(netfid);
+
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	pSMB->hdr.smb_buf_length += byte_count;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc)
+		cFYI(1, ("CIFSSMBTranSetNmPHandState returned %d", rc));
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto setnmaphandstateretry;
+
+	return rc;
+}
+
+int
+CIFSSMBTransPeekNmPipe(const int xid, struct cifsTconInfo *tcon,
+		unsigned long arg, __u16 netfid,
+		const struct nls_table *nls_codepage, int remap)
+{
+	TRANS_REQ *pSMB = NULL;
+	TRANS_RSP *pSMBr = NULL;
+	int rc = 0;
+	int name_len;
+	int pad;
+	int bytes_returned = 0;
+	int size;
+	__u16 offset;
+	__u16 byte_count = 0;
+	char *fileName = "\\PIPE\\";
+	char *bcc_ptr;
+
+	cFYI(1, ("In CIFSSMBTransPeekNmPipe"));
+peeknmpiperetry:
+	rc = smb_init(SMB_COM_TRANSACTION, 16, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	offset = offsetof(TRANS_REQ, Name) - 4;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifsConvertToUCS((__le16 *) bcc_ptr, fileName,
+				     PATH_MAX, nls_codepage, remap);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(bcc_ptr, fileName, name_len);
+	}
+	byte_count += (1 + pad + name_len);
+
+	offset += name_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->ParameterCount = 0;
+	pSMB->TotalParameterCount = 0;
+	pSMB->ParameterOffset = offset;
+	byte_count += pad;
+
+	pSMB->DataOffset = 0;
+	pSMB->DataCount = 0;
+	pSMB->TotalDataCount = 0;
+
+	pSMB->MaxParameterCount = 6;
+	/* BB find max SMB PDU from sess */
+	pSMB->MaxDataCount = cpu_to_le16(4280);
+	pSMB->MaxSetupCount = 0;
+
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+
+	pSMB->SetupCount = 2;
+	pSMB->Function = cpu_to_le16(TRANS_PEEK_NMPIPE);
+	pSMB->Fid = cpu_to_le16(netfid);
+
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	pSMB->hdr.smb_buf_length += byte_count;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("CIFSSMBTranPeekNmPipe returned %d", rc));
+	} else {
+		offset = le16_to_cpu(pSMBr->ParameterOffset);
+		bcc_ptr = (char *)pSMBr + offset + 4;
+		((struct peeknmp_info *)arg)->bavail =
+				le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		((struct peeknmp_info *)arg)->bremain =
+			le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		((struct peeknmp_info *)arg)->conntype =
+			le16_to_cpu(*(unsigned short *)bcc_ptr);
+		bcc_ptr += 2;
+		if (((struct peeknmp_info *)arg)->size >
+				((struct peeknmp_info *)arg)->bavail)
+			size = ((struct peeknmp_info *)arg)->bavail;
+		else
+			size = ((struct peeknmp_info *)arg)->size;
+		memcpy(((struct peeknmp_info *)arg)->buffer, bcc_ptr, size);
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto peeknmpiperetry;
+
+	return rc;
+}
+
+int
+CIFSSMBTransGetNmPHState(const int xid, struct cifsTconInfo *tcon,
+		unsigned long arg, __u16 netfid,
+		const struct nls_table *nls_codepage, int remap)
+{
+	TRANS_REQ *pSMB = NULL;
+	TRANS_RSP *pSMBr = NULL;
+	int rc = 0;
+	int name_len;
+	int pad;
+	int bytes_returned = 0;
+	__u16 offset;
+	__u16 byte_count = 0;
+	char *fileName = "\\PIPE\\";
+	char *bcc_ptr;
+	struct qnmp_hinfo qnmpipehinfo;
+
+	cFYI(1, ("In CIFSSMBTransSetNmPHandState"));
+getnmaphandstateretry:
+	rc = smb_init(SMB_COM_TRANSACTION, 16, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	offset = offsetof(TRANS_REQ, Name) - 4;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifsConvertToUCS((__le16 *) bcc_ptr, fileName,
+				     PATH_MAX, nls_codepage, remap);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(bcc_ptr, fileName, name_len);
+	}
+	byte_count += (1 + pad + name_len);
+
+	offset += name_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->ParameterCount = 0;
+	pSMB->TotalParameterCount = 0;
+	pSMB->ParameterOffset = offset;
+
+	pSMB->DataCount = 0;
+	pSMB->TotalDataCount = 0;
+	pSMB->DataOffset = offset;
+
+	pSMB->MaxParameterCount = 2;
+	pSMB->MaxDataCount = 0;
+	pSMB->MaxSetupCount = 0;
+
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+
+	pSMB->SetupCount = 2;
+	pSMB->Function = cpu_to_le16(TRANS_QUERY_NMPIPE_STATE);
+	pSMB->Fid = cpu_to_le16(netfid);
+
+	byte_count += pad;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	pSMB->hdr.smb_buf_length += byte_count;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("CIFSSMBTranGetNmPHandState returned %d", rc));
+	} else {
+		offset = le16_to_cpu(pSMBr->ParameterOffset);
+		bcc_ptr = (char *)pSMBr + offset + 4;
+		qnmpipehinfo.mode = le16_to_cpu(*(unsigned short *)bcc_ptr);
+		memcpy((char *)arg, &qnmpipehinfo, sizeof(struct qnmp_hinfo));
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto getnmaphandstateretry;
+
+	return rc;
+}
+
+int
+CIFSSMBTransNmPipe(const int xid, struct cifsTconInfo *tcon,
+		unsigned char *arg, __u16 netfid,
+		const struct nls_table *nls_codepage, int remap)
+{
+	TRANS_REQ *pSMB = NULL;
+	TRANS_RSP *pSMBr = NULL;
+	int rc = 0;
+	int name_len;
+	int pad;
+	int bytes_returned = 0;
+	__u16 offset;
+	__u16 byte_count = 0;
+	char *fileName = "\\PIPE\\";
+	char *bcc_ptr;
+
+	cFYI(1, ("In CIFSSMBTransNmPipe"));
+transnmpiperetry:
+	rc = smb_init(SMB_COM_TRANSACTION, 16, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	offset = offsetof(TRANS_REQ, Name) - 4;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifsConvertToUCS((__le16 *) bcc_ptr, fileName,
+				     PATH_MAX, nls_codepage, remap);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(bcc_ptr, fileName, name_len);
+	}
+	byte_count += (1 + pad + name_len);
+
+	offset += name_len;
+	pad = offset % 4;
+	if (pad)
+		offset += pad;
+	pSMB->ParameterOffset = offset;
+	pSMB->ParameterCount = 0;
+	pSMB->TotalParameterCount = 0;
+
+	pSMB->DataOffset = offset;
+	pSMB->DataCount = ((struct transnmp_info *)arg)->wsize;
+	pSMB->TotalDataCount = pSMB->DataCount;
+	bcc_ptr = (char *)pSMB + offset + 4;
+	memcpy(bcc_ptr, ((struct transnmp_info *)arg)->sendbuf,
+					pSMB->DataCount);
+	byte_count += (pad + pSMB->DataCount);
+
+	pSMB->MaxParameterCount = 0;
+	/* BB find max SMB PDU from sess */
+	pSMB->MaxDataCount = cpu_to_le16(4280);
+	pSMB->MaxSetupCount = 0;
+
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+
+	pSMB->SetupCount = 2;
+	pSMB->Function = cpu_to_le16(TRANS_TRANSACT_NMPIPE);
+	pSMB->Fid = cpu_to_le16(netfid);
+
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	pSMB->hdr.smb_buf_length += byte_count;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("CIFSSMBTransQNmPipe returned %d", rc));
+	} else {
+		offset = le16_to_cpu(pSMBr->DataOffset);
+		bcc_ptr = ((char *)pSMBr + offset + 4);
+		byte_count = le16_to_cpu(pSMBr->DataCount);
+		((struct transnmp_info *)arg)->rsize = byte_count;
+		memcpy(((struct transnmp_info *)arg)->recvbuf, bcc_ptr,
+				byte_count);
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto transnmpiperetry;
+
+	return rc;
+}
 #endif
--

-- 
1.5.2
Shirish Pargaonkar | 15 Oct 19:44 2009
Picon

[patch][3/3] ioctl calls for Named Pipes

ioctl calls to invoke SMBTrans functions/transactions

From ce2bf9594358470e4bcb0822b0d3777620c023f7 Mon Sep 17 00:00:00 2001
From: Shirish Pargaonkar <shirishpargaonkar <at> gmail.com>
Date: Thu, 15 Oct 2009 08:17:37 -0500
Subject: [PATCH] ioctl functions for Named Pipe support

---
 fs/cifs/ioctl.c |   74 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 70 insertions(+), 4 deletions(-)

diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index f946506..d351321 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
 <at>  <at>  -30,11 +30,46  <at>  <at> 

 #define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)

+int
+ChkNMPHmode(unsigned short smode)
+{
+	int rc = -1;
+
+	if ((smode & BYTESTREAMNMREAD) && (smode & MESSAGENMREAD)) {
+		cFYI(1, ("SetNMPHMode both bye and message read bytes set"));
+		return rc;
+	}
+	if ((smode & BLOCKINGNMPIPE) && (smode & NONBLOCKINGNMPIPE))
+		return rc;
+
+	return 0;
+}
+
+unsigned short
+SetNMPHmode(unsigned short smode, unsigned short cmode)
+{
+	unsigned short mode;
+
+	mode = cmode;
+
+	if (smode & NONBLOCKINGNMPIPE)
+		mode = mode & 0x7FFF;
+	if (smode & BLOCKINGNMPIPE)
+		mode = mode | 0x8000;
+	if (smode & BYTESTREAMNMREAD)
+		mode = mode & 0xFCFF;
+	if (smode & MESSAGENMREAD)
+		mode = mode | 0x0100;
+
+	return mode;
+}
+
 long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 {
 	struct inode *inode = filep->f_dentry->d_inode;
 	int rc = -ENOTTY; /* strange error - but the precedent */
 	int xid;
+	unsigned short cmode, smode;
 	struct cifs_sb_info *cifs_sb;
 #ifdef CONFIG_CIFS_POSIX
 	__u64	ExtAttrBits = 0;
 <at>  <at>  -60,6 +95,12  <at>  <at>  long cifs_ioctl(struct file *filep, unsigned int
command, unsigned long arg)
 		FreeXid(xid);
 		return -EIO;
 	}
+
+	if (!pSMBFile && (command != CIFS_IOC_CHECKUMOUNT)) {
+		cFYI(1, ("cifs_ioctl: NULL file pointer"));
+		FreeXid(xid);
+		return -EBADF;
+	}
 #endif /* CONFIG_CIFS_POSIX */

 	switch (command) {
 <at>  <at>  -75,8 +116,6  <at>  <at>  long cifs_ioctl(struct file *filep, unsigned int
command, unsigned long arg)
 #ifdef CONFIG_CIFS_POSIX
 		case FS_IOC_GETFLAGS:
 			if (CIFS_UNIX_EXTATTR_CAP & caps) {
-				if (pSMBFile == NULL)
-					break;
 				rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
 					&ExtAttrBits, &ExtAttrMask);
 				if (rc == 0)
 <at>  <at>  -92,14 +131,41  <at>  <at>  long cifs_ioctl(struct file *filep, unsigned int
command, unsigned long arg)
 					rc = -EFAULT;
 					break;
 				}
-				if (pSMBFile == NULL)
-					break;
 				/* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
 					extAttrBits, &ExtAttrMask);*/
 			}
 			cFYI(1, ("set flags not implemented yet"));
 			break;
 #endif /* CONFIG_CIFS_POSIX */
+		case CIFS_QUERYNMPIPE:
+			rc = CIFSSMBTransQNmPipe(xid, tcon, arg,
+				pSMBFile->netfid, cifs_sb->local_nls, 0);
+			break;
+		case CIFS_PEEKNMPIPE:
+			rc = CIFSSMBTransPeekNmPipe(xid, tcon, arg,
+				 pSMBFile->netfid, cifs_sb->local_nls, 0);
+			break;
+		case CIFS_GETNMPIPEHANDSTATE:
+			rc = CIFSSMBTransGetNmPHState(xid, tcon, arg,
+				pSMBFile->netfid, cifs_sb->local_nls, 0);
+			break;
+		case CIFS_SETNMPIPEHANDSTATE:
+			smode = ((struct qnmp_hinfo *)arg)->mode;
+			if (ChkNMPHmode(smode) == -1)
+				break;
+			rc = CIFSSMBTransGetNmPHState(xid, tcon, arg,
+				pSMBFile->netfid, cifs_sb->local_nls, 0);
+			if (rc)
+				break;
+			cmode = ((struct qnmp_hinfo *)arg)->mode;
+			((struct qnmp_hinfo *)arg)->mode =
+					SetNMPHmode(smode, cmode);
+			rc = CIFSSMBTransSetNmPHState(xid, tcon, arg,
+				pSMBFile->netfid, cifs_sb->local_nls, 0);
+			break;
+		case CIFS_TRANSACTNMPIPE:
+			rc = CIFSSMBTransNmPipe(xid, tcon, (char *)arg,
+				pSMBFile->netfid, cifs_sb->local_nls, 0);
 		default:
 			cFYI(1, ("unsupported ioctl"));
 			break;
--

-- 
1.5.2

Gmane