]> git.hungrycats.org Git - linux/commitdiff
[PATCH] kNFSd: Implement the nfsv4 RELEASE_LOCKOWNER operation.
authorAndrew Morton <akpm@osdl.org>
Thu, 26 Feb 2004 14:49:31 +0000 (06:49 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 26 Feb 2004 14:49:31 +0000 (06:49 -0800)
From: NeilBrown <neilb@cse.unsw.edu.au>

Implement the nfsv4 RELEASE_LOCKOWNER operation.

fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
include/linux/nfs4.h
include/linux/nfsd/nfsd.h
include/linux/nfsd/xdr4.h

index 7f00a8b91f01e9328a3657f464d50d5e75f92e69..3c7e30d99970f73e8a5cdad5de8f550c4eea3fc0 100644 (file)
@@ -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;
index 151e3f439de21d5ef2f47d291b26cae8f5f9ce8e..2dd0372cf566cec4ccc4ab57c26eca9c547a6208 100644 (file)
@@ -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 @@ 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
  */
index 3ced62b6031a0f7a443a81a59c8655473f61abbc..94432654fe634dde3bbd59b7807265e93d8fa732 100644 (file)
@@ -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;
        }
index 35baf20a5b5c6b0c73f3470dd7fda62b47ce624e..069d10a31547e3dd6aaea8c25cf9bac5c276b03d 100644 (file)
@@ -86,6 +86,7 @@ enum nfs_opnum4 {
        OP_SETCLIENTID_CONFIRM = 36,
        OP_VERIFY = 37,
        OP_WRITE = 38,
+       OP_RELEASE_LOCKOWNER = 39,
 };
 
 enum nfsstat4 {
index 20b1f4a3fb1022cb99be2d6be357f243863de602..4b04429237154d2391739edeec871656e286200d 100644 (file)
@@ -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.
index 4e275cea93b54ae4a192fe329f1add51460b7606..df35cb397dc627a3c1b483d7936377235e17f171 100644 (file)
@@ -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
 
 /*