[RFC 36/85] nfs41: create_session operation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Andy Adamson <andros@xxxxxxxxxx>

Implement the create_session operation conforming to
http://tools.ietf.org/html/draft-ietf-nfsv4-minorversion1-26

Signed-off-by: Ricardo Labiaga <ricardo.labiaga@xxxxxxxxxx>
Signed-off-by: Andy Adamson<andros@xxxxxxxxx>
Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx>
---
 fs/nfs/nfs4proc.c       |  141 ++++++++++++++++++++++++++++++++++-
 fs/nfs/nfs4xdr.c        |  193 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/nfs_xdr.h |   17 ++++
 3 files changed, 350 insertions(+), 1 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index f1918fa..7607dfd 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -55,6 +55,7 @@
 #include "internal.h"
 #include "iostat.h"
 #if defined(CONFIG_NFS_V4_1)
+#include "callback.h"
 #include <linux/nfs4_session.h>
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -4448,9 +4449,147 @@ void nfs4_get_session(struct nfs_client *clp)
 		atomic_inc(&clp->cl_session->ref_count);
 }
 
+/* Initialize the values to be used by the client in CREATE_SESSION */
+static void nfs4_init_channel_attrs(struct nfs_client *clp,
+				    struct nfs4_channel_attrs *fc_attrs,
+				    struct nfs4_channel_attrs *bc_attrs)
+{
+	/* XXX: We need to have good values here... 32K is a wild guess */
+	fc_attrs->headerpadsz = bc_attrs->headerpadsz = 0;
+	fc_attrs->max_rqst_sz = bc_attrs->max_rqst_sz = NFS_MAX_FILE_IO_SIZE;
+	fc_attrs->max_resp_sz = bc_attrs->max_resp_sz = NFS_MAX_FILE_IO_SIZE;
+	fc_attrs->max_resp_sz_cached = bc_attrs->max_resp_sz_cached =
+		NFS_MAX_FILE_IO_SIZE;
+	fc_attrs->max_ops = bc_attrs->max_ops = 0xFFFFFFFF;
+	fc_attrs->max_reqs = bc_attrs->max_reqs =
+				clp->cl_rpcclient->cl_xprt->max_reqs;
+	fc_attrs->rdma_attrs = bc_attrs->rdma_attrs = 0;
+}
+
+/* Check the values returned by the server for CREATE_SESSION. Since we made
+ * our needs known, if the server gives us more than we need, we don't bother
+ * with it.
+ */
+static void nfs4_adjust_channel_attrs(struct nfs4_channel_attrs *req_attrs,
+				      struct nfs4_channel_attrs *resp_attrs)
+{
+	dprintk("%s: before adjusting: max_rqst_sz=%u max_resp_sz=%u "
+		"max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n",
+		__func__,
+		resp_attrs->max_rqst_sz, resp_attrs->max_resp_sz,
+		resp_attrs->max_resp_sz_cached, resp_attrs->max_ops,
+		resp_attrs->max_reqs);
+
+	if (req_attrs->max_rqst_sz < resp_attrs->max_rqst_sz)
+		resp_attrs->max_rqst_sz = req_attrs->max_rqst_sz;
+
+	if (req_attrs->max_resp_sz < resp_attrs->max_resp_sz)
+		resp_attrs->max_resp_sz = req_attrs->max_resp_sz;
+
+	if (req_attrs->max_resp_sz_cached < resp_attrs->max_resp_sz)
+		resp_attrs->max_resp_sz = req_attrs->max_resp_sz_cached;
+
+	if (req_attrs->max_ops < resp_attrs->max_ops)
+		resp_attrs->max_ops = req_attrs->max_ops;
+
+	if (req_attrs->max_reqs < resp_attrs->max_reqs)
+		resp_attrs->max_reqs = req_attrs->max_reqs;
+
+	dprintk("%s: after  adjusting: max_rqst_sz=%u max_resp_sz=%u "
+		"max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n",
+		__func__,
+		resp_attrs->max_rqst_sz, resp_attrs->max_resp_sz,
+		resp_attrs->max_resp_sz_cached, resp_attrs->max_ops,
+		resp_attrs->max_reqs);
+
+	/* We ignore the rdma channel attributes */
+}
+
+static int _nfs4_proc_create_session(struct nfs4_session *session)
+{
+	struct nfs_client *clp = session->clp;
+	struct nfs41_create_session_args args = {
+		.client = clp,
+		.session = session,
+		.cb_program = NFS4_CALLBACK,
+	};
+
+	struct nfs41_create_session_res res = {
+		.client = clp,
+		.session = session,
+	};
+
+	struct rpc_message msg = {
+		.rpc_proc = nfs4_proc(clp, NFSPROC4_CLNT_CREATE_SESSION),
+		.rpc_argp = &args,
+		.rpc_resp = &res,
+	};
+	int status;
+
+	nfs4_init_channel_attrs(clp, &args.fc_attrs, &args.bc_attrs);
+	args.flags = (SESSION4_PERSIST);
+
+	status = rpc_call_sync(session->clnt, &msg, 0);
+
+	/* Set the negotiated values in the session's channel_attrs struct */
+
+	if (!status) {
+		nfs4_adjust_channel_attrs(&args.fc_attrs,
+					&session->fore_channel.chan_attrs);
+		nfs4_adjust_channel_attrs(&args.bc_attrs,
+					&session->back_channel.chan_attrs);
+		/* Increment the clientid slot sequence id */
+		clp->cl_seqid++;
+	}
+
+	return status;
+}
+
+/*
+ * Issues a CREATE_SESSION operation to the server.
+ * It is the responsibility of the caller to verify the session is
+ * expired before calling this routine.
+ */
 int nfs4_proc_create_session(struct nfs4_session *session)
 {
-	return -1;	/* stub */
+	int status;
+	u32 *ptr;
+	struct nfs_fsinfo fsinfo;
+	struct nfs_client *clp = session->clp;
+
+	dprintk("--> %s clp=%p session=%p\n", __func__, clp, session);
+
+	status = _nfs4_proc_create_session(session);
+	if (status)
+		goto out;
+
+	session->clnt = clp->cl_rpcclient;
+
+	/* Init the fore channel */
+	status = nfs4_init_slot_table(&session->fore_channel);
+	dprintk("fore channel initialization returned %d\n", status);
+	if (status)
+		goto out;
+
+	dprintk("%s client>seqid %d\n", __func__, clp->cl_seqid);
+	ptr = (int *)session->sess_id;
+	dprintk("sessionid is: %u:%u:%u:%u\n", ptr[0], ptr[1], ptr[2], ptr[3]);
+
+	/* Get the lease time */
+	status = nfs4_proc_get_lease_time(clp, session, &fsinfo);
+	if (status == 0) {
+		/* Update lease time and schedule renewal */
+		spin_lock(&clp->cl_lock);
+		clp->cl_lease_time = fsinfo.lease_time * HZ;
+		clp->cl_last_renewal = jiffies;
+		clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+		spin_unlock(&clp->cl_lock);
+
+		nfs4_schedule_state_renewal(clp);
+	}
+out:
+	dprintk("<-- %s\n", __func__);
+	return status;
 }
 
 int nfs4_proc_destroy_session(struct nfs4_session *session)
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 7b7d4e8..4dfb04e 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -242,6 +242,8 @@ static int nfs4_stat_to_errno(int);
 				(0)
 
 #if defined(CONFIG_NFS_V4_1)
+#define NFS4_MAX_MACHINE_NAME_LEN (64)
+
 #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \
 				encode_verifier_maxsz + \
 				1 /* co_ownerid.len */ + \
@@ -263,6 +265,31 @@ static int nfs4_stat_to_errno(int);
 				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
 				1 /* eir_server_impl_id array length */ + \
 				0 /* ignored eir_server_impl_id contents */)
+#define encode_channel_attrs_maxsz  (6 + 1 /* ca_rdma_ird.len (0) */)
+#define decode_channel_attrs_maxsz  (6 + \
+				     1 /* ca_rdma_ird.len */ + \
+				     1 /* ca_rdma_ird */)
+#define encode_create_session_maxsz  (op_encode_hdr_maxsz + \
+				     2 /* csa_clientid */ + \
+				     1 /* csa_sequence */ + \
+				     1 /* csa_flags */ + \
+				     encode_channel_attrs_maxsz + \
+				     encode_channel_attrs_maxsz + \
+				     1 /* csa_cb_program */ + \
+				     1 /* csa_sec_parms.len (1) */ + \
+				     1 /* cb_secflavor (AUTH_SYS) */ + \
+				     1 /* stamp */ + \
+				     1 /* machinename.len */ + \
+				     XDR_QUADLEN(NFS4_MAX_MACHINE_NAME_LEN) + \
+				     1 /* uid */ + \
+				     1 /* gid */ + \
+				     1 /* gids.len (0) */)
+#define decode_create_session_maxsz  (op_decode_hdr_maxsz +	\
+				     XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
+				     1 /* csr_sequence */ + \
+				     1 /* csr_flags */ + \
+				     decode_channel_attrs_maxsz + \
+				     decode_channel_attrs_maxsz)
 #define encode_sequence_maxsz	0 /* stub */
 #define decode_sequence_maxsz	0 /* stub */
 #else /* CONFIG_NFS_V4_1 */
@@ -618,6 +645,12 @@ static int nfs4_stat_to_errno(int);
 #define NFS4_dec_exchange_id_sz \
 				(compound_decode_hdr_maxsz + \
 				 decode_exchange_id_maxsz)
+#define NFS4_enc_create_session_sz \
+				(compound_encode_hdr_maxsz + \
+				 encode_create_session_maxsz)
+#define NFS4_dec_create_session_sz \
+				(compound_decode_hdr_maxsz + \
+				 decode_create_session_maxsz)
 #define NFS4_enc_get_lease_time_sz	(compound_encode_hdr_maxsz + \
 					 encode_sequence_maxsz + \
 					 encode_putrootfh_maxsz + \
@@ -1601,6 +1634,69 @@ static int encode_exchange_id(struct xdr_stream *xdr,
 	return 0;
 }
 
+static int encode_create_session(struct xdr_stream *xdr,
+				 struct nfs41_create_session_args *args,
+				 struct compound_hdr *hdr)
+{
+	uint32_t *p;
+	char machine_name[NFS4_MAX_MACHINE_NAME_LEN];
+	uint32_t len;
+	struct nfs_client *clp = args->client;
+
+	RESERVE_SPACE(4);
+	WRITE32(OP_CREATE_SESSION);
+
+	RESERVE_SPACE(8);
+	WRITE64(clp->cl_ex_clid);
+
+	RESERVE_SPACE(8);
+	WRITE32(clp->cl_seqid);			/*Sequence id */
+	WRITE32(args->flags);			/*flags */
+
+	RESERVE_SPACE(2*28);			/* 2 channel_attrs */
+	/* Fore Channel */
+	WRITE32(args->fc_attrs.headerpadsz);	/* header padding size */
+	WRITE32(args->fc_attrs.max_rqst_sz);	/* max req size */
+	WRITE32(args->fc_attrs.max_resp_sz);	/* max resp size */
+	WRITE32(args->fc_attrs.max_resp_sz_cached);	/* Max resp sz cached */
+	WRITE32(args->fc_attrs.max_ops);	/* max operations */
+	WRITE32(args->fc_attrs.max_reqs);	/* max requests */
+	WRITE32(0);				/* rdmachannel_attrs */
+
+	/* Back Channel */
+	WRITE32(args->fc_attrs.headerpadsz);	/* header padding size */
+	WRITE32(args->bc_attrs.max_rqst_sz);	/* max req size */
+	WRITE32(args->bc_attrs.max_resp_sz);	/* max resp size */
+	WRITE32(args->bc_attrs.max_resp_sz_cached);	/* Max resp sz cached */
+	WRITE32(args->bc_attrs.max_ops);	/* max operations */
+	WRITE32(args->bc_attrs.max_reqs);	/* max requests */
+	WRITE32(0);				/* rdmachannel_attrs */
+
+	RESERVE_SPACE(4);
+	WRITE32(args->cb_program);		/* cb_program */
+
+	RESERVE_SPACE(4);			/* # of security flavors */
+	WRITE32(1);
+
+	RESERVE_SPACE(4);
+	WRITE32(RPC_AUTH_UNIX);			/* auth_sys */
+
+	/* authsys_parms rfc1831 */
+	RESERVE_SPACE(4);
+	WRITE32((u32)clp->cl_boot_time.tv_nsec);	/* stamp */
+	len = scnprintf(machine_name, sizeof(machine_name), "%s",
+			clp->cl_ipaddr);
+	RESERVE_SPACE(16 + len);
+	WRITE32(len);
+	WRITEMEM(machine_name, len);
+	WRITE32(0);				/* UID */
+	WRITE32(0);				/* GID */
+	WRITE32(0);				/* No more gids */
+	hdr->nops++;
+
+	return 0;
+}
+
 static int encode_sequence(struct xdr_stream *xdr,
 			   const struct nfs41_sequence_args *args,
 			   struct compound_hdr *hdr)
@@ -2567,6 +2663,27 @@ static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p,
 }
 
 /*
+ * a CREATE_SESSION request
+ */
+static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p,
+					struct nfs41_create_session_args *args)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.minorversion = req->rq_task->tk_client->cl_mvers,
+	};
+	int status;
+	__be32 *nops;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	nops = encode_compound_hdr(&xdr, &hdr);
+
+	status = encode_create_session(&xdr, args, &hdr);
+	encode_nops(nops, &hdr);
+	return status;
+}
+
+/*
  * a GET_LEASE_TIME request
  */
 static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p,
@@ -4270,6 +4387,64 @@ static int decode_exchange_id(struct xdr_stream *xdr,
 	return 0;
 }
 
+static int decode_create_session(struct xdr_stream *xdr,
+				 struct nfs41_create_session_res *res)
+{
+	uint32_t *p;
+	int status;
+	u32 nr_attrs;
+
+	struct nfs4_session *session = res->session;
+	struct nfs_client *clp = res->client;
+
+	status = decode_op_hdr(xdr, OP_CREATE_SESSION);
+
+	if (status)
+		return status;
+
+	/* sessionid */
+	READ_BUF(NFS4_MAX_SESSIONID_LEN);
+	COPYMEM(&session->sess_id, NFS4_MAX_SESSIONID_LEN);
+
+	/* seqid, flags */
+	READ_BUF(8);
+	READ32(clp->cl_seqid);
+	READ32(session->flags);
+
+	/* Channel attributes */
+	/* fore channel */
+	READ_BUF(24);
+	READ32(session->fore_channel.chan_attrs.headerpadsz);
+	READ32(session->fore_channel.chan_attrs.max_rqst_sz);
+	READ32(session->fore_channel.chan_attrs.max_resp_sz);
+	READ32(session->fore_channel.chan_attrs.max_resp_sz_cached);
+	READ32(session->fore_channel.chan_attrs.max_ops);
+	READ32(session->fore_channel.chan_attrs.max_reqs);
+	READ_BUF(4);
+	READ32(nr_attrs);
+	if (nr_attrs == 1) {
+		READ_BUF(4);
+		READ32(session->fore_channel.chan_attrs.rdma_attrs);
+	}
+
+	/* back channel */
+	READ_BUF(24);
+	READ32(session->fore_channel.chan_attrs.headerpadsz);
+	READ32(session->back_channel.chan_attrs.max_rqst_sz);
+	READ32(session->back_channel.chan_attrs.max_resp_sz);
+	READ32(session->back_channel.chan_attrs.max_resp_sz_cached);
+	READ32(session->back_channel.chan_attrs.max_ops);
+	READ32(session->back_channel.chan_attrs.max_reqs);
+	READ_BUF(4);
+	READ32(nr_attrs);
+	if (nr_attrs == 1) {
+		READ_BUF(4);
+		READ32(session->back_channel.chan_attrs.rdma_attrs);
+	}
+
+	return 0;
+}
+
 static int decode_sequence(struct xdr_stream *xdr,
 			   struct nfs41_sequence_res *res,
 			   struct rpc_rqst *rqstp)
@@ -5148,6 +5323,23 @@ static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p,
 }
 
 /*
+ * a CREATE_SESSION request
+ */
+static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p,
+					struct nfs41_create_session_res *res)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	status = decode_compound_hdr(&xdr, &hdr);
+	if (!status)
+		status = decode_create_session(&xdr, res);
+	return status;
+}
+
+/*
  * a GET_LEASE_TIME request
  */
 static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p,
@@ -5414,6 +5606,7 @@ struct rpc_procinfo	nfs4_procedures[] = {
   PROC(FS_LOCATIONS,	enc_fs_locations, dec_fs_locations),
 #if defined(CONFIG_NFS_V4_1)
   PROC(EXCHANGE_ID,	enc_exchange_id,	dec_exchange_id),
+  PROC(CREATE_SESSION,	enc_create_session,	dec_create_session),
   PROC(GET_LEASE_TIME,	enc_get_lease_time,	dec_get_lease_time),
 #endif /* CONFIG_NFS_V4_1 */
 };
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 976ced7..18fcc96 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -2,6 +2,9 @@
 #define _LINUX_NFS_XDR_H
 
 #include <linux/nfsacl.h>
+#ifdef CONFIG_NFS_V4_1
+#include <linux/nfs4_session.h>
+#endif
 
 /*
  * To change the maximum rsize and wsize supported by the NFS client, adjust
@@ -899,6 +902,20 @@ struct nfs41_exchange_id_res {
 	struct server_scope		server_scope;
 	struct nfs_impl_id4		impl_id;
 };
+
+struct nfs41_create_session_args {
+	struct nfs_client	       *client;
+	struct nfs4_session	       *session;
+	uint32_t			flags;
+	uint32_t			cb_program;
+	struct nfs4_channel_attrs	fc_attrs;	/* Fore Channel */
+	struct nfs4_channel_attrs	bc_attrs;	/* Back Channel */
+};
+
+struct nfs41_create_session_res {
+	struct nfs_client	       *client;
+	struct nfs4_session	       *session;
+};
 #endif /* CONFIG_NFS_V4_1 */
 
 struct nfs_page;
-- 
1.6.0.2

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux