Copyright (c) 2006 The Regents of the University of Michigan All rights reserved. Permission is granted to use, copy, create derivative works and redistribute this software and such derivative works for any purpose, so long as the name of the University of Michigan is not used in any advertising or publicity pertaining to the use or distribution of this software without specific, written prior authorization. If the above copyright notice or any other identification of the university of michigan is included in any copy of any portion of this software, then the disclaimer below must also be included. This software is provided as is, without representation from the University of Michigan as to its fitness for any purpose, and without warranty by the university of michigan of any kind, either express or implied, including without limitation the implied warranties of merchantability and fitness for a particular purpose. The Regents of the University of Michigan shall not be liable for any damages, including special, indirect, incidental, or consequential damages, with respect to any claim arising out or in connection with the use of the software, even if it has been or is hereafter advised of the possibility of such damages. Signed-off-by: George Dunlap Index: linux-sessions-2.6.14/fs/nfs/callback.h =================================================================== --- linux-sessions-2.6.14.orig/fs/nfs/callback.h 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/fs/nfs/callback.h 2005-11-29 16:11:14.000000000 -0500 @@ -20,6 +20,7 @@ enum nfs4_callback_opnum { OP_CB_GETATTR = 3, OP_CB_RECALL = 4, + OP_CB_RECALL_CREDIT = 5, /* v4.1 */ OP_CB_ILLEGAL = 10044, }; Index: linux-sessions-2.6.14/fs/nfs/nfs4proc.c =================================================================== --- linux-sessions-2.6.14.orig/fs/nfs/nfs4proc.c 2005-11-29 16:11:13.000000000 -0500 +++ linux-sessions-2.6.14/fs/nfs/nfs4proc.c 2005-12-03 15:13:01.000000000 -0500 @@ -116,6 +116,72 @@ 0 }; + +/* + * small amount of session machinery. + * - need more safety + */ + +void +nfs_seq_setup(struct nfs4_client_session *sess, struct nfs4_sequence_args *sa) +{ + int slot; + +if ((sess == 0) || (sa == 0)) + printk("nfs_seq_setup: sess %p sa %p\n", sess, sa); + + + /* + ** do the basic setup we expect to manage the decode, + ** then see if we need to allocate slots. + */ + sa->session = sess; + if (sess->cs_nfs4version == 0) { + return; + } + + + spin_lock(&sess->cs_lock); + slot = nfs4_client_findslot(sess); + while (slot == -1) { + DECLARE_WAITQUEUE(wq, current); + add_wait_queue_exclusive(&sess->cs_wantSlots, &wq); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock(&sess->cs_lock); +printk("nfs_seq_setup: need slots\n"); + schedule(); + /* while loop for nfs4_client_findslot with schedule call */ + set_current_state(TASK_RUNNING); + remove_wait_queue(&sess->cs_wantSlots, &wq); + spin_lock(&sess->cs_lock); + slot = nfs4_client_findslot(sess); +printk("nfs_seq_setup: got %d\n", slot); + } +if (sess->cs_magic != NFS4_SESS_MAGIC) + panic("nfs_seq_setup: magic wrong\n" ); + + nfs4_client_markslot(sess, slot); + /* + ** populate the nfs4_sequence_args + */ + sa->slotId = slot; + + sa->seqId = sa->session->cs_seqId++; + + /* + ** determine max slot. + */ + sa->maxslot = sess->cs_totalrequests; + spin_unlock(&sess->cs_lock); +} + +/* + * + */ + + + + static void nfs4_setup_readdir(u64 cookie, struct dentry *dentry, struct nfs4_readdir_arg *readdir) { @@ -229,6 +295,7 @@ }; struct nfs_openres o_res = { .server = server, /* Grrr */ + .session = server->nfs4_state->cl_session, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR], @@ -248,6 +315,7 @@ } o_arg.u.delegation_type = delegation->type; } + nfs_seq_setup(server->nfs4_state->cl_session, &o_arg.sessargs); status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); nfs4_increment_seqid(status, sp); if (status == 0) { @@ -296,6 +364,7 @@ }; struct nfs_openres res = { .server = server, + .session = server->nfs4_state->cl_session, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR], @@ -314,6 +383,7 @@ arg.seqid = sp->so_seqid; arg.open_flags = state->state; memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data)); + nfs_seq_setup(server->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); nfs4_increment_seqid(status, sp); if (status >= 0) { @@ -349,7 +419,7 @@ return err; } -static inline int _nfs4_proc_open_confirm(struct nfs_server *server, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid) +static inline int _nfs4_proc_open_confirm(struct nfs_server *server, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs4_client_session *sess) { struct rpc_clnt *clnt = server->client; struct nfs_open_confirmargs arg = { @@ -357,7 +427,9 @@ .seqid = sp->so_seqid, .stateid = *stateid, }; - struct nfs_open_confirmres res; + struct nfs_open_confirmres res = { + .session = sess, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], .rpc_argp = &arg, @@ -367,6 +439,7 @@ }; int status; + nfs_seq_setup(sess, &arg.sessargs); status = rpc_call_sync(clnt, &msg, RPC_TASK_NOINTR); nfs4_increment_seqid(status, sp); if (status >= 0) @@ -391,13 +464,14 @@ o_arg->id = sp->so_id; o_arg->clientid = sp->so_client->cl_clientid; + nfs_seq_setup(server->nfs4_state->cl_session, &o_arg->sessargs); status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); nfs4_increment_seqid(status, sp); if (status != 0) goto out; update_changeattr(dir, &o_res->cinfo); if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { - status = _nfs4_proc_open_confirm(server, &o_res->fh, sp, &o_res->stateid); + status = _nfs4_proc_open_confirm(server, &o_res->fh, sp, &o_res->stateid, server->nfs4_state->cl_session); if (status != 0) goto out; } @@ -654,6 +728,7 @@ struct nfs_openres o_res = { .f_attr = &f_attr, .server = server, + .session = server->nfs4_state->cl_session, }; /* Protect against reboot recovery conflicts */ @@ -752,6 +827,7 @@ struct nfs_setattrres res = { .fattr = fattr, .server = server, + .session = server->nfs4_state->cl_session, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], @@ -769,6 +845,7 @@ } else memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); + nfs_seq_setup(server->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(server->client, &msg, 0); return status; } @@ -877,10 +954,13 @@ calldata->state = state; calldata->arg.fh = NFS_FH(inode); /* Serialization for the sequence id */ + calldata->res.session = NFS_SERVER(inode)->nfs4_state->cl_session; calldata->arg.seqid = state->owner->so_seqid; calldata->arg.open_flags = mode; memcpy(&calldata->arg.stateid, &state->stateid, sizeof(calldata->arg.stateid)); + nfs_seq_setup(NFS_SERVER(inode)->nfs4_state->cl_session, + &calldata->arg.sessargs); status = nfs4_close_call(NFS_SERVER(inode), calldata); /* * Return -EINPROGRESS on success in order to indicate to the @@ -949,15 +1029,21 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) { - struct nfs4_server_caps_res res = {}; + struct nfs4_server_caps_arg arg = { + .fhandle = fhandle, + }; + struct nfs4_server_caps_res res = { + .session = server->nfs4_state->cl_session, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], - .rpc_argp = fhandle, + .rpc_argp = &arg, .rpc_resp = &res, .rpc_iosp = server->rio_stats, }; int status; + nfs_seq_setup(server->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(server->client, &msg, 0); if (status == 0) { memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); @@ -995,6 +1081,7 @@ .server = server, .fattr = fattr, .fh = fhandle, + .session = server->nfs4_state->cl_session, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP_ROOT], @@ -1003,6 +1090,7 @@ .rpc_iosp = server->rio_stats, }; fattr->valid = 0; + nfs_seq_setup(server->nfs4_state->cl_session, &args.sessargs); return rpc_call_sync(server->client, &msg, 0); } @@ -1019,6 +1107,130 @@ return err; } +int nfs4_session_cons(struct nfs4_client *clp) +{ + struct nfs4_client_session *s = clp->cl_session; + int status; + + if (s == 0) { + s = kmalloc(sizeof(struct nfs4_client_session), GFP_NOIO); + memset(s, 0, sizeof(struct nfs4_client_session)); + s->cs_magic = NFS4_SESS_MAGIC; + spin_lock_init(&s->cs_lock); + init_waitqueue_head(&s->cs_wantSlots); + s->cs_flags = 0; + + clp->cl_session = s; + } else { + if (s->cs_flags & (NFS4_CLSESS_OPERACTIVE|NFS4_CLSESS_FAILED)) + return 0; + } + + /* + * Try to cons up a session + * notice that the args are similar to setcliendid. + * notice that the session struct we have associated with + * the nfs4_state is partially populated... + */ + + struct nfs4_create_clientid_args cc_args = { + .sessargs.session = s, + }; + + struct nfs4_create_clientid_res cc_res; + + + struct rpc_message create_client = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_CLIENTID], + .rpc_argp = &cc_args, + .rpc_resp = &cc_res, + }; + + + { + struct timespec tv; + u32 *tp; + + tv = CURRENT_TIME; + tp = (u32*)cc_args.verifier.data; + *tp++ = (u32)tv.tv_sec; + *tp = (u32)tv.tv_nsec; + } + + /* + * "name" is supposed to be highly unique... + */ + cc_args.name = clp->cl_ipaddr; + + status = rpc_call_sync(clp->cl_rpcclient, &create_client, 0); + if (status) { + printk("nfs4_session_cons: NFS4.0\n"); + s->cs_nfs4version = 0; + goto out; + } + printk("nfs4_session_cons: NFS4.1 -- sessions enabled\n"); + s->cs_nfs4version = 1; + + struct nfs4_create_session_args sess_args = { + .persist = 1, + .maxrequestsize = 32 * 1024, + .maxresponsesize = 32 * 1024, + .maxrequests = NFS4_SESSION_REQUESTS, + .clientid_confirm = 1, + .mode = NFS4_STREAM, + .headerpadsize = 0, + .sessargs.session = s, + }; + + + struct nfs_fsinfo sess_fsinfo; + struct nfs4_create_session_res sess_res = { + .fsinfo = &sess_fsinfo, + .session = s, + }; + + struct rpc_message session = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION], + .rpc_argp = &sess_args, + .rpc_resp = &sess_res, + }; + + memcpy(&sess_args.clientid, &cc_res.clientid, + sizeof(sess_args.clientid)); + sess_args.clientid_confirm = 1; + memcpy(&sess_args.confirm, &cc_res.confirm, sizeof(sess_args.confirm)); + + status = rpc_call_sync(clp->cl_rpcclient, &session, 0); + if (status) { + goto out; + } + + memcpy(s->cs_sessions, sess_res.sessionid, sizeof(s->cs_sessions)); + s->cs_persists = sess_res.persist; + s->cs_totalrequests = NFS4_SESSION_REQUESTS; + if (sess_res.maxrequests < s->cs_totalrequests) + s->cs_totalrequests = sess_res.maxrequests; +printk("nfs4_session_cons: req %d\n", s->cs_totalrequests); +printk("nfs4_session_cons: maxresponse %d\n", sess_res.maxresponsesize); + + memcpy(&clp->cl_clientid, &cc_res.clientid, sizeof(clp->cl_clientid)); + memcpy(&clp->cl_confirm, &cc_res.confirm, sizeof(clp->cl_confirm)); + + /* + * we only add SEQUENCE ONCE we got sessions done... + */ + s->cs_flags |= NFS4_CLSESS_OPERACTIVE; + /* note: +8 for the additinoal opcode header... */ + s->cs_xdr_inline = (sizeof(s->cs_sessions)+4+4+4+8) >> 2; +printk("nfs4_session_cons: bytes: %d\n", (sizeof(s->cs_sessions)+4+4+4)); +printk("nfs4_session_cons: words: %d\n", s->cs_xdr_inline); + + + out: + return status; + +} + static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { @@ -1043,6 +1255,18 @@ }; int status; + + /* + * Try to cons up a session + */ + nfs4_session_cons(server->nfs4_state); + /* + * don't forget to stuff the session into the result struct + */ + res.session = server->nfs4_state->cl_session; + + + /* * Now we do a separate LOOKUP for each component of the mount path. * The LOOKUPs are done separately so that we can conveniently @@ -1067,6 +1291,7 @@ do { fattr->valid = 0; + nfs_seq_setup(server->nfs4_state->cl_session, &args.sessargs); status = nfs4_handle_exception(server, rpc_call_sync(server->client, &msg, 0), &exception); @@ -1083,6 +1308,12 @@ status = nfs4_server_capabilities(server, fhandle); if (status == 0) status = nfs4_do_fsinfo(server, fhandle, info); + if (status == 0) { + spin_lock(&server->nfs4_state->cl_lock); + server->nfs4_state->cl_lease_time = info->lease_time * HZ; + server->nfs4_state->cl_last_renewal = (unsigned long)jiffies; + spin_unlock(&server->nfs4_state->cl_lock); + } out: return status; } @@ -1096,6 +1327,7 @@ struct nfs4_getattr_res res = { .fattr = fattr, .server = server, + .session = server->nfs4_state->cl_session, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR], @@ -1105,6 +1337,7 @@ }; fattr->valid = 0; + nfs_seq_setup(server->nfs4_state->cl_session, &args.sessargs); return rpc_call_sync(server->client, &msg, 0); } @@ -1185,6 +1418,7 @@ .server = server, .fattr = fattr, .fh = fhandle, + .session = NFS_SERVER(dir)->nfs4_state->cl_session, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], @@ -1196,6 +1430,7 @@ fattr->valid = 0; dprintk("NFS call lookup %s\n", name->name); + nfs_seq_setup(NFS_SERVER(dir)->nfs4_state->cl_session, &args.sessargs); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); dprintk("NFS reply lookup: %d\n", status); return status; @@ -1218,7 +1453,10 @@ struct nfs4_accessargs args = { .fh = NFS_FH(inode), }; - struct nfs4_accessres res = { 0 }; + struct nfs4_accessres res = { + .supported = 0, + .session = NFS_SERVER(inode)->nfs4_state->cl_session, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], .rpc_argp = &args, @@ -1245,6 +1483,7 @@ if (mode & MAY_EXEC) args.access |= NFS4_ACCESS_EXECUTE; } + nfs_seq_setup(NFS_SERVER(inode)->nfs4_state->cl_session, &args.sessargs); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (!status) { entry->mask = 0; @@ -1306,10 +1545,11 @@ struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], .rpc_argp = &args, - .rpc_resp = NULL, + .rpc_resp = NFS_SERVER(inode)->nfs4_state->cl_session, .rpc_iosp = NFS_SERVER(inode)->rio_stats, }; + nfs_seq_setup(NFS_SERVER(inode)->nfs4_state->cl_session, &args.sessargs); return rpc_call_sync(NFS_CLIENT(inode), &msg, 0); } @@ -1346,6 +1586,8 @@ (long long) rdata->args.offset); fattr->valid = 0; + rdata->res.session = NFS_SERVER(inode)->nfs4_state->cl_session; + nfs_seq_setup(NFS_SERVER(inode)->nfs4_state->cl_session, &rdata->args.sessargs); status = rpc_call_sync(server->client, &msg, flags); if (!status) renew_lease(server, timestamp); @@ -1384,6 +1626,8 @@ (long long) wdata->args.offset); fattr->valid = 0; + wdata->res.session = NFS_SERVER(inode)->nfs4_state->cl_session; + nfs_seq_setup(NFS_SERVER(inode)->nfs4_state->cl_session, &wdata->args.sessargs); status = rpc_call_sync(server->client, &msg, rpcflags); dprintk("NFS reply write: %d\n", status); return status; @@ -1419,6 +1663,7 @@ (long long) cdata->args.offset); fattr->valid = 0; + nfs_seq_setup(server->nfs4_state->cl_session, &cdata->args.sessargs); status = rpc_call_sync(server->client, &msg, 0); dprintk("NFS reply commit: %d\n", status); return status; @@ -1490,7 +1735,10 @@ .fh = NFS_FH(dir), .name = name, }; - struct nfs4_change_info res; + struct nfs4_remove_res res = { + .session = NFS_SERVER(dir)->nfs4_state->cl_session, + }; + struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE], .rpc_argp = &args, @@ -1499,9 +1747,10 @@ }; int status; + nfs_seq_setup(NFS_SERVER(dir)->nfs4_state->cl_session, &args.sessargs); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (status == 0) - update_changeattr(dir, &res); + update_changeattr(dir, &res.cinfo); return status; } @@ -1519,7 +1768,7 @@ struct unlink_desc { struct nfs4_remove_arg args; - struct nfs4_change_info res; + struct nfs4_remove_res res; }; static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, @@ -1533,10 +1782,12 @@ up->args.fh = NFS_FH(dir->d_inode); up->args.name = name; + up->res.session = NFS_SERVER(dir->d_inode)->nfs4_state->cl_session; msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; msg->rpc_argp = &up->args; msg->rpc_resp = &up->res; + nfs_seq_setup(NFS_SERVER(dir->d_inode)->nfs4_state->cl_session, &up->args.sessargs); msg->rpc_iosp = NFS_SERVER(dir->d_inode)->rio_stats; return 0; } @@ -1548,7 +1799,7 @@ if (msg->rpc_resp != NULL) { up = container_of(msg->rpc_resp, struct unlink_desc, res); - update_changeattr(dir->d_inode, &up->res); + update_changeattr(dir->d_inode, &up->res.cinfo); kfree(up); msg->rpc_resp = NULL; msg->rpc_argp = NULL; @@ -1565,7 +1816,9 @@ .old_name = old_name, .new_name = new_name, }; - struct nfs4_rename_res res = { }; + struct nfs4_rename_res res = { + .session = NFS_SERVER(old_dir)->nfs4_state->cl_session, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], .rpc_argp = &arg, @@ -1574,6 +1827,7 @@ }; int status; + nfs_seq_setup(NFS_SERVER(old_dir)->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); if (!status) { @@ -1605,14 +1859,19 @@ .name = name, }; struct nfs4_change_info cinfo = { }; + struct nfs4_link_res res = { + .cinfo = &cinfo, + .session = NFS_SERVER(dir)->nfs4_state->cl_session, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], .rpc_argp = &arg, - .rpc_resp = &cinfo, + .rpc_resp = &res, .rpc_iosp = NFS_SERVER(inode)->rio_stats, }; int status; + nfs_seq_setup(NFS_SERVER(dir)->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (!status) update_changeattr(dir, &cinfo); @@ -1649,6 +1908,7 @@ .server = server, .fh = fhandle, .fattr = fattr, + .session = NFS_SERVER(dir)->nfs4_state->cl_session, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK], @@ -1663,6 +1923,7 @@ arg.u.symlink = path; fattr->valid = 0; + nfs_seq_setup(NFS_SERVER(dir)->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (!status) update_changeattr(dir, &res.dir_cinfo); @@ -1702,6 +1963,7 @@ .server = server, .fh = &fhandle, .fattr = &fattr, + .session = NFS_SERVER(dir)->nfs4_state->cl_session, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], @@ -1713,6 +1975,7 @@ fattr.valid = 0; + nfs_seq_setup(NFS_SERVER(dir)->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (!status) { update_changeattr(dir, &res.dir_cinfo); @@ -1738,17 +2001,20 @@ u64 cookie, struct page *page, unsigned int count, int plus) { struct inode *dir = dentry->d_inode; - struct nfs4_readdir_arg args = { + struct nfs_server *server = NFS_SERVER(dentry->d_inode); + struct nfs4_readdir_arg arg = { .fh = NFS_FH(dir), .pages = &page, .pgbase = 0, .count = count, - .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, + .bitmask = server->attr_bitmask, + }; + struct nfs4_readdir_res res = { + .session = server->nfs4_state->cl_session, }; - struct nfs4_readdir_res res; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR], - .rpc_argp = &args, + .rpc_argp = &arg, .rpc_resp = &res, .rpc_cred = cred, .rpc_iosp = NFS_SERVER(dir)->rio_stats, @@ -1760,8 +2026,10 @@ dentry->d_name.name, (unsigned long long)cookie); - nfs4_setup_readdir(cookie, dentry, &args); - res.pgbase = args.pgbase; + nfs4_setup_readdir(cookie, dentry, &arg); + res.pgbase = arg.pgbase; + nfs_seq_setup(server->nfs4_state->cl_session, &arg.sessargs); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (status == 0) nfs4_save_verifier(dir, &res.verifier); @@ -1800,6 +2068,7 @@ .server = server, .fh = &fh, .fattr = &fattr, + .session = NFS_SERVER(dir)->nfs4_state->cl_session, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], @@ -1829,6 +2098,7 @@ else arg.ftype = NF4SOCK; + nfs_seq_setup(NFS_SERVER(dir)->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (status == 0) { update_changeattr(dir, &res.dir_cinfo); @@ -1857,14 +2127,19 @@ .fh = fhandle, .bitmask = server->attr_bitmask, }; + struct nfs4_statfs_res res = { + .fsstat = fsstat, + .session = server->nfs4_state->cl_session, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], .rpc_argp = &args, - .rpc_resp = fsstat, + .rpc_resp = &res, .rpc_iosp = server->rio_stats, }; fsstat->fattr->valid = 0; + nfs_seq_setup(server->nfs4_state->cl_session, &args.sessargs); return rpc_call_sync(server->client, &msg, 0); } @@ -1887,13 +2162,18 @@ .fh = fhandle, .bitmask = server->attr_bitmask, }; + struct nfs4_fsinfo_res res = { + .fsinfo = fsinfo, + .session = server->nfs4_state->cl_session, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], .rpc_argp = &args, - .rpc_resp = fsinfo, + .rpc_resp = &res, .rpc_iosp = server->rio_stats, }; + nfs_seq_setup(server->nfs4_state->cl_session, &args.sessargs); return rpc_call_sync(server->client, &msg, 0); } @@ -1923,10 +2203,14 @@ .fh = fhandle, .bitmask = server->attr_bitmask, }; + struct nfs4_pathconf_res res = { + .nfs_pathconf = pathconf, + .session = server->nfs4_state->cl_session, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], .rpc_argp = &args, - .rpc_resp = pathconf, + .rpc_resp = &res, .rpc_iosp = server->rio_stats, }; @@ -1936,6 +2220,7 @@ return 0; } + nfs_seq_setup(server->nfs4_state->cl_session, &args.sessargs); pathconf->fattr->valid = 0; return rpc_call_sync(server->client, &msg, 0); } @@ -1989,6 +2274,9 @@ /* N.B. Do we need to test? Never called for swapfile inode */ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); + nfs_seq_setup(NFS_SERVER(inode)->nfs4_state->cl_session, &data->args.sessargs); + data->res.session = NFS_SERVER(inode)->nfs4_state->cl_session; + /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs4_read_done, flags); rpc_call_setup(task, &msg, 0); @@ -2040,6 +2328,9 @@ /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; + nfs_seq_setup(NFS_SERVER(inode)->nfs4_state->cl_session, &data->args.sessargs); + data->res.session = NFS_SERVER(inode)->nfs4_state->cl_session; + /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags); rpc_call_setup(task, &msg, 0); @@ -2075,6 +2366,8 @@ /* Set the initial flags for the task. */ flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; + nfs_seq_setup(NFS_SERVER(inode)->nfs4_state->cl_session, &data->args.sessargs); + data->res.session = NFS_SERVER(inode)->nfs4_state->cl_session; /* Finalize the task. */ rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags); @@ -2118,9 +2411,11 @@ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], .rpc_argp = clp, .rpc_cred = clp->cl_cred, + .rpc_resp = clp, .rpc_iosp = NULL, }; + nfs_seq_setup(clp->cl_session, &clp->cl_seqargs); return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, renew_done, (void *)jiffies); } @@ -2132,11 +2427,13 @@ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], .rpc_argp = clp, .rpc_cred = clp->cl_cred, + .rpc_resp = clp, .rpc_iosp = NULL, }; unsigned long now = jiffies; int status; + nfs_seq_setup(clp->cl_session, &clp->cl_seqargs); status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); if (status < 0) return status; @@ -2302,17 +2599,22 @@ static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) { struct page *pages[NFS4ACL_MAXPAGES]; + struct nfs4_client_session * sess = NFS_SERVER(inode)->nfs4_state->cl_session; struct nfs_getaclargs args = { .fh = NFS_FH(inode), .acl_pages = pages, .acl_len = buflen, }; + struct nfs_getaclres res = { + .acl_len = buflen, + .session = sess, + }; size_t resp_len = buflen; void *resp_buf; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], .rpc_argp = &args, - .rpc_resp = &resp_len, + .rpc_resp = &res, .rpc_iosp = NFS_SERVER(inode)->rio_stats, }; struct page *localpage = NULL; @@ -2327,26 +2629,27 @@ return -ENOMEM; args.acl_pages[0] = localpage; args.acl_pgbase = 0; - args.acl_len = PAGE_SIZE; + res.acl_len = args.acl_len = PAGE_SIZE; } else { resp_buf = buf; buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); } + nfs_seq_setup(sess, &args.sessargs); ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (ret) goto out_free; - if (resp_len > args.acl_len) - nfs4_write_cached_acl(inode, NULL, resp_len); + if (res.acl_len > args.acl_len) + nfs4_write_cached_acl(inode, NULL, res.acl_len); else - nfs4_write_cached_acl(inode, resp_buf, resp_len); + nfs4_write_cached_acl(inode, resp_buf, res.acl_len); if (buf) { ret = -ERANGE; - if (resp_len > buflen) + if (res.acl_len > buflen) goto out_free; if (localpage) - memcpy(buf, resp_buf, resp_len); + memcpy(buf, resp_buf, res.acl_len); } - ret = resp_len; + ret = res.acl_len; out_free: if (localpage) __free_page(localpage); @@ -2381,7 +2684,7 @@ struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], .rpc_argp = &arg, - .rpc_resp = NULL, + .rpc_resp = server->nfs4_state->cl_session, .rpc_iosp = server->rio_stats, }; int ret; @@ -2389,6 +2692,7 @@ if (!nfs4_server_supports_acls(server)) return -EOPNOTSUPP; buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); + nfs_seq_setup(server->nfs4_state->cl_session, &arg.sessargs); ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); if (ret == 0) nfs4_write_cached_acl(inode, buf, buflen); @@ -2493,6 +2797,7 @@ break; case -NFS4ERR_GRACE: case -NFS4ERR_DELAY: +printk("schedule_timeout: timeout %ld\n", exception->timeout); ret = nfs4_delay(server->client, &exception->timeout); if (ret == 0) exception->retry = 1; @@ -2539,6 +2844,7 @@ sizeof(setclientid.sc_uaddr), "%s.%d.%d", clp->cl_ipaddr, port >> 8, port & 255); + nfs_seq_setup(clp->cl_session, &setclientid.sc_sessargs); status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); if (status != -NFS4ERR_CLID_INUSE) break; @@ -2557,16 +2863,24 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp) { struct nfs_fsinfo fsinfo; + struct nfs4_setclientid_confirm_arg arg = { + .clp = clp, + }; + struct nfs4_setclientid_confirm_res res = { + .fsinfo = &fsinfo, + .session = clp->cl_session, + }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], - .rpc_argp = clp, - .rpc_resp = &fsinfo, + .rpc_argp = &arg, + .rpc_resp = &res, .rpc_cred = clp->cl_cred, .rpc_iosp = NULL, }; unsigned long now; int status; + nfs_seq_setup(clp->cl_session, &arg.sessargs); now = jiffies; status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); if (status == 0) { @@ -2588,9 +2902,12 @@ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN], .rpc_argp = &args, .rpc_cred = cred, + .rpc_resp = NFS_SERVER(inode)->nfs4_state->cl_session, .rpc_iosp = NFS_SERVER(inode)->rio_stats, }; + nfs_seq_setup(NFS_SERVER(inode)->nfs4_state->cl_session, + &args.sessargs); return rpc_call_sync(NFS_CLIENT(inode), &msg, 0); } @@ -2666,7 +2983,9 @@ }; struct nfs_lockres res = { .server = server, + .session = server->nfs4_state->cl_session, }; + struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT], .rpc_argp = &arg, @@ -2687,6 +3006,7 @@ lsp = request->fl_u.nfs4_fl.owner; nlo.id = lsp->ls_id; arg.u.lockt = &nlo; + nfs_seq_setup(server->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(server->client, &msg, 0); if (!status) { request->fl_type = F_UNLCK; @@ -2757,6 +3077,7 @@ }; struct nfs_lockres res = { .server = server, + .session = server->nfs4_state->cl_session, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], @@ -2781,6 +3102,8 @@ luargs.seqid = lsp->ls_seqid; memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); arg.u.locku = &luargs; + + nfs_seq_setup(server->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); nfs4_increment_lock_seqid(status, lsp); @@ -2821,6 +3144,7 @@ }; struct nfs_lockres res = { .server = server, + .session = server->nfs4_state->cl_session, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], @@ -2851,6 +3175,7 @@ arg.u.lock = &largs; down(&owner->so_sema); otl.open_seqid = owner->so_seqid; + nfs_seq_setup(server->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); /* increment open_owner seqid on success, and * seqid mutating errors */ @@ -2867,6 +3192,7 @@ memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); largs.u.exist_lock = ⪙ arg.u.lock = &largs; + nfs_seq_setup(server->nfs4_state->cl_session, &arg.sessargs); status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); /* increment seqid on success, and * seqid mutating errors*/ nfs4_increment_lock_seqid(status, lsp); Index: linux-sessions-2.6.14/fs/nfs/nfs4renewd.c =================================================================== --- linux-sessions-2.6.14.orig/fs/nfs/nfs4renewd.c 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/fs/nfs/nfs4renewd.c 2005-11-29 16:11:14.000000000 -0500 @@ -102,6 +102,7 @@ { long timeout; + spin_lock(&clp->cl_lock); timeout = (2 * clp->cl_lease_time) / 3 + (long)clp->cl_last_renewal - (long)jiffies; Index: linux-sessions-2.6.14/fs/nfs/nfs4state.c =================================================================== --- linux-sessions-2.6.14.orig/fs/nfs/nfs4state.c 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/fs/nfs/nfs4state.c 2005-12-03 15:13:01.000000000 -0500 @@ -203,9 +203,15 @@ static int __nfs4_init_client(struct nfs4_client *clp) { - int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, nfs_callback_tcpport); - if (status == 0) - status = nfs4_proc_setclientid_confirm(clp); + int status = nfs4_session_cons(clp); + /* + * fallback to non session based code + */ + if (status != 0) { + status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, nfs_callback_tcpport); + if (status == 0) + status = nfs4_proc_setclientid_confirm(clp); + } if (status == 0) nfs4_schedule_state_renewal(clp); return status; @@ -476,6 +482,7 @@ list_del(&state->open_states); iput(inode); BUG_ON (state->state != 0); + /* BUG_ON (state->state != 0); */ nfs4_free_open_state(state); nfs4_put_state_owner(owner); } @@ -841,6 +848,8 @@ daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr)); allow_signal(SIGKILL); + printk( "RECLAIMER %s %d\n", __LINE__, args); + atomic_inc(&clp->cl_count); complete(&args->complete); Index: linux-sessions-2.6.14/fs/nfs/nfs4xdr.c =================================================================== --- linux-sessions-2.6.14.orig/fs/nfs/nfs4xdr.c 2005-11-29 16:11:13.000000000 -0500 +++ linux-sessions-2.6.14/fs/nfs/nfs4xdr.c 2005-12-03 15:13:01.000000000 -0500 @@ -71,10 +71,13 @@ * we currently use size 1 (u32) out of (NFS4_OPAQUE_LIMIT >> 2) */ #define owner_id_maxsz (1 + 1) +#define encode_sequence_maxsz (6) +#define decode_sequence_maxsz (5) #define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) #define compound_decode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) #define op_encode_hdr_maxsz (1) #define op_decode_hdr_maxsz (2) + #define encode_putfh_maxsz (op_encode_hdr_maxsz + 1 + \ (NFS4_FHSIZE >> 2)) #define decode_putfh_maxsz (op_decode_hdr_maxsz) @@ -298,9 +301,14 @@ decode_putrootfh_maxsz + \ decode_getattr_maxsz + \ decode_getfh_maxsz) +#if 0 +#define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz) +#else #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_remove_maxsz) +#endif #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ op_decode_hdr_maxsz + 5) @@ -380,6 +388,18 @@ decode_putfh_maxsz + \ op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) +/* XXXX */ + +#define NFS4_dec_create_clientid_sz compound_decode_hdr_maxsz + 4 +#define NFS4_enc_create_clientid_sz compound_decode_hdr_maxsz + 4 +#define NFS4_dec_create_session_sz compound_decode_hdr_maxsz + 4 +#define NFS4_enc_create_session_sz compound_decode_hdr_maxsz + 4 +#define NFS4_dec_bind_backchannel_sz compound_decode_hdr_maxsz + 4 +#define NFS4_enc_bind_backchannel_sz compound_decode_hdr_maxsz + 4 +#define NFS4_dec_destroy_session_sz compound_decode_hdr_maxsz + 4 +#define NFS4_enc_destroy_session_sz compound_decode_hdr_maxsz + 4 + + static struct { unsigned int mode; unsigned int nfs2type; @@ -437,7 +457,26 @@ xdr_encode_opaque(p, str, len); } -static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) +static int +encode_sequence(struct xdr_stream *xdr, const struct nfs4_sequence_args *sa) +{ + struct nfs4_client_session *sess = sa->session; + uint32_t *p; + + dprintk("encode_sequence: seqId %d slotId %d maxslot %d\n", + sa->seqId, sa->slotId, sa->maxslot); + RESERVE_SPACE(4+ + sizeof(sess->cs_sessions)+4+4+4+4); + WRITE32(OP_SEQUENCE); + WRITEMEM(sess->cs_sessions, sizeof(sess->cs_sessions)); + WRITE32(sa->seqId); + WRITE32(sa->slotId); + WRITE32(sa->maxslot); + WRITE32(NFS4_NOCHAIN); + return 0; +} + +static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr, const struct nfs4_sequence_args *sa) { uint32_t *p; @@ -446,8 +485,16 @@ RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); WRITE32(hdr->taglen); WRITEMEM(hdr->tag, hdr->taglen); - WRITE32(NFS4_MINOR_VERSION); - WRITE32(hdr->nops); + WRITE32(sa->session->cs_nfs4version); + + /* NFS 4.1 related session encoding */ + if (sa->session->cs_flags & NFS4_CLSESS_OPERACTIVE) { + WRITE32(hdr->nops+1); + return encode_sequence(xdr, sa); + } else { + WRITE32(hdr->nops); + } + return 0; } @@ -591,6 +638,8 @@ { uint32_t *p; + dprintk("encode_access\n"); + RESERVE_SPACE(8); WRITE32(OP_ACCESS); WRITE32(access); @@ -601,6 +650,7 @@ static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg) { uint32_t *p; + dprintk("encode_close\n"); RESERVE_SPACE(8+sizeof(arg->stateid.data)); WRITE32(OP_CLOSE); @@ -612,6 +662,7 @@ static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args) { + dprintk("encode_commit\n"); uint32_t *p; RESERVE_SPACE(16); @@ -625,6 +676,7 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create) { uint32_t *p; + dprintk("encode_create\n"); RESERVE_SPACE(8); WRITE32(OP_CREATE); @@ -657,6 +709,7 @@ static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap) { uint32_t *p; + dprintk("encode_getattr_one\n"); RESERVE_SPACE(12); WRITE32(OP_GETATTR); @@ -668,6 +721,7 @@ static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1) { uint32_t *p; + dprintk("encode_getattr_two\n"); RESERVE_SPACE(16); WRITE32(OP_GETATTR); @@ -686,6 +740,7 @@ static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask) { + dprintk("encode_fsinfo\n"); return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], bitmask[1] & nfs4_fsinfo_bitmap[1]); } @@ -693,6 +748,7 @@ static int encode_getfh(struct xdr_stream *xdr) { uint32_t *p; + dprintk("encode_getfh\n"); RESERVE_SPACE(4); WRITE32(OP_GETFH); @@ -703,6 +759,7 @@ static int encode_link(struct xdr_stream *xdr, const struct qstr *name) { uint32_t *p; + dprintk("encode_link\n"); RESERVE_SPACE(8 + name->len); WRITE32(OP_LINK); @@ -712,6 +769,17 @@ return 0; } +static +uint32_t * +encode_clientid(uint32_t *p, clientid4 clientid) +{ + WRITEMEM(&clientid, 8); + + return p; + +} + + /* * opcode,type,reclaim,offset,length,new_lock_owner = 32 * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 @@ -735,7 +803,7 @@ WRITE32(ol->open_seqid); WRITEMEM(&ol->open_stateid, sizeof(ol->open_stateid)); WRITE32(ol->lock_seqid); - WRITE64(ol->lock_owner.clientid); + p = encode_clientid(p, ol->lock_owner.clientid); WRITE32(4); WRITE32(ol->lock_owner.id); } @@ -760,7 +828,7 @@ WRITE32(arg->type); WRITE64(arg->offset); WRITE64(arg->length); - WRITE64(opargs->clientid); + p = encode_clientid(p, opargs->clientid); WRITE32(4); WRITE32(opargs->id); @@ -824,12 +892,13 @@ * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4, * owner 4 = 32 */ + dprintk("encode_openhdr\n"); RESERVE_SPACE(8); WRITE32(OP_OPEN); WRITE32(arg->seqid); encode_share_access(xdr, arg->open_flags); RESERVE_SPACE(16); - WRITE64(arg->clientid); + p = encode_clientid(p, arg->clientid); WRITE32(4); WRITE32(arg->id); } @@ -916,6 +985,7 @@ static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg) { + dprintk("encode_open\n"); encode_openhdr(xdr, arg); encode_opentype(xdr, arg); switch (arg->claim) { @@ -937,6 +1007,7 @@ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg) { uint32_t *p; + dprintk("encode_confirm\n"); RESERVE_SPACE(8+sizeof(arg->stateid.data)); WRITE32(OP_OPEN_CONFIRM); @@ -975,6 +1046,7 @@ static int encode_putrootfh(struct xdr_stream *xdr) { uint32_t *p; + dprintk("encode_putrootfh\n"); RESERVE_SPACE(4); WRITE32(OP_PUTROOTFH); @@ -998,6 +1070,7 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) { uint32_t *p; + dprintk("encode_read\n"); RESERVE_SPACE(4); WRITE32(OP_READ); @@ -1020,6 +1093,7 @@ }; int replen; uint32_t *p; + dprintk("encode_readdir\n"); RESERVE_SPACE(32+sizeof(nfs4_verifier)); WRITE32(OP_READDIR); @@ -1047,7 +1121,8 @@ * toplevel_status + taglen + rescount + OP_PUTFH + status * + OP_READDIR + status + verifer(2) = 9 */ - replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; + replen = (RPC_REPHDRSIZE + auth->au_rslack + 9 + + readdir->sessargs.session->cs_xdr_inline) << 2; xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages, readdir->pgbase, readdir->count); dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", @@ -1061,6 +1136,7 @@ { struct rpc_auth *auth = req->rq_task->tk_auth; unsigned int replen; + int cs_xdr_inline = readlink->sessargs.session->cs_xdr_inline; uint32_t *p; RESERVE_SPACE(4); @@ -1070,10 +1146,9 @@ * toplevel_status + taglen + rescount + OP_PUTFH + status * + OP_READLINK + status + string length = 8 */ - replen = (RPC_REPHDRSIZE + auth->au_rslack + 8) << 2; + replen = (RPC_REPHDRSIZE + auth->au_rslack + 8 + cs_xdr_inline) << 2; xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, readlink->pgbase, readlink->pglen); - return 0; } @@ -1111,7 +1186,7 @@ RESERVE_SPACE(12); WRITE32(OP_RENEW); - WRITE64(client_stateid->cl_clientid); + p = encode_clientid(p, client_stateid->cl_clientid); return 0; } @@ -1164,6 +1239,7 @@ static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid) { uint32_t *p; + dprintk("encode_setclientid\n"); RESERVE_SPACE(4 + sizeof(setclientid->sc_verifier->data)); WRITE32(OP_SETCLIENTID); @@ -1186,7 +1262,7 @@ RESERVE_SPACE(12 + sizeof(client_state->cl_confirm.data)); WRITE32(OP_SETCLIENTID_CONFIRM); - WRITE64(client_state->cl_clientid); + p = encode_clientid(p, client_state->cl_clientid); WRITEMEM(client_state->cl_confirm.data, sizeof(client_state->cl_confirm.data)); return 0; @@ -1195,6 +1271,7 @@ static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args) { uint32_t *p; + dprintk("encode_write\n"); RESERVE_SPACE(4); WRITE32(OP_WRITE); @@ -1222,6 +1299,100 @@ return 0; } + +static int +encode_create_clientid(struct xdr_stream *xdr, struct nfs4_create_clientid_args *args) +{ + uint32_t *p; + int len; + dprintk("encode_create_clientid\n"); + + len = strlen(args->name); + RESERVE_SPACE(4 + sizeof(args->verifier) + 4 + len); + WRITE32(OP_CREATECLIENTID); + + WRITEMEM(&args->verifier, sizeof(args->verifier)); + WRITE32(len); + WRITEMEM(args->name, len); + + return 0; +} + +static int +encode_create_session(struct xdr_stream *xdr, struct nfs4_create_session_args *args) +{ + uint32_t *p; + dprintk("encode_create_session\n"); + + RESERVE_SPACE(4 + sizeof(args->clientid) + + (6 * 4)); + WRITE32(OP_CREATESESSION); + p = encode_clientid(p, args->clientid); + WRITE32(args->persist); /* 1 */ + WRITE32(args->maxrequestsize); /* 2 */ + WRITE32(args->maxresponsesize); /* 3 */ + WRITE32(args->maxrequests); /* 4 */ + WRITE32(args->headerpadsize); /* 5 */ + WRITE32(args->clientid_confirm); /* 6 */ + if (args->clientid_confirm) { + RESERVE_SPACE(sizeof(args->confirm)); + WRITEMEM(&args->confirm, sizeof(args->confirm)); + } + RESERVE_SPACE(sizeof(args->mode)); + WRITE32(args->mode); + switch (args->mode) { + case NFS4_RDMA: + RESERVE_SPACE(4); + WRITE32(args->maxrdmareads); + case NFS4_DEFAULT: + case NFS4_STREAM: + ; + } + + return 0; +} + +static int +encode_bind_backchannel(struct xdr_stream *xdr, struct nfs4_bind_backchannel_args *args) +{ + uint32_t *p; + dprintk("encode_bind_backchannel\n"); + + RESERVE_SPACE(4 + sizeof(args->clientid) + 6 * 4); + + WRITE32(OP_BIND_BACKCHANNEL); + p = encode_clientid(p, args->clientid); + WRITE32(args->callback_prog); /* 1 */ + WRITE32(args->callback_ident); /* 2 */ + WRITE32(args->maxreqsize); /* 3 */ + WRITE32(args->maxrespsize); /* 4 */ + WRITE32(args->maxreqs); /* 5 */ + WRITE32(args->mode); /* 6 */ + + switch (args->mode) { + case NFS4_RDMA: + RESERVE_SPACE(4); + WRITE32(args->maxrdmareads); + case NFS4_DEFAULT: + case NFS4_STREAM: + ; + } + + return 0; +} + +static int +encode_destroy_session(struct xdr_stream *xdr) +{ + uint32_t *p; + dprintk("encode_destroy_session\n"); + + RESERVE_SPACE(sizeof(int)); + WRITE32(OP_DESTROYSESSION); + return 0; +} + + /* * END OF "GENERIC" ENCODE ROUTINES. */ @@ -1238,7 +1409,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); if ((status = encode_putfh(&xdr, args->fh)) == 0) status = encode_access(&xdr, args->access); return status; @@ -1256,7 +1427,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) goto out; if ((status = encode_lookup(&xdr, args->name)) != 0) @@ -1278,9 +1449,10 @@ .nops = 3, }; int status; + dprintk("encode_lookup_root\n"); xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); if ((status = encode_putrootfh(&xdr)) != 0) goto out; if ((status = encode_getfh(&xdr)) == 0) @@ -1301,7 +1473,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); if ((status = encode_putfh(&xdr, args->fh)) == 0) status = encode_remove(&xdr, args->name); return status; @@ -1319,7 +1491,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); if ((status = encode_putfh(&xdr, args->old_dir)) != 0) goto out; if ((status = encode_savefh(&xdr)) != 0) @@ -1343,7 +1515,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); if ((status = encode_putfh(&xdr, args->fh)) != 0) goto out; if ((status = encode_savefh(&xdr)) != 0) @@ -1367,7 +1539,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); if ((status = encode_putfh(&xdr, args->dir_fh)) != 0) goto out; if ((status = encode_create(&xdr, args)) != 0) @@ -1399,7 +1571,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); if ((status = encode_putfh(&xdr, args->fh)) == 0) status = encode_getfattr(&xdr, args->bitmask); return status; @@ -1417,7 +1589,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if(status) goto out; @@ -1438,7 +1610,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if (status) goto out; @@ -1465,7 +1637,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if(status) goto out; @@ -1486,7 +1658,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if (status) goto out; @@ -1507,7 +1679,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if (status) goto out; @@ -1528,7 +1700,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if(status) goto out; @@ -1549,7 +1721,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if(status) goto out; @@ -1570,7 +1742,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if(status) goto out; @@ -1591,7 +1763,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if(status) goto out; @@ -1612,7 +1784,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if(status) goto out; @@ -1634,7 +1806,7 @@ int replen, status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if (status) goto out; @@ -1646,7 +1818,8 @@ * toplevel status + taglen=0 + rescount + OP_PUTFH + status * + OP_READ + status + eof + datalen = 9 */ - replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2; + replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz + + args->sessargs.session->cs_xdr_inline) << 2; xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->count); out: @@ -1666,7 +1839,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if(status) goto out; @@ -1693,7 +1866,7 @@ int replen, status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if (status) goto out; @@ -1718,7 +1891,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if (status) goto out; @@ -1739,7 +1912,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if (status) goto out; @@ -1760,7 +1933,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if (!status) status = encode_fsinfo(&xdr, args->bitmask); @@ -1779,7 +1952,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if (!status) status = encode_getattr_one(&xdr, @@ -1799,7 +1972,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if (status == 0) status = encode_getattr_two(&xdr, @@ -1811,7 +1984,7 @@ /* * GETATTR_BITMAP request */ -static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const struct nfs_fh *fhandle) +static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, struct nfs4_server_caps_arg *arg) { struct xdr_stream xdr; struct compound_hdr hdr = { @@ -1820,8 +1993,8 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); - status = encode_putfh(&xdr, fhandle); + encode_compound_hdr(&xdr, &hdr, &arg->sessargs); + status = encode_putfh(&xdr, arg->fhandle); if (status == 0) status = encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| FATTR4_WORD0_LINK_SUPPORT| @@ -1841,12 +2014,13 @@ }; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &clp->cl_seqargs); return encode_renew(&xdr, clp); } /* * a SETCLIENTID request + * (note: SETCLIENTID ought to not happen in for nfs41 sessions) */ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid *sc) { @@ -1856,15 +2030,16 @@ }; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &sc->sc_sessargs); return encode_setclientid(&xdr, sc); } /* * a SETCLIENTID_CONFIRM request */ -static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) +static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid_confirm_arg *arg) { + struct nfs4_client *clp = arg->clp; struct xdr_stream xdr; struct compound_hdr hdr = { .nops = 3, @@ -1873,7 +2048,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &arg->sessargs); status = encode_setclientid_confirm(&xdr, clp); if (!status) status = encode_putrootfh(&xdr); @@ -1894,12 +2069,82 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); if ((status = encode_putfh(&xdr, args->fhandle)) == 0) status = encode_delegreturn(&xdr, args->stateid); return status; } +static int +nfs4_xdr_enc_create_clientid(struct rpc_rqst *req, uint32_t *p, + struct nfs4_create_clientid_args *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 1, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); + status = encode_create_clientid(&xdr, args); + + return status; +} + +static int +nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p, + struct nfs4_create_session_args *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 1, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); + status = encode_create_session(&xdr, args); + + return status; +} + + +static int +nfs4_xdr_enc_bind_backchannel(struct rpc_rqst *req, uint32_t *p, + struct nfs4_bind_backchannel_args *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 1, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); + status = encode_bind_backchannel(&xdr, args); + + return status; +} + +static int +nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p, + struct nfs4_destroy_session_args *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 1, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); + status = encode_destroy_session(&xdr); + + return status; +} + + /* * START OF "GENERIC" DECODE ROUTINES. * These may look a little ugly since they are imported from a "generic" @@ -1945,6 +2190,7 @@ return 0; } + static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { uint32_t *p; @@ -1957,24 +2203,80 @@ hdr->tag = (char *)p; p += XDR_QUADLEN(hdr->taglen); READ32(hdr->nops); + if (hdr->nops == 0) { + printk("decode_compound_hdr: general failure: %d\n", hdr->status); + return -nfs_stat_to_errno(hdr->status);; + } return 0; } -static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) +/* + * decode_sequence + * this is a bit odd... cause its called from decode_op_hdr... + * (the op has already been eaten byt decode_op_hdr + */ +int stupid_debug_crap = 0; + +static int +decode_sequence(struct xdr_stream *xdr, struct nfs4_sequence_res *res, struct nfs4_client_session *sess) +{ + uint32_t *p; + + READ_BUF(sizeof(res->sessionid)+4+4+4); + COPYMEM(&res->sessionid, sizeof(res->sessionid)); + READ32(res->sequenceid); + READ32(res->slotid); + READ32(res->maxslot); + if (stupid_debug_crap) + printk("decode_sequence: slot %d\n", res->slotid); + + if (sess && (res->slotid >= 0) && (res->slotid < NFS4_SESSION_REQUESTS)) { + nfs4_client_unmarkslot(sess, res->slotid); + wake_up(&sess->cs_wantSlots); + } + else + printk("decode_death: %d\n", sess->cs_slotId[0]); + + return NFS_OK; +} + + +static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected, struct nfs4_client_session *sess) { uint32_t *p; uint32_t opnum; int32_t nfserr; + int sequence = 0; + retry: READ_BUF(8); READ32(opnum); if (opnum != expected) { - printk(KERN_NOTICE - "nfs4_decode_op_hdr: Server returned operation" - " %d but we issued a request for %d\n", - opnum, expected); - return -EIO; - } + struct nfs4_sequence_res res; + if (opnum == OP_SEQUENCE) { + /* + * don't forget the sequence status + */ + sequence++; + READ32(nfserr); + if (nfserr != NFS_OK) { + printk("decode_op_hdr: sequence failed %d\n", nfserr); + return -nfs_stat_to_errno(nfserr); + } + if ((nfserr = decode_sequence(xdr, &res, sess)) != NFS_OK) { + return nfserr; + } + goto retry; + } + printk(KERN_NOTICE + "nfs4_decode_op_hdr: Server returned operation" + " %d but we issued a request for %d\n", + opnum, expected); + if (sequence) + printk("nfs4_decode_op_hdr: %d/%d/%d\n", + res.sequenceid, res.slotid, res.maxslot); + return -EIO; + } READ32(nfserr); if (nfserr != NFS_OK) return -nfs_stat_to_errno(nfserr); @@ -2373,8 +2675,8 @@ READ_BUF(len); if (len < XDR_MAX_NETOBJ) { if (nfs_map_name_to_uid(clp, (char *)p, len, uid) != 0) - dprintk("%s: nfs_map_name_to_uid failed!\n", - __FUNCTION__); + dprintk("%s: nfs_map_name_to_uid failed! %s\n", + __FUNCTION__, (char *)p); } else printk(KERN_WARNING "%s: name too long (%u)!\n", __FUNCTION__, len); @@ -2397,8 +2699,8 @@ READ_BUF(len); if (len < XDR_MAX_NETOBJ) { if (nfs_map_group_to_gid(clp, (char *)p, len, gid) != 0) - dprintk("%s: nfs_map_group_to_gid failed!\n", - __FUNCTION__); + dprintk("%s: nfs_map_group_to_gid failed! %s\n", + __FUNCTION__, (char *)p); } else printk(KERN_WARNING "%s: name too long (%u)!\n", __FUNCTION__, len); @@ -2593,7 +2895,7 @@ uint32_t supp, acc; int status; - status = decode_op_hdr(xdr, OP_ACCESS); + status = decode_op_hdr(xdr, OP_ACCESS, access->session); if (status) return status; READ_BUF(8); @@ -2609,7 +2911,7 @@ uint32_t *p; int status; - status = decode_op_hdr(xdr, OP_CLOSE); + status = decode_op_hdr(xdr, OP_CLOSE, res->session); if (status) return status; READ_BUF(sizeof(res->stateid.data)); @@ -2622,7 +2924,7 @@ uint32_t *p; int status; - status = decode_op_hdr(xdr, OP_COMMIT); + status = decode_op_hdr(xdr, OP_COMMIT, res->session); if (status) return status; READ_BUF(8); @@ -2630,16 +2932,16 @@ return 0; } -static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) +static int decode_create(struct xdr_stream *xdr, struct nfs4_create_res *res) { uint32_t *p; uint32_t bmlen; int status; - status = decode_op_hdr(xdr, OP_CREATE); + status = decode_op_hdr(xdr, OP_CREATE, res->session); if (status) return status; - if ((status = decode_change_info(xdr, cinfo))) + if ((status = decode_change_info(xdr, &res->dir_cinfo))) return status; READ_BUF(4); READ32(bmlen); @@ -2654,7 +2956,7 @@ bitmap[2] = {0}; int status; - if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + if ((status = decode_op_hdr(xdr, OP_GETATTR, res->session)) != 0) goto xdr_error; if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) goto xdr_error; @@ -2675,14 +2977,15 @@ return status; } -static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) +static int decode_statfs(struct xdr_stream *xdr, struct nfs4_statfs_res *res) { + struct nfs_fsstat *fsstat = res->fsstat; uint32_t *savep; uint32_t attrlen, bitmap[2] = {0}; int status; - if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + if ((status = decode_op_hdr(xdr, OP_GETATTR, res->session)) != 0) goto xdr_error; if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) goto xdr_error; @@ -2709,14 +3012,15 @@ return status; } -static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf) +static int decode_pathconf(struct xdr_stream *xdr, struct nfs4_pathconf_res *res) { + struct nfs_pathconf *pathconf = res->nfs_pathconf; uint32_t *savep; uint32_t attrlen, bitmap[2] = {0}; int status; - if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + if ((status = decode_op_hdr(xdr, OP_GETATTR, res->session)) != 0) goto xdr_error; if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) goto xdr_error; @@ -2743,7 +3047,7 @@ type; int status, fmode = 0; - if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + if ((status = decode_op_hdr(xdr, OP_GETATTR, server->nfs4_state->cl_session)) != 0) goto xdr_error; if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) goto xdr_error; @@ -2798,13 +3102,13 @@ } -static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) +static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo, struct nfs4_client_session *sess) { uint32_t *savep; uint32_t attrlen, bitmap[2]; int status; - if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + if ((status = decode_op_hdr(xdr, OP_GETATTR, sess)) != 0) goto xdr_error; if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) goto xdr_error; @@ -2831,13 +3135,13 @@ return status; } -static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh) +static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh, struct nfs4_client_session *sess) { uint32_t *p; uint32_t len; int status; - status = decode_op_hdr(xdr, OP_GETFH); + status = decode_op_hdr(xdr, OP_GETFH, sess); if (status) return status; /* Zero handle first to allow comparisons */ @@ -2853,16 +3157,25 @@ return 0; } -static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) +static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo, struct nfs4_client_session *sess) { int status; - status = decode_op_hdr(xdr, OP_LINK); + status = decode_op_hdr(xdr, OP_LINK, sess); if (status) return status; return decode_change_info(xdr, cinfo); } +static +uint32_t * +decode_clientid(uint32_t *p, clientid4 *clientid) +{ + COPYMEM(clientid, 8); + return p; +} + + /* * We create the owner, so we know a proper owner.id length is 4. */ @@ -2875,7 +3188,7 @@ READ64(denied->offset); READ64(denied->length); READ32(denied->type); - READ64(denied->owner.clientid); + p = decode_clientid(p, &denied->owner.clientid); READ32(namelen); READ_BUF(namelen); if (namelen == 4) @@ -2888,7 +3201,7 @@ uint32_t *p; int status; - status = decode_op_hdr(xdr, OP_LOCK); + status = decode_op_hdr(xdr, OP_LOCK, res->session); if (status == 0) { READ_BUF(sizeof(nfs4_stateid)); COPYMEM(&res->u.stateid, sizeof(res->u.stateid)); @@ -2900,7 +3213,7 @@ static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res) { int status; - status = decode_op_hdr(xdr, OP_LOCKT); + status = decode_op_hdr(xdr, OP_LOCKT, res->session); if (status == -NFS4ERR_DENIED) return decode_lock_denied(xdr, &res->u.denied); return status; @@ -2911,7 +3224,7 @@ uint32_t *p; int status; - status = decode_op_hdr(xdr, OP_LOCKU); + status = decode_op_hdr(xdr, OP_LOCKU, res->session); if (status == 0) { READ_BUF(sizeof(nfs4_stateid)); COPYMEM(&res->u.stateid, sizeof(res->u.stateid)); @@ -2919,9 +3232,9 @@ return status; } -static int decode_lookup(struct xdr_stream *xdr) +static int decode_lookup(struct xdr_stream *xdr, struct nfs4_client_session *sess) { - return decode_op_hdr(xdr, OP_LOOKUP); + return decode_op_hdr(xdr, OP_LOOKUP, sess); } /* This is too sick! */ @@ -2976,7 +3289,7 @@ uint32_t bmlen; int status; - status = decode_op_hdr(xdr, OP_OPEN); + status = decode_op_hdr(xdr, OP_OPEN, res->session); if (status) return status; READ_BUF(sizeof(res->stateid.data)); @@ -3003,7 +3316,7 @@ uint32_t *p; int status; - status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); + status = decode_op_hdr(xdr, OP_OPEN_CONFIRM, res->session); if (status) return status; READ_BUF(sizeof(res->stateid.data)); @@ -3016,7 +3329,7 @@ uint32_t *p; int status; - status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE); + status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE, res->session); if (status) return status; READ_BUF(sizeof(res->stateid.data)); @@ -3024,14 +3337,14 @@ return 0; } -static int decode_putfh(struct xdr_stream *xdr) +static int decode_putfh(struct xdr_stream *xdr, struct nfs4_client_session *sess) { - return decode_op_hdr(xdr, OP_PUTFH); + return decode_op_hdr(xdr, OP_PUTFH, sess); } -static int decode_putrootfh(struct xdr_stream *xdr) +static int decode_putrootfh(struct xdr_stream *xdr, struct nfs4_client_session *sess) { - return decode_op_hdr(xdr, OP_PUTROOTFH); + return decode_op_hdr(xdr, OP_PUTROOTFH, sess); } static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res) @@ -3041,7 +3354,7 @@ uint32_t count, eof, recvd, hdrlen; int status; - status = decode_op_hdr(xdr, OP_READ); + status = decode_op_hdr(xdr, OP_READ, res->session); if (status) return status; READ_BUF(8); @@ -3071,7 +3384,7 @@ uint32_t len, attrlen; int hdrlen, recvd, status; - status = decode_op_hdr(xdr, OP_READDIR); + status = decode_op_hdr(xdr, OP_READDIR, readdir->session); if (status) return status; READ_BUF(8); @@ -3135,7 +3448,7 @@ return -errno_NFSERR_IO; } -static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) +static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_client_session *sess) { struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct kvec *iov = rcvbuf->head; @@ -3144,7 +3457,7 @@ char *kaddr; int status; - status = decode_op_hdr(xdr, OP_READLINK); + status = decode_op_hdr(xdr, OP_READLINK, sess); if (status) return status; @@ -3176,24 +3489,25 @@ return 0; } -static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo) +static int decode_remove(struct xdr_stream *xdr, struct nfs4_remove_res *res) { int status; - status = decode_op_hdr(xdr, OP_REMOVE); + status = decode_op_hdr(xdr, OP_REMOVE, res->session); if (status) goto out; - status = decode_change_info(xdr, cinfo); + status = decode_change_info(xdr, &res->cinfo); out: return status; } static int decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo, - struct nfs4_change_info *new_cinfo) + struct nfs4_change_info *new_cinfo, + struct nfs4_client_session *sess) { int status; - status = decode_op_hdr(xdr, OP_RENAME); + status = decode_op_hdr(xdr, OP_RENAME, sess); if (status) goto out; if ((status = decode_change_info(xdr, old_cinfo))) @@ -3203,14 +3517,15 @@ return status; } -static int decode_renew(struct xdr_stream *xdr) +static int decode_renew(struct xdr_stream *xdr, struct nfs4_client_session *sess) { - return decode_op_hdr(xdr, OP_RENEW); + return decode_op_hdr(xdr, OP_RENEW, sess); } static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, - size_t *acl_len) + struct nfs_getaclres * res) { + size_t * acl_len = &res->acl_len; uint32_t *savep; uint32_t attrlen, bitmap[2] = {0}; @@ -3218,7 +3533,7 @@ int status; *acl_len = 0; - if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + if ((status = decode_op_hdr(xdr, OP_GETATTR, res->session)) != 0) goto out; if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) goto out; @@ -3250,19 +3565,19 @@ } static int -decode_savefh(struct xdr_stream *xdr) +decode_savefh(struct xdr_stream *xdr, struct nfs4_client_session *sess) { - return decode_op_hdr(xdr, OP_SAVEFH); + return decode_op_hdr(xdr, OP_SAVEFH, sess); } -static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) +static int decode_setattr(struct xdr_stream *xdr, struct nfs4_client_session *sess) { uint32_t *p; uint32_t bmlen; int status; - status = decode_op_hdr(xdr, OP_SETATTR); + status = decode_op_hdr(xdr, OP_SETATTR, sess); if (status) return status; READ_BUF(4); @@ -3288,7 +3603,7 @@ READ32(nfserr); if (nfserr == NFS_OK) { READ_BUF(8 + sizeof(clp->cl_confirm.data)); - READ64(clp->cl_clientid); + p = decode_clientid(p, &clp->cl_clientid); COPYMEM(clp->cl_confirm.data, sizeof(clp->cl_confirm.data)); } else if (nfserr == NFSERR_CLID_INUSE) { uint32_t len; @@ -3309,9 +3624,9 @@ return 0; } -static int decode_setclientid_confirm(struct xdr_stream *xdr) +static int decode_setclientid_confirm(struct xdr_stream *xdr, struct nfs4_client_session *sess) { - return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM); + return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM, sess); } static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res) @@ -3319,7 +3634,7 @@ uint32_t *p; int status; - status = decode_op_hdr(xdr, OP_WRITE); + status = decode_op_hdr(xdr, OP_WRITE, res->session); if (status) return status; @@ -3330,9 +3645,9 @@ return 0; } -static int decode_delegreturn(struct xdr_stream *xdr) +static int decode_delegreturn(struct xdr_stream *xdr, struct nfs4_client_session *sess) { - return decode_op_hdr(xdr, OP_DELEGRETURN); + return decode_op_hdr(xdr, OP_DELEGRETURN, sess); } /* @@ -3348,7 +3663,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_open_downgrade(&xdr, res); @@ -3372,7 +3687,7 @@ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) goto out; - if ((status = decode_putfh(&xdr)) == 0) + if ((status = decode_putfh(&xdr, res->session)) == 0) status = decode_access(&xdr, res); out: return status; @@ -3390,11 +3705,11 @@ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) goto out; - if ((status = decode_putfh(&xdr)) != 0) + if ((status = decode_putfh(&xdr, res->session)) != 0) goto out; - if ((status = decode_lookup(&xdr)) != 0) + if ((status = decode_lookup(&xdr, res->session)) != 0) goto out; - if ((status = decode_getfh(&xdr, res->fh)) != 0) + if ((status = decode_getfh(&xdr, res->fh, res->session)) != 0) goto out; status = decode_getfattr(&xdr, res->fattr, res->server); out: @@ -3413,9 +3728,9 @@ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) goto out; - if ((status = decode_putrootfh(&xdr)) != 0) + if ((status = decode_putrootfh(&xdr, res->session)) != 0) goto out; - if ((status = decode_getfh(&xdr, res->fh)) == 0) + if ((status = decode_getfh(&xdr, res->fh, res->session)) == 0) status = decode_getfattr(&xdr, res->fattr, res->server); out: return status; @@ -3424,7 +3739,7 @@ /* * Decode REMOVE response */ -static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo) +static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_remove_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3433,8 +3748,8 @@ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) goto out; - if ((status = decode_putfh(&xdr)) == 0) - status = decode_remove(&xdr, cinfo); + if ((status = decode_putfh(&xdr, res->session)) == 0) + status = decode_remove(&xdr, res); out: return status; } @@ -3451,13 +3766,13 @@ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) goto out; - if ((status = decode_putfh(&xdr)) != 0) + if ((status = decode_putfh(&xdr, res->session)) != 0) goto out; - if ((status = decode_savefh(&xdr)) != 0) + if ((status = decode_savefh(&xdr, res->session)) != 0) goto out; - if ((status = decode_putfh(&xdr)) != 0) + if ((status = decode_putfh(&xdr, res->session)) != 0) goto out; - status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo); + status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo, res->session); out: return status; } @@ -3465,7 +3780,7 @@ /* * Decode LINK response */ -static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo) +static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_link_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3474,13 +3789,13 @@ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) goto out; - if ((status = decode_putfh(&xdr)) != 0) + if ((status = decode_putfh(&xdr, res->session)) != 0) goto out; - if ((status = decode_savefh(&xdr)) != 0) + if ((status = decode_savefh(&xdr, res->session)) != 0) goto out; - if ((status = decode_putfh(&xdr)) != 0) + if ((status = decode_putfh(&xdr, res->session)) != 0) goto out; - status = decode_link(&xdr, cinfo); + status = decode_link(&xdr, res->cinfo, res->session); out: return status; } @@ -3497,11 +3812,11 @@ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) goto out; - if ((status = decode_putfh(&xdr)) != 0) + if ((status = decode_putfh(&xdr, res->session)) != 0) goto out; - if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0) + if ((status = decode_create(&xdr, res)) != 0) goto out; - if ((status = decode_getfh(&xdr, res->fh)) != 0) + if ((status = decode_getfh(&xdr, res->fh, res->session)) != 0) goto out; status = decode_getfattr(&xdr, res->fattr, res->server); if (status == NFS4ERR_DELAY) @@ -3531,7 +3846,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_getfattr(&xdr, res->fattr, res->server); @@ -3553,7 +3868,7 @@ int status; xdr_init_encode(&xdr, &req->rq_snd_buf, p); - encode_compound_hdr(&xdr, &hdr); + encode_compound_hdr(&xdr, &hdr, &args->sessargs); status = encode_putfh(&xdr, args->fh); if (status) goto out; @@ -3565,7 +3880,7 @@ * Decode SETACL response */ static int -nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res) +nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_client_session *sess) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3575,10 +3890,10 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, sess); if (status) goto out; - status = decode_setattr(&xdr, res); + status = decode_setattr(&xdr, sess); out: return status; } @@ -3587,7 +3902,7 @@ * Decode GETACL response */ static int -nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, size_t *acl_len) +nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_getaclres *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3597,10 +3912,10 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; - status = decode_getacl(&xdr, rqstp, acl_len); + status = decode_getacl(&xdr, rqstp, res); out: return status; @@ -3619,7 +3934,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_close(&xdr, res); @@ -3640,18 +3955,16 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_open(&xdr, res); if (status) goto out; - status = decode_getfh(&xdr, &res->fh); + status = decode_getfh(&xdr, &res->fh, res->session); if (status) goto out; status = decode_getfattr(&xdr, res->f_attr, res->server); - if (status == NFS4ERR_DELAY) - status = 0; out: return status; } @@ -3669,7 +3982,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_open_confirm(&xdr, res); @@ -3690,7 +4003,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_open(&xdr, res); @@ -3711,10 +4024,10 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; - status = decode_setattr(&xdr, res); + status = decode_setattr(&xdr, res->session); if (status) goto out; status = decode_getfattr(&xdr, res->fattr, res->server); @@ -3737,7 +4050,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_lock(&xdr, res); @@ -3758,7 +4071,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_lockt(&xdr, res); @@ -3779,7 +4092,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_locku(&xdr, res); @@ -3790,7 +4103,7 @@ /* * Decode READLINK response */ -static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, void *res) +static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_client_session *sess) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3800,10 +4113,10 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, sess); if (status) goto out; - status = decode_readlink(&xdr, rqstp); + status = decode_readlink(&xdr, rqstp, sess); out: return status; } @@ -3821,7 +4134,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_readdir(&xdr, rqstp, res); @@ -3842,7 +4155,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_read(&xdr, rqstp, res); @@ -3865,7 +4178,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_write(&xdr, res); @@ -3888,7 +4201,7 @@ status = decode_compound_hdr(&xdr, &hdr); if (status) goto out; - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (status) goto out; status = decode_commit(&xdr, res); @@ -3899,7 +4212,7 @@ /* * FSINFO request */ -static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo) +static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fsinfo_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3908,9 +4221,9 @@ xdr_init_decode(&xdr, &req->rq_rcv_buf, p); status = decode_compound_hdr(&xdr, &hdr); if (!status) - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (!status) - status = decode_fsinfo(&xdr, fsinfo); + status = decode_fsinfo(&xdr, res->fsinfo, res->session); if (!status) status = -nfs_stat_to_errno(hdr.status); return status; @@ -3919,7 +4232,7 @@ /* * PATHCONF request */ -static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_pathconf *pathconf) +static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs4_pathconf_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3928,16 +4241,16 @@ xdr_init_decode(&xdr, &req->rq_rcv_buf, p); status = decode_compound_hdr(&xdr, &hdr); if (!status) - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (!status) - status = decode_pathconf(&xdr, pathconf); + status = decode_pathconf(&xdr, res); return status; } /* * STATFS request */ -static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fsstat *fsstat) +static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs4_statfs_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3946,9 +4259,9 @@ xdr_init_decode(&xdr, &req->rq_rcv_buf, p); status = decode_compound_hdr(&xdr, &hdr); if (!status) - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, res->session); if (!status) - status = decode_statfs(&xdr, fsstat); + status = decode_statfs(&xdr, res); return status; } @@ -3964,7 +4277,7 @@ xdr_init_decode(&xdr, &req->rq_rcv_buf, p); if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) goto out; - if ((status = decode_putfh(&xdr)) != 0) + if ((status = decode_putfh(&xdr, res->session)) != 0) goto out; status = decode_server_caps(&xdr, res); out: @@ -3974,7 +4287,7 @@ /* * Decode RENEW response */ -static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) +static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_client *clp) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -3982,8 +4295,10 @@ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); status = decode_compound_hdr(&xdr, &hdr); + stupid_debug_crap = 1; if (!status) - status = decode_renew(&xdr); + status = decode_renew(&xdr, clp->cl_session); + stupid_debug_crap = 0; return status; } @@ -4009,7 +4324,7 @@ /* * a SETCLIENTID_CONFIRM request */ -static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo) +static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid_confirm_res *res) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4018,20 +4333,113 @@ xdr_init_decode(&xdr, &req->rq_rcv_buf, p); status = decode_compound_hdr(&xdr, &hdr); if (!status) - status = decode_setclientid_confirm(&xdr); + status = decode_setclientid_confirm(&xdr, res->session); if (!status) - status = decode_putrootfh(&xdr); + status = decode_putrootfh(&xdr, res->session); if (!status) - status = decode_fsinfo(&xdr, fsinfo); + status = decode_fsinfo(&xdr, res->fsinfo, res->session); if (!status) status = -nfs_stat_to_errno(hdr.status); return status; } +static int +decode_create_session(struct xdr_stream *xdr, struct nfs4_create_session_res *res) +{ + uint32_t *p; + int status; + + status = decode_op_hdr(xdr, OP_CREATESESSION, 0); + if (status) + return status; + + READ_BUF(sizeof(res->sessionid) + (6 * 4)); + COPYMEM(&res->sessionid, sizeof(res->sessionid)); + READ32(res->persist); /* 1 */ + READ32(res->maxrequestsize); /* 2 */ + READ32(res->maxresponsesize); /* 3 */ + READ32(res->maxrequests); /* 4 */ + READ32(res->headerpadsize); /* 5 */ + READ32(res->mode); /* 6 */ + switch(res->mode){ + case NFS4_DEFAULT: + case NFS4_STREAM: + break; + case NFS4_RDMA: + READ_BUF(4); + READ32(res->maxrdmareads); + break; + } + + return(0); + +} + +static int +decode_bind_backchannel(struct xdr_stream *xdr, struct nfs4_bind_backchannel_res *res) +{ + uint32_t *p; + int status; + + status = decode_op_hdr(xdr, OP_BIND_BACKCHANNEL, 0); + if (status) + return status; + + READ_BUF(4 * 4); + READ32(res->maxreqsize); + READ32(res->maxrespsize); + READ32(res->maxreqs); + READ32(res->mode); + switch(res->mode){ + case NFS4_RDMA: + READ_BUF(4); + READ32(res->maxrdmareads); + case NFS4_DEFAULT: + case NFS4_STREAM: + ; + } + + return 0; +} + + +static int +decode_create_clientid(struct xdr_stream *xdr, struct nfs4_create_clientid_res *res) +{ + uint32_t *p; + int status; + + status = decode_op_hdr(xdr, OP_CREATECLIENTID, res->session); + if (status) + return status; + + READ_BUF(8 + sizeof(res->confirm)); + p = decode_clientid(p, &res->clientid); + COPYMEM(&res->confirm, sizeof(res->confirm)); + + return 0; +} + +static int +decode_destroy_session(struct xdr_stream *xdr, struct nfs4_destroy_session_res *res) +{ + uint32_t *p; + int status; + + status = decode_op_hdr(xdr, OP_CREATECLIENTID, 0); + if (status) + return status; + + READ_BUF(sizeof(res->sessionid)); + COPYMEM(&res->sessionid, sizeof(res->sessionid)); + + return 0; +} + /* * DELEGRETURN request */ -static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) +static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_client_session *sess) { struct xdr_stream xdr; struct compound_hdr hdr; @@ -4040,9 +4448,9 @@ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); status = decode_compound_hdr(&xdr, &hdr); if (status == 0) { - status = decode_putfh(&xdr); + status = decode_putfh(&xdr, sess); if (status == 0) - status = decode_delegreturn(&xdr); + status = decode_delegreturn(&xdr, sess); } return status; } @@ -4099,10 +4507,70 @@ return p; } -/* - * We need to translate between nfs status return values and - * the local errno values which may not be the same. - */ +static int +nfs4_xdr_dec_create_clientid(struct rpc_rqst *req, uint32_t *p, + struct nfs4_create_clientid_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &req->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (!status) + status = decode_create_clientid(&xdr, res); + return status; +} + + +static int +nfs4_xdr_dec_create_session(struct rpc_rqst *req, uint32_t *p, + struct nfs4_create_session_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &req->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (!status) + status = decode_create_session(&xdr, res); + return status; +} + + +static int +nfs4_xdr_dec_bind_backchannel(struct rpc_rqst *req, uint32_t *p, + struct nfs4_bind_backchannel_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &req->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (!status) + status = decode_bind_backchannel(&xdr, res); + return status; +} + +static int +nfs4_xdr_dec_destroy_session(struct rpc_rqst *req, uint32_t *p, + struct nfs4_destroy_session_res *res) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &req->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (!status) + status = decode_destroy_session(&xdr, res); + return status; +} + + + static struct { int stat; int errno; @@ -4218,6 +4686,10 @@ PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), PROC(GETACL, enc_getacl, dec_getacl), PROC(SETACL, enc_setacl, dec_setacl), + PROC(CREATE_CLIENTID, enc_create_clientid, dec_create_clientid), + PROC(CREATE_SESSION, enc_create_session, dec_create_session), + PROC(BIND_BACKCHANNEL, enc_bind_backchannel, dec_bind_backchannel), + PROC(DESTROY_SESSION, enc_destroy_session, dec_destroy_session), }; struct rpc_version nfs_version4 = { Index: linux-sessions-2.6.14/fs/nfsd/nfs4proc.c =================================================================== --- linux-sessions-2.6.14.orig/fs/nfsd/nfs4proc.c 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/fs/nfsd/nfs4proc.c 2005-12-03 15:13:53.000000000 -0500 @@ -719,8 +719,6 @@ { return nfs_ok; } - - /* * COMPOUND call. */ @@ -729,13 +727,17 @@ struct nfsd4_compoundargs *args, struct nfsd4_compoundres *resp) { - struct nfsd4_op *op; + struct nfsd4_op *op = NULL; struct svc_fh *current_fh = NULL; struct svc_fh *save_fh = NULL; struct nfs4_stateowner *replay_owner = NULL; int slack_space; /* in words, not bytes! */ int status; - + struct nfs4_session *session = NULL; + struct nfs4_cache_entry *cache_entry = NULL; + char fmt[sizeof("\ttag = \"%.###s\"\n")]; + char *fmtfmt = "\ttag = \"%%.%ds\"\n"; + status = nfserr_resource; current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL); if (current_fh == NULL) @@ -761,10 +763,48 @@ * According to RFC3010, this takes precedence over all other errors. */ status = nfserr_minor_vers_mismatch; + dprintk("nfsd: nfsd4_proc_compound: minor %u\n", args->minorversion); + snprintf(fmt, sizeof(fmt), fmtfmt, args->taglen); + dprintk(fmt, args->tag); + if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION) goto out; status = nfs_ok; + + op = &args->ops[0]; + if (op->opnum == OP_SEQUENCE) { /* must be 1st if present */ + resp->opcnt++; + op->status = nfsd4_sequence(resp, &op->u.sequence, + &session, &cache_entry); + + if (op->status == nfserr_inprog) { + if (cache_entry->ce_compstat == nfserr_dropit) { + /* continue from where we left off */ + dprintk("nfsd: resuming revisited request; opcnt = %u\n", resp->opcnt); + read_cache_entry(rqstp, cache_entry); + current_fh = cache_entry->ce_current_fh; + save_fh = cache_entry->ce_save_fh; + resp->opcnt = cache_entry->ce_opcnt; + goto op_loop; + } else { + /* drop the whole COMPOUND */ + printk("nfsd: dropping duplicate of in-progress request\n"); + status = nfserr_inprog; + goto out; + } + } else if (op->status == NFSERR_REPLAY_ME) { + /* replay the whole compound */ + dprintk("nfsd: got duplicate request; replaying original response\n"); + status = read_cache_entry(rqstp, cache_entry); + goto out; + } + + /* normal processing */ + goto encode_op; + } + +op_loop: while (!status && resp->opcnt < args->opcnt) { op = &args->ops[resp->opcnt++]; @@ -795,6 +835,10 @@ * * SETATTR NOFILEHANDLE error handled in nfsd4_setattr * due to required returned bitmap argument + * + * Sessions operations (CREATECLIENTID, CREATESESSION, + * BIND_BACKCHANNEL, DESTROYSESSION, and SEQUENCE) do not + * require a current filehandle either. */ if ((!current_fh->fh_dentry) && !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) || @@ -802,10 +846,16 @@ (op->opnum == OP_SETCLIENTID_CONFIRM) || (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) || (op->opnum == OP_RELEASE_LOCKOWNER) || - (op->opnum == OP_SETATTR))) { + (op->opnum == OP_SETATTR) || + (op->opnum == OP_CREATECLIENTID) || + (op->opnum == OP_CREATESESSION) || + (op->opnum == OP_BIND_BACKCHANNEL) || + (op->opnum == OP_DESTROYSESSION) || + (op->opnum == OP_SEQUENCE))) { op->status = nfserr_nofilehandle; goto encode_op; } + switch (op->opnum) { case OP_ACCESS: op->status = nfsd4_access(rqstp, current_fh, &op->u.access); @@ -910,6 +960,24 @@ case OP_RELEASE_LOCKOWNER: op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner); break; + /* v4.1 operations */ + case OP_CREATECLIENTID: + op->status = nfsd4_createclientid(rqstp, &op->u.createclientid); + break; + case OP_CREATESESSION: + op->status = nfsd4_createsession(rqstp, &op->u.createsession); + break; + case OP_BIND_BACKCHANNEL: + /* not implemented yet */ + break; + case OP_DESTROYSESSION: + op->status = nfsd4_destroysession(&op->u.destroysession, + &session, + &cache_entry); + break; + case OP_SEQUENCE: + /* SEQUENCE must be the first op in COMPOUND */ + op->status = nfserr_inval; /* XXX new error? */ default: BUG_ON(op->status == nfs_ok); break; @@ -920,7 +988,13 @@ op->replay = &replay_owner->so_replay; nfsd4_encode_replay(resp, op); status = op->status = op->replay->rp_status; + } else if (op->status == nfserr_dropit) { + dprintk("nfsd: got nfserr_dropit, skipping encode of op # %d\n", op->opnum); + status = op->status; } else { + if (op->status) { + dprintk("nfsd: encoding op # %d normally (status = %u)\n", op->opnum, htonl(op->status)); + } nfsd4_encode_operation(resp, op); status = op->status; } @@ -932,15 +1006,31 @@ if (op->opnum == OP_READ && op->u.read.rd_filp) fput(op->u.read.rd_filp); } - + out: nfsd4_release_compoundargs(args); - if (current_fh) - fh_put(current_fh); - kfree(current_fh); - if (save_fh) - fh_put(save_fh); - kfree(save_fh); + + /* If this op is being deferred due to an upcall, + * don't free the filehandles, since they'll be saved + */ + if (!(cache_entry && status == nfserr_dropit)) { + if (current_fh) + fh_put(current_fh); + kfree(current_fh); + current_fh = NULL; + if (save_fh) + fh_put(save_fh); + kfree(save_fh); + save_fh = NULL; + } + + if (cache_entry != NULL + && status != nfserr_badslot + && status != nfserr_inprog) { + write_cache_entry(cache_entry, rqstp, status, resp->opcnt - 1, + current_fh, save_fh); + } + return status; } Index: linux-sessions-2.6.14/fs/nfsd/nfs4state.c =================================================================== --- linux-sessions-2.6.14.orig/fs/nfsd/nfs4state.c 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/fs/nfsd/nfs4state.c 2005-11-29 16:11:14.000000000 -0500 @@ -227,7 +227,7 @@ } /* - * SETCLIENTID state + * SETCLIENTID/SESSION_CREATE/BIND_CHANNEL state */ /* Hash tables for nfs4_clientid state */ @@ -261,6 +261,7 @@ static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE]; static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE]; static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; +static struct list_head client_xprt_hashtbl[CLIENT_HASH_SIZE]; static struct list_head client_lru; static struct list_head close_lru; @@ -273,6 +274,7 @@ dprintk("renewing client (clientid %08x/%08x)\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); + list_move_tail(&clp->cl_lru, &client_lru); clp->cl_time = get_seconds(); } @@ -312,12 +314,45 @@ return clp; } +static inline struct nfs4_session * +alloc_session(void) { + struct nfs4_session *sp = kmalloc(sizeof(*sp), GFP_KERNEL); + + if (sp != NULL) memset(sp, 0, sizeof(*sp)); + return sp; +} + +static inline void +free_session(struct nfs4_session *sp) { + int i = 0; + + while (i < sp->se_maxreqs) { /* release DRC pages */ + clear_cahe_entry(&sp->se_drc[i++]); + } + + list_del(&sp->se_perclient); + kfree(sp); +} + static inline void free_client(struct nfs4_client *clp) { + struct nfs4_session *sp; + if (clp->cl_cred.cr_group_info) put_group_info(clp->cl_cred.cr_group_info); kfree(clp->cl_name.data); + + if (clp->cl_minorvers > 0) { + while (!list_empty(&clp->cl_sessions)) { + sp = list_entry(clp->cl_sessions.next, + struct nfs4_session, + se_perclient); + free_session(sp); + } + list_del(&clp->cl_sessions); + } + kfree(clp); } @@ -368,6 +403,7 @@ sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); release_stateowner(sop); } +dprintk("NFSD: calling put_nfs4_client(%p)\n", clp); put_nfs4_client(clp); } @@ -386,6 +422,22 @@ INIT_LIST_HEAD(&clp->cl_delegations); INIT_LIST_HEAD(&clp->cl_lru); out: +dprintk("NFSD: created client %p (minor = %u)\n", clp, clp->cl_minorvers); + return clp; +} + +static struct nfs4_client * +create_client_ver(struct xdr_netobj name, char * recdir, u32 minorversion) { + struct nfs4_client *clp; + + if (!(clp = create_client(name, recdir))) + return NULL; + + clp->cl_minorvers = minorversion; + if (minorversion == 1) { + INIT_LIST_HEAD(&clp->cl_sessions); + clp->cl_currsessid = 1; /* 0 indicates overflow */ + } return clp; } @@ -435,7 +487,17 @@ static void gen_clid(struct nfs4_client *clp) { clp->cl_clientid.cl_boot = boot_time; - clp->cl_clientid.cl_id = current_clientid++; + clp->cl_clientid.cl_id = current_clientid++; + if (clp->cl_clientid.cl_id == 0) { + dprintk("%s: gen_clid(): clientid overflow!", __FILE__); + } +} + +static inline void +gen_sessionid(struct nfs4_client *clp, struct nfs4_session *sp) { + if ((sp->se_id = clp->cl_currsessid++) == 0) { + dprintk("%s: gen_sessionid(): sessionid overflow!", __FILE__); + } } static void @@ -1037,6 +1099,92 @@ return -ENOMEM; } +/* + * Creates a new duplicate request cache attached to the given session + * with values based on the createsession OP's arguments + * createsession and session are assumed to be non NULL + * This should only be called when the state lock is held + */ +static struct nfs4_cache_entry * +create_drc(struct nfsd4_createsession *createsession, + struct nfs4_session *session) { + + int cachesize; /* size in bytes */ + int order; /* smallest N s.t. PAGE_SIZE * lg N > cachesize */ + struct nfs4_cache_entry *drc; + + /* XXX some limits should be imposed here */ + session->se_maxreqs = createsession->cs_maxreqs; + + if (!createsession->cs_persist) return NULL; + + cachesize = session->se_maxreqs * sizeof(struct nfs4_cache_entry); + + dprintk("nfsd: create_drc: allocating %d bytes for DRC\n", cachesize); + + if (cachesize >= PAGE_SIZE) { + for (order = 0; (PAGE_SIZE << order) < cachesize; order++) + ; + drc = (struct nfs4_cache_entry *) + __get_free_pages(GFP_KERNEL, order); + } else { + drc = kmalloc(cachesize, GFP_KERNEL); + } + + if (!drc) { + printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for reply cache\n", cachesize); + return NULL; + } + + memset(drc, 0, cachesize); + + return drc; +} + +/* + * Creates a new session attached to the given client + * client and createsess are assumed to be non NULL + * This should only be called when the state lock is held + */ +static struct nfs4_session * +create_session(struct nfs4_client *client, + struct nfsd4_createsession *createsession) +{ + struct nfs4_session *session; + + if ((session = alloc_session()) != NULL) { + + INIT_LIST_HEAD(&session->se_perclient); + session->se_client = client; + gen_sessionid(client, session); + + session->se_maxrespsize = + createsession->cs_maxrespsize < NFSD_BUFSIZE + ? createsession->cs_maxrespsize + : NFSD_BUFSIZE; + session->se_drc = create_drc(createsession, session); + /* XXX set some upper bound? */ + session->se_maxreqsize = createsession->cs_maxreqsize; + session->se_headerpad = 0; + /* XXX ignore bc_maxrdmareads for now */ + + list_add_tail(&session->se_perclient, &client->cl_sessions); + } + + return session; +} + +void +add_to_confirmed(struct nfs4_client *clp) +{ + unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); + unsigned int strhashval = clientstr_hashval(clp->cl_recdir); + + list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); + list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); + renew_client(clp); +} + void nfs4_free_stateowner(struct kref *kref) { @@ -1937,6 +2085,7 @@ clp->cl_clientid.cl_id); nfsd4_remove_clid_dir(clp); expire_client(clp); +dprintk("NFSD: expire_client successful\n"); } INIT_LIST_HEAD(&reaplist); spin_lock(&recall_lock); @@ -1975,6 +2124,7 @@ if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; nfs4_unlock_state(); +dprintk("NFSD: nfs4_laundromat done\n"); return clientid_val; } @@ -2457,6 +2607,337 @@ } +/* v4.1 operations */ + +/* This call needs to track nfsd4_setclientid functionality */ +int +nfsd4_createclientid(struct svc_rqst *rqstp, + struct nfsd4_createclientid *createclid) +{ + struct xdr_netobj clname = { + .len = createclid->cc_namelen, + .data = createclid->cc_name + }; + unsigned int strhashval; + int status = nfs_ok; + struct list_head *pos, *next; + struct nfs4_client *new, *clp; + char dname[HEXDIR_LEN]; + + dprintk("nfsd4_createclientid for \"%s\"\n", createclid->cc_name); + + if (!check_name(clname)) { + status = nfserr_inval; + goto out; + } + + status = nfs4_make_rec_clidname(dname, &clname); + if (status) + return status; + + /** XXX check special DRC for SESSION_CREATE? */ + + strhashval = clientstr_hashval(dname); + + nfs4_lock_state(); +#if 0 + list_for_each_safe(pos, next, &conf_str_hashtbl[strhashval]) { + clp = list_entry(pos, struct nfs4_client, cl_strhash); + if (!cmp_name(&clp->cl_name, &clname)) + continue; + /* XXX handle duplicate name cases & reconnect*/ + } +#endif + clp = find_confirmed_client_by_str(dname, strhashval); + + /* FIXME -- handle duplicate name cases, reconnect, &c */ + BUG_ON(clp); + + /* Normal case */ + if (!(new = create_client_ver(clname, dname, 1))) { + status = nfserr_resource; + goto out; + } + + /* set client state */ + /* list ptrs and cl_name set by create_client_ver() */ + copy_verf(new, &createclid->cc_verifier); + copy_cred(&new->cl_cred, &rqstp->rq_cred); + gen_clid(new); + gen_confirm(new); + /* zero out usused fields for v4.1 in nfs4_client struct*/ + memset(&new->cl_addr, 0, sizeof(new->cl_addr)); + add_to_unconfirmed(new, strhashval); + + /* set RPC reply values */ + memcpy(&createclid->cc_clientid, &new->cl_clientid, sizeof(clientid_t)); + memcpy(createclid->cc_confirm.data, new->cl_confirm.data, + sizeof(createclid->cc_confirm.data)); + + dprintk("nfsd4_createclientid successful"); + dprintk("\t\"%s\" -> (clientid %08x/%08x)\n", new->cl_name.data, + new->cl_clientid.cl_boot, + new->cl_clientid.cl_id); + +out: + nfs4_unlock_state(); + return status; +} + +/* + * Returns a pointer to the nfs4_client structure for the client ID, + * in the given table, or NULL if not present. + * This should only be called while state lock is held. + */ +static struct nfs4_client * +get_client(clientid_t* id, struct list_head* table) { + int idhashval = clientid_hashval(id->cl_id); + struct list_head *pos, *next; + struct nfs4_client *clp; + + list_for_each_safe(pos, next, &table[idhashval]) { + clp = list_entry(pos, struct nfs4_client, cl_idhash); + if (cmp_clid(&clp->cl_clientid, id)) + return clp; + } + + return NULL; +} + +/* + * Returns the session associated with the given id, or NULL if there is none + * This should only be called while state lock is held. + */ +static struct nfs4_session * +get_session(sessionid_t* id) { + struct nfs4_client *client; + struct nfs4_session *session; + struct list_head *pos, *next; + + if (STALE_CLIENTID(&id->se_clientid)) { + return NULL; + } + + if ((client = get_client(&id->se_clientid, conf_id_hashtbl)) != NULL) { + list_for_each_safe(pos, next, &client->cl_sessions) { + session = list_entry(pos, struct nfs4_session, + se_perclient); + if (session->se_id == id->se_id) + return session; + } + } + + return NULL; +} + +int +nfsd4_createsession(struct svc_rqst *rqstp, + struct nfsd4_createsession *createsess) +{ + int status = nfs_ok; + struct nfs4_client *client; + struct nfs4_session *session; + + dprintk("nfsd4_createsession for (clientid %08x/%08x)\n", + createsess->cs_clientid.cl_boot, + createsess->cs_clientid.cl_id); + dprintk("\tpersist: %c\n", createsess->cs_persist ? 'T' : 'F'); + dprintk("\tmax request size: %d\n", createsess->cs_maxreqsize); + dprintk("\tmax response size: %d\n", createsess->cs_maxrespsize); + dprintk("\tmax requests: %d\n", createsess->cs_maxreqs); + dprintk("\theader pad: %d\n", createsess->cs_headerpad); + dprintk("\tconfirming client: %c", + createsess->cs_clientid_confirm ? 'T' : 'F'); + switch (createsess->cs_mode) { + case NFS4_DEFAULT: + dprintk("\tconnection mode: DEFAULT\n"); + break; + case NFS4_STREAM: + dprintk("\tconnection mode: STREAM\n"); + break; + case NFS4_RDMA: + dprintk("\tconnection mode: RDMA\n"); + dprintk("\tmax RDMA reads: %d\n", createsess->cs_maxrdmareads); + } + + if (STALE_CLIENTID(&createsess->cs_clientid)) { + status = nfserr_stale_clientid; + goto out; + } + + /* + * XXX The Duplicate Request Cache (DRC) has been checked (??) + * We get here on a DRC miss. + */ + + nfs4_lock_state(); + + client = get_client(&createsess->cs_clientid, unconf_id_hashtbl); + + if (client == NULL) { + status = nfserr_stale_clientid; + goto out; + } else if (!cmp_creds(&client->cl_cred, &rqstp->rq_cred)) { + status = nfserr_clid_inuse; + goto out; + } else if (createsess->cs_mode == NFS4_RDMA) { + status = nfserr_notsupp; /* XXX new error for this? */ + goto out; + } else if (createsess->cs_maxrespsize < 8) { + status = nfserr_notsupp; /* XXX new error for this? */ + goto out; + } + /* XXX check for some minimum value of max response size? */ + + if ((session = create_session(client, createsess)) == NULL) { + status = nfserr_resource; + goto out; + } + + move_to_confirmed(client); + + /* set RPC reply values */ + createsess->cs_sessionid.se_clientid = client->cl_clientid; + createsess->cs_sessionid.se_unused = 0; + createsess->cs_sessionid.se_id = session->se_id; + createsess->cs_persist = session->se_drc != NULL; + createsess->cs_maxreqsize = session->se_maxreqsize; + createsess->cs_maxrespsize = session->se_maxrespsize; + createsess->cs_maxreqs = session->se_maxreqs; + createsess->cs_headerpad = session->se_headerpad; + + dprintk("nfsd4_createsession successful\n"); + dprintk("\tsessionid %x for (clientid %08x/%08x)\n", + session->se_id, + client->cl_clientid.cl_boot, + client->cl_clientid.cl_id); +out: + nfs4_unlock_state(); + return status; +} + +int +nfsd4_destroysession(sessionid_t *sessionid, + struct nfs4_session **sessionpp, + struct nfs4_cache_entry **cache_entrypp) +{ + int status = nfs_ok; + struct nfs4_session *session; + + dprintk("nfsd4_destroysession: sessionid %x of (clientid %08x/%08x)\n", + sessionid->se_id, + sessionid->se_clientid.cl_boot, + sessionid->se_clientid.cl_id); + + nfs4_lock_state(); + + if ((session = get_session(sessionid)) == NULL) { + dprintk("nfsd: attempt to destroy invalid session\n"); + status = nfserr_badsession; + goto out; + } + + free_session(session); + +out: + *sessionpp = NULL; + *cache_entrypp = NULL; + nfs4_unlock_state(); + return status; +} + +/* NOTE: This function sets the value of the session and cache entry pointers + * for the caller + */ +int +nfsd4_sequence(struct nfsd4_compoundres *resp, struct nfsd4_sequence *seq, + struct nfs4_session **session, + struct nfs4_cache_entry **cache_entry) +{ + int status = nfs_ok; + struct nfs4_session *sess = NULL; + struct nfs4_cache_entry *entry = NULL; + + dprintk("nfsd4_sequence: sessionid %x of (clientid %08x/%08x)\n", + seq->se_sessionid.se_id, + seq->se_sessionid.se_clientid.cl_boot, + seq->se_sessionid.se_clientid.cl_id); + dprintk("\tslotid = %u\n\tsequenceid = %u\n", + seq->se_slotid, + seq->se_sequenceid); + + nfs4_lock_state(); + + if ((sess = get_session(&seq->se_sessionid)) == NULL) { + status = nfserr_badsession; /* need different error? */ + dprintk("nfsd: got invalid session\n"); + *session = NULL; + *cache_entry = NULL; + goto out; + } + *session = sess; + + if (sess->se_drc == NULL) goto renew; + + if (seq->se_slotid >= sess->se_maxreqs) { + status = nfserr_badslot; + dprintk("nfsd: got invalid slot\n"); + *cache_entry = NULL; + goto out; + } + + entry = &sess->se_drc[seq->se_slotid]; + *cache_entry = entry; + +/* + dprintk("nfsd4_sequence: cache slot %u: ", seq->se_slotid); + print_cache_entry(entry); +*/ + if (seq->se_sequenceid != entry->ce_sequenceid) { /* normal req */ + switch (entry->ce_status) { + default: + dprintk("nfsd: Invalid cache entry status; treating as available"); + case NFS4_CE_AVAILABLE: + case NFS4_CE_COMPLETE: + clear_cahe_entry(entry); + entry->ce_sequenceid = seq->se_sequenceid; + entry->ce_status = NFS4_CE_INPROGRESS; + break; + case NFS4_CE_INPROGRESS: /* previous op not done yet */ + dprintk("nfsd4_sequence: bad slot\n"); + status = nfserr_badslot; /* XXX slot_inuse instead? */ + *cache_entry = NULL; + goto out; + } + } else { /* replay */ + switch (entry->ce_status) { + default: + dprintk("nfsd: Invalid cache entry status; treating as available"); + case NFS4_CE_AVAILABLE: + /* Not actually a replay, sequenceid just a coincidence */ + clear_cahe_entry(entry); + entry->ce_status = NFS4_CE_INPROGRESS; + break; + case NFS4_CE_INPROGRESS: + status = nfserr_inprog; + /* If this is a revisit, we continue processing, + * Otherwise, this will be dropped w/o reply + */ + break; + case NFS4_CE_COMPLETE: + /* do replay here */ + status = NFSERR_REPLAY_ME; + break; + } + } + +renew: + renew_client(sess->se_client); +out: + nfs4_unlock_state(); + return status; +} + /* * Lock owner state (byte-range locks) */ @@ -3187,6 +3668,7 @@ for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&conf_id_hashtbl[i]); INIT_LIST_HEAD(&conf_str_hashtbl[i]); + INIT_LIST_HEAD(&client_xprt_hashtbl[i]); INIT_LIST_HEAD(&unconf_str_hashtbl[i]); INIT_LIST_HEAD(&unconf_id_hashtbl[i]); } Index: linux-sessions-2.6.14/fs/nfsd/nfs4xdr.c =================================================================== --- linux-sessions-2.6.14.orig/fs/nfsd/nfs4xdr.c 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/fs/nfsd/nfs4xdr.c 2005-11-29 16:11:14.000000000 -0500 @@ -97,7 +97,7 @@ status = nfserr_bad_xdr; \ goto out -#define READ32(x) (x) = ntohl(*p++) +#define READ32(x) ((x) = ntohl(*p++)) #define READ64(x) do { \ (x) = (u64)ntohl(*p++) << 32; \ (x) |= ntohl(*p++); \ @@ -968,13 +968,115 @@ DECODE_TAIL; } +/* v4.1 operations */ + +static int +nfsd4_decode_createclientid(struct nfsd4_compoundargs *argp, + struct nfsd4_createclientid *create_clid) +{ + DECODE_HEAD; + + READ_BUF(NFS4_VERIFIER_SIZE + 4); + COPYMEM(create_clid->cc_verifier.data, NFS4_VERIFIER_SIZE); + READ32(create_clid->cc_namelen); + + READ_BUF(create_clid->cc_namelen); + SAVEMEM(create_clid->cc_name, create_clid->cc_namelen); + + DECODE_TAIL; +} + +static int +nfsd4_decode_createsession(struct nfsd4_compoundargs *argp, + struct nfsd4_createsession *cs) +{ + DECODE_HEAD; + + READ_BUF(sizeof(cs->cs_clientid) + (6 * 4)); + COPYMEM(&cs->cs_clientid, sizeof(cs->cs_clientid)); + READ32(cs->cs_persist); /* 1 */ + READ32(cs->cs_maxreqsize); /* 2 */ + READ32(cs->cs_maxrespsize); /* 3 */ + READ32(cs->cs_maxreqs); /* 4 */ + READ32(cs->cs_headerpad); /* 5 */ + if (READ32(cs->cs_clientid_confirm)) { /* 6 */ + READ_BUF(sizeof(cs->cs_confirm)); + COPYMEM(&cs->cs_confirm, sizeof(cs->cs_confirm)); + } + READ_BUF(4); + switch (READ32(cs->cs_mode)) { + case NFS4_DEFAULT: break; + case NFS4_STREAM: break; + case NFS4_RDMA: + READ_BUF(4); + READ32(cs->cs_maxrdmareads); + break; + default: goto xdr_error; + } + + DECODE_TAIL; +} + +static int +nfsd4_decode_bind_backchannel(struct nfsd4_compoundargs *argp, + struct nfsd4_bind_backchannel *bb) +{ + DECODE_HEAD; + + READ_BUF(sizeof(bb->bb_clientid) + (4 * 6)); + COPYMEM(&bb->bb_clientid, sizeof(bb->bb_clientid)); + READ32(bb->bb_callback_prog); /* 1 */ + READ32(bb->bb_callback_ident); /* 2 */ + READ32(bb->bb_maxreqsize); /* 3 */ + READ32(bb->bb_maxrespsize); /* 4 */ + READ32(bb->bb_maxreqs); /* 5 */ + switch (READ32(bb->bb_mode)) { /* 6 */ + case NFS4_DEFAULT: break; + case NFS4_STREAM: break; + case NFS4_RDMA: + READ_BUF(4); + READ32(bb->bb_maxrdmareads); + break; + default: goto xdr_error; + } + DECODE_TAIL; +} + +static int +nfsd4_decode_destroysession(struct nfsd4_compoundargs *argp, sessionid_t *sid) +{ + DECODE_HEAD; + + READ_BUF(sizeof(*sid)); + COPYMEM(sid, sizeof(*sid)); + + DECODE_TAIL; +} + +static int +nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, + struct nfsd4_sequence *seq) +{ + DECODE_HEAD; + + READ_BUF(sizeof(seq->se_sessionid) + (4 * 4)); + COPYMEM(&seq->se_sessionid, sizeof(seq->se_sessionid)); + READ32(seq->se_sequenceid); /* 1 */ + READ32(seq->se_slotid); /* 2 */ + READ32(seq->se_maxslot); /* 3 */ + READ32(seq->se_chainflags); /* 4 */ + if (!valid_nfs4_chainflags(seq->se_chainflags)) goto xdr_error; + + DECODE_TAIL; +} + static int nfsd4_decode_compound(struct nfsd4_compoundargs *argp) { DECODE_HEAD; - struct nfsd4_op *op; + struct nfsd4_op *op = NULL; int i; - + /* * XXX: According to spec, we should check the tag * for UTF-8 compliance. I'm postponing this for @@ -987,7 +1089,7 @@ SAVEMEM(argp->tag, argp->taglen); READ32(argp->minorversion); READ32(argp->opcnt); - + if (argp->taglen > NFSD4_MAX_TAGLEN) goto xdr_error; if (argp->opcnt > 100) @@ -1146,6 +1248,22 @@ case OP_RELEASE_LOCKOWNER: op->status = nfsd4_decode_release_lockowner(argp, &op->u.release_lockowner); break; + /* v4.1 operations */ + case OP_CREATECLIENTID: + op->status = nfsd4_decode_createclientid(argp, &op->u.createclientid); + break; + case OP_CREATESESSION: + op->status = nfsd4_decode_createsession(argp, &op->u.createsession); + break; + case OP_BIND_BACKCHANNEL: + op->status = nfsd4_decode_bind_backchannel(argp, &op->u.bind_backchannel); + break; + case OP_SEQUENCE: + op->status = nfsd4_decode_sequence(argp, &op->u.sequence); + break; + case OP_DESTROYSESSION: + op->status = nfsd4_decode_destroysession(argp, &op->u.destroysession); + break; default: op->opnum = OP_ILLEGAL; op->status = nfserr_op_illegal; @@ -2324,6 +2442,93 @@ } } +/* v4.1 operations */ + +static void +nfsd4_encode_createclientid(struct nfsd4_compoundres *resp, int nfserr, + struct nfsd4_createclientid *cc) +{ + ENCODE_HEAD; + + if (!nfserr) { + RESERVE_SPACE(sizeof(cc->cc_clientid) + sizeof(cc->cc_confirm)); + WRITEMEM(&cc->cc_clientid, sizeof(cc->cc_clientid)); + WRITEMEM(&cc->cc_confirm, sizeof(cc->cc_confirm)); + ADJUST_ARGS(); + } +} + +static void +nfsd4_encode_createsession(struct nfsd4_compoundres *resp, int nfserr, + struct nfsd4_createsession *cs) +{ + ENCODE_HEAD; + + if (!nfserr) { + RESERVE_SPACE(sizeof(cs->cs_sessionid) + (4 * 6)); + WRITEMEM(&cs->cs_sessionid, sizeof(cs->cs_sessionid)); + WRITE32(cs->cs_persist); /* 1 */ + WRITE32(cs->cs_maxreqsize); /* 2 */ + WRITE32(cs->cs_maxrespsize); /* 3 */ + WRITE32(cs->cs_maxreqs); /* 4 */ + WRITE32(cs->cs_headerpad); /* 5 */ + WRITE32(cs->cs_mode); /* 6 */ + switch (cs->cs_mode) { + case NFS4_DEFAULT: break; + case NFS4_STREAM: break; + case NFS4_RDMA: + RESERVE_SPACE(4); + WRITE32(cs->cs_maxrdmareads); + break; + default: + BUG_ON(cs->cs_mode); + } + ADJUST_ARGS(); + } +} + +static void +nfsd4_encode_bind_backchannel(struct nfsd4_compoundres *resp, int nfserr, + struct nfsd4_bind_backchannel *bb) +{ + ENCODE_HEAD; + + if (!nfserr) { + RESERVE_SPACE(4 * 4); + WRITE32(bb->bb_maxreqsize); /* 1 */ + WRITE32(bb->bb_maxrespsize); /* 2 */ + WRITE32(bb->bb_maxreqs); /* 3 */ + WRITE32(bb->bb_mode); /* 4 */ + switch (bb->bb_mode) { + case NFS4_DEFAULT: break; + case NFS4_STREAM: break; + case NFS4_RDMA: + RESERVE_SPACE(4); + WRITE32(bb->bb_maxrdmareads); + break; + default: + BUG_ON(bb->bb_mode); + } + ADJUST_ARGS(); + } +} + +static void +nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, + struct nfsd4_sequence *seq) +{ + ENCODE_HEAD; + + if (!nfserr) { + RESERVE_SPACE(sizeof(seq->se_sessionid) + (4 * 3)); + WRITEMEM(&seq->se_sessionid, sizeof(seq->se_sessionid)); + WRITE32(seq->se_sequenceid); /* 1 */ + WRITE32(seq->se_slotid); /* 2 */ + WRITE32(seq->se_maxslot); /* 3 */ + ADJUST_ARGS(); + } +} + void nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) { @@ -2423,6 +2628,24 @@ break; case OP_RELEASE_LOCKOWNER: break; + /* v4.1 operations */ + case OP_CREATECLIENTID: + nfsd4_encode_createclientid(resp, op->status, + &op->u.createclientid); + break; + case OP_CREATESESSION: + nfsd4_encode_createsession(resp, op->status, + &op->u.createsession); + break; + case OP_BIND_BACKCHANNEL: + nfsd4_encode_bind_backchannel(resp, op->status, + &op->u.bind_backchannel); + break; + case OP_DESTROYSESSION: + break; + case OP_SEQUENCE: + nfsd4_encode_sequence(resp, op->status, &op->u.sequence); + break; default: break; } @@ -2516,6 +2739,7 @@ * All that remains is to write the tag and operation count... */ struct kvec *iov; + p = resp->tagp; *p++ = htonl(resp->taglen); memcpy(p, resp->tag, resp->taglen); Index: linux-sessions-2.6.14/fs/nfsd/nfssvc.c =================================================================== --- linux-sessions-2.6.14.orig/fs/nfsd/nfssvc.c 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/fs/nfsd/nfssvc.c 2005-11-29 16:11:14.000000000 -0500 @@ -298,22 +298,28 @@ kxdrproc_t xdr; u32 nfserr; u32 *nfserrp; - + u32 status_offset = -1; /* bytes from RPC header base */ + int use_old_cache = 1; + dprintk("nfsd_dispatch: vers %d proc %d\n", rqstp->rq_vers, rqstp->rq_proc); + status_offset = ((void*)statp) - page_address(rqstp->rq_respages[0]); proc = rqstp->rq_procinfo; - /* Check whether we have this call in the cache. */ - switch (nfsd_cache_lookup(rqstp, proc->pc_cachetype)) { - case RC_INTR: - case RC_DROPIT: - return 0; - case RC_REPLY: - return 1; - case RC_DOIT:; - /* do it */ + /* FIXME this needs to distinguish between 4.0 and 4.1 */ + if (rqstp->rq_vers < 4 || use_old_cache) { + /* Check whether we have this call in the cache. */ + switch (nfsd_cache_lookup(rqstp, proc->pc_cachetype)) { + case RC_INTR: + case RC_DROPIT: + return 0; + case RC_REPLY: + return 1; + case RC_DOIT:; + /* do it */ + } } - + /* Decode arguments */ xdr = proc->pc_decode; if (xdr && !xdr(rqstp, (u32*)rqstp->rq_arg.head[0].iov_base, @@ -333,12 +339,20 @@ /* Now call the procedure handler, and encode NFS status. */ nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); + + /* Update statp, in case rqstp->rq_respages[0] changed */ + statp = page_address(rqstp->rq_respages[0]) + status_offset; + nfserrp = statp + 1; /* nfs status is right after RPC status */ + if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2) nfserr = nfserr_dropit; if (nfserr == nfserr_dropit) { - dprintk("nfsd: Dropping request due to malloc failure!\n"); + dprintk("nfsd: Dropping request due to upcall delay!\n"); nfsd_cache_update(rqstp, RC_NOCACHE, NULL); return 0; + } else if (nfserr == nfserr_inprog) { + dprintk("nfsd: Dropping replay of in-progress request!\n"); + return 0; } if (rqstp->rq_proc != 0) @@ -359,8 +373,11 @@ } } - /* Store reply in cache. */ - nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1); + /* FIXME this needs to distinguish between 4.0 and 4.1 */ + if (rqstp->rq_vers < 4 || use_old_cache) { + /* Store reply in cache. */ + nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1); + } return 1; } Index: linux-sessions-2.6.14/include/linux/nfs4.h =================================================================== --- linux-sessions-2.6.14.orig/include/linux/nfs4.h 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/include/linux/nfs4.h 2005-11-29 16:11:14.000000000 -0500 @@ -20,6 +20,7 @@ #define NFS4_FHSIZE 128 #define NFS4_MAXPATHLEN PATH_MAX #define NFS4_MAXNAMLEN NAME_MAX +#define NFS4_OPAQUE_LIMIT 1024 #define NFS4_ACCESS_READ 0x0001 #define NFS4_ACCESS_LOOKUP 0x0002 @@ -152,9 +153,23 @@ OP_VERIFY = 37, OP_WRITE = 38, OP_RELEASE_LOCKOWNER = 39, + OP_CREATECLIENTID = 40, /* v4.1 */ + OP_CREATESESSION = 41, /* v4.1 */ + OP_BIND_BACKCHANNEL = 42, /* v4.1 */ + OP_DESTROYSESSION = 43, /* v4.1 */ + OP_SEQUENCE = 44, /* v4.1 */ OP_ILLEGAL = 10044, }; +#ifdef NEVER_NEVER +enum nfs_cb_opnum4 { + OP_CB_GETATTR = 3, + OP_CB_RECALL = 4, + OP_CB_RECALL_CREDIT = 5, /* v4.1 */ + OP_CB_ILLEGAL = 10044 +}; +#endif /* NEVER NEVER */ + enum nfsstat4 { NFS4_OK = 0, NFS4ERR_PERM = 1, @@ -222,7 +237,12 @@ NFS4ERR_DEADLOCK = 10045, NFS4ERR_FILE_OPEN = 10046, NFS4ERR_ADMIN_REVOKED = 10047, - NFS4ERR_CB_PATH_DOWN = 10048 + NFS4ERR_CB_PATH_DOWN = 10048, + /* v4.1-only errors */ + NFS4ERR_BADSESSION = 10049, + NFS4ERR_BADSLOT = 10050, + NFS4ERR_BADCHAIN = 10051, + NFS4ERR_CHAIN_BROKEN = 10052 }; /* @@ -279,6 +299,31 @@ NFS4_WRITEW_LT = 4 }; +enum nfs4_channel_mode { + NFS4_DEFAULT = 0, + NFS4_STREAM = 1, + NFS4_RDMA = 2 +}; + +static inline int valid_nfs4_channel_mode(enum nfs4_channel_mode value) { + return (value == NFS4_DEFAULT) + || (value == NFS4_STREAM) + || (value == NFS4_RDMA); +} + +enum nfs4_chainflags { + NFS4_NOCHAIN = 0, + NFS4_CHAINBEGIN = 1, + NFS4_CHAINCONTINUE = 2, + NFS4_CHAINEND = 3 +}; + +static inline int valid_nfs4_chainflags(enum nfs4_chainflags value) { + return (value == NFS4_NOCHAIN) + || (value == NFS4_CHAINBEGIN) + || (value == NFS4_CHAINCONTINUE) + || (value == NFS4_CHAINEND); +} /* Mandatory Attributes */ #define FATTR4_WORD0_SUPPORTED_ATTRS (1UL << 0) @@ -342,7 +387,7 @@ #define NFSPROC4_NULL 0 #define NFSPROC4_COMPOUND 1 -#define NFS4_MINOR_VERSION 0 +#define NFS4_MINOR_VERSION 1 #define NFS4_DEBUG 1 #ifdef __KERNEL__ @@ -384,6 +429,11 @@ NFSPROC4_CLNT_DELEGRETURN, NFSPROC4_CLNT_GETACL, NFSPROC4_CLNT_SETACL, + NFSPROC4_CLNT_CREATE_CLIENTID, + NFSPROC4_CLNT_CREATE_SESSION, + NFSPROC4_CLNT_BIND_BACKCHANNEL, + NFSPROC4_CLNT_DESTROY_SESSION, + NFSPROC4_CLNT_SEQUENCE, }; #endif Index: linux-sessions-2.6.14/include/linux/nfsd/nfsd.h =================================================================== --- linux-sessions-2.6.14.orig/include/linux/nfsd/nfsd.h 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/include/linux/nfsd/nfsd.h 2005-11-29 16:11:14.000000000 -0500 @@ -28,7 +28,7 @@ * nfsd version */ #define NFSD_VERSION "0.5" -#define NFSD_SUPPORTED_MINOR_VERSION 0 +#define NFSD_SUPPORTED_MINOR_VERSION 1 #ifdef __KERNEL__ /* @@ -232,14 +232,20 @@ #define nfserr_badname __constant_htonl(NFSERR_BADNAME) #define nfserr_cb_path_down __constant_htonl(NFSERR_CB_PATH_DOWN) #define nfserr_locked __constant_htonl(NFSERR_LOCKED) +#define nfserr_badsession __constant_htonl(NFSERR_BADSESSION) +#define nfserr_badslot __constant_htonl(NFSERR_BADSLOT) +#define nfserr_badchain __constant_htonl(NFSERR_BADCHAIN) +#define nfserr_chain_broken __constant_htonl(NFSERR_CHAIN_BROKEN) /* error codes for internal use */ -/* if a request fails due to kmalloc failure, it gets dropped. - * Client should resend eventually +/* if a request fails due to upcall delay, it gets dropped. + * Call will be revisited later */ #define nfserr_dropit __constant_htonl(30000) /* end-of-file indicator in readdir */ #define nfserr_eof __constant_htonl(30001) +/* replay of a request which is in progress, it gets dropped */ +#define nfserr_inprog __constant_htonl(30002) /* Check for dir entries '.' and '..' */ #define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) Index: linux-sessions-2.6.14/include/linux/nfsd/state.h =================================================================== --- linux-sessions-2.6.14.orig/include/linux/nfsd/state.h 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/include/linux/nfsd/state.h 2005-11-29 16:11:14.000000000 -0500 @@ -41,13 +41,18 @@ #include #include -#define NFS4_OPAQUE_LIMIT 1024 typedef struct { u32 cl_boot; u32 cl_id; } clientid_t; typedef struct { + clientid_t se_clientid; + u32 se_unused; + u32 se_id; +} sessionid_t; + +typedef struct { u32 so_boot; u32 so_stateownerid; u32 so_fileid; @@ -132,6 +137,23 @@ struct nfs4_callback cl_callback; /* callback info */ atomic_t cl_count; /* ref count */ u32 cl_firststate; /* recovery dir creation */ + u32 cl_minorvers; /* minor version */ + struct list_head cl_sessions; /* list: sessions */ + u32 cl_currsessid; /* id of next new session */ +}; + +/* + * State associated with the v4.1 session abstraction. *:1 with nfs4_client. + */ +struct nfs4_session { + struct list_head se_perclient; /* nfs4_client->cl_sessions */ + struct nfs4_client *se_client; /* owner of the session */ + u32 se_id; /* sessionid_t.se_id */ + u32 se_maxreqsize; /* max request size */ + u32 se_maxrespsize; /* max response size */ + u32 se_maxreqs; /* max for channel */ + u32 se_headerpad; /* header pad size */ + struct nfs4_cache_entry *se_drc; /* duplicate request cache */ }; /* struct nfs4_client_reset Index: linux-sessions-2.6.14/include/linux/nfsd/xdr4.h =================================================================== --- linux-sessions-2.6.14.orig/include/linux/nfsd/xdr4.h 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/include/linux/nfsd/xdr4.h 2005-11-29 16:11:14.000000000 -0500 @@ -333,6 +333,52 @@ nfs4_verifier wr_verifier; /* response */ }; +/* v4.1 structures */ + +struct nfsd4_createclientid { + nfs4_verifier cc_verifier; /* request */ + u32 cc_namelen; /* request */ + char * cc_name; /* request */ + clientid_t cc_clientid; /* response */ + nfs4_verifier cc_confirm; /* response */ +}; + +struct nfsd4_createsession { + clientid_t cs_clientid; /* request */ + sessionid_t cs_sessionid; /* response */ + u32 cs_persist; /* both */ + u32 cs_maxreqsize; /* both */ + u32 cs_maxrespsize; /* both */ + u32 cs_maxreqs; /* both */ + u32 cs_headerpad; /* both */ + u32 cs_clientid_confirm; /* request */ + /* cc_confirm only occurs when cs_clientid_confirm is true */ + nfs4_verifier cs_confirm; /* request */ + enum nfs4_channel_mode cs_mode; /* both */ + /* cc_maxrdmareads only occurs when cs_mode == NFS4_RDMA */ + u32 cs_maxrdmareads; /* both */ +}; + +struct nfsd4_bind_backchannel { + clientid_t bb_clientid; /* request */ + u32 bb_callback_prog; /* request */ + u32 bb_callback_ident; /* request */ + u32 bb_maxreqsize; /* both */ + u32 bb_maxrespsize; /* both */ + u32 bb_maxreqs; /* both */ + enum nfs4_channel_mode bb_mode; /* both */ + /* cc_maxrdmareads only occurs when bb_mode == NFS4_RDMA */ + u32 bb_maxrdmareads; /* both */ +}; + +struct nfsd4_sequence { + sessionid_t se_sessionid; /* both */ + u32 se_sequenceid; /* both */ + u32 se_slotid; /* both */ + u32 se_maxslot; /* both */ + enum nfs4_chainflags se_chainflags; /* request */ +}; + struct nfsd4_op { int opnum; int status; @@ -366,6 +412,11 @@ struct nfsd4_verify verify; struct nfsd4_write write; struct nfsd4_release_lockowner release_lockowner; + struct nfsd4_createclientid createclientid; + struct nfsd4_createsession createsession; + struct nfsd4_bind_backchannel bind_backchannel; + sessionid_t destroysession; + struct nfsd4_sequence sequence; } u; struct nfs4_replay * replay; }; @@ -409,6 +460,183 @@ #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs) +struct nfs4_cache_entry { + /* For client replay */ + enum { + NFS4_CE_AVAILABLE = 0, + NFS4_CE_INPROGRESS = 1, + NFS4_CE_COMPLETE = 2 + } ce_status; + u32 ce_sequenceid; + struct xdr_buf ce_xdr; + struct page * ce_respages[RPCSVC_MAXPAGES]; + int ce_restailpage; + short ce_resused; + int ce_compstat; /* compound return */ + + /* For deferred op resume (due to upcall) */ + struct nfsd4_compoundres ce_resp; /* XDR scratch variables */ + int ce_opcnt; /* index of last OK op */ + struct svc_fh *ce_current_fh; + struct svc_fh *ce_save_fh; +}; + +static inline void +print_cache_entry(struct nfs4_cache_entry *entry) { + int i; + + printk("nfs4_cache_entry @ %p\n", entry); + if (entry) { + switch (entry->ce_status) { + case NFS4_CE_AVAILABLE: + printk("\tstatus = available\n"); + break; + case NFS4_CE_INPROGRESS: + printk("\tstatus = in progress\n"); + break; + case NFS4_CE_COMPLETE: + printk("\tstatus = complete\n"); + break; + default: + printk("\tstatus = unknown value\n"); + break; + } + printk("\tsequenceid = %u\n", entry->ce_sequenceid); + printk("\tcompound status = %u\n", ntohl(entry->ce_compstat)); + if (entry->ce_status == NFS4_CE_INPROGRESS) + printk("\top count = %u\n", entry->ce_opcnt); + if (entry->ce_resp.xbuf) { + printk("\txbuf = %p\n", entry->ce_resp.xbuf); + printk("\thead.iov_base = %p\n", entry->ce_resp.xbuf->head[0].iov_base); + printk("\thead.iov_len = %u\n", entry->ce_resp.xbuf->head[0].iov_len); + printk("\tpage_lin = %u\n", entry->ce_resp.xbuf->page_len); + printk("\ttail.iov_base = %p\n", entry->ce_resp.xbuf->tail[0].iov_base); + printk("\ttail.iov_len = %u\n", entry->ce_resp.xbuf->tail[0].iov_len); + printk("\tp = %p\n",entry->ce_resp.p); + } + printk("\tend = %p\n",entry->ce_resp.end); + printk("\txdr_buf = %p\n",entry->ce_resp.xbuf); + printk("\trqstp = %p\n",entry->ce_resp.rqstp); + printk("\topcnt = %u\n",entry->ce_resp.opcnt); + + for (i = 0; i < RPCSVC_MAXPAGES; i++) { + if (entry->ce_respages[i]) { + printk("\tce_respages[%d] = %p -> %p\n", i, entry->ce_respages[i], page_address(entry->ce_respages[i])); + } + } + printk("\tce_resused = %d\n", entry->ce_resused); + printk("\tce_current_fh = %p\n", entry->ce_current_fh); + printk("\tce_save_fh = %p\n", entry->ce_save_fh); + } +} + +/* Called after processing and XDR encoding before reply is sent */ +static inline void +write_cache_entry(struct nfs4_cache_entry *entry, + struct svc_rqst *rqstp, int compstat, u32 opcnt, + struct svc_fh *current_fh, struct svc_fh *save_fh) { + int i; + + /* nfserr_dropit implies that we are stalled, waiting on an upcall + * This compound will be revisited when it returns. + * Otherwise, we can assume this function is being called because + * processing is complete and we are about to send the reply */ + if (compstat != nfserr_dropit) { + entry->ce_status = NFS4_CE_COMPLETE; + } + + /* FIXME don't copy certain data unless deferring op */ + memcpy(&entry->ce_resp, rqstp->rq_resp, sizeof(entry->ce_resp)); + memcpy(&entry->ce_xdr, &rqstp->rq_res, sizeof(struct xdr_buf)); + memcpy(entry->ce_respages, rqstp->rq_respages, + RPCSVC_MAXPAGES * sizeof(struct page *)); + entry->ce_restailpage = rqstp->rq_restailpage; + entry->ce_resused = rqstp->rq_resused; + entry->ce_compstat = compstat; + entry->ce_opcnt = opcnt; + entry->ce_current_fh = current_fh; + entry->ce_save_fh = save_fh; + + for (i = 0; i < entry->ce_resused; i++) { + if (!entry->ce_respages[i]) { + continue; + } + + get_page(entry->ce_respages[i]); + } +} + +static inline int +read_cache_entry(struct svc_rqst *rqstp, struct nfs4_cache_entry *entry) { + struct nfsd4_compoundres * resp; + resp = (struct nfsd4_compoundres *)rqstp->rq_resp; + + /* + * Becase rqstp may be different than when this entry was cached, + * we need to be very careful with pointers and such. Because we + * saved the array of pages, pointers into the actual data are still + * valid. So are the filehandle pointers. However, pointers into the + * rqstp structure itself need to be swizzled to point to the new + * rqstp structure. + */ + + /* First, free all existing pages for this rqstp. */ + svc_free_allpages(rqstp); + + /* Then, copy in the pointers to the pages & appropriate info. */ + memcpy(rqstp->rq_respages, entry->ce_respages, + RPCSVC_MAXPAGES * sizeof(struct page *)); + rqstp->rq_restailpage = entry->ce_restailpage; + rqstp->rq_resused = entry->ce_resused; + + /* Then, copy in the old values of the xdr struct... */ + memcpy(&rqstp->rq_res, &entry->ce_xdr, sizeof(struct xdr_buf)); + /* ...swizzling the appropriate pointers. The following pointers are + * into the target data (AFAICT) and don't need to be swizzled: + * .head[0].iov_base + * .tail[0].iov_base + * .page_base + */ + rqstp->rq_res.pages = rqstp->rq_respages; + + /* Then, copy in the old values of rq_rsp... */ + char *stag = resp->tag; + int staglen = resp->taglen; + memcpy(resp, &entry->ce_resp, sizeof(entry->ce_resp)); + /* ...swizzling the appropriate pointers. The following pointers + * are into the target data (AFAICT) and don't need to be swizzled: + * .p + * .end + * .tagp + * These pointers seem to want to point to something new, so use + * the values that were passed: + * .tag, .taglen + */ + resp->rqstp = rqstp; + resp->xbuf = &rqstp->rq_res; + resp->tag = stag; + resp->taglen = staglen; + + return entry->ce_compstat; +} + +/* Other values will be overwritten when entry is reused. We only need to + * return the pages we were keeping around at this point + */ +static inline void +clear_cahe_entry(struct nfs4_cache_entry *entry) { + int i; + + for (i = 0; i < entry->ce_resused; i++) { + if (!entry->ce_respages[i]) { + continue; + } + + put_page(entry->ce_respages[i]); + entry->ce_respages[i] = NULL; + } +} + static inline void set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) { @@ -427,6 +655,7 @@ struct nfsd4_compoundres *); void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); +int nfsd4_encode_compound_replay(struct nfsd4_compoundres *resp); int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval, struct svc_rqst *); @@ -460,6 +689,19 @@ extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *); extern int nfsd4_delegreturn(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_delegreturn *dr); +/* v4.1 operations */ +extern int nfsd4_createclientid(struct svc_rqst *rqstp, + struct nfsd4_createclientid *create_clientid); +extern int nfsd4_createsession(struct svc_rqst *rqstp, + struct nfsd4_createsession *createsession); +extern int nfsd4_bind_backchannel(struct nfsd4_bind_backchannel *bind_backchannel); +extern int nfsd4_destroysession(sessionid_t *sessionid, + struct nfs4_session **sessionpp, + struct nfs4_cache_entry **cache_entrypp); +extern int nfsd4_sequence(struct nfsd4_compoundres *resp, + struct nfsd4_sequence *seq, + struct nfs4_session **session, + struct nfs4_cache_entry **cache_entry); #endif /* Index: linux-sessions-2.6.14/include/linux/nfs.h =================================================================== --- linux-sessions-2.6.14.orig/include/linux/nfs.h 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/include/linux/nfs.h 2005-11-29 16:11:14.000000000 -0500 @@ -112,7 +112,12 @@ NFSERR_FILE_OPEN = 10046, /* v4 */ NFSERR_ADMIN_REVOKED = 10047, /* v4 */ NFSERR_CB_PATH_DOWN = 10048, /* v4 */ - NFSERR_REPLAY_ME = 10049 /* v4 */ + NFSERR_BADSESSION = 10049, /* v4.1 */ + NFSERR_BADSLOT = 10050, /* v4.1 */ + NFSERR_BADCHAIN = 10051, /* v4.1 */ + NFSERR_CHAIN_BROKEN = 10052, /* v4.1 */ + /* not a part of the spec; used internally; must be > any valid err */ + NFSERR_REPLAY_ME = 10053 /* v4 */ }; /* NFSv2 file types - beware, these are not the same in NFSv3 */ Index: linux-sessions-2.6.14/include/linux/nfs_xdr.h =================================================================== --- linux-sessions-2.6.14.orig/include/linux/nfs_xdr.h 2005-11-29 16:11:13.000000000 -0500 +++ linux-sessions-2.6.14/include/linux/nfs_xdr.h 2005-12-03 15:13:01.000000000 -0500 @@ -106,6 +106,31 @@ u64 after; }; +#ifdef CONFIG_NFS_V4 +/* + * Arguments to the session sequence op. + */ + +struct nfs4_sequence_args { + int slotId; + u32 maxslot; + u32 seqId; + struct nfs4_client_session * session; +}; + +typedef u8 sessionid4[16]; + +struct nfs4_sequence_res { + sessionid4 sessionid; + u32 sequenceid; + u32 slotid; + u32 maxslot; +}; +#endif /* CONFIG_NFS_V4 */ + + + + /* * Arguments to the open call. */ @@ -125,6 +150,9 @@ const struct nfs_server *server; /* Needed for ID mapping */ const u32 * bitmask; __u32 claim; +#ifdef CONFIG_NFS_V4 + struct nfs4_sequence_args sessargs; +#endif /* CONFIG_NFS_V4 */ }; struct nfs_openres { @@ -138,6 +166,9 @@ nfs4_stateid delegation; __u32 do_recall; __u64 maxsize; +#ifdef CONFIG_NFS_V4 + struct nfs4_client_session *session; +#endif /* CONFIG_NFS_V4 */ }; /* @@ -147,10 +178,16 @@ const struct nfs_fh * fh; nfs4_stateid stateid; __u32 seqid; +#ifdef CONFIG_NFS_V4 + struct nfs4_sequence_args sessargs; +#endif /* CONFIG_NFS_V4 */ }; struct nfs_open_confirmres { nfs4_stateid stateid; +#ifdef CONFIG_NFS_V4 + struct nfs4_client_session *session; +#endif /* CONFIG_NFS_V4 */ }; /* @@ -161,14 +198,20 @@ nfs4_stateid stateid; __u32 seqid; int open_flags; +#ifdef CONFIG_NFS_V4 + struct nfs4_sequence_args sessargs; +#endif /* CONFIG_NFS_V4 */ }; struct nfs_closeres { nfs4_stateid stateid; +#ifdef CONFIG_NFS_V4 + struct nfs4_client_session *session; +#endif /* CONFIG_NFS_V4 */ }; /* - * * Arguments to the lock,lockt, and locku call. - * */ + * Arguments to the lock,lockt, and locku call. + */ struct nfs_lowner { __u64 clientid; u32 id; @@ -210,6 +253,9 @@ struct nfs_lowner *lockt; /* LOCKT */ struct nfs_locku_opargs *locku; /* LOCKU */ } u; +#ifdef CONFIG_NFS_V4 + struct nfs4_sequence_args sessargs; +#endif /* CONFIG_NFS_V4 */ }; struct nfs_lock_denied { @@ -225,11 +271,17 @@ struct nfs_lock_denied denied; /* LOCK failed, LOCKT success */ } u; const struct nfs_server * server; +#ifdef CONFIG_NFS_V4 + struct nfs4_client_session * session; +#endif /* CONFIG_NFS_V4 */ }; struct nfs4_delegreturnargs { const struct nfs_fh *fhandle; const nfs4_stateid *stateid; +#ifdef CONFIG_NFS_V4 + struct nfs4_sequence_args sessargs; +#endif /* CONFIG_NFS_V4 */ }; /* @@ -242,12 +294,18 @@ __u32 count; unsigned int pgbase; struct page ** pages; +#ifdef CONFIG_NFS_V4 + struct nfs4_sequence_args sessargs; +#endif /* CONFIG_NFS_V4 */ }; struct nfs_readres { struct nfs_fattr * fattr; __u32 count; int eof; +#ifdef CONFIG_NFS_V4 + struct nfs4_client_session *session; /* session relationship */ +#endif }; /* @@ -261,6 +319,9 @@ enum nfs3_stable_how stable; unsigned int pgbase; struct page ** pages; +#ifdef CONFIG_NFS_V4 + struct nfs4_sequence_args sessargs; +#endif }; struct nfs_writeverf { @@ -272,6 +333,9 @@ struct nfs_fattr * fattr; struct nfs_writeverf * verf; __u32 count; +#ifdef CONFIG_NFS_V4 + struct nfs4_client_session *session; /* session relationship */ +#endif }; /* @@ -324,6 +388,9 @@ struct iattr * iap; const struct nfs_server * server; /* Needed for name mapping */ const u32 * bitmask; +#ifdef CONFIG_NFS_V4 + struct nfs4_sequence_args sessargs; +#endif /* CONFIG_NFS_V4 */ }; struct nfs_setaclargs { @@ -331,6 +398,9 @@ size_t acl_len; unsigned int acl_pgbase; struct page ** acl_pages; +#ifdef CONFIG_NFS_V4 + struct nfs4_sequence_args sessargs; +#endif /* CONFIG_NFS_V4 */ }; struct nfs_getaclargs { @@ -338,11 +408,25 @@ size_t acl_len; unsigned int acl_pgbase; struct page ** acl_pages; +#ifdef CONFIG_NFS_V4 + struct nfs4_sequence_args sessargs; +#endif /* CONFIG_NFS_V4 */ }; +struct nfs_getaclres { + ssize_t acl_len; +#ifdef CONFIG_NFS_V4 + struct nfs4_client_session * session; +#endif /* CONFIG_NFS_V4 */ +}; + + struct nfs_setattrres { struct nfs_fattr * fattr; const struct nfs_server * server; +#ifdef CONFIG_NFS_V4 + struct nfs4_client_session * session; +#endif /* CONFIG_NFS_V4 */ }; struct nfs_linkargs { @@ -525,11 +609,13 @@ struct nfs4_accessargs { const struct nfs_fh * fh; u32 access; + struct nfs4_sequence_args sessargs; }; struct nfs4_accessres { u32 supported; u32 access; + struct nfs4_client_session * session; }; struct nfs4_create_arg { @@ -546,6 +632,7 @@ const struct iattr * attrs; const struct nfs_fh * dir_fh; const u32 * bitmask; + struct nfs4_sequence_args sessargs; }; struct nfs4_create_res { @@ -553,48 +640,72 @@ struct nfs_fh * fh; struct nfs_fattr * fattr; struct nfs4_change_info dir_cinfo; + struct nfs4_client_session * session; }; struct nfs4_fsinfo_arg { const struct nfs_fh * fh; const u32 * bitmask; + struct nfs4_sequence_args sessargs; +}; + +struct nfs4_fsinfo_res { + struct nfs_fsinfo *fsinfo; + struct nfs4_client_session * session; }; struct nfs4_getattr_arg { const struct nfs_fh * fh; const u32 * bitmask; + struct nfs4_sequence_args sessargs; }; struct nfs4_getattr_res { const struct nfs_server * server; struct nfs_fattr * fattr; + struct nfs4_client_session * session; }; struct nfs4_link_arg { const struct nfs_fh * fh; const struct nfs_fh * dir_fh; const struct qstr * name; + struct nfs4_sequence_args sessargs; +}; + +struct nfs4_link_res { + struct nfs4_change_info * cinfo; + struct nfs4_client_session * session; }; struct nfs4_lookup_arg { const struct nfs_fh * dir_fh; const struct qstr * name; const u32 * bitmask; + struct nfs4_sequence_args sessargs; }; struct nfs4_lookup_res { const struct nfs_server * server; struct nfs_fattr * fattr; struct nfs_fh * fh; + struct nfs4_client_session *session; }; struct nfs4_lookup_root_arg { const u32 * bitmask; + struct nfs4_sequence_args sessargs; }; struct nfs4_pathconf_arg { const struct nfs_fh * fh; const u32 * bitmask; + struct nfs4_sequence_args sessargs; +}; + +struct nfs4_pathconf_res { + struct nfs_pathconf * nfs_pathconf; + struct nfs4_client_session * session; }; struct nfs4_readdir_arg { @@ -605,11 +716,13 @@ struct page ** pages; /* zero-copy data */ unsigned int pgbase; /* zero-copy data */ const u32 * bitmask; + struct nfs4_sequence_args sessargs; }; struct nfs4_readdir_res { nfs4_verifier verifier; unsigned int pgbase; + struct nfs4_client_session * session; }; struct nfs4_readlink { @@ -617,11 +730,18 @@ unsigned int pgbase; unsigned int pglen; /* zero-copy data */ struct page ** pages; /* zero-copy data */ + struct nfs4_sequence_args sessargs; }; struct nfs4_remove_arg { const struct nfs_fh * fh; const struct qstr * name; + struct nfs4_sequence_args sessargs; +}; + +struct nfs4_remove_res { + struct nfs4_change_info cinfo; + struct nfs4_client_session * session; }; struct nfs4_rename_arg { @@ -629,11 +749,13 @@ const struct nfs_fh * new_dir; const struct qstr * old_name; const struct qstr * new_name; + struct nfs4_sequence_args sessargs; }; struct nfs4_rename_res { struct nfs4_change_info old_cinfo; struct nfs4_change_info new_cinfo; + struct nfs4_client_session * session; }; struct nfs4_setclientid { @@ -646,11 +768,33 @@ unsigned int sc_uaddr_len; char sc_uaddr[24]; /* request */ u32 sc_cb_ident; /* request */ + struct nfs4_sequence_args sc_sessargs; +}; + +struct nfs4_setclientid_confirm_arg { + struct nfs4_client * clp; + struct nfs4_sequence_args sessargs; +}; + +struct nfs4_setclientid_confirm_res { + struct nfs_fsinfo * fsinfo; + struct nfs4_client_session * session; }; struct nfs4_statfs_arg { const struct nfs_fh * fh; const u32 * bitmask; + struct nfs4_sequence_args sessargs; +}; + +struct nfs4_statfs_res { + struct nfs_fsstat * fsstat; + struct nfs4_client_session * session; +}; + +struct nfs4_server_caps_arg { + const struct nfs_fh * fhandle; + struct nfs4_sequence_args sessargs; }; struct nfs4_server_caps_res { @@ -658,6 +802,87 @@ u32 acl_bitmask; u32 has_links; u32 has_symlinks; + struct nfs4_client_session * session; +}; + +struct nfs4_create_clientid_args { + nfs4_verifier verifier; + char * name; + struct nfs4_sequence_args sessargs; +}; + +struct nfs4_create_clientid_res { + clientid4 clientid; + nfs4_verifier confirm; + struct nfs4_client_session * session; +}; + +struct nfs4_create_session_args { + clientid4 clientid; + u32 persist; + u32 maxrequestsize; + u32 maxresponsesize; + u32 maxrequests; + u32 headerpadsize; + u32 clientid_confirm; + /* confirm only occurs when clientid_confirm is true */ + nfs4_verifier confirm; + enum nfs4_channel_mode mode; + /* maxrdmareads only occurs when mode == NFS4_RDMA */ + u32 maxrdmareads; + struct nfs4_sequence_args sessargs; +}; + +struct nfs4_create_session_res { + sessionid4 sessionid; + u32 persist; + u32 maxrequestsize; + u32 maxresponsesize; + u32 maxrequests; + u32 headerpadsize; + enum nfs4_channel_mode mode; + /* maxrdmareads only occurs when mode == NFS4_RDMA */ + u32 maxrdmareads; + struct nfs_fsinfo *fsinfo; + struct nfs4_client_session *session; +}; + +struct nfs4_bind_backchannel_args { + clientid4 clientid; + u32 callback_prog; + u32 callback_ident; + u32 maxreqsize; + u32 maxrespsize; + u32 maxreqs; + enum nfs4_channel_mode mode; + /* maxrdmareads only occurs when mode == NFS4_RDMA */ + u32 maxrdmareads; + + struct nfs4_sequence_args sessargs; /* session relationship */ +}; + +struct nfs4_bind_backchannel_res { + u32 maxreqsize; + u32 maxrespsize; + u32 maxreqs; + enum nfs4_channel_mode mode; + /* maxrdmareads only occurs when mode == NFS4_RDMA */ + u32 maxrdmareads; +}; + + + +struct nfs4_destroy_session_args { + struct nfs4_sequence_args sessargs; /* session relationship */ +}; + +struct nfs4_destroy_session_res { + sessionid4 sessionid; +}; + +struct nfs4_cb_credit_recall_args { + u32 targetcredits; + struct nfs4_sequence_args sessargs; /* session relationship */ }; #endif /* CONFIG_NFS_V4 */ Index: linux-sessions-2.6.14/net/sunrpc/svc.c =================================================================== --- linux-sessions-2.6.14.orig/net/sunrpc/svc.c 2005-11-29 16:11:13.000000000 -0500 +++ linux-sessions-2.6.14/net/sunrpc/svc.c 2005-11-29 16:11:14.000000000 -0500 @@ -262,7 +262,9 @@ struct kvec * argv = &rqstp->rq_arg.head[0]; struct kvec * resv = &rqstp->rq_res.head[0]; kxdrproc_t xdr; - u32 *statp; + u32 status = -1; + u32 status_offset = -1; /* bytes from RPC hdr base */ + u32 *statp = NULL; /* -> status in RPC header */ u32 dir, prog, vers, proc, auth_stat, rpc_stat; int auth_res; @@ -361,7 +363,8 @@ serv->sv_stats->rpccnt++; /* Build the reply header. */ - statp = resv->iov_base +resv->iov_len; + status_offset = resv->iov_len; + statp = resv->iov_base + status_offset; svc_putu32(resv, rpc_success); /* RPC_SUCCESS */ /* Bump per-procedure stats counter */ @@ -384,10 +387,13 @@ if (xdr && !xdr(rqstp, argv->iov_base, rqstp->rq_argp)) goto err_garbage; - *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); + /* resv->iov_base may have changed during processing */ + status = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); + statp = resv->iov_base + status_offset; + *statp = status; /* Encode reply */ - if (*statp == rpc_success && (xdr = procp->pc_encode) + if (*statp == rpc_success && (xdr = procp->pc_encode) && !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) { dprintk("svc: failed to encode reply\n"); /* serv->sv_stats->rpcsystemerr++; */ @@ -401,8 +407,10 @@ procp->pc_release(rqstp, NULL, rqstp->rq_resp); goto dropit; } + /* resv->iov_base may have changed during processing */ + statp = resv->iov_base + status_offset; } - + /* Check RPC status result */ if (*statp != rpc_success) resv->iov_len = ((void*)statp) - resv->iov_base + 4; Index: linux-sessions-2.6.14/fs/nfs/nfs4_fs.h =================================================================== --- linux-sessions-2.6.14.orig/fs/nfs/nfs4_fs.h 2005-11-29 16:07:40.000000000 -0500 +++ linux-sessions-2.6.14/fs/nfs/nfs4_fs.h 2005-12-03 15:13:01.000000000 -0500 @@ -11,6 +11,82 @@ #ifdef CONFIG_NFS_V4 +/* + * NFS4 session management + * its possible for rpc's to travel without sessions. + */ + +#define NFS4_SESSION_REQUESTS 512 + +struct nfs4_client_session { + u32 cs_magic; + u32 cs_flags; + clientid4 cs_clientid; /* in client struct? */ + u32 cs_nfs4version; + u32 cs_xdr_inline; + u32 cs_persists; + sessionid4 cs_sessions; + u32 cs_seqId; + u32 cs_totalrequests; + u8 cs_streamId; + u8 cs_slotId[NFS4_SESSION_REQUESTS]; + spinlock_t cs_lock; + wait_queue_head_t cs_wantSlots; +}; + +#define NFS4_SESS_MAGIC 0xfefefe + +#define NFS4_CLSESS_OPERACTIVE 1 /* oper control on the sess */ +#define NFS4_CLSESS_FAILED 2 /* failed in session create */ + +static inline +int +nfs4_client_findslot(struct nfs4_client_session *sess) +{ + int i; + for (i=0; ics_totalrequests; ++i) { + if (sess->cs_slotId[i] == 0) + return i; + } + return -1; +} + +static inline +int +nfs4_client_maxslot(struct nfs4_client_session *sess) +{ + int i; + for (i=sess->cs_totalrequests; i>=0; --i) { + if (sess->cs_slotId[i] == 1) + return i; + } + return -1; +} + +static inline +void +nfs4_client_markslot(struct nfs4_client_session *sess, int slot) +{ + sess->cs_slotId[slot] = 1; +} + +static inline +void +nfs4_client_unmarkslot(struct nfs4_client_session *sess, int slot) +{ + if ((slot >= 0) && (slot < sess->cs_totalrequests)) + sess->cs_slotId[slot] = 0; +} + + +static inline +void +nfs4_client_resetslots(struct nfs4_client_session *sess) +{ + memset(&sess->cs_slotId, '0', sizeof(sess->cs_slotId)); +} + + struct idmap; /* @@ -90,6 +166,10 @@ */ char cl_ipaddr[16]; unsigned char cl_id_uniquifier; + + struct nfs4_sequence_res cl_sequence; + struct nfs4_sequence_args cl_seqargs; /* ONLY for renew */ + struct nfs4_client_session *cl_session; }; /* @@ -231,6 +311,7 @@ extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); extern const nfs4_stateid zero_stateid; +extern int nfs4_session_cons(struct nfs4_client *); /* nfs4xdr.c */ extern uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus);