From d77d76ffb638bd013782138cca6d8f4918c5afd6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 16 Jun 2010 09:52:27 -0400 Subject: NFSv41: Clean up exclusive create Signed-off-by: Trond Myklebust --- include/linux/nfs_xdr.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'include/linux/nfs_xdr.h') diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 51914d7d6cc..a319cb926ab 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -196,8 +196,10 @@ struct nfs_openargs { __u64 clientid; __u64 id; union { - struct iattr * attrs; /* UNCHECKED, GUARDED */ - nfs4_verifier verifier; /* EXCLUSIVE */ + struct { + struct iattr * attrs; /* UNCHECKED, GUARDED */ + nfs4_verifier verifier; /* EXCLUSIVE */ + }; nfs4_stateid delegation; /* CLAIM_DELEGATE_CUR */ fmode_t delegation_type; /* CLAIM_PREVIOUS */ } u; -- cgit v1.2.3-70-g09d2 From f11ac8db5d07b6e99d41ff4aa39d878ee5cef1c5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 25 Jun 2010 16:35:53 -0400 Subject: NFSv4: Ensure that we track the NFSv4 lock state in read/write requests. This patch fixes bugzilla entry 14501: https://bugzilla.kernel.org/show_bug.cgi?id=14501 Signed-off-by: Trond Myklebust --- fs/nfs/direct.c | 29 +++++++++++++++----- fs/nfs/inode.c | 70 +++++++++++++++++++++++++++++++++++++++++++++--- fs/nfs/nfs4xdr.c | 8 +++--- fs/nfs/pagelist.c | 8 +++++- fs/nfs/read.c | 1 + fs/nfs/write.c | 5 +++- include/linux/nfs_fs.h | 13 +++++++-- include/linux/nfs_page.h | 1 + include/linux/nfs_xdr.h | 2 ++ 9 files changed, 118 insertions(+), 19 deletions(-) (limited to 'include/linux/nfs_xdr.h') diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index ad4cd31d605..064a8096167 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -69,6 +69,7 @@ struct nfs_direct_req { /* I/O parameters */ struct nfs_open_context *ctx; /* file open context info */ + struct nfs_lock_context *l_ctx; /* Lock context info */ struct kiocb * iocb; /* controlling i/o request */ struct inode * inode; /* target file of i/o */ @@ -160,6 +161,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) INIT_LIST_HEAD(&dreq->rewrite_list); dreq->iocb = NULL; dreq->ctx = NULL; + dreq->l_ctx = NULL; spin_lock_init(&dreq->lock); atomic_set(&dreq->io_count, 0); dreq->count = 0; @@ -173,6 +175,8 @@ static void nfs_direct_req_free(struct kref *kref) { struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); + if (dreq->l_ctx != NULL) + nfs_put_lock_context(dreq->l_ctx); if (dreq->ctx != NULL) put_nfs_open_context(dreq->ctx); kmem_cache_free(nfs_direct_cachep, dreq); @@ -336,6 +340,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, data->cred = msg.rpc_cred; data->args.fh = NFS_FH(inode); data->args.context = ctx; + data->args.lock_context = dreq->l_ctx; data->args.offset = pos; data->args.pgbase = pgbase; data->args.pages = data->pagevec; @@ -416,24 +421,28 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { - ssize_t result = 0; + ssize_t result = -ENOMEM; struct inode *inode = iocb->ki_filp->f_mapping->host; struct nfs_direct_req *dreq; dreq = nfs_direct_req_alloc(); - if (!dreq) - return -ENOMEM; + if (dreq == NULL) + goto out; dreq->inode = inode; dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); + dreq->l_ctx = nfs_get_lock_context(dreq->ctx); + if (dreq->l_ctx == NULL) + goto out_release; if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); if (!result) result = nfs_direct_wait(dreq); +out_release: nfs_direct_req_release(dreq); - +out: return result; } @@ -574,6 +583,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) data->args.offset = 0; data->args.count = 0; data->args.context = dreq->ctx; + data->args.lock_context = dreq->l_ctx; data->res.count = 0; data->res.fattr = &data->fattr; data->res.verf = &data->verf; @@ -761,6 +771,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, data->cred = msg.rpc_cred; data->args.fh = NFS_FH(inode); data->args.context = ctx; + data->args.lock_context = dreq->l_ctx; data->args.offset = pos; data->args.pgbase = pgbase; data->args.pages = data->pagevec; @@ -845,7 +856,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos, size_t count) { - ssize_t result = 0; + ssize_t result = -ENOMEM; struct inode *inode = iocb->ki_filp->f_mapping->host; struct nfs_direct_req *dreq; size_t wsize = NFS_SERVER(inode)->wsize; @@ -853,7 +864,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, dreq = nfs_direct_req_alloc(); if (!dreq) - return -ENOMEM; + goto out; nfs_alloc_commit_data(dreq); if (dreq->commit_data == NULL || count < wsize) @@ -861,14 +872,18 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, dreq->inode = inode; dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); + dreq->l_ctx = nfs_get_lock_context(dreq->ctx); + if (dreq->l_ctx != NULL) + goto out_release; if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); if (!result) result = nfs_direct_wait(dreq); +out_release: nfs_direct_req_release(dreq); - +out: return result; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 099b3518fee..ec7a8f96a2c 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -530,6 +530,68 @@ out: return err; } +static void nfs_init_lock_context(struct nfs_lock_context *l_ctx) +{ + atomic_set(&l_ctx->count, 1); + l_ctx->lockowner = current->files; + l_ctx->pid = current->tgid; + INIT_LIST_HEAD(&l_ctx->list); +} + +static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) +{ + struct nfs_lock_context *pos; + + list_for_each_entry(pos, &ctx->lock_context.list, list) { + if (pos->lockowner != current->files) + continue; + if (pos->pid != current->tgid) + continue; + atomic_inc(&pos->count); + return pos; + } + return NULL; +} + +struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) +{ + struct nfs_lock_context *res, *new = NULL; + struct inode *inode = ctx->path.dentry->d_inode; + + spin_lock(&inode->i_lock); + res = __nfs_find_lock_context(ctx); + if (res == NULL) { + spin_unlock(&inode->i_lock); + new = kmalloc(sizeof(*new), GFP_KERNEL); + if (new == NULL) + return NULL; + nfs_init_lock_context(new); + spin_lock(&inode->i_lock); + res = __nfs_find_lock_context(ctx); + if (res == NULL) { + list_add_tail(&new->list, &ctx->lock_context.list); + new->open_context = ctx; + res = new; + new = NULL; + } + } + spin_unlock(&inode->i_lock); + kfree(new); + return res; +} + +void nfs_put_lock_context(struct nfs_lock_context *l_ctx) +{ + struct nfs_open_context *ctx = l_ctx->open_context; + struct inode *inode = ctx->path.dentry->d_inode; + + if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock)) + return; + list_del(&l_ctx->list); + spin_unlock(&inode->i_lock); + kfree(l_ctx); +} + /** * nfs_close_context - Common close_context() routine NFSv2/v3 * @ctx: pointer to context @@ -566,11 +628,11 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct path_get(&ctx->path); ctx->cred = get_rpccred(cred); ctx->state = NULL; - ctx->lockowner = current->files; ctx->flags = 0; ctx->error = 0; ctx->dir_cookie = 0; - atomic_set(&ctx->count, 1); + nfs_init_lock_context(&ctx->lock_context); + ctx->lock_context.open_context = ctx; } return ctx; } @@ -578,7 +640,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) { if (ctx != NULL) - atomic_inc(&ctx->count); + atomic_inc(&ctx->lock_context.count); return ctx; } @@ -586,7 +648,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) { struct inode *inode = ctx->path.dentry->d_inode; - if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) + if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock)) return; list_del(&ctx->list); spin_unlock(&inode->i_lock); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1f7781d636a..873b62f209e 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1324,14 +1324,14 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) hdr->replen += decode_putrootfh_maxsz; } -static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) +static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx) { nfs4_stateid stateid; __be32 *p; p = reserve_space(xdr, NFS4_STATEID_SIZE); if (ctx->state != NULL) { - nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner); + nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner); xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE); } else xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); @@ -1344,7 +1344,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, p = reserve_space(xdr, 4); *p = cpu_to_be32(OP_READ); - encode_stateid(xdr, args->context); + encode_stateid(xdr, args->context, args->lock_context); p = reserve_space(xdr, 12); p = xdr_encode_hyper(p, args->offset); @@ -1523,7 +1523,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg p = reserve_space(xdr, 4); *p = cpu_to_be32(OP_WRITE); - encode_stateid(xdr, args->context); + encode_stateid(xdr, args->context, args->lock_context); p = reserve_space(xdr, 16); p = xdr_encode_hyper(p, args->offset); diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index a3654e57b58..919490232e1 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -79,6 +79,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, req->wb_pgbase = offset; req->wb_bytes = count; req->wb_context = get_nfs_open_context(ctx); + req->wb_lock_context = nfs_get_lock_context(ctx); kref_init(&req->wb_kref); return req; } @@ -141,11 +142,16 @@ void nfs_clear_request(struct nfs_page *req) { struct page *page = req->wb_page; struct nfs_open_context *ctx = req->wb_context; + struct nfs_lock_context *l_ctx = req->wb_lock_context; if (page != NULL) { page_cache_release(page); req->wb_page = NULL; } + if (l_ctx != NULL) { + nfs_put_lock_context(l_ctx); + req->wb_lock_context = NULL; + } if (ctx != NULL) { put_nfs_open_context(ctx); req->wb_context = NULL; @@ -235,7 +241,7 @@ static int nfs_can_coalesce_requests(struct nfs_page *prev, { if (req->wb_context->cred != prev->wb_context->cred) return 0; - if (req->wb_context->lockowner != prev->wb_context->lockowner) + if (req->wb_lock_context->lockowner != prev->wb_lock_context->lockowner) return 0; if (req->wb_context->state != prev->wb_context->state) return 0; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 5a33a92e816..87adc274424 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -190,6 +190,7 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, data->args.pages = data->pagevec; data->args.count = count; data->args.context = get_nfs_open_context(req->wb_context); + data->args.lock_context = req->wb_lock_context; data->res.fattr = &data->fattr; data->res.count = count; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 03df22822c4..5eccea127ca 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -689,7 +689,9 @@ int nfs_flush_incompatible(struct file *file, struct page *page) req = nfs_page_find_request(page); if (req == NULL) return 0; - do_flush = req->wb_page != page || req->wb_context != ctx; + do_flush = req->wb_page != page || req->wb_context != ctx || + req->wb_lock_context->lockowner != current->files || + req->wb_lock_context->pid != current->tgid; nfs_release_request(req); if (!do_flush) return 0; @@ -813,6 +815,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req, data->args.pages = data->pagevec; data->args.count = count; data->args.context = get_nfs_open_context(req->wb_context); + data->args.lock_context = req->wb_lock_context; data->args.stable = NFS_UNSTABLE; if (how & FLUSH_STABLE) { data->args.stable = NFS_DATA_SYNC; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 77c2ae53431..a9d80261508 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -72,13 +72,20 @@ struct nfs_access_entry { int mask; }; +struct nfs_lock_context { + atomic_t count; + struct list_head list; + struct nfs_open_context *open_context; + fl_owner_t lockowner; + pid_t pid; +}; + struct nfs4_state; struct nfs_open_context { - atomic_t count; + struct nfs_lock_context lock_context; struct path path; struct rpc_cred *cred; struct nfs4_state *state; - fl_owner_t lockowner; fmode_t mode; unsigned long flags; @@ -353,6 +360,8 @@ extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr); extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); extern void put_nfs_open_context(struct nfs_open_context *ctx); extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode); +extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx); +extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx); extern u64 nfs_compat_user_ino64(u64 fileid); extern void nfs_fattr_init(struct nfs_fattr *fattr); diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 3c60685d972..f8b60e7f4c4 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -39,6 +39,7 @@ struct nfs_page { struct list_head wb_list; /* Defines state of page: */ struct page *wb_page; /* page to read in/write out */ struct nfs_open_context *wb_context; /* File state context info */ + struct nfs_lock_context *wb_lock_context; /* lock context info */ atomic_t wb_complete; /* i/os we're waiting for */ pgoff_t wb_index; /* Offset >> PAGE_CACHE_SHIFT */ unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */ diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index a319cb926ab..87202c7026e 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -334,6 +334,7 @@ struct nfs4_delegreturnres { struct nfs_readargs { struct nfs_fh * fh; struct nfs_open_context *context; + struct nfs_lock_context *lock_context; __u64 offset; __u32 count; unsigned int pgbase; @@ -354,6 +355,7 @@ struct nfs_readres { struct nfs_writeargs { struct nfs_fh * fh; struct nfs_open_context *context; + struct nfs_lock_context *lock_context; __u64 offset; __u32 count; enum nfs3_stable_how stable; -- cgit v1.2.3-70-g09d2 From d3c7b7ccc199ee564177ee914c04771d6bc00295 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 1 Jul 2010 12:49:01 -0400 Subject: NFSv4: Add support for the RELEASE_LOCKOWNER operation This is needed by NFSv4.0 servers in order to keep the number of locking stateids at a manageable level. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 1 + fs/nfs/nfs4proc.c | 28 +++++++++++++++++++++++++ fs/nfs/nfs4state.c | 2 ++ fs/nfs/nfs4xdr.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 4 ++++ 6 files changed, 91 insertions(+) (limited to 'include/linux/nfs_xdr.h') diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index cee871471e8..deaf37f5a7a 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -236,6 +236,7 @@ extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nam extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, struct nfs4_fs_locations *fs_locations, struct page *page); +extern void nfs4_release_lockowner(const struct nfs4_lock_state *); #if defined(CONFIG_NFS_V4_1) static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index de9ff1505a2..5d3e8a2db99 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -4414,6 +4414,34 @@ out: return err; } +static void nfs4_release_lockowner_release(void *calldata) +{ + kfree(calldata); +} + +const struct rpc_call_ops nfs4_release_lockowner_ops = { + .rpc_release = nfs4_release_lockowner_release, +}; + +void nfs4_release_lockowner(const struct nfs4_lock_state *lsp) +{ + struct nfs_server *server = lsp->ls_state->owner->so_server; + struct nfs_release_lockowner_args *args; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER], + }; + + if (server->nfs_client->cl_mvops->minor_version != 0) + return; + args = kmalloc(sizeof(*args), GFP_NOFS); + if (!args) + return; + args->lock_owner.clientid = server->nfs_client->cl_clientid; + args->lock_owner.id = lsp->ls_id.id; + msg.rpc_argp = args; + rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args); +} + #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 13e17e32e3e..13a4f27e727 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -701,6 +701,8 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp) if (list_empty(&state->lock_states)) clear_bit(LK_STATE_IN_USE, &state->flags); spin_unlock(&state->state_lock); + if (lsp->ls_flags & NFS_LOCK_INITIALIZED) + nfs4_release_lockowner(lsp); nfs4_free_lock_state(lsp); } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 49df05afdc6..15185c2abd1 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -220,6 +220,11 @@ static int nfs4_stat_to_errno(int); 4) #define decode_locku_maxsz (op_decode_hdr_maxsz + \ decode_stateid_maxsz) +#define encode_release_lockowner_maxsz \ + (op_encode_hdr_maxsz + \ + encode_lockowner_maxsz) +#define decode_release_lockowner_maxsz \ + (op_decode_hdr_maxsz) #define encode_access_maxsz (op_encode_hdr_maxsz + 1) #define decode_access_maxsz (op_decode_hdr_maxsz + 2) #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ @@ -474,6 +479,12 @@ static int nfs4_stat_to_errno(int); decode_sequence_maxsz + \ decode_putfh_maxsz + \ decode_locku_maxsz) +#define NFS4_enc_release_lockowner_sz \ + (compound_encode_hdr_maxsz + \ + encode_lockowner_maxsz) +#define NFS4_dec_release_lockowner_sz \ + (compound_decode_hdr_maxsz + \ + decode_lockowner_maxsz) #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ encode_sequence_maxsz + \ encode_putfh_maxsz + \ @@ -1116,6 +1127,17 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar hdr->replen += decode_locku_maxsz; } +static void encode_release_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner, struct compound_hdr *hdr) +{ + __be32 *p; + + p = reserve_space(xdr, 4); + *p = cpu_to_be32(OP_RELEASE_LOCKOWNER); + encode_lockowner(xdr, lowner); + hdr->nops++; + hdr->replen += decode_release_lockowner_maxsz; +} + static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) { int len = name->len; @@ -2056,6 +2078,20 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_ return 0; } +static int nfs4_xdr_enc_release_lockowner(struct rpc_rqst *req, __be32 *p, struct nfs_release_lockowner_args *args) +{ + struct xdr_stream xdr; + struct compound_hdr hdr = { + .minorversion = 0, + }; + + xdr_init_encode(&xdr, &req->rq_snd_buf, p); + encode_compound_hdr(&xdr, req, &hdr); + encode_release_lockowner(&xdr, &args->lock_owner, &hdr); + encode_nops(&hdr); + return 0; +} + /* * Encode a READLINK request */ @@ -3981,6 +4017,11 @@ static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res) return status; } +static int decode_release_lockowner(struct xdr_stream *xdr) +{ + return decode_op_hdr(xdr, OP_RELEASE_LOCKOWNER); +} + static int decode_lookup(struct xdr_stream *xdr) { return decode_op_hdr(xdr, OP_LOOKUP); @@ -5267,6 +5308,19 @@ out: return status; } +static int nfs4_xdr_dec_release_lockowner(struct rpc_rqst *rqstp, __be32 *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) + status = decode_release_lockowner(&xdr); + return status; +} + /* * Decode READLINK response */ @@ -5874,6 +5928,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(GETACL, enc_getacl, dec_getacl), PROC(SETACL, enc_setacl, dec_setacl), PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), + PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), #if defined(CONFIG_NFS_V4_1) PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), PROC(CREATE_SESSION, enc_create_session, dec_create_session), diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 9b8299af374..07e40c62597 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -523,6 +523,7 @@ enum { NFSPROC4_CLNT_GETACL, NFSPROC4_CLNT_SETACL, NFSPROC4_CLNT_FS_LOCATIONS, + NFSPROC4_CLNT_RELEASE_LOCKOWNER, /* nfs41 */ NFSPROC4_CLNT_EXCHANGE_ID, diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 87202c7026e..fc461926c41 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -315,6 +315,10 @@ struct nfs_lockt_res { struct nfs4_sequence_res seq_res; }; +struct nfs_release_lockowner_args { + struct nfs_lowner lock_owner; +}; + struct nfs4_delegreturnargs { const struct nfs_fh *fhandle; const nfs4_stateid *stateid; -- cgit v1.2.3-70-g09d2