diff options
| author | Neil Brown <neilb@cse.unsw.edu.au> | 2003-09-22 05:23:13 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.osdl.org> | 2003-09-22 05:23:13 -0700 |
| commit | 754bc7682bfe6a877785a1248bf899b097984a11 (patch) | |
| tree | 0effaeda4614db37f55646ca75e15e28ab58d4d9 | |
| parent | 50676cf4aae7dc2080b9499e3e3afa4712adc255 (diff) | |
[PATCH] knfsd: nfsdv4 byte range locking - LOCKU
From: "William A.(Andy) Adamson" <andros@citi.umich.edu>
This implments the LOCKU operation. These all pass the connectathon
lock test suite against the solaris nfsv4 client.
| -rw-r--r-- | fs/nfsd/nfs4proc.c | 3 | ||||
| -rw-r--r-- | fs/nfsd/nfs4state.c | 59 | ||||
| -rw-r--r-- | fs/nfsd/nfs4xdr.c | 39 | ||||
| -rw-r--r-- | include/linux/nfsd/xdr4.h | 14 |
4 files changed, 115 insertions, 0 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3322cd464e14..ba0a43a99548 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -687,6 +687,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, case OP_LOCKT: op->status = nfsd4_lockt(rqstp, ¤t_fh, &op->u.lockt); break; + case OP_LOCKU: + op->status = nfsd4_locku(rqstp, ¤t_fh, &op->u.locku); + break; case OP_LOOKUP: op->status = nfsd4_lookup(rqstp, ¤t_fh, &op->u.lookup); break; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f8ebbf5c09cd..1858b5232685 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2033,6 +2033,65 @@ out: return status; } +int +nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku) +{ + struct nfs4_stateid *stp; + struct file *filp = NULL; + struct file_lock file_lock; + int status; + + dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", + locku->lu_offset, locku->lu_length); + nfs4_lock_state(); + + if ((status = nfs4_preprocess_seqid_op(current_fh, + locku->lu_seqid, + &locku->lu_stateid, + CHECK_FH | LOCK_STATE, + &locku->lu_stateowner, &stp))) + goto out; + + filp = &stp->st_vfs_file; + BUG_ON(!filp); + file_lock.fl_type = F_UNLCK; + file_lock.fl_owner = (fl_owner_t) locku->lu_stateowner; + file_lock.fl_pid = lockownerid_hashval(locku->lu_stateowner->so_id); + file_lock.fl_file = filp; + file_lock.fl_flags = FL_POSIX; + file_lock.fl_notify = NULL; + file_lock.fl_insert = NULL; + file_lock.fl_remove = NULL; + file_lock.fl_start = locku->lu_offset; + + if ((locku->lu_length == ~(u64)0) || LOFF_OVERFLOW(locku->lu_offset, locku->lu_length)) + file_lock.fl_end = ~(u64)0; + else + file_lock.fl_end = locku->lu_offset + locku->lu_length - 1; + nfs4_transform_lock_offset(&file_lock); + + /* + * Try to unlock the file in the VFS. + */ + status = posix_lock_file(filp, &file_lock); + if (status) { + printk("NFSD: nfs4_locku: posix_lock_file failed!\n"); + goto out_nfserr; + } + /* + * OK, unlock succeeded; the only thing left to do is update the stateid. + */ + update_stateid(&stp->st_stateid); + memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t)); + +out: + nfs4_unlock_state(); + return status; + +out_nfserr: + status = nfserrno(status); + goto out; +} /* * Start and stop routines diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 96c245cb13f3..476c969412f9 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -625,6 +625,24 @@ nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) } static int +nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) +{ + DECODE_HEAD; + + READ_BUF(24 + sizeof(stateid_t)); + READ32(locku->lu_type); + if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT)) + goto xdr_error; + READ32(locku->lu_seqid); + READ32(locku->lu_stateid.si_generation); + COPYMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t)); + READ64(locku->lu_offset); + READ64(locku->lu_length); + + DECODE_TAIL; +} + +static int nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup) { DECODE_HEAD; @@ -1052,6 +1070,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) case OP_LOCKT: op->status = nfsd4_decode_lockt(argp, &op->u.lockt); break; + case OP_LOCKU: + op->status = nfsd4_decode_locku(argp, &op->u.locku); + break; case OP_LOOKUP: op->status = nfsd4_decode_lookup(argp, &op->u.lookup); break; @@ -1815,6 +1836,21 @@ nfsd4_encode_lockt(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock nfsd4_encode_lock_denied(resp, &lockt->lt_denied); } +static void +nfsd4_encode_locku(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_locku *locku) +{ + ENCODE_SEQID_OP_HEAD; + + if (!nfserr) { + RESERVE_SPACE(sizeof(stateid_t)); + WRITE32(locku->lu_stateid.si_generation); + WRITEMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t)); + ADJUST_ARGS(); + } + + ENCODE_SEQID_OP_TAIL(locku->lu_stateowner); +} + static void nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link *link) @@ -2232,6 +2268,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) case OP_LOCKT: nfsd4_encode_lockt(resp, op->status, &op->u.lockt); break; + case OP_LOCKU: + nfsd4_encode_locku(resp, op->status, &op->u.locku); + break; case OP_LOOKUP: break; case OP_LOOKUPP: diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index a39e3c2951e3..5140f2061b30 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -173,6 +173,17 @@ struct nfsd4_lockt { struct nfsd4_lock_denied lt_denied; }; + +struct nfsd4_locku { + u32 lu_type; + u32 lu_seqid; + stateid_t lu_stateid; + u64 lu_offset; + u64 lu_length; + struct nfs4_stateowner *lu_stateowner; +}; + + struct nfsd4_lookup { u32 lo_len; /* request */ char * lo_name; /* request */ @@ -330,6 +341,7 @@ struct nfsd4_op { struct nfsd4_link link; struct nfsd4_lock lock; struct nfsd4_lockt lockt; + struct nfsd4_locku locku; struct nfsd4_lookup lookup; struct nfsd4_verify nverify; struct nfsd4_open open; @@ -425,6 +437,8 @@ extern int nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock); 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); #endif /* |
