From 50676cf4aae7dc2080b9499e3e3afa4712adc255 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Mon, 22 Sep 2003 05:23:04 -0700 Subject: [PATCH] [PATCH] knfsd: nfsdv4 byte range locking - LOCKT From: "William A.(Andy) Adamson" This implements the LOCKT operation. --- fs/nfsd/nfs4proc.c | 3 ++ fs/nfsd/nfs4state.c | 92 +++++++++++++++++++++++++++++++++++++++ fs/nfsd/nfs4xdr.c | 33 ++++++++++++++ include/linux/nfsd/xdr4.h | 14 ++++++ 4 files changed, 142 insertions(+) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 8f89a263f0022..3322cd464e141 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -684,6 +684,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, case OP_LOCK: op->status = nfsd4_lock(rqstp, ¤t_fh, &op->u.lock); break; + case OP_LOCKT: + op->status = nfsd4_lockt(rqstp, ¤t_fh, &op->u.lockt); + 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 80da15300d0df..f8ebbf5c09cdc 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1942,6 +1942,98 @@ out: return status; } +/* + * LOCKT operation + */ +int +nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt) +{ + struct inode *inode; + struct nfs4_stateowner *sop; + struct file file; + struct file_lock file_lock; + struct file_lock *conflicting_lock; + unsigned int strhashval; + int status; + + lockt->lt_stateowner = NULL; + nfs4_lock_state(); + + status = nfserr_stale_clientid; + if (STALE_CLIENTID(&lockt->lt_clientid)) { + printk("NFSD: nfsd4_lockt: clientid is stale!\n"); + goto out; + } + + if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) { + printk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); + goto out; + } + + inode = current_fh->fh_dentry->d_inode; + switch (lockt->lt_type) { + case NFS4_READ_LT: + case NFS4_READW_LT: + file_lock.fl_type = F_RDLCK; + break; + case NFS4_WRITE_LT: + case NFS4_WRITEW_LT: + file_lock.fl_type = F_WRLCK; + break; + default: + printk("NFSD: nfs4_lockt: bad lock type!\n"); + status = nfserr_inval; + goto out; + } + + strhashval = lock_ownerstr_hashval(inode, + lockt->lt_clientid.cl_id, lockt->lt_owner); + + if (find_lockstateowner_str(strhashval, &lockt->lt_owner, + &lockt->lt_clientid, + &lockt->lt_stateowner)) { + printk("NFSD: nsfd4_lockt: lookup_lockowner() failed!\n"); + goto out; + } + + sop = lockt->lt_stateowner; + if (sop) { + file_lock.fl_owner = (fl_owner_t) sop; + file_lock.fl_pid = lockownerid_hashval(sop->so_id); + } else { + file_lock.fl_owner = NULL; + file_lock.fl_pid = 0; + } + file_lock.fl_flags = FL_POSIX; + + file_lock.fl_start = lockt->lt_offset; + if ((lockt->lt_length == ~(u64)0) || LOFF_OVERFLOW(lockt->lt_offset, lockt->lt_length)) + file_lock.fl_end = ~(u64)0; + else + file_lock.fl_end = lockt->lt_offset + lockt->lt_length - 1; + + nfs4_transform_lock_offset(&file_lock); + + /* posix_test_lock uses the struct file _only_ to resolve the inode. + * since LOCKT doesn't require an OPEN, and therefore a struct + * file may not exist, pass posix_test_lock a struct file with + * only the dentry:inode set. + */ + memset(&file, 0, sizeof (struct file)); + file.f_dentry = current_fh->fh_dentry; + + status = nfs_ok; + conflicting_lock = posix_test_lock(&file, &file_lock); + if (conflicting_lock) { + status = nfserr_denied; + nfs4_set_lock_denied(conflicting_lock, &lockt->lt_denied); + } +out: + nfs4_unlock_state(); + return status; +} + + /* * Start and stop routines */ diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 1158815985330..96c245cb13f3f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -605,6 +605,25 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) DECODE_TAIL; } +static int +nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) +{ + DECODE_HEAD; + + READ_BUF(32); + READ32(lockt->lt_type); + if((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT)) + goto xdr_error; + READ64(lockt->lt_offset); + READ64(lockt->lt_length); + COPYMEM(&lockt->lt_clientid, 8); + READ32(lockt->lt_owner.len); + READ_BUF(lockt->lt_owner.len); + READMEM(lockt->lt_owner.data, lockt->lt_owner.len); + + DECODE_TAIL; +} + static int nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup) { @@ -1030,6 +1049,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) case OP_LOCK: op->status = nfsd4_decode_lock(argp, &op->u.lock); break; + case OP_LOCKT: + op->status = nfsd4_decode_lockt(argp, &op->u.lockt); + break; case OP_LOOKUP: op->status = nfsd4_decode_lookup(argp, &op->u.lookup); break; @@ -1786,6 +1808,14 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock ENCODE_SEQID_OP_TAIL(lock->lk_stateowner); } +static void +nfsd4_encode_lockt(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lockt *lockt) +{ + if (nfserr == nfserr_denied) + nfsd4_encode_lock_denied(resp, &lockt->lt_denied); +} + + static void nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link *link) { @@ -2199,6 +2229,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) case OP_LOCK: nfsd4_encode_lock(resp, op->status, &op->u.lock); break; + case OP_LOCKT: + nfsd4_encode_lockt(resp, op->status, &op->u.lockt); + break; case OP_LOOKUP: break; case OP_LOOKUPP: diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index bbb037e08f18c..a39e3c2951e31 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -162,6 +162,17 @@ struct nfsd4_lock { #define lk_resp_stateid u.ok.stateid #define lk_denied u.denied + +struct nfsd4_lockt { + u32 lt_type; + clientid_t lt_clientid; + struct xdr_netobj lt_owner; + u64 lt_offset; + u64 lt_length; + struct nfs4_stateowner * lt_stateowner; + struct nfsd4_lock_denied lt_denied; +}; + struct nfsd4_lookup { u32 lo_len; /* request */ char * lo_name; /* request */ @@ -318,6 +329,7 @@ struct nfsd4_op { struct svc_fh * getfh; struct nfsd4_link link; struct nfsd4_lock lock; + struct nfsd4_lockt lockt; struct nfsd4_lookup lookup; struct nfsd4_verify nverify; struct nfsd4_open open; @@ -411,6 +423,8 @@ extern int nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od); 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); #endif /* -- 2.53.0