[RFC PATCH 0/9] sunrpc: teach the SUNRPC layer how to speak SMB

View: New views
11 Messages — Rating Filter:   Alert me  

[RFC PATCH 0/9] sunrpc: teach the SUNRPC layer how to speak SMB

by Jeff Layton-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

This patchset is still preliminary and is just an RFC...

First, some background. When I was at Connectathon this year, Trond
mentioned an interesting idea to me. He said (paraphrasing):

"Why doesn't CIFS just use the RPC layer for transport? It's very
efficient at shoveling bits out onto the wire. You'd just need to
abstract out the XDR/RPC specific bits."

The idea has been floating around in the back of my head until recently,
when I decided to give it a go. This patchset represents a first, rough
draft at a patchset to do this. There's also a proof of concept module
that demonstrates that it works as expected.

The patchset is still very rough. Reconnect behavior is still very
"RPC-ish", for instance. There are doubtless other changes that will
need to be made before I had anything merge-worthy.

At this point, I'm just interested in feedback on the general approach.
Should I continue to pursue this or is it a non-starter for some
reason?

The next step here, obviously is to start building a fs on top of it.
I'd particularly be interested in using this as a foundation of a
new smb2fs.

I've also got this patchset up on my public git tree:

    http://git.samba.org/?p=jlayton/cifs.git;a=summary

Here are some questions I anticipate on this, and their answers:

------------------------------------------------------------------------
Q: Are you insane? Why would you attempt to do this?

A: Maybe...but in the last couple of years, I've spent a substantial
amount of time working on the CIFS code. Much of that time has been
spent fixing bugs. Many of those bugs exist in the low-level transport
code which has been hacked on, kludged around and hand tweaked to
where it is today. Unfortunately that's made it a very hard to work
on mess. This drives away potential developers.

CIFS in particular is also designed around synchronous ops, which
seriously limits throughput. Retrofitting it for asynchronous operation
will be adding even more kludges. The sunrpc code is already
fundamentally asynchronous.
------------------------------------------------------------------------
Q: Okay, what's the benefit of hooking it up to sunrpc rather than
building a new transport layer (or fixing the transport in the other two
filesystems)?

A: Using sunrpc allows us to share a lot of the rpc scheduler code with
sunrpc. At a high level, NFS/RPC and SMB aren't really very different.
Sure, they have different formats, and one is big endian on the wire and
the other isn't...still there are significant similarities.

We also get access to the great upcall mechanisms that sunrpc has, and
the possibility to share code like the gssapi upcalls. The sunrpc layer
has a credential and authentication management framework that we can
build on to make a truly multiuser CIFS/SMB filesystem.

I've heard it claimed before that Linux's sunrpc layer is
over-engineered, but in this case that works in our favor...
------------------------------------------------------------------------
Q: can we hook up cifs or smbfs to use this as a transport?

A: Not trivially. CIFS in particular is not designed with each call
having discrete encode and decode functions. They're sort of mashed
together. smbfs might be possible...I'm a little less familiar with it,
but it does have a transport layer that more closely resembles the
sunrpc one. Still though, it'd take significant work to make that
happen. I'm not opposed to the idea however.

In the end though, I think we'll probably need to design something new
to sit on top of this. We will probably be able to borrow code and
concepts from the other filesystems however.
------------------------------------------------------------------------
Q: could we use this as a transport layer for a smb2fs ?

A: Yes, I think so. This particular prototype is build around SMB1, but
SMB2 could be supported with only minor modifications. One of the
reasons for sending this patchset now before I've built a filesystem on
top of it is because I know that SMB2 work is in progress. I'd like to
see it based around a more asynchronous transport model, or at least
built with cleaner layering so that we can eventually bolt on a different
transport layer if we so choose.

Jeff Layton (9):
  sunrpc: abstract out encoding function at rpc_clnt level
  sunrpc: move check for too small reply size into rpc_verify_header
  sunrpc: abstract our call decoding routine
  sunrpc: move rpc_xdr_buf_init to clnt.h
  sunrpc: make call_bind non-static
  sunrpc: add new SMB transport class for sunrpc
  sunrpc: add encoding and decoding routines for SMB
  sunrpc: add Kconfig option for CONFIG_SUNRPC_SMB
  smbtest: simple module for testing SMB/RPC code

 fs/Makefile                    |    2 +
 fs/lockd/host.c                |    4 +
 fs/lockd/mon.c                 |    4 +
 fs/nfs/client.c                |    4 +
 fs/nfs/mount_clnt.c            |    4 +
 fs/nfsd/nfs4callback.c         |    4 +
 fs/smbtest/Makefile            |    1 +
 fs/smbtest/smbtest.c           |  204 +++++
 include/linux/sunrpc/clnt.h    |   24 +-
 include/linux/sunrpc/smb.h     |   42 +
 include/linux/sunrpc/xprtsmb.h |   59 ++
 net/sunrpc/Kconfig             |   11 +
 net/sunrpc/Makefile            |    1 +
 net/sunrpc/clnt.c              |   98 ++-
 net/sunrpc/rpcb_clnt.c         |    8 +
 net/sunrpc/smb.c               |  120 +++
 net/sunrpc/sunrpc_syms.c       |    3 +
 net/sunrpc/xprtsmb.c           | 1723 ++++++++++++++++++++++++++++++++++++++++
 18 files changed, 2272 insertions(+), 44 deletions(-)
 create mode 100644 fs/smbtest/Makefile
 create mode 100644 fs/smbtest/smbtest.c
 create mode 100644 include/linux/sunrpc/smb.h
 create mode 100644 include/linux/sunrpc/xprtsmb.h
 create mode 100644 net/sunrpc/smb.c
 create mode 100644 net/sunrpc/xprtsmb.c

_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client

[RFC PATCH 1/9] sunrpc: abstract out encoding function at rpc_clnt level

by Jeff Layton-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

In order to add the ability to do an SMB call with the sunrpc layer, we
need to abstract out the call encoding. Add a function pointer that hangs
off of the rpc_clnt to do the encoding. For now, all of the existing
callers will simply set it to rpc_xdr_encode.

Signed-off-by: Jeff Layton <jlayton@...>
---
 fs/lockd/host.c             |    3 +++
 fs/lockd/mon.c              |    3 +++
 fs/nfs/client.c             |    3 +++
 fs/nfs/mount_clnt.c         |    3 +++
 fs/nfsd/nfs4callback.c      |    3 +++
 include/linux/sunrpc/clnt.h |    7 +++++++
 net/sunrpc/clnt.c           |   14 ++++++++++----
 net/sunrpc/rpcb_clnt.c      |    6 ++++++
 8 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 4600c20..b7189ce 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -362,6 +362,9 @@ nlm_bind_host(struct nlm_host *host)
  .program = &nlm_program,
  .version = host->h_version,
  .authflavor = RPC_AUTH_UNIX,
+ .encode = rpc_xdr_encode,
+ .callhdr_size = RPC_CALLHDRSIZE,
+ .replhdr_size = RPC_REPHDRSIZE,
  .flags = (RPC_CLNT_CREATE_NOPING |
    RPC_CLNT_CREATE_AUTOBIND),
  };
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index f956651..ea24301 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -75,6 +75,9 @@ static struct rpc_clnt *nsm_create(void)
  .program = &nsm_program,
  .version = NSM_VERSION,
  .authflavor = RPC_AUTH_NULL,
+ .encode = rpc_xdr_encode,
+ .callhdr_size = RPC_CALLHDRSIZE,
+ .replhdr_size = RPC_REPHDRSIZE,
  .flags = RPC_CLNT_CREATE_NOPING,
  };
 
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 63976c0..5505ddf 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -606,6 +606,9 @@ static int nfs_create_rpc_client(struct nfs_client *clp,
  .servername = clp->cl_hostname,
  .program = &nfs_program,
  .version = clp->rpc_ops->version,
+ .encode = rpc_xdr_encode,
+ .callhdr_size = RPC_CALLHDRSIZE,
+ .replhdr_size = RPC_REPHDRSIZE,
  .authflavor = flavor,
  };
 
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index 0adefc4..14f79e5 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -159,6 +159,9 @@ int nfs_mount(struct nfs_mount_request *info)
  .servername = info->hostname,
  .program = &mnt_program,
  .version = info->version,
+ .encode = rpc_xdr_encode,
+ .callhdr_size = RPC_CALLHDRSIZE,
+ .replhdr_size = RPC_REPHDRSIZE,
  .authflavor = RPC_AUTH_UNIX,
  };
  struct rpc_clnt *mnt_clnt;
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 24e8d78..dbfd91c 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -494,6 +494,9 @@ int setup_callback_client(struct nfs4_client *clp)
  .authflavor = clp->cl_flavor,
  .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
  .client_name    = clp->cl_principal,
+ .encode = rpc_xdr_encode,
+ .callhdr_size = RPC_CALLHDRSIZE,
+ .replhdr_size = RPC_REPHDRSIZE,
  };
  struct rpc_clnt *client;
 
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 8ed9642..6209c39 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -63,6 +63,9 @@ struct rpc_clnt {
  struct rpc_program * cl_program;
  char cl_inline_name[32];
  char *cl_principal; /* target to authenticate to */
+ void (*cl_encode) (struct rpc_task *task);
+ size_t cl_callhdr_sz; /* in quadwords */
+ size_t cl_replhdr_sz; /* in quadwords */
 };
 
 /*
@@ -115,6 +118,9 @@ struct rpc_create_args {
  unsigned long flags;
  char *client_name;
  struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */
+ size_t callhdr_size; /* in quadwords */
+ size_t replhdr_size; /* in quadwords */
+ void (*encode) (struct rpc_task *task);
 };
 
 /* Values for "flags" field */
@@ -150,6 +156,7 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred,
        int flags);
 void rpc_restart_call_prepare(struct rpc_task *);
 void rpc_restart_call(struct rpc_task *);
+void rpc_xdr_encode(struct rpc_task *);
 void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
 size_t rpc_max_payload(struct rpc_clnt *);
 void rpc_force_rebind(struct rpc_clnt *);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 38829e2..f675416 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -200,6 +200,10 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
  clnt->cl_vers     = version->number;
  clnt->cl_stats    = program->stats;
  clnt->cl_metrics  = rpc_alloc_iostats(clnt);
+ clnt->cl_encode   = args->encode;
+ clnt->cl_callhdr_sz = args->callhdr_size;
+ clnt->cl_replhdr_sz = args->replhdr_size;
+
  err = -ENOMEM;
  if (clnt->cl_metrics == NULL)
  goto out_no_stats;
@@ -905,6 +909,7 @@ call_allocate(struct rpc_task *task)
  unsigned int slack = task->tk_msg.rpc_cred->cr_auth->au_cslack;
  struct rpc_rqst *req = task->tk_rqstp;
  struct rpc_xprt *xprt = task->tk_xprt;
+ struct rpc_clnt *clnt = task->tk_client;
  struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
 
  dprint_status(task);
@@ -926,9 +931,9 @@ call_allocate(struct rpc_task *task)
  * and reply headers, and convert both values
  * to byte sizes.
  */
- req->rq_callsize = RPC_CALLHDRSIZE + (slack << 1) + proc->p_arglen;
+ req->rq_callsize = clnt->cl_callhdr_sz + (slack << 1) + proc->p_arglen;
  req->rq_callsize <<= 2;
- req->rq_rcvsize = RPC_REPHDRSIZE + slack + proc->p_replen;
+ req->rq_rcvsize = clnt->cl_replhdr_sz + slack + proc->p_replen;
  req->rq_rcvsize <<= 2;
 
  req->rq_buffer = xprt->ops->buf_alloc(task,
@@ -975,7 +980,7 @@ rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
 /*
  * 3. Encode arguments of an RPC call
  */
-static void
+void
 rpc_xdr_encode(struct rpc_task *task)
 {
  struct rpc_rqst *req = task->tk_rqstp;
@@ -1005,6 +1010,7 @@ rpc_xdr_encode(struct rpc_task *task)
  task->tk_status = rpcauth_wrap_req(task, encode, req, p,
  task->tk_msg.rpc_argp);
 }
+EXPORT_SYMBOL_GPL(rpc_xdr_encode);
 
 /*
  * 4. Get the server port number if not yet set
@@ -1148,7 +1154,7 @@ call_transmit(struct rpc_task *task)
  /* Encode here so that rpcsec_gss can use correct sequence number. */
  if (rpc_task_need_encode(task)) {
  BUG_ON(task->tk_rqstp->rq_bytes_sent != 0);
- rpc_xdr_encode(task);
+ task->tk_client->cl_encode(task);
  /* Did the encode result in an error condition? */
  if (task->tk_status != 0) {
  /* Was the error nonfatal? */
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 830faf4..65764ba 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -174,6 +174,9 @@ static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
  .program = &rpcb_program,
  .version = version,
  .authflavor = RPC_AUTH_UNIX,
+ .encode = rpc_xdr_encode,
+ .callhdr_size = RPC_CALLHDRSIZE,
+ .replhdr_size = RPC_REPHDRSIZE,
  .flags = RPC_CLNT_CREATE_NOPING,
  };
 
@@ -191,6 +194,9 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
  .program = &rpcb_program,
  .version = version,
  .authflavor = RPC_AUTH_UNIX,
+ .encode = rpc_xdr_encode,
+ .callhdr_size = RPC_CALLHDRSIZE,
+ .replhdr_size = RPC_REPHDRSIZE,
  .flags = (RPC_CLNT_CREATE_NOPING |
  RPC_CLNT_CREATE_NONPRIVPORT),
  };
--
1.6.0.6

_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client

[RFC PATCH 2/9] sunrpc: move check for too small reply size into rpc_verify_header

by Jeff Layton-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

...this should introduce no behavioral changes.

Signed-off-by: Jeff Layton <jlayton@...>
---
 net/sunrpc/clnt.c |   24 ++++++++++++------------
 1 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index f675416..e504b59 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -1411,18 +1411,6 @@ call_decode(struct rpc_task *task)
  WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
  sizeof(req->rq_rcv_buf)) != 0);
 
- if (req->rq_rcv_buf.len < 12) {
- if (!RPC_IS_SOFT(task)) {
- task->tk_action = call_bind;
- clnt->cl_stats->rpcretrans++;
- goto out_retry;
- }
- dprintk("RPC:       %s: too small RPC reply size (%d bytes)\n",
- clnt->cl_protname, task->tk_status);
- task->tk_action = call_timeout;
- goto out_retry;
- }
-
  p = rpc_verify_header(task);
  if (IS_ERR(p)) {
  if (p == ERR_PTR(-EAGAIN))
@@ -1518,6 +1506,18 @@ rpc_verify_header(struct rpc_task *task)
  u32 n;
  int error = -EACCES;
 
+ if (task->tk_rqstp->rq_rcv_buf.len < 12) {
+ if (!RPC_IS_SOFT(task)) {
+ task->tk_action = call_bind;
+ task->tk_client->cl_stats->rpcretrans++;
+ goto out_retry;
+ }
+ dprintk("RPC:       %s: too small RPC reply size (%d bytes)\n",
+ task->tk_client->cl_protname, task->tk_status);
+ task->tk_action = call_timeout;
+ goto out_retry;
+ }
+
  if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {
  /* RFC-1014 says that the representation of XDR data must be a
  * multiple of four bytes
--
1.6.0.6

_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client

[RFC PATCH 3/9] sunrpc: abstract our call decoding routine

by Jeff Layton-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

...all of the existing rpc users will use the new rpc_xdr_decode function.

Signed-off-by: Jeff Layton <jlayton@...>
---
 fs/lockd/host.c             |    1 +
 fs/lockd/mon.c              |    1 +
 fs/nfs/client.c             |    1 +
 fs/nfs/mount_clnt.c         |    1 +
 fs/nfsd/nfs4callback.c      |    1 +
 include/linux/sunrpc/clnt.h |    3 ++
 net/sunrpc/clnt.c           |   46 +++++++++++++++++++++++++++++-------------
 net/sunrpc/rpcb_clnt.c      |    2 +
 8 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index b7189ce..2159ee2 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -363,6 +363,7 @@ nlm_bind_host(struct nlm_host *host)
  .version = host->h_version,
  .authflavor = RPC_AUTH_UNIX,
  .encode = rpc_xdr_encode,
+ .decode = rpc_xdr_decode,
  .callhdr_size = RPC_CALLHDRSIZE,
  .replhdr_size = RPC_REPHDRSIZE,
  .flags = (RPC_CLNT_CREATE_NOPING |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index ea24301..bb4e1ad 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -76,6 +76,7 @@ static struct rpc_clnt *nsm_create(void)
  .version = NSM_VERSION,
  .authflavor = RPC_AUTH_NULL,
  .encode = rpc_xdr_encode,
+ .decode = rpc_xdr_decode,
  .callhdr_size = RPC_CALLHDRSIZE,
  .replhdr_size = RPC_REPHDRSIZE,
  .flags = RPC_CLNT_CREATE_NOPING,
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 5505ddf..5ec2a45 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -607,6 +607,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp,
  .program = &nfs_program,
  .version = clp->rpc_ops->version,
  .encode = rpc_xdr_encode,
+ .decode = rpc_xdr_decode,
  .callhdr_size = RPC_CALLHDRSIZE,
  .replhdr_size = RPC_REPHDRSIZE,
  .authflavor = flavor,
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index 14f79e5..86a3b9e 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -160,6 +160,7 @@ int nfs_mount(struct nfs_mount_request *info)
  .program = &mnt_program,
  .version = info->version,
  .encode = rpc_xdr_encode,
+ .decode = rpc_xdr_decode,
  .callhdr_size = RPC_CALLHDRSIZE,
  .replhdr_size = RPC_REPHDRSIZE,
  .authflavor = RPC_AUTH_UNIX,
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index dbfd91c..bb655a2 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -495,6 +495,7 @@ int setup_callback_client(struct nfs4_client *clp)
  .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
  .client_name    = clp->cl_principal,
  .encode = rpc_xdr_encode,
+ .decode = rpc_xdr_decode,
  .callhdr_size = RPC_CALLHDRSIZE,
  .replhdr_size = RPC_REPHDRSIZE,
  };
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 6209c39..00afedc 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -64,6 +64,7 @@ struct rpc_clnt {
  char cl_inline_name[32];
  char *cl_principal; /* target to authenticate to */
  void (*cl_encode) (struct rpc_task *task);
+ int (*cl_decode) (struct rpc_task *task);
  size_t cl_callhdr_sz; /* in quadwords */
  size_t cl_replhdr_sz; /* in quadwords */
 };
@@ -121,6 +122,7 @@ struct rpc_create_args {
  size_t callhdr_size; /* in quadwords */
  size_t replhdr_size; /* in quadwords */
  void (*encode) (struct rpc_task *task);
+ int (*decode) (struct rpc_task *task);
 };
 
 /* Values for "flags" field */
@@ -157,6 +159,7 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred,
 void rpc_restart_call_prepare(struct rpc_task *);
 void rpc_restart_call(struct rpc_task *);
 void rpc_xdr_encode(struct rpc_task *);
+int rpc_xdr_decode(struct rpc_task *);
 void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
 size_t rpc_max_payload(struct rpc_clnt *);
 void rpc_force_rebind(struct rpc_clnt *);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index e504b59..f05d289 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -201,6 +201,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
  clnt->cl_stats    = program->stats;
  clnt->cl_metrics  = rpc_alloc_iostats(clnt);
  clnt->cl_encode   = args->encode;
+ clnt->cl_decode   = args->decode;
  clnt->cl_callhdr_sz = args->callhdr_size;
  clnt->cl_replhdr_sz = args->replhdr_size;
 
@@ -1379,6 +1380,27 @@ retry:
  task->tk_status = 0;
 }
 
+int
+rpc_xdr_decode(struct rpc_task *task)
+{
+ struct rpc_rqst *req = task->tk_rqstp;
+ kxdrproc_t decode = task->tk_msg.rpc_proc->p_decode;
+ __be32 *p;
+
+ p = rpc_verify_header(task);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
+ if (decode)
+ task->tk_status = rpcauth_unwrap_resp(task, decode, req, p,
+      task->tk_msg.rpc_resp);
+
+ dprintk("RPC: %5u %s result %d\n", task->tk_pid, __func__,
+ task->tk_status);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rpc_xdr_decode);
+
 /*
  * 7. Decode the RPC reply
  */
@@ -1387,8 +1409,7 @@ call_decode(struct rpc_task *task)
 {
  struct rpc_clnt *clnt = task->tk_client;
  struct rpc_rqst *req = task->tk_rqstp;
- kxdrproc_t decode = task->tk_msg.rpc_proc->p_decode;
- __be32 *p;
+ int status;
 
  dprintk("RPC: %5u call_decode (status %d)\n",
  task->tk_pid, task->tk_status);
@@ -1411,22 +1432,19 @@ call_decode(struct rpc_task *task)
  WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
  sizeof(req->rq_rcv_buf)) != 0);
 
- p = rpc_verify_header(task);
- if (IS_ERR(p)) {
- if (p == ERR_PTR(-EAGAIN))
- goto out_retry;
+ if (!clnt->cl_decode)
+ BUG();
+
+ status = clnt->cl_decode(task);
+
+ if (status == -EAGAIN)
+ goto out_retry;
+ else if (status)
  return;
- }
 
  task->tk_action = rpc_exit_task;
-
- if (decode) {
- task->tk_status = rpcauth_unwrap_resp(task, decode, req, p,
-      task->tk_msg.rpc_resp);
- }
- dprintk("RPC: %5u call_decode result %d\n", task->tk_pid,
- task->tk_status);
  return;
+
 out_retry:
  task->tk_status = 0;
  /* Note: rpc_verify_header() may have freed the RPC slot */
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 65764ba..db053bf 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -175,6 +175,7 @@ static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
  .version = version,
  .authflavor = RPC_AUTH_UNIX,
  .encode = rpc_xdr_encode,
+ .decode = rpc_xdr_decode,
  .callhdr_size = RPC_CALLHDRSIZE,
  .replhdr_size = RPC_REPHDRSIZE,
  .flags = RPC_CLNT_CREATE_NOPING,
@@ -195,6 +196,7 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
  .version = version,
  .authflavor = RPC_AUTH_UNIX,
  .encode = rpc_xdr_encode,
+ .decode = rpc_xdr_decode,
  .callhdr_size = RPC_CALLHDRSIZE,
  .replhdr_size = RPC_REPHDRSIZE,
  .flags = (RPC_CLNT_CREATE_NOPING |
--
1.6.0.6

_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client

[RFC PATCH 4/9] sunrpc: move rpc_xdr_buf_init to clnt.h

by Jeff Layton-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

...so that it can be used elsewhere.

Signed-off-by: Jeff Layton <jlayton@...>
---
 include/linux/sunrpc/clnt.h |   13 ++++++++++++-
 net/sunrpc/clnt.c           |   12 ------------
 2 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 00afedc..307a3ec 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -165,7 +165,6 @@ size_t rpc_max_payload(struct rpc_clnt *);
 void rpc_force_rebind(struct rpc_clnt *);
 size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
 const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
-
 size_t rpc_ntop(const struct sockaddr *, char *, const size_t);
 size_t rpc_pton(const char *, const size_t,
  struct sockaddr *, const size_t);
@@ -197,6 +196,18 @@ static inline void rpc_set_port(struct sockaddr *sap,
  }
 }
 
+static inline void
+rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
+{
+ buf->head[0].iov_base = start;
+ buf->head[0].iov_len = len;
+ buf->tail[0].iov_len = 0;
+ buf->page_len = 0;
+ buf->flags = 0;
+ buf->len = 0;
+ buf->buflen = len;
+}
+
 #define IPV6_SCOPE_DELIMITER '%'
 #define IPV6_SCOPE_ID_LEN sizeof("%nnnnnnnnnn")
 
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index f05d289..42688af 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -966,18 +966,6 @@ rpc_task_force_reencode(struct rpc_task *task)
  task->tk_rqstp->rq_bytes_sent = 0;
 }
 
-static inline void
-rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
-{
- buf->head[0].iov_base = start;
- buf->head[0].iov_len = len;
- buf->tail[0].iov_len = 0;
- buf->page_len = 0;
- buf->flags = 0;
- buf->len = 0;
- buf->buflen = len;
-}
-
 /*
  * 3. Encode arguments of an RPC call
  */
--
1.6.0.6

_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client

[RFC PATCH 5/9] sunrpc: make call_bind non-static

by Jeff Layton-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

...is there a better way to do this?

Signed-off-by: Jeff Layton <jlayton@...>
---
 include/linux/sunrpc/clnt.h |    1 +
 net/sunrpc/clnt.c           |    4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 307a3ec..92ff85d 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -171,6 +171,7 @@ size_t rpc_pton(const char *, const size_t,
 char * rpc_sockaddr2uaddr(const struct sockaddr *);
 size_t rpc_uaddr2sockaddr(const char *, const size_t,
    struct sockaddr *, const size_t);
+void call_bind(struct rpc_task *task);
 
 static inline unsigned short rpc_get_port(const struct sockaddr *sap)
 {
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 42688af..f2b0815 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -63,7 +63,6 @@ static void call_reserve(struct rpc_task *task);
 static void call_reserveresult(struct rpc_task *task);
 static void call_allocate(struct rpc_task *task);
 static void call_decode(struct rpc_task *task);
-static void call_bind(struct rpc_task *task);
 static void call_bind_status(struct rpc_task *task);
 static void call_transmit(struct rpc_task *task);
 #if defined(CONFIG_NFS_V4_1)
@@ -1004,7 +1003,7 @@ EXPORT_SYMBOL_GPL(rpc_xdr_encode);
 /*
  * 4. Get the server port number if not yet set
  */
-static void
+void
 call_bind(struct rpc_task *task)
 {
  struct rpc_xprt *xprt = task->tk_xprt;
@@ -1018,6 +1017,7 @@ call_bind(struct rpc_task *task)
  xprt->ops->rpcbind(task);
  }
 }
+EXPORT_SYMBOL_GPL(call_bind);
 
 /*
  * 4a. Sort out bind result
--
1.6.0.6

_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client

[RFC PATCH 7/9] sunrpc: add encoding and decoding routines for SMB

by Jeff Layton-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Add a new smb.c file to hold encode and decode routines for SMB packets.

Signed-off-by: Jeff Layton <jlayton@...>
---
 include/linux/sunrpc/smb.h     |   42 ++++++++++++++
 include/linux/sunrpc/xprtsmb.h |    6 +-
 net/sunrpc/smb.c               |  120 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 165 insertions(+), 3 deletions(-)
 create mode 100644 include/linux/sunrpc/smb.h
 create mode 100644 net/sunrpc/smb.c

diff --git a/include/linux/sunrpc/smb.h b/include/linux/sunrpc/smb.h
new file mode 100644
index 0000000..304ab8c
--- /dev/null
+++ b/include/linux/sunrpc/smb.h
@@ -0,0 +1,42 @@
+/*
+ *   net/sunrpc/smb.h -- SMB transport for sunrpc
+ *
+ *   Copyright (c) 2009 Red Hat, Inc.
+ *   Author(s): Jeff Layton (jlayton@...)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * xprtsmb.h
+ *
+ * This file contains the public interfaces for the SMB transport for
+ * the sunrpc layer.
+ */
+
+#ifndef _LINUX_SUNRPC_SMB_H
+#define _LINUX_SUNRPC_SMB_H
+
+/*
+ * This is the generic SMB function. rqstp is either a rpc_rqst (client
+ * side) or svc_rqst pointer (server side).
+ * Encode functions always assume there's enough room in the buffer.
+ */
+typedef int     (*ksmbproc_t)(void *rqstp, __le32 *data, void *obj);
+
+void smb_encode(struct rpc_task *task);
+int smb_decode(struct rpc_task *task);
+
+#endif /* _LINUX_SUNRPC_SMB_H */
diff --git a/include/linux/sunrpc/xprtsmb.h b/include/linux/sunrpc/xprtsmb.h
index d55e85b..731cce2 100644
--- a/include/linux/sunrpc/xprtsmb.h
+++ b/include/linux/sunrpc/xprtsmb.h
@@ -34,9 +34,6 @@
  */
 #define XPRT_TRANSPORT_SMB 1024
 
-int init_smb_xprt(void);
-void cleanup_smb_xprt(void);
-
 /* standard SMB header */
 struct smb_header {
  __u8 protocol[4];
@@ -56,4 +53,7 @@ struct smb_header {
 /* SMB Header Flags of interest */
 #define SMBFLG_RESPONSE 0x80 /* response from server */
 
+int init_smb_xprt(void);
+void cleanup_smb_xprt(void);
+
 #endif /* _LINUX_SUNRPC_XPRTSMB_H */
diff --git a/net/sunrpc/smb.c b/net/sunrpc/smb.c
new file mode 100644
index 0000000..5511bb2
--- /dev/null
+++ b/net/sunrpc/smb.c
@@ -0,0 +1,120 @@
+/*
+ * net/sunrpc/smb.c -- smb encode and decode routines
+ *
+ * Copyright (C) 2009 Red Hat, Inc -- Jeff Layton <jlayton@...>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprtsmb.h>
+#include <linux/sunrpc/smb.h>
+#include <linux/smbno.h>
+
+static __le32 *
+smb_verify_header(struct rpc_task *task)
+{
+ struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
+ __le32 *p = iov->iov_base;
+
+ if (task->tk_rqstp->rq_rcv_buf.len < sizeof(struct smb_header)) {
+ task->tk_action = call_bind;
+ task->tk_client->cl_stats->rpcretrans++;
+ return ERR_PTR(-EAGAIN);
+ }
+
+ /* FIXME: check for errors and return them */
+
+ /*
+ * with SMB, we occasionally need to refer back to the SMB header for
+ * info (flags, etc). The header is fixed-length however, so just
+ * return a pointer to the start of the SMB header.
+ */
+ return p;
+}
+
+static __le32 *
+smb_encode_header(struct rpc_task *task)
+{
+ struct rpc_rqst *req = task->tk_rqstp;
+ u32 *p =  (u32 *) req->rq_svec[0].iov_base;
+ struct smb_header *h;
+
+ /* transport header is always 32 bits */
+ ++p;
+ memset(p, 0, sizeof(*h));
+
+ h = (struct smb_header *) p;
+
+ h->protocol[0] = 0xFF;
+ h->protocol[1] = 'S';
+ h->protocol[2] = 'M';
+ h->protocol[3] = 'B';
+
+ h->command = task->tk_msg.rpc_proc->p_proc;
+ h->flags2 = SMB_FLAGS2_LONG_PATH_COMPONENTS;
+ h->pid = cpu_to_le16((u16) current->tgid);
+ h->pidhigh = cpu_to_le16((u16) (current->tgid >> 16));
+
+ /*
+ * SMB MID's are similar to XID's in RPC, but they're only 16 bits.
+ * For now we just use the xid field and mask off the upper bits.
+ */
+ req->rq_xid &= 0x0000ffff;
+ h->mid = cpu_to_le16((u16) req->rq_xid);
+
+ req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], (__be32 *) (h + 1));
+
+ return (__le32 *) (h + 1);
+}
+
+void
+smb_encode(struct rpc_task *task)
+{
+ struct rpc_rqst *req = task->tk_rqstp;
+ __le32 *p;
+ ksmbproc_t encode = (ksmbproc_t) task->tk_msg.rpc_proc->p_encode;
+
+ rpc_xdr_buf_init(&req->rq_snd_buf, req->rq_buffer, req->rq_callsize);
+ rpc_xdr_buf_init(&req->rq_rcv_buf,
+ (char *)req->rq_buffer + req->rq_callsize,
+ req->rq_rcvsize);
+
+ p = smb_encode_header(task);
+
+ encode(req, p, NULL);
+ return;
+}
+EXPORT_SYMBOL_GPL(smb_encode);
+
+int
+smb_decode(struct rpc_task *task)
+{
+ struct rpc_rqst *req = task->tk_rqstp;
+ kxdrproc_t decode = task->tk_msg.rpc_proc->p_decode;
+ __le32 *p;
+
+ p = smb_verify_header(task);
+ if (IS_ERR(p))
+ return  PTR_ERR(p);
+
+ if (decode)
+ task->tk_status = decode(req, p, task->tk_msg.rpc_resp);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(smb_decode);
--
1.6.0.6

_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client

[RFC PATCH 8/9] sunrpc: add Kconfig option for CONFIG_SUNRPC_SMB

by Jeff Layton-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

...and the necessary Makefile bits so to compile support into the sunrpc
module.

Signed-off-by: Jeff Layton <jlayton@...>
---
 net/sunrpc/Kconfig       |   11 +++++++++++
 net/sunrpc/Makefile      |    1 +
 net/sunrpc/sunrpc_syms.c |    3 +++
 net/sunrpc/xprtsmb.c     |    7 +++++--
 4 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig
index 443c161..63f5ee7 100644
--- a/net/sunrpc/Kconfig
+++ b/net/sunrpc/Kconfig
@@ -54,3 +54,14 @@ config RPCSEC_GSS_SPKM3
   available from http://linux-nfs.org/.
 
   If unsure, say N.
+
+config SUNRPC_SMB
+ bool "SMB/CIFS Transport for the SUNRPC Layer (EXPERIMENTAL)"
+ depends on SUNRPC && EXPERIMENTAL
+ help
+    This option adds the ability for the kernels SUNRPC Layer to
+    send and receive Sever Message Block (SMB) traffic. This
+    protocol is widely used by Microsoft Windows servers for
+    filesharing.
+
+    If unsure, say N.
diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile
index 9d2fca5..691e62f 100644
--- a/net/sunrpc/Makefile
+++ b/net/sunrpc/Makefile
@@ -16,3 +16,4 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
 sunrpc-$(CONFIG_NFS_V4_1) += backchannel_rqst.o bc_svc.o
 sunrpc-$(CONFIG_PROC_FS) += stats.o
 sunrpc-$(CONFIG_SYSCTL) += sysctl.o
+sunrpc-$(CONFIG_SUNRPC_SMB) += xprtsmb.o smb.o
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 8cce921..65b4dec 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -21,6 +21,7 @@
 #include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/xprtsock.h>
+#include <linux/sunrpc/xprtsmb.h>
 
 extern struct cache_detail ip_map_cache, unix_gid_cache;
 
@@ -45,6 +46,7 @@ init_sunrpc(void)
  cache_register(&unix_gid_cache);
  svc_init_xprt_sock(); /* svc sock transport */
  init_socket_xprt(); /* clnt sock transport */
+ init_smb_xprt();
  rpcauth_init_module();
 out:
  return err;
@@ -54,6 +56,7 @@ static void __exit
 cleanup_sunrpc(void)
 {
  rpcauth_remove_module();
+ cleanup_smb_xprt();
  cleanup_socket_xprt();
  svc_cleanup_xprt_sock();
  unregister_rpc_pipefs();
diff --git a/net/sunrpc/xprtsmb.c b/net/sunrpc/xprtsmb.c
index 585cf37..362600a 100644
--- a/net/sunrpc/xprtsmb.c
+++ b/net/sunrpc/xprtsmb.c
@@ -1691,7 +1691,8 @@ static struct xprt_class xs_smb_transport = {
  * init_socket_xprt - set up xprtsock's sysctls, register with RPC client
  *
  */
-int init_smb_xprt(void)
+int
+init_smb_xprt(void)
 {
 #ifdef RPC_DEBUG
  if (!sunrpc_table_header)
@@ -1707,7 +1708,8 @@ int init_smb_xprt(void)
  * cleanup_socket_xprt - remove xprtsock's sysctls, unregister
  *
  */
-void cleanup_smb_xprt(void)
+void
+cleanup_smb_xprt(void)
 {
 #ifdef RPC_DEBUG
  if (sunrpc_table_header) {
@@ -1718,3 +1720,4 @@ void cleanup_smb_xprt(void)
 
  xprt_unregister_transport(&xs_smb_transport);
 }
+
--
1.6.0.6

_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client

[RFC PATCH 9/9] smbtest: simple module for testing SMB/RPC code

by Jeff Layton-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Proof of concept module. This just sends a NEGOTIATE_PROTOCOL request to
a server and verifies the response.

Signed-off-by: Jeff Layton <jlayton@...>
---
 fs/Makefile          |    2 +
 fs/smbtest/Makefile  |    1 +
 fs/smbtest/smbtest.c |  204 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 207 insertions(+), 0 deletions(-)
 create mode 100644 fs/smbtest/Makefile
 create mode 100644 fs/smbtest/smbtest.c

diff --git a/fs/Makefile b/fs/Makefile
index af6d047..0e9d1df 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -124,3 +124,5 @@ obj-$(CONFIG_OCFS2_FS) += ocfs2/
 obj-$(CONFIG_BTRFS_FS) += btrfs/
 obj-$(CONFIG_GFS2_FS)           += gfs2/
 obj-$(CONFIG_EXOFS_FS)          += exofs/
+
+obj-m += smbtest/
diff --git a/fs/smbtest/Makefile b/fs/smbtest/Makefile
new file mode 100644
index 0000000..d861f82
--- /dev/null
+++ b/fs/smbtest/Makefile
@@ -0,0 +1 @@
+obj-m += smbtest.o
diff --git a/fs/smbtest/smbtest.c b/fs/smbtest/smbtest.c
new file mode 100644
index 0000000..cfcb672
--- /dev/null
+++ b/fs/smbtest/smbtest.c
@@ -0,0 +1,204 @@
+/*
+ * fs/smbtest/smbtest.c -- proof of concept test for SMB code in sunrpc
+ *
+ * Copyright (C) 2009 Red Hat, Inc -- Jeff Layton <jlayton@...>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/inet.h>
+#include <linux/sched.h>
+#include <linux/smbno.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprt.h>
+#include <linux/sunrpc/xprtsmb.h>
+#include <linux/sunrpc/smb.h>
+
+#define CIFS_NEGOTIATE 0
+#define SMB_COM_NEGOTIATE 0x72
+
+static char server_address[INET6_ADDRSTRLEN];
+module_param_string(server_address, server_address, INET6_ADDRSTRLEN, 0);
+MODULE_PARM_DESC(server_address, "IPv4 address of server");
+
+typedef struct negotiate_req {
+        __u8 WordCount;
+        __le16 ByteCount;
+        unsigned char DialectsArray[1];
+} __attribute__((packed)) NEGOTIATE_REQ;
+
+typedef struct negotiate_rsp {
+        __u8 WordCount;
+        __le16 DialectIndex; /* 0xFFFF = no dialect acceptable */
+        __u8 SecurityMode;
+        __le16 MaxMpxCount;
+        __le16 MaxNumberVcs;
+        __le32 MaxBufferSize;
+        __le32 MaxRawSize;
+        __le32 SessionKey;
+        __le32 Capabilities;    /* see below */
+        __le32 SystemTimeLow;
+        __le32 SystemTimeHigh;
+        __le16 ServerTimeZone;
+        __u8 EncryptionKeyLength;
+        __u16 ByteCount;
+        union {
+                unsigned char EncryptionKey[1]; /* cap extended security off */
+                /* followed by Domain name - if extended security is off */
+                /* followed by 16 bytes of server GUID */
+                /* then security blob if cap_extended_security negotiated */
+                struct {
+                        unsigned char GUID[16];
+                        unsigned char SecurityBlob[1];
+                } __attribute__((packed)) extended_response;
+        } __attribute__((packed)) u;
+} __attribute__((packed)) NEGOTIATE_RSP;
+
+/*
+ * SMB doesn't mandate that buffers are always quadword aligned. XDR/RPC
+ * does however and that concept is pretty pervasive in the sunrpc code.
+ * Eventually, it might be better to specify sizes in bytes, but it doesn't
+ * really matter much.
+ */
+#define SMB_HDR_QUADS XDR_QUADLEN(sizeof(struct smb_header))
+
+static int
+smb_enc_negotiate(struct rpc_rqst *req, NEGOTIATE_REQ *buf, void *obj)
+{
+ char *dialects = buf->DialectsArray;
+
+ buf->WordCount = 0;
+ buf->ByteCount = 12;
+
+ dialects[0] = 0x02; /* buffer format byte */
+ strncpy(&dialects[1], "NT LM 0.12", 1000);
+
+ req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0],
+ (__be32 *) &dialects[12]);
+
+ return 0;
+}
+
+static int
+smb_dec_negotiate(void *rqstp, char *data, void *obj)
+{
+ NEGOTIATE_RSP *buf = (NEGOTIATE_RSP *) (data + sizeof(struct smb_header));
+
+ printk("smbtest: Server wants dialect index %u\n",
+ le16_to_cpu(buf->DialectIndex));
+ return 0;
+}
+
+static struct rpc_procinfo smbtest_procedures[] = {
+[CIFS_NEGOTIATE] = {
+ .p_proc = SMB_COM_NEGOTIATE,
+ .p_encode = (kxdrproc_t) smb_enc_negotiate,
+ .p_decode = (kxdrproc_t) smb_dec_negotiate,
+ .p_arglen = XDR_QUADLEN(sizeof(NEGOTIATE_REQ) + 1024),
+ .p_replen = XDR_QUADLEN(sizeof(NEGOTIATE_RSP) + 1024),
+ .p_timer = 0,
+ .p_statidx = CIFS_NEGOTIATE,
+ .p_name = "NEGOTIATE",
+ },
+};
+
+static struct rpc_version smbtest_version1 = {
+ .number = 1,
+ .nrprocs = ARRAY_SIZE(smbtest_procedures),
+ .procs = smbtest_procedures,
+};
+
+static struct rpc_version * smbtest_version[] = {
+ [1] = &smbtest_version1,
+};
+
+static struct rpc_stat smbtest_stats;
+
+static struct rpc_program cifs_rpc_prog = {
+ .name = "smbtest",
+ .number = 0,
+ .nrvers = ARRAY_SIZE(smbtest_version),
+ .version = smbtest_version,
+ .stats = &smbtest_stats,
+};
+
+static struct rpc_clnt *smbtest_clnt;
+
+static int smbtest_init(void)
+{
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ .sin_port = htons(445),
+ };
+ u8 *addr = (u8 *) &sin.sin_addr.s_addr;
+ int status;
+ struct rpc_create_args create_args = {
+ .protocol = XPRT_TRANSPORT_SMB,
+ .address = (struct sockaddr *) &sin,
+ .addrsize = sizeof(sin),
+ .servername = "cifs",
+ .program = &cifs_rpc_prog,
+ .version = 1,
+ .authflavor = RPC_AUTH_NULL,
+ .encode = smb_encode,
+ .decode = smb_decode,
+ .callhdr_size = SMB_HDR_QUADS,
+ .replhdr_size = SMB_HDR_QUADS,
+ .flags = RPC_CLNT_CREATE_NOPING |
+  RPC_CLNT_CREATE_NONPRIVPORT,
+ };
+
+ NEGOTIATE_REQ req = { };
+ NEGOTIATE_RSP rsp = { };
+
+ struct rpc_message msg = {
+ .rpc_argp = &req,
+ .rpc_resp = &rsp,
+ };
+
+ if (!in4_pton(server_address, -1, addr, '\0', NULL)) {
+ printk("smbtest: in4_pton failed\n");
+ return -EINVAL;
+ }
+
+ smbtest_clnt = rpc_create(&create_args);
+ if (IS_ERR(smbtest_clnt)) {
+ printk("smbtest: rpc client creation failed\n");
+ return PTR_ERR(smbtest_clnt);
+ }
+ printk("smbtest: rpc client create succeeded\n");
+
+ msg.rpc_proc = &smbtest_clnt->cl_procinfo[CIFS_NEGOTIATE];
+ status = rpc_call_sync(smbtest_clnt, &msg, 0);
+ printk("smbtest: rpc_call_sync returned %d\n", status);
+
+ return status;
+}
+
+static void smbtest_exit(void)
+{
+ printk("%s\n", __func__);
+ rpc_shutdown_client(smbtest_clnt);
+}
+
+module_init(smbtest_init);
+module_exit(smbtest_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jeff Layton <jlayton@...>");
--
1.6.0.6

_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client

Re: [RFC PATCH 0/9] sunrpc: teach the SUNRPC layer how to speak SMB

by Shirish Pargaonkar :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



On Sun, Sep 27, 2009 at 11:50 AM, Jeff Layton <jlayton@...> wrote:
This patchset is still preliminary and is just an RFC...

First, some background. When I was at Connectathon this year, Trond
mentioned an interesting idea to me. He said (paraphrasing):

"Why doesn't CIFS just use the RPC layer for transport? It's very
efficient at shoveling bits out onto the wire. You'd just need to
abstract out the XDR/RPC specific bits."

The idea has been floating around in the back of my head until recently,
when I decided to give it a go. This patchset represents a first, rough
draft at a patchset to do this. There's also a proof of concept module
that demonstrates that it works as expected.

The patchset is still very rough. Reconnect behavior is still very
"RPC-ish", for instance. There are doubtless other changes that will
need to be made before I had anything merge-worthy.

At this point, I'm just interested in feedback on the general approach.
Should I continue to pursue this or is it a non-starter for some
reason?

The next step here, obviously is to start building a fs on top of it.
I'd particularly be interested in using this as a foundation of a
new smb2fs.

I've also got this patchset up on my public git tree:

   http://git.samba.org/?p=jlayton/cifs.git;a=summary

Here are some questions I anticipate on this, and their answers:

------------------------------------------------------------------------
Q: Are you insane? Why would you attempt to do this?

A: Maybe...but in the last couple of years, I've spent a substantial
amount of time working on the CIFS code. Much of that time has been
spent fixing bugs. Many of those bugs exist in the low-level transport
code which has been hacked on, kludged around and hand tweaked to
where it is today. Unfortunately that's made it a very hard to work
on mess. This drives away potential developers.

CIFS in particular is also designed around synchronous ops, which
seriously limits throughput. Retrofitting it for asynchronous operation
will be adding even more kludges. The sunrpc code is already
fundamentally asynchronous.
------------------------------------------------------------------------
Q: Okay, what's the benefit of hooking it up to sunrpc rather than
building a new transport layer (or fixing the transport in the other two
filesystems)?

A: Using sunrpc allows us to share a lot of the rpc scheduler code with
sunrpc. At a high level, NFS/RPC and SMB aren't really very different.
Sure, they have different formats, and one is big endian on the wire and
the other isn't...still there are significant similarities.

We also get access to the great upcall mechanisms that sunrpc has, and
the possibility to share code like the gssapi upcalls. The sunrpc layer
has a credential and authentication management framework that we can
build on to make a truly multiuser CIFS/SMB filesystem.

I've heard it claimed before that Linux's sunrpc layer is
over-engineered, but in this case that works in our favor...
------------------------------------------------------------------------
Q: can we hook up cifs or smbfs to use this as a transport?

A: Not trivially. CIFS in particular is not designed with each call
having discrete encode and decode functions. They're sort of mashed
together. smbfs might be possible...I'm a little less familiar with it,
but it does have a transport layer that more closely resembles the
sunrpc one. Still though, it'd take significant work to make that
happen. I'm not opposed to the idea however.

In the end though, I think we'll probably need to design something new
to sit on top of this. We will probably be able to borrow code and
concepts from the other filesystems however.
------------------------------------------------------------------------
Q: could we use this as a transport layer for a smb2fs ?

A: Yes, I think so. This particular prototype is build around SMB1, but
SMB2 could be supported with only minor modifications. One of the
reasons for sending this patchset now before I've built a filesystem on
top of it is because I know that SMB2 work is in progress. I'd like to
see it based around a more asynchronous transport model, or at least
built with cleaner layering so that we can eventually bolt on a different
transport layer if we so choose.

Jeff Layton (9):
 sunrpc: abstract out encoding function at rpc_clnt level
 sunrpc: move check for too small reply size into rpc_verify_header
 sunrpc: abstract our call decoding routine
 sunrpc: move rpc_xdr_buf_init to clnt.h
 sunrpc: make call_bind non-static
 sunrpc: add new SMB transport class for sunrpc
 sunrpc: add encoding and decoding routines for SMB
 sunrpc: add Kconfig option for CONFIG_SUNRPC_SMB
 smbtest: simple module for testing SMB/RPC code

 fs/Makefile                    |    2 +
 fs/lockd/host.c                |    4 +
 fs/lockd/mon.c                 |    4 +
 fs/nfs/client.c                |    4 +
 fs/nfs/mount_clnt.c            |    4 +
 fs/nfsd/nfs4callback.c         |    4 +
 fs/smbtest/Makefile            |    1 +
 fs/smbtest/smbtest.c           |  204 +++++
 include/linux/sunrpc/clnt.h    |   24 +-
 include/linux/sunrpc/smb.h     |   42 +
 include/linux/sunrpc/xprtsmb.h |   59 ++
 net/sunrpc/Kconfig             |   11 +
 net/sunrpc/Makefile            |    1 +
 net/sunrpc/clnt.c              |   98 ++-
 net/sunrpc/rpcb_clnt.c         |    8 +
 net/sunrpc/smb.c               |  120 +++
 net/sunrpc/sunrpc_syms.c       |    3 +
 net/sunrpc/xprtsmb.c           | 1723 ++++++++++++++++++++++++++++++++++++++++
 18 files changed, 2272 insertions(+), 44 deletions(-)
 create mode 100644 fs/smbtest/Makefile
 create mode 100644 fs/smbtest/smbtest.c
 create mode 100644 include/linux/sunrpc/smb.h
 create mode 100644 include/linux/sunrpc/xprtsmb.h
 create mode 100644 net/sunrpc/smb.c
 create mode 100644 net/sunrpc/xprtsmb.c

_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client
 
 
Jeff,
 
So servers need to speak SUNRPC as well right?
Are_threre/how_many servers are out there that speak CIFS/SMB over SUNRPC or SMB2 over SUNRPC?
 

 

_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client

Re: [RFC PATCH 0/9] sunrpc: teach the SUNRPC layer how to speak SMB

by Jeff Layton-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sun, 27 Sep 2009 21:21:40 -0500
Shirish Pargaonkar <shirishpargaonkar@...> wrote:

> On Sun, Sep 27, 2009 at 11:50 AM, Jeff Layton <jlayton@...> wrote:
>
> > This patchset is still preliminary and is just an RFC...
> >
> > First, some background. When I was at Connectathon this year, Trond
> > mentioned an interesting idea to me. He said (paraphrasing):
> >
> > "Why doesn't CIFS just use the RPC layer for transport? It's very
> > efficient at shoveling bits out onto the wire. You'd just need to
> > abstract out the XDR/RPC specific bits."
> >
> > The idea has been floating around in the back of my head until recently,
> > when I decided to give it a go. This patchset represents a first, rough
> > draft at a patchset to do this. There's also a proof of concept module
> > that demonstrates that it works as expected.
> >
> > The patchset is still very rough. Reconnect behavior is still very
> > "RPC-ish", for instance. There are doubtless other changes that will
> > need to be made before I had anything merge-worthy.
> >
> > At this point, I'm just interested in feedback on the general approach.
> > Should I continue to pursue this or is it a non-starter for some
> > reason?
> >
> > The next step here, obviously is to start building a fs on top of it.
> > I'd particularly be interested in using this as a foundation of a
> > new smb2fs.
> >
> > I've also got this patchset up on my public git tree:
> >
> >    http://git.samba.org/?p=jlayton/cifs.git;a=summary
> >
> > Here are some questions I anticipate on this, and their answers:
> >
> > ------------------------------------------------------------------------
> > Q: Are you insane? Why would you attempt to do this?
> >
> > A: Maybe...but in the last couple of years, I've spent a substantial
> > amount of time working on the CIFS code. Much of that time has been
> > spent fixing bugs. Many of those bugs exist in the low-level transport
> > code which has been hacked on, kludged around and hand tweaked to
> > where it is today. Unfortunately that's made it a very hard to work
> > on mess. This drives away potential developers.
> >
> > CIFS in particular is also designed around synchronous ops, which
> > seriously limits throughput. Retrofitting it for asynchronous operation
> > will be adding even more kludges. The sunrpc code is already
> > fundamentally asynchronous.
> > ------------------------------------------------------------------------
> > Q: Okay, what's the benefit of hooking it up to sunrpc rather than
> > building a new transport layer (or fixing the transport in the other two
> > filesystems)?
> >
> > A: Using sunrpc allows us to share a lot of the rpc scheduler code with
> > sunrpc. At a high level, NFS/RPC and SMB aren't really very different.
> > Sure, they have different formats, and one is big endian on the wire and
> > the other isn't...still there are significant similarities.
> >
> > We also get access to the great upcall mechanisms that sunrpc has, and
> > the possibility to share code like the gssapi upcalls. The sunrpc layer
> > has a credential and authentication management framework that we can
> > build on to make a truly multiuser CIFS/SMB filesystem.
> >
> > I've heard it claimed before that Linux's sunrpc layer is
> > over-engineered, but in this case that works in our favor...
> > ------------------------------------------------------------------------
> > Q: can we hook up cifs or smbfs to use this as a transport?
> >
> > A: Not trivially. CIFS in particular is not designed with each call
> > having discrete encode and decode functions. They're sort of mashed
> > together. smbfs might be possible...I'm a little less familiar with it,
> > but it does have a transport layer that more closely resembles the
> > sunrpc one. Still though, it'd take significant work to make that
> > happen. I'm not opposed to the idea however.
> >
> > In the end though, I think we'll probably need to design something new
> > to sit on top of this. We will probably be able to borrow code and
> > concepts from the other filesystems however.
> > ------------------------------------------------------------------------
> > Q: could we use this as a transport layer for a smb2fs ?
> >
> > A: Yes, I think so. This particular prototype is build around SMB1, but
> > SMB2 could be supported with only minor modifications. One of the
> > reasons for sending this patchset now before I've built a filesystem on
> > top of it is because I know that SMB2 work is in progress. I'd like to
> > see it based around a more asynchronous transport model, or at least
> > built with cleaner layering so that we can eventually bolt on a different
> > transport layer if we so choose.
> >
> > Jeff Layton (9):
> >  sunrpc: abstract out encoding function at rpc_clnt level
> >  sunrpc: move check for too small reply size into rpc_verify_header
> >  sunrpc: abstract our call decoding routine
> >  sunrpc: move rpc_xdr_buf_init to clnt.h
> >  sunrpc: make call_bind non-static
> >  sunrpc: add new SMB transport class for sunrpc
> >  sunrpc: add encoding and decoding routines for SMB
> >  sunrpc: add Kconfig option for CONFIG_SUNRPC_SMB
> >  smbtest: simple module for testing SMB/RPC code
> >
> >  fs/Makefile                    |    2 +
> >  fs/lockd/host.c                |    4 +
> >  fs/lockd/mon.c                 |    4 +
> >  fs/nfs/client.c                |    4 +
> >  fs/nfs/mount_clnt.c            |    4 +
> >  fs/nfsd/nfs4callback.c         |    4 +
> >  fs/smbtest/Makefile            |    1 +
> >  fs/smbtest/smbtest.c           |  204 +++++
> >  include/linux/sunrpc/clnt.h    |   24 +-
> >  include/linux/sunrpc/smb.h     |   42 +
> >  include/linux/sunrpc/xprtsmb.h |   59 ++
> >  net/sunrpc/Kconfig             |   11 +
> >  net/sunrpc/Makefile            |    1 +
> >  net/sunrpc/clnt.c              |   98 ++-
> >  net/sunrpc/rpcb_clnt.c         |    8 +
> >  net/sunrpc/smb.c               |  120 +++
> >  net/sunrpc/sunrpc_syms.c       |    3 +
> >  net/sunrpc/xprtsmb.c           | 1723
> > ++++++++++++++++++++++++++++++++++++++++
> >  18 files changed, 2272 insertions(+), 44 deletions(-)
> >  create mode 100644 fs/smbtest/Makefile
> >  create mode 100644 fs/smbtest/smbtest.c
> >  create mode 100644 include/linux/sunrpc/smb.h
> >  create mode 100644 include/linux/sunrpc/xprtsmb.h
> >  create mode 100644 net/sunrpc/smb.c
> >  create mode 100644 net/sunrpc/xprtsmb.c
> >
> > _______________________________________________
> > linux-cifs-client mailing list
> > linux-cifs-client@...
> > https://lists.samba.org/mailman/listinfo/linux-cifs-client
> >
>
>
> Jeff,
>
> So servers need to speak SUNRPC as well right?
> Are_threre/how_many servers are out there that speak CIFS/SMB over SUNRPC or
> SMB2 over SUNRPC?

No...sorry if that wasn't clear. The on the wire protocol is still the
same as cifs or smbfs talks. You could use this to talk to windows
servers for instance. The idea is to use the existing code in the Linux
kernel's sunrpc engine and teach it how to speak a new "dialect" on the
wire...the SMB or SMB2 protocol.

For example, to test this, I sent a NegotiateProtocol request to a
samba server over its normal port 445. No ONC-RPC required.

--
Jeff Layton <jlayton@...>
_______________________________________________
linux-cifs-client mailing list
linux-cifs-client@...
https://lists.samba.org/mailman/listinfo/linux-cifs-client