Commit b0ac617e authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] kNFSd: Implement the nfsv4 RELEASE_LOCKOWNER operation.

From: NeilBrown <neilb@cse.unsw.edu.au>

Implement the nfsv4 RELEASE_LOCKOWNER operation.
parent 0dff23e5
......@@ -728,6 +728,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
(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 *rqstp,
case OP_WRITE:
op->status = nfsd4_write(rqstp, &current_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;
......
......@@ -43,6 +43,7 @@
#include <linux/nfsd/cache.h>
#include <linux/mount.h>
#include <linux/workqueue.h>
#include <linux/smp_lock.h>
#include <linux/nfs4.h>
#include <linux/nfsd/state.h>
#include <linux/nfsd/xdr4.h>
......@@ -2138,6 +2139,84 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
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
*/
......
......@@ -992,6 +992,20 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
DECODE_TAIL;
}
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)
{
......@@ -1157,6 +1171,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
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_compoundres *resp, struct nfsd4_op *op)
case OP_WRITE:
nfsd4_encode_write(resp, op->status, &op->u.write);
break;
case OP_RELEASE_LOCKOWNER:
break;
default:
break;
}
......
......@@ -86,6 +86,7 @@ enum nfs_opnum4 {
OP_SETCLIENTID_CONFIRM = 36,
OP_VERIFY = 37,
OP_WRITE = 38,
OP_RELEASE_LOCKOWNER = 39,
};
enum nfsstat4 {
......
......@@ -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.
......
......@@ -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 *rqstp, struct svc_fh *current_fh,
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
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment