diff -u --recursive --new-file --show-c-function linux-2.6.6-10-file_ctx2/fs/nfs/Makefile linux-2.6.6-11-delegation1/fs/nfs/Makefile --- linux-2.6.6-10-file_ctx2/fs/nfs/Makefile 2004-04-21 15:27:20.000000000 -0400 +++ linux-2.6.6-11-delegation1/fs/nfs/Makefile 2004-04-21 15:30:03.000000000 -0400 @@ -9,6 +9,6 @@ nfs-y := dir.o file.o inode.o nfs2xdr nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ - idmap.o + delegation.o idmap.o nfs-$(CONFIG_NFS_DIRECTIO) += direct.o nfs-objs := $(nfs-y) diff -u --recursive --new-file --show-c-function linux-2.6.6-10-file_ctx2/fs/nfs/delegation.c linux-2.6.6-11-delegation1/fs/nfs/delegation.c --- linux-2.6.6-10-file_ctx2/fs/nfs/delegation.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.6-11-delegation1/fs/nfs/delegation.c 2004-04-21 23:49:19.000000000 -0400 @@ -0,0 +1,80 @@ +/* + * linux/fs/nfs/delegation.c + * + * Copyright (C) 2004 Trond Myklebust + * + * NFS file delegation management + * + */ +#include +#include +#include +#include + +#include "delegation.h" + +/* + * Set up a delegation on an inode + */ +void nfs_inode_set_delegation(struct inode *inode, struct nfs_openres *res) +{ + struct nfs_delegation *delegation = &NFS_I(inode)->delegation; + struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; + unsigned int type = 0; + + spin_lock(&clp->cl_lock); + memcpy(delegation->stateid.data, res->delegation.data, + sizeof(delegation->stateid.data)); + delegation->type = type; + if (list_empty(&delegation->list)) + list_add(&delegation->list, &clp->cl_delegations); + spin_unlock(&clp->cl_lock); +} + +/* + * Inform the world that we no longer possess a delegation + */ +void nfs_inode_clear_delegation(struct inode *inode) +{ + struct nfs_delegation *delegation = &NFS_I(inode)->delegation; + struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; + + if (list_empty(&delegation->list)) + return; + spin_lock(&clp->cl_lock); + if (!list_empty(&delegation->list)) { + delegation->type = 0; + list_del_init(&delegation->list); + } + spin_unlock(&clp->cl_lock); +} + +/* + * Basic procedure for returning a delegation to the server + */ +int nfs_inode_return_delegation(struct inode *inode) +{ + nfs_wb_all(inode); + if (NFS_I(inode)->delegation.type == 0) + return 0; + nfs_inode_clear_delegation(inode); + return nfs4_proc_delegreturn(inode); +} + +/* + * Retrieve the inode associated with a delegation + */ +struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle) +{ + struct nfs_inode *nfsi; + struct inode *res = NULL; + spin_lock(&clp->cl_lock); + list_for_each_entry(nfsi, &clp->cl_delegations, delegation.list) { + if (nfs_compare_fh(fhandle, &nfsi->fh) == 0) { + res = igrab(inode); + break; + } + } + spin_unlock(&clp->cl_lock); + return res; +} diff -u --recursive --new-file --show-c-function linux-2.6.6-10-file_ctx2/fs/nfs/delegation.h linux-2.6.6-11-delegation1/fs/nfs/delegation.h --- linux-2.6.6-10-file_ctx2/fs/nfs/delegation.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.6-11-delegation1/fs/nfs/delegation.h 2004-04-21 15:30:03.000000000 -0400 @@ -0,0 +1,19 @@ +/* + * linux/fs/nfs/delegation.h + * + * Copyright (c) Trond Myklebust + * + * Definitions pertaining to NFS delegated files + */ +#ifndef FS_NFS_DELEGATION_H +#define FS_NFS_DELEGATION_H + +void nfs_inode_set_delegation(struct inode *inode, struct nfs_openres *res); +void nfs_inode_clear_delegation(struct inode *inode); +int nfs_inode_return_delegation(struct inode *inode); + +struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); +/* NFSv4 delegation-related procedures */ +int nfs4_proc_delegreturn(struct inode *inode); + +#endif diff -u --recursive --new-file --show-c-function linux-2.6.6-10-file_ctx2/fs/nfs/inode.c linux-2.6.6-11-delegation1/fs/nfs/inode.c --- linux-2.6.6-10-file_ctx2/fs/nfs/inode.c 2004-04-21 15:29:54.000000000 -0400 +++ linux-2.6.6-11-delegation1/fs/nfs/inode.c 2004-04-21 15:30:03.000000000 -0400 @@ -1439,6 +1439,8 @@ static struct file_system_type nfs_fs_ty #ifdef CONFIG_NFS_V4 +#include "delegation.h" + static void nfs4_clear_inode(struct inode *); static struct super_operations nfs4_sops = { @@ -1462,6 +1464,8 @@ static void nfs4_clear_inode(struct inod { struct nfs_inode *nfsi = NFS_I(inode); + /* If we are holding a delegation, return it! */ + nfs_inode_return_delegation(inode); /* First call standard NFS clear_inode() code */ nfs_clear_inode(inode); /* Now clear out any remaining state */ @@ -1760,6 +1764,8 @@ static struct file_system_type nfs4_fs_t #define nfs4_zero_state(nfsi) \ do { \ INIT_LIST_HEAD(&(nfsi)->open_states); \ + INIT_LIST_HEAD(&(nfsi)->delegation.list); \ + nfsi->delegation.type = NFS4_OPEN_DELEGATE_NONE; \ } while(0) #define register_nfs4fs() register_filesystem(&nfs4_fs_type) #define unregister_nfs4fs() unregister_filesystem(&nfs4_fs_type) diff -u --recursive --new-file --show-c-function linux-2.6.6-10-file_ctx2/fs/nfs/nfs4proc.c linux-2.6.6-11-delegation1/fs/nfs/nfs4proc.c --- linux-2.6.6-10-file_ctx2/fs/nfs/nfs4proc.c 2004-04-21 15:29:54.000000000 -0400 +++ linux-2.6.6-11-delegation1/fs/nfs/nfs4proc.c 2004-04-21 15:30:03.000000000 -0400 @@ -47,6 +47,8 @@ #include #include +#include "delegation.h" + #define NFSDBG_FACILITY NFSDBG_PROC #define NFS4_POLL_RETRY_TIME (15*HZ) @@ -236,6 +238,7 @@ nfs4_do_open(struct inode *dir, struct q struct nfs4_state_owner *sp; struct nfs4_state *state = NULL; struct nfs_server *server = NFS_SERVER(dir); + struct nfs4_client *clp = server->nfs4_state; struct inode *inode = NULL; int status; struct nfs_fattr f_attr = { @@ -278,7 +281,7 @@ retry: down(&sp->so_sema); o_arg.seqid = sp->so_seqid; o_arg.id = sp->so_id; - o_arg.clientid = NFS_SERVER(dir)->nfs4_state->cl_clientid, + o_arg.clientid = clp->cl_clientid, status = rpc_call_sync(server->client, &msg, 0); nfs4_increment_seqid(status, sp); @@ -322,7 +325,8 @@ retry: state->nwriters++; state->state |= flags & (FMODE_READ|FMODE_WRITE); spin_unlock(&inode->i_lock); - + if (o_res.delegation_type != 0) + nfs_inode_set_delegation(inode, &o_res); up(&sp->so_sema); nfs4_put_state_owner(sp); return state; @@ -1660,6 +1664,22 @@ nfs4_proc_setclientid_confirm(struct nfs return status; } +int nfs4_proc_delegreturn(struct inode *inode) +{ + struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; + struct nfs4_delegreturnargs args = { + .fhandle = NFS_FH(inode), + .stateid = &NFS_I(inode)->delegation.stateid, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN], + .rpc_argp = &args, + .rpc_cred = clp->cl_cred, + }; + + return nfs4_map_errors(rpc_call_sync(clp->cl_rpcclient, &msg, 0)); +} + #define NFS4_LOCK_MINTIMEOUT (1 * HZ) #define NFS4_LOCK_MAXTIMEOUT (30 * HZ) diff -u --recursive --new-file --show-c-function linux-2.6.6-10-file_ctx2/fs/nfs/nfs4state.c linux-2.6.6-11-delegation1/fs/nfs/nfs4state.c --- linux-2.6.6-10-file_ctx2/fs/nfs/nfs4state.c 2004-04-21 15:29:17.000000000 -0400 +++ linux-2.6.6-11-delegation1/fs/nfs/nfs4state.c 2004-04-21 15:30:03.000000000 -0400 @@ -97,6 +97,7 @@ nfs4_alloc_client(struct in_addr *addr) memset(clp, 0, sizeof(*clp)); memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); init_rwsem(&clp->cl_sem); + INIT_LIST_HEAD(&clp->cl_delegations); INIT_LIST_HEAD(&clp->cl_state_owners); INIT_LIST_HEAD(&clp->cl_unused); spin_lock_init(&clp->cl_lock); diff -u --recursive --new-file --show-c-function linux-2.6.6-10-file_ctx2/fs/nfs/nfs4xdr.c linux-2.6.6-11-delegation1/fs/nfs/nfs4xdr.c --- linux-2.6.6-10-file_ctx2/fs/nfs/nfs4xdr.c 2004-04-21 15:29:59.000000000 -0400 +++ linux-2.6.6-11-delegation1/fs/nfs/nfs4xdr.c 2004-04-21 15:30:03.000000000 -0400 @@ -122,6 +122,8 @@ static int nfs_stat_to_errno(int); 2 + 2 * nfs4_name_maxsz + \ nfs4_fattr_bitmap_maxsz) #define decode_create_maxsz (op_decode_hdr_maxsz + 8) +#define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) +#define decode_delegreturn_maxsz (op_decode_hdr_maxsz) #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ @@ -339,6 +341,11 @@ static int nfs_stat_to_errno(int); encode_getattr_maxsz) #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ decode_getattr_maxsz) +#define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ + encode_putfh_maxsz + \ + encode_delegreturn_maxsz) +#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ + decode_delegreturn_maxsz) static struct { unsigned int mode; @@ -896,6 +903,19 @@ static int encode_putrootfh(struct xdr_s return 0; } +static int encode_delegation(struct xdr_stream *xdr, const struct nfs_open_context *ctx, unsigned int type) +{ + const struct nfs_delegation *delegation; + uint32_t *p; + + delegation = &NFS_I(ctx->inode)->delegation; + if (delegation->type < type) + return 1; + RESERVE_SPACE(16); + WRITEMEM(delegation->stateid.data, sizeof(delegation->stateid.data)); + return 0; +} + static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) { extern nfs4_stateid zero_stateid; @@ -917,7 +937,8 @@ static int encode_read(struct xdr_stream RESERVE_SPACE(4); WRITE32(OP_READ); - encode_stateid(xdr, args->context); + if (encode_delegation(xdr, args->context, FMODE_READ) != 0) + encode_stateid(xdr, args->context); RESERVE_SPACE(12); WRITE64(args->offset); @@ -1075,7 +1096,8 @@ static int encode_write(struct xdr_strea RESERVE_SPACE(4); WRITE32(OP_WRITE); - encode_stateid(xdr, args->context); + if (encode_delegation(xdr, args->context, FMODE_WRITE) != 0) + encode_stateid(xdr, args->context); RESERVE_SPACE(16); WRITE64(args->offset); @@ -1086,6 +1108,18 @@ static int encode_write(struct xdr_strea return 0; } + +static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid) +{ + uint32_t *p; + + RESERVE_SPACE(20); + + WRITE32(OP_DELEGRETURN); + WRITEMEM(stateid->data, sizeof(stateid->data)); + return 0; + +} /* * END OF "GENERIC" ENCODE ROUTINES. */ @@ -1716,6 +1750,24 @@ static int nfs4_xdr_enc_setclientid_conf } /* + * DELEGRETURN request + */ +static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const struct nfs4_delegreturnargs *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .nops = 2, + }; + int status; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, &hdr); + if ((status = encode_putfh(&xdr, args->fhandle)) == 0) + status = encode_delegreturn(&xdr, args->stateid); + return status; +} + +/* * START OF "GENERIC" DECODE ROUTINES. * These may look a little ugly since they are imported from a "generic" * set of XDR encode/decode routines which are intended to be shared by @@ -1749,6 +1801,17 @@ static int nfs4_xdr_enc_setclientid_conf } \ } while (0) +static int decode_opaque_inline(struct xdr_stream *xdr, uint32_t *len, char **string) +{ + uint32_t *p; + + READ_BUF(4); + READ32(*len); + READ_BUF(*len); + *string = (char *)p; + return 0; +} + static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) { uint32_t *p; @@ -1785,6 +1848,17 @@ static int decode_op_hdr(struct xdr_stre return 0; } +/* Dummy routine */ +static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp) +{ + uint32_t *p; + uint32_t strlen; + char *str; + + READ_BUF(12); + return decode_opaque_inline(xdr, &strlen, &str); +} + static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) { uint32_t bmlen, *p; @@ -2740,8 +2814,22 @@ static int decode_open(struct xdr_stream READ_BUF((bmlen << 2) + 4); p += bmlen; READ32(delegation_type); + switch (delegation_type) { + case NFS4_OPEN_DELEGATE_NONE: + res->delegation_type = 0; + break; + case NFS4_OPEN_DELEGATE_READ: + res->delegation_type = FMODE_READ; + break; + case NFS4_OPEN_DELEGATE_WRITE: + res->delegation_type = FMODE_WRITE|FMODE_READ; + } if (delegation_type == NFS4_OPEN_DELEGATE_NONE) return 0; + READ_BUF(20); + COPYMEM(res->delegation.data, sizeof(res->delegation.data)); + READ32(res->do_recall); + return decode_ace(xdr, NULL, res->server->nfs4_state); xdr_error: printk(KERN_NOTICE "%s: xdr error!\n", __FUNCTION__); return -EIO; @@ -3048,6 +3136,11 @@ static int decode_write(struct xdr_strea return 0; } +static int decode_delegreturn(struct xdr_stream *xdr) +{ + return decode_op_hdr(xdr, OP_DELEGRETURN); +} + /* * Decode OPEN_DOWNGRADE response */ @@ -3665,6 +3758,25 @@ static int nfs4_xdr_dec_setclientid_conf return status; } +/* + * DELEGRETURN request + */ +static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) +{ + struct xdr_stream xdr; + struct compound_hdr hdr; + int status; + + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); + status = decode_compound_hdr(&xdr, &hdr); + if (status == 0) { + status = decode_putfh(&xdr); + if (status == 0) + status = decode_delegreturn(&xdr); + } + return status; +} + uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) { uint32_t len; @@ -3810,6 +3922,7 @@ struct rpc_procinfo nfs4_procedures[] = PROC(READLINK, enc_readlink, dec_readlink), PROC(READDIR, enc_readdir, dec_readdir), PROC(SERVER_CAPS, enc_server_caps, dec_server_caps), + PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), }; struct rpc_version nfs_version4 = { diff -u --recursive --new-file --show-c-function linux-2.6.6-10-file_ctx2/include/linux/nfs4.h linux-2.6.6-11-delegation1/include/linux/nfs4.h --- linux-2.6.6-10-file_ctx2/include/linux/nfs4.h 2004-04-21 15:27:31.000000000 -0400 +++ linux-2.6.6-11-delegation1/include/linux/nfs4.h 2004-04-21 15:30:03.000000000 -0400 @@ -321,6 +321,7 @@ enum { NFSPROC4_CLNT_READLINK, NFSPROC4_CLNT_READDIR, NFSPROC4_CLNT_SERVER_CAPS, + NFSPROC4_CLNT_DELEGRETURN, }; #endif diff -u --recursive --new-file --show-c-function linux-2.6.6-10-file_ctx2/include/linux/nfs_fs.h linux-2.6.6-11-delegation1/include/linux/nfs_fs.h --- linux-2.6.6-10-file_ctx2/include/linux/nfs_fs.h 2004-04-21 15:29:54.000000000 -0400 +++ linux-2.6.6-11-delegation1/include/linux/nfs_fs.h 2004-04-21 15:30:03.000000000 -0400 @@ -96,6 +96,15 @@ struct nfs_open_context { }; /* + * NFSv4 delegation + */ +struct nfs_delegation { + struct list_head list; + nfs4_stateid stateid; + int type; +}; + +/* * nfs fs inode data in memory */ struct nfs_inode { @@ -175,6 +184,7 @@ struct nfs_inode { #ifdef CONFIG_NFS_V4 /* NFSv4 state */ struct list_head open_states; + struct nfs_delegation delegation; #endif /* CONFIG_NFS_V4*/ struct inode vfs_inode; @@ -270,6 +280,18 @@ static inline int nfs_verify_change_attr && chattr == NFS_I(inode)->cache_change_attribute; } +/** + * nfs_compare_fh - compare two filehandles for equality + * @fh1 - pointer to first filehandle + * @fh2 - pointer to second filehandle + */ +static inline int nfs_compare_fh(const struct nfs_fh *fh1, const struct nfs_fh *fh2) +{ + if (fh1->size == fh2->size) + return memcmp(fh1->data, fh2->data, fh1->size); + return (fh1->size > fh2->size) ? 1 : -1; +} + /* * linux/fs/nfs/inode.c */ @@ -539,6 +561,7 @@ struct nfs4_client { */ struct rw_semaphore cl_sem; + struct list_head cl_delegations; struct list_head cl_state_owners; struct list_head cl_unused; int cl_nunused; diff -u --recursive --new-file --show-c-function linux-2.6.6-10-file_ctx2/include/linux/nfs_xdr.h linux-2.6.6-11-delegation1/include/linux/nfs_xdr.h --- linux-2.6.6-10-file_ctx2/include/linux/nfs_xdr.h 2004-04-21 15:29:59.000000000 -0400 +++ linux-2.6.6-11-delegation1/include/linux/nfs_xdr.h 2004-04-21 15:30:03.000000000 -0400 @@ -122,6 +122,9 @@ struct nfs_openres { __u32 rflags; struct nfs_fattr * f_attr; const struct nfs_server *server; + __u32 delegation_type; + nfs4_stateid delegation; + __u32 do_recall; }; /* @@ -224,6 +227,11 @@ struct nfs_lockres { const struct nfs_server * server; }; +struct nfs4_delegreturnargs { + const struct nfs_fh *fhandle; + const nfs4_stateid *stateid; +}; + /* * Arguments to the read call. */