Create XDR and surrounding functions on the client for the CB_LAYOUTRECALL command. --- linux-2.6.14-andros/fs/nfs/callback.h | 9 +++++ linux-2.6.14-andros/fs/nfs/callback_proc.c | 46 +++++++++++++++++++++++++++++ linux-2.6.14-andros/fs/nfs/callback_xdr.c | 29 +++++++++++++++++- 3 files changed, 83 insertions(+), 1 deletion(-) diff -puN fs/nfs/callback.h~client-layoutrecall fs/nfs/callback.h --- linux-2.6.14/fs/nfs/callback.h~client-layoutrecall 2005-12-23 12:02:22.000000000 -0500 +++ linux-2.6.14-andros/fs/nfs/callback.h 2005-12-23 12:28:26.000000000 -0500 @@ -20,6 +20,7 @@ enum nfs4_callback_procnum { enum nfs4_callback_opnum { OP_CB_GETATTR = 3, OP_CB_RECALL = 4, + OP_CB_LAYOUTRECALL = 5, OP_CB_ILLEGAL = 10044, }; @@ -59,8 +60,16 @@ struct cb_recallargs { uint32_t truncate; }; +struct cb_pnfs_layoutrecallargs { + struct sockaddr_in *addr; + struct nfs_fh fh; + uint64_t offset; + uint64_t length; +}; + extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy); +extern unsigned nfs4_callback_pnfs_layoutrecall(struct cb_pnfs_layoutrecallargs *args, void *dummy); extern int nfs_callback_up(void); extern int nfs_callback_down(void); diff -puN fs/nfs/callback_proc.c~client-layoutrecall fs/nfs/callback_proc.c --- linux-2.6.14/fs/nfs/callback_proc.c~client-layoutrecall 2005-12-23 12:02:22.000000000 -0500 +++ linux-2.6.14-andros/fs/nfs/callback_proc.c 2005-12-23 12:54:51.000000000 -0500 @@ -84,3 +84,49 @@ out: dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); return res; } + +/* + * Layout is not actually returned until the client executes the + * LAYOUTRETURN operation. + * The general semantics are that once a layout has been recalled, + * all in flight I/O ops are completed and then LAYOUTRETURN is called. + * + * XXX The layout driver needs to choose to write all buffered I/O using: + * 1) the layoutdriver if still available or + * 2) the NFSv4 READ/WRITE ops after the layout is returned + */ +unsigned nfs4_callback_pnfs_layoutrecall(struct cb_pnfs_layoutrecallargs *args, void *dummy) +{ + struct nfs4_client *clp; + struct inode *inode; + unsigned res; + + res = htonl(NFS4ERR_BADHANDLE); + clp = nfs4_find_client(&args->addr->sin_addr); + if (clp == NULL) + goto out; + + /* XXX Need to customize this lookup for a layout delegation */ + inode = nfs_delegation_find_inode(clp, &args->fh); + if (inode == NULL) + goto out_putclient; + /* XXX Need to actually implement recall of layout */ + /* Set up a helper thread to actually return the delegation + switch(nfs_async_inode_return_delegation(inode, &args->stateid)) { + case 0: + res = 0; + break; + case -ENOENT: + res = htonl(NFS4ERR_BAD_STATEID); + break; + default: + res = htonl(NFS4ERR_RESOURCE); + } + */ + iput(inode); +out_putclient: + nfs4_put_client(clp); +out: + dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); + return res; +} diff -puN fs/nfs/callback_xdr.c~client-layoutrecall fs/nfs/callback_xdr.c --- linux-2.6.14/fs/nfs/callback_xdr.c~client-layoutrecall 2005-12-23 12:02:22.000000000 -0500 +++ linux-2.6.14-andros/fs/nfs/callback_xdr.c 2005-12-23 12:56:40.000000000 -0500 @@ -20,6 +20,7 @@ CB_OP_GETATTR_BITMAP_MAXSZ + \ 2 + 2 + 3 + 3) #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) +#define CB_OP_LAYOUTRECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) #define NFSDBG_FACILITY NFSDBG_CALLBACK @@ -205,6 +206,27 @@ out: return 0; } +static unsigned decode_pnfs_layoutrecall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_pnfs_layoutrecallargs *args) +{ + uint32_t *p; + unsigned status; + + args->addr = &rqstp->rq_addr; + status = decode_fh(xdr, &args->fh); + if (unlikely(status != 0)) + goto out; + p = read_buf(xdr, 16); + if (unlikely(p == NULL)) { + status = htonl(NFS4ERR_RESOURCE); + goto out; + } + p = xdr_decode_hyper(p, &args->offset); + p = xdr_decode_hyper(p, &args->length); +out: + dprintk("%s: exit with status = %d\n", __FUNCTION__, status); + return 0; +} + static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) { uint32_t *p; @@ -369,7 +391,7 @@ static unsigned process_op(struct svc_rq if (unlikely(status != 0)) { op_nr = OP_CB_ILLEGAL; op = &callback_ops[0]; - } else if (unlikely(op_nr != OP_CB_GETATTR && op_nr != OP_CB_RECALL)) { + } else if (unlikely(op_nr != OP_CB_GETATTR && op_nr != OP_CB_RECALL && op_nr != OP_CB_LAYOUTRECALL)) { op_nr = OP_CB_ILLEGAL; op = &callback_ops[0]; status = htonl(NFS4ERR_OP_ILLEGAL); @@ -449,6 +471,11 @@ static struct callback_op callback_ops[] .process_op = (callback_process_op_t)nfs4_callback_recall, .decode_args = (callback_decode_arg_t)decode_recall_args, .res_maxsize = CB_OP_RECALL_RES_MAXSZ, + }, + [OP_CB_LAYOUTRECALL] = { + .process_op = (callback_process_op_t)nfs4_callback_pnfs_layoutrecall, + .decode_args = (callback_decode_arg_t)decode_pnfs_layoutrecall_args, + .res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ, } }; _