On Nov. 10, 2008, 22:49 +0200, Benny Halevy <bhalevy@xxxxxxxxxxx> wrote: > From: Ricardo Labiaga <ricardo.labiaga@xxxxxxxxxx> > > Implement the create_session operation confoming to > http://tools.ietf.org/html/draft-ietf-nfsv4-minorversion1-26 > > Look up the client id (generated by the server on exchange_id, > given by the client on create_session). > If neither a confirmed or unconfirmed client is found > then the client id is stale > If a confirmed cilent is found (i.e. we already received > create_session for it) then compare the sequence id > to determine if it's a replay or possibly a mis-ordered rpc. > If the seqid is in order, update the confirmed client seqid > and procedd with updating the session parameters. > > If an unconfirmed client_id is found then verify the creds > and seqid. If both match move the client id to confirmed state > and proceed with processing the create_session. > > Currently, we do not support persistent sessions, and RDMA. > > alloc_init_session generates a new sessionid and creates > a session structure. > > TODO: improve resource pre-allocation and negotiate session > parameters accordingly. > > Signed-off-by: Marc Eshel <eshel@xxxxxxxxxxxxxxx> > Signed-off-by: Dean Hildebrand <dhildeb@xxxxxxxxxx> > Signed-off-by: Andy Adamson<andros@xxxxxxxxxx> > Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx> > --- > fs/nfsd/nfs4state.c | 139 +++++++++++++++++++++++++++++++++++++++++- > fs/nfsd/nfs4xdr.c | 147 +++++++++++++++++++++++++++++++++++++++++++- > include/linux/nfsd/state.h | 3 + > include/linux/nfsd/xdr4.h | 21 ++++++- > 4 files changed, 306 insertions(+), 4 deletions(-) > > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c > index cbbb733..73bc8de 100644 > --- a/fs/nfsd/nfs4state.c > +++ b/fs/nfsd/nfs4state.c > @@ -73,6 +73,9 @@ static u32 current_delegid = 1; > static u32 nfs4_init; > static stateid_t zerostateid; /* bits all 0 */ > static stateid_t onestateid; /* bits all 1 */ > +#if defined(CONFIG_NFSD_V4_1) > +static u64 current_sessionid = 1; > +#endif > > #define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t))) > #define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) > @@ -352,6 +355,72 @@ dump_sessionid(const char *fn, nfs41_sessionid *sessionid) > dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); > } > > +static void > +gen_sessionid(struct nfs41_session *ses) > +{ > + struct nfs4_client *clp = ses->se_client; > + u32 *p = (u32 *)ses->se_sessionid; > + > + *p++ = clp->cl_clientid.cl_boot; > + *p++ = clp->cl_clientid.cl_id; > + *p++ = (u32)boot_time; revewiw 11-13: find something useful to put here boot_time is already part of the clientid part. (or reserve as 0) > + *p++ = current_sessionid++; > + BUG_ON((char *)p - (char *)ses->se_sessionid != > + sizeof(ses->se_sessionid)); remove BUG_ON > +} > + > +static int > +alloc_init_session(struct nfs4_client *clp, struct nfsd4_create_session *cses) > +{ > + struct nfs41_session *new; > + int idx, status = nfserr_resource, slotsize, i; > + > + new = kzalloc(sizeof(*new), GFP_KERNEL); > + if (!new) > + goto out; > + > + if (cses->fore_channel.maxreqs >= NFS41_MAX_SLOTS) > + cses->fore_channel.maxreqs = NFS41_MAX_SLOTS; > + new->se_fnumslots = cses->fore_channel.maxreqs; > + slotsize = new->se_fnumslots * sizeof(struct nfs41_slot); > + > + new->se_slots = kzalloc(slotsize, GFP_KERNEL); > + if (!new->se_slots) > + goto out_free; > + > + for (i = 0; i < new->se_fnumslots; i++) { > + new->se_slots[i].sl_session = new; > + nfs41_set_slot_state(&new->se_slots[i], NFS4_SLOT_AVAILABLE); > + } > + > + new->se_client = clp; > + gen_sessionid(new); > + idx = hash_sessionid(&new->se_sessionid); > + memcpy(&clp->cl_sessionid, &new->se_sessionid, sizeof(nfs41_sessionid)); > + > + new->se_flags = cses->flags; > + > + /* for now, accept the client values */ > + new->se_fheaderpad_sz = cses->fore_channel.headerpadsz; > + new->se_fmaxreq_sz = cses->fore_channel.maxreq_sz; > + new->se_fmaxresp_sz = cses->fore_channel.maxresp_sz; > + new->se_fmaxresp_cached = cses->fore_channel.maxresp_cached; > + new->se_fmaxops = cses->fore_channel.maxops; review 11-13: this is being rewritten by Andy. > + > + kref_init(&new->se_ref); > + INIT_LIST_HEAD(&new->se_hash); > + INIT_LIST_HEAD(&new->se_perclnt); > + list_add(&new->se_hash, &sessionid_hashtbl[idx]); > + list_add(&new->se_perclnt, &clp->cl_sessions); > + > + status = nfs_ok; > +out: > + return status; > +out_free: > + kfree(new); > + goto out; > +} > + > struct nfs41_session * > find_in_sessionid_hashtbl(nfs41_sessionid *sessionid) > { > @@ -905,7 +974,75 @@ nfsd4_create_session(struct svc_rqst *rqstp, > struct nfsd4_compound_state *cstate, > struct nfsd4_create_session *cr_ses) > { > - return -1; /* stub */ > + u32 ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr; > + struct nfs4_client *conf, *unconf; > + __u32 max_blocksize = svc_max_payload(rqstp); > + int status = 0; > + > + if (STALE_CLIENTID(&cr_ses->clientid)) > + return nfserr_stale_clientid; review 11-13: no need to check that here since we're returning the same error if we can't find it. Do the same for setclientid_confirm. > + > + nfs4_lock_state(); > + unconf = find_unconfirmed_client(&cr_ses->clientid); > + conf = find_confirmed_client(&cr_ses->clientid); > + > + if (!conf && !unconf) { > + status = nfserr_stale_clientid; > + goto out; > + } review 11-13: move downward as the final else lag. > + if (conf) { > + status = nfs_ok; > + if (conf->cl_seqid == cr_ses->seqid) { > + dprintk("Got a create_session replay! seqid= %d\n", > + conf->cl_seqid); > + goto out_replay; > + } else if (cr_ses->seqid != conf->cl_seqid + 1) { > + status = nfserr_seq_misordered; > + dprintk("Sequence misordered!\n"); > + dprintk("Expected seqid= %d but got seqid= %d\n", > + conf->cl_seqid, cr_ses->seqid); > + goto out; > + } > + conf->cl_seqid++; > + } else if (unconf) { > + if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || > + (ip_addr != unconf->cl_addr)) { > + status = nfserr_clid_inuse; > + goto out; > + } > + > + if (unconf->cl_seqid != cr_ses->seqid) { > + status = nfserr_seq_misordered; > + goto out; > + } > + > + move_to_confirmed(unconf); > + > + /* > + * We do not support RDMA or persistent sessions > + */ > + cr_ses->flags &= ~SESSION4_PERSIST; > + cr_ses->flags &= ~SESSION4_RDMA; > + > + conf = unconf; > + } > + > + status = alloc_init_session(conf, cr_ses); > + > +out_replay: > + memcpy(cr_ses->sessionid, conf->cl_sessionid, 16); > + cr_ses->seqid = conf->cl_seqid; > + cr_ses->fore_channel.maxreq_sz = max_blocksize; > + cr_ses->fore_channel.maxresp_sz = max_blocksize; > + cr_ses->fore_channel.maxresp_cached = max_blocksize; > + cr_ses->back_channel.maxreq_sz = max_blocksize; > + cr_ses->back_channel.maxresp_sz = max_blocksize; > + cr_ses->back_channel.maxresp_cached = max_blocksize; > + > +out: > + nfs4_unlock_state(); > + dprintk("%s returns %d\n", __func__, ntohl(status)); > + return status; > } > > __be32 > diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c > index 055f1ad..02c82d4 100644 > --- a/fs/nfsd/nfs4xdr.c > +++ b/fs/nfsd/nfs4xdr.c > @@ -1119,7 +1119,108 @@ static __be32 > nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, > struct nfsd4_create_session *sess) > { > - return nfserr_opnotsupp; /* stub */ > + DECODE_HEAD; > + > + u32 dummy; > + char *machine_name; > + int i; > + int nr_secflavs; > + > + READ_BUF(16); > + COPYMEM(&sess->clientid, 8); > + READ32(sess->seqid); > + READ32(sess->flags); > + > + /* Fore channel attrs */ > + READ_BUF(28); > + READ32(sess->fore_channel.headerpadsz); > + READ32(sess->fore_channel.maxreq_sz); > + READ32(sess->fore_channel.maxresp_sz); > + READ32(sess->fore_channel.maxresp_cached); > + READ32(sess->fore_channel.maxops); > + READ32(sess->fore_channel.maxreqs); > + READ32(sess->fore_channel.nr_rdma_attrs); > + if (sess->fore_channel.nr_rdma_attrs == 1) { > + READ_BUF(4); > + READ32(sess->fore_channel.rdma_attrs); > + } else if (sess->fore_channel.nr_rdma_attrs > 1) { > + dprintk("Too many fore channel attr bitmaps!\n"); > + goto xdr_error; > + } > + > + /* Back channel attrs */ > + READ_BUF(28); > + READ32(sess->back_channel.headerpadsz); > + READ32(sess->back_channel.maxreq_sz); > + READ32(sess->back_channel.maxresp_sz); > + READ32(sess->back_channel.maxresp_cached); > + READ32(sess->back_channel.maxops); > + READ32(sess->back_channel.maxreqs); > + READ32(sess->back_channel.nr_rdma_attrs); > + if (sess->back_channel.nr_rdma_attrs == 1) { > + READ_BUF(4); > + READ32(sess->back_channel.rdma_attrs); > + } else if (sess->back_channel.nr_rdma_attrs > 1) { > + dprintk("Too many back channel attr bitmaps!\n"); > + goto xdr_error; > + } > + > + READ_BUF(8); > + READ32(sess->callback_prog); > + > + /* callback_sec_params4 */ > + READ32(nr_secflavs); > + for (i = 0; i < nr_secflavs; ++i) { > + READ_BUF(4); > + READ32(dummy); > + switch (dummy) { > + case RPC_AUTH_NULL: > + /* Nothing to read */ > + break; > + case RPC_AUTH_UNIX: > + READ_BUF(8); > + /* stamp */ > + READ32(dummy); > + > + /* machine name */ > + READ32(dummy); > + READ_BUF(dummy); > + SAVEMEM(machine_name, dummy); > + > + /* uid, gid */ > + READ_BUF(8); > + READ32(sess->uid); > + READ32(sess->gid); > + > + /* more gids */ > + READ_BUF(4); > + READ32(dummy); > + READ_BUF(dummy * 4); > + for (i = 0; i < dummy; ++i) > + READ32(dummy); > + break; > + case RPC_AUTH_GSS: > + dprintk("RPC_AUTH_GSS callback secflavor " > + "not supported!\n"); > + READ_BUF(8); > + /* gcbp_service */ > + READ32(dummy); > + /* gcbp_handle_from_server */ > + READ32(dummy); > + READ_BUF(dummy); > + p += XDR_QUADLEN(dummy); > + /* gcbp_handle_from_client */ > + READ_BUF(4); > + READ32(dummy); > + READ_BUF(dummy); > + p += XDR_QUADLEN(dummy); > + break; > + default: > + dprintk("Illegal callback secflavor\n"); > + return nfserr_inval; > + } > + } > + DECODE_TAIL; > } > > static __be32 > @@ -2839,7 +2940,49 @@ static __be32 > nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, > struct nfsd4_create_session *sess) > { > - /* stub */ > + ENCODE_HEAD; > + > + if (nfserr) > + goto out; > + > + RESERVE_SPACE(24); > + WRITEMEM(sess->sessionid, sizeof(sess->sessionid)); > + WRITE32(sess->seqid); > + WRITE32(sess->flags); > + ADJUST_ARGS(); > + > + RESERVE_SPACE(28); > + WRITE32(sess->fore_channel.headerpadsz); > + WRITE32(sess->fore_channel.maxreq_sz); > + WRITE32(sess->fore_channel.maxresp_sz); > + WRITE32(sess->fore_channel.maxresp_cached); > + WRITE32(sess->fore_channel.maxops); > + WRITE32(sess->fore_channel.maxreqs); > + WRITE32(sess->fore_channel.nr_rdma_attrs); > + ADJUST_ARGS(); > + > + if (sess->fore_channel.nr_rdma_attrs) { > + RESERVE_SPACE(4); > + WRITE32(sess->fore_channel.rdma_attrs); > + ADJUST_ARGS(); > + } > + > + RESERVE_SPACE(28); > + WRITE32(sess->back_channel.headerpadsz); > + WRITE32(sess->back_channel.maxreq_sz); > + WRITE32(sess->back_channel.maxresp_sz); > + WRITE32(sess->back_channel.maxresp_cached); > + WRITE32(sess->back_channel.maxops); > + WRITE32(sess->back_channel.maxreqs); > + WRITE32(sess->back_channel.nr_rdma_attrs); > + ADJUST_ARGS(); > + > + if (sess->back_channel.nr_rdma_attrs) { > + RESERVE_SPACE(4); > + WRITE32(sess->back_channel.rdma_attrs); > + ADJUST_ARGS(); > + } > +out: > return nfserr; > } > > diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h > index 9bbfd88..94b5366 100644 > --- a/include/linux/nfsd/state.h > +++ b/include/linux/nfsd/state.h > @@ -217,6 +217,9 @@ struct nfs4_client { > #if defined(CONFIG_NFSD_V4_1) > u32 cl_seqid; /* seqid for create_session */ > u32 cl_exchange_flags; > + nfs41_sessionid cl_sessionid; > + > + struct svc_xprt *cl_cb_xprt; /* 4.1 callback transport */ > #endif /* CONFIG_NFSD_V4_1 */ > }; > > diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h > index aee8996..75d93ab 100644 > --- a/include/linux/nfsd/xdr4.h > +++ b/include/linux/nfsd/xdr4.h > @@ -362,8 +362,27 @@ struct nfsd4_exchange_id { > u32 seqid; > }; > > +struct nfsd4_channel { > + u32 headerpadsz; > + u32 maxreq_sz; > + u32 maxresp_sz; > + u32 maxresp_cached; > + u32 maxops; > + u32 maxreqs; > + u32 nr_rdma_attrs; > + u32 rdma_attrs; > +}; > + > struct nfsd4_create_session { > - int foo; /* stub */ > + clientid_t clientid; > + nfs41_sessionid sessionid; > + u32 seqid; > + u32 flags; > + struct nfsd4_channel fore_channel; > + struct nfsd4_channel back_channel; > + u32 callback_prog; > + u32 uid; > + u32 gid; > }; > > struct nfsd4_sequence { -- 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