From: NeilBrown --- fs/nfsd/nfs4proc.c | 4 ++ fs/nfsd/nfs4state.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++ fs/nfsd/nfs4xdr.c | 19 +++++++++++ include/linux/nfs4.h | 1 include/linux/nfsd/nfsd.h | 1 include/linux/nfsd/xdr4.h | 8 ++++ 6 files changed, 112 insertions(+) diff -puN fs/nfsd/nfs4proc.c~knfsd-implement-RELEASE_LOCKOWNER fs/nfsd/nfs4proc.c --- 25/fs/nfsd/nfs4proc.c~knfsd-implement-RELEASE_LOCKOWNER 2004-02-25 02:32:20.000000000 -0800 +++ 25-akpm/fs/nfsd/nfs4proc.c 2004-02-25 02:32:20.000000000 -0800 @@ -728,6 +728,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs (op->opnum == OP_SETCLIENTID) || (op->opnum == OP_SETCLIENTID_CONFIRM) || (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) || + (op->opnum == OP_RELEASE_LOCKOWNER) || (op->opnum == OP_SETATTR))) { op->status = nfserr_nofilehandle; goto encode_op; @@ -834,6 +835,9 @@ nfsd4_proc_compound(struct svc_rqst *rqs case OP_WRITE: op->status = nfsd4_write(rqstp, ¤t_fh, &op->u.write); break; + case OP_RELEASE_LOCKOWNER: + op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner); + break; default: BUG_ON(op->status == nfs_ok); break; diff -puN fs/nfsd/nfs4state.c~knfsd-implement-RELEASE_LOCKOWNER fs/nfsd/nfs4state.c --- 25/fs/nfsd/nfs4state.c~knfsd-implement-RELEASE_LOCKOWNER 2004-02-25 02:32:20.000000000 -0800 +++ 25-akpm/fs/nfsd/nfs4state.c 2004-02-25 02:32:20.000000000 -0800 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -2138,6 +2139,84 @@ out_nfserr: goto out; } +/* + * returns + * 1: locks held by lockowner + * 0: no locks held by lockowner + */ +static int +check_for_locks(struct file *filp, struct nfs4_stateowner *lowner) +{ + struct file_lock **flpp; + struct inode *inode = filp->f_dentry->d_inode; + int status = 0; + + lock_kernel(); + for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { + if ((*flpp)->fl_owner == (fl_owner_t)lowner) + status = 1; + goto out; + } +out: + unlock_kernel(); + return status; +} + +int +nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner) +{ + clientid_t *clid = &rlockowner->rl_clientid; + struct list_head *pos, *next; + struct nfs4_stateowner *local = NULL; + struct xdr_netobj *owner = &rlockowner->rl_owner; + int status, i; + + dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", + clid->cl_boot, clid->cl_id); + + /* XXX check for lease expiration */ + + status = nfserr_stale_clientid; + if (STALE_CLIENTID(clid)) { + printk("NFSD: nfsd4_release_lockowner: clientid is stale!\n"); + return status; + } + + nfs4_lock_state(); + + /* find the lockowner */ + status = nfs_ok; + for (i=0; i < LOCK_HASH_SIZE; i++) { + list_for_each_safe(pos, next, &lock_ownerstr_hashtbl[i]) { + local = list_entry(pos, struct nfs4_stateowner, + so_strhash); + if(cmp_owner_str(local, owner, clid)) + break; + } + } + if (local) { + struct nfs4_stateid *stp; + + /* check for any locks held by any stateid associated with the + * (lock) stateowner */ + status = nfserr_locks_held; + list_for_each_safe(pos, next, &local->so_perfilestate) { + stp = list_entry(pos, struct nfs4_stateid, + st_perfilestate); + if(stp->st_vfs_set) { + if (check_for_locks(&stp->st_vfs_file, local)) + goto out; + } + } + /* no locks held by (lock) stateowner */ + status = nfs_ok; + release_stateowner(local); + } +out: + nfs4_unlock_state(); + return status; +} + /* * Start and stop routines */ diff -puN fs/nfsd/nfs4xdr.c~knfsd-implement-RELEASE_LOCKOWNER fs/nfsd/nfs4xdr.c --- 25/fs/nfsd/nfs4xdr.c~knfsd-implement-RELEASE_LOCKOWNER 2004-02-25 02:32:20.000000000 -0800 +++ 25-akpm/fs/nfsd/nfs4xdr.c 2004-02-25 02:32:20.000000000 -0800 @@ -993,6 +993,20 @@ nfsd4_decode_write(struct nfsd4_compound } static int +nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner) +{ + DECODE_HEAD; + + READ_BUF(12); + COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t)); + READ32(rlockowner->rl_owner.len); + READ_BUF(rlockowner->rl_owner.len); + READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len); + + DECODE_TAIL; +} + +static int nfsd4_decode_compound(struct nfsd4_compoundargs *argp) { DECODE_HEAD; @@ -1157,6 +1171,9 @@ nfsd4_decode_compound(struct nfsd4_compo case OP_WRITE: op->status = nfsd4_decode_write(argp, &op->u.write); break; + case OP_RELEASE_LOCKOWNER: + op->status = nfsd4_decode_release_lockowner(argp, &op->u.release_lockowner); + break; default: /* * According to spec, anything greater than OP_WRITE @@ -2349,6 +2366,8 @@ nfsd4_encode_operation(struct nfsd4_comp case OP_WRITE: nfsd4_encode_write(resp, op->status, &op->u.write); break; + case OP_RELEASE_LOCKOWNER: + break; default: break; } diff -puN include/linux/nfs4.h~knfsd-implement-RELEASE_LOCKOWNER include/linux/nfs4.h --- 25/include/linux/nfs4.h~knfsd-implement-RELEASE_LOCKOWNER 2004-02-25 02:32:20.000000000 -0800 +++ 25-akpm/include/linux/nfs4.h 2004-02-25 02:32:20.000000000 -0800 @@ -86,6 +86,7 @@ enum nfs_opnum4 { OP_SETCLIENTID_CONFIRM = 36, OP_VERIFY = 37, OP_WRITE = 38, + OP_RELEASE_LOCKOWNER = 39, }; enum nfsstat4 { diff -puN include/linux/nfsd/nfsd.h~knfsd-implement-RELEASE_LOCKOWNER include/linux/nfsd/nfsd.h --- 25/include/linux/nfsd/nfsd.h~knfsd-implement-RELEASE_LOCKOWNER 2004-02-25 02:32:20.000000000 -0800 +++ 25-akpm/include/linux/nfsd/nfsd.h 2004-02-25 02:32:20.000000000 -0800 @@ -194,6 +194,7 @@ void nfsd_lockd_shutdown(void); #define nfserr_attrnotsupp __constant_htonl(NFSERR_ATTRNOTSUPP) #define nfserr_bad_xdr __constant_htonl(NFSERR_BAD_XDR) #define nfserr_openmode __constant_htonl(NFSERR_OPENMODE) +#define nfserr_locks_held __constant_htonl(NFSERR_LOCKS_HELD) /* error codes for internal use */ /* if a request fails due to kmalloc failure, it gets dropped. diff -puN include/linux/nfsd/xdr4.h~knfsd-implement-RELEASE_LOCKOWNER include/linux/nfsd/xdr4.h --- 25/include/linux/nfsd/xdr4.h~knfsd-implement-RELEASE_LOCKOWNER 2004-02-25 02:32:20.000000000 -0800 +++ 25-akpm/include/linux/nfsd/xdr4.h 2004-02-25 02:32:20.000000000 -0800 @@ -263,6 +263,10 @@ struct nfsd4_readdir { u32 * offset; }; +struct nfsd4_release_lockowner { + clientid_t rl_clientid; + struct xdr_netobj rl_owner; +}; struct nfsd4_readlink { struct svc_rqst *rl_rqstp; /* request */ struct svc_fh * rl_fhp; /* request */ @@ -359,6 +363,7 @@ struct nfsd4_op { struct nfsd4_setclientid_confirm setclientid_confirm; struct nfsd4_verify verify; struct nfsd4_write write; + struct nfsd4_release_lockowner release_lockowner; } u; struct nfs4_replay * replay; }; @@ -441,6 +446,9 @@ extern int nfsd4_lockt(struct svc_rqst * struct nfsd4_lockt *lockt); extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku); +extern int +nfsd4_release_lockowner(struct svc_rqst *rqstp, + struct nfsd4_release_lockowner *rlockowner); #endif /* _