X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=fs%2Fnfsd%2Fnfs4proc.c;h=18ead1790bb388461b08d42e3e5fcc5c1d1807cd;hb=160acc2e899f26356bde92bc257253b7ca78f0c3;hp=1b6756aa013cf993791de489cc48dfd26d8c5d7c;hpb=ca3643171bc6e08b7c4d1f9a2ce659541a01a7fe;p=linux-2.6-omap-h63xx.git diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 1b6756aa013..18ead1790bb 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -33,13 +33,6 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Note: some routines in this file are just trivial wrappers - * (e.g. nfsd4_lookup()) defined solely for the sake of consistent - * naming. Since all such routines have been declared "inline", - * there shouldn't be any associated overhead. At some point in - * the future, I might inline these "by hand" to clean up a - * little. */ #include @@ -54,6 +47,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_PROC @@ -106,7 +100,15 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &open->op_iattr, &resfh, open->op_createmode, - (u32 *)open->op_verf.data, &open->op_truncate, &created); + (u32 *)open->op_verf.data, + &open->op_truncate, &created); + + /* If we ever decide to use different attrs to store the + * verifier in nfsd_create_v3, then we'll need to change this + */ + if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0) + open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS | + FATTR4_WORD1_TIME_MODIFY); } else { status = nfsd_lookup(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &resfh); @@ -161,9 +163,9 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ } -static inline __be32 +static __be32 nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, - struct nfsd4_open *open, struct nfs4_stateowner **replay_owner) + struct nfsd4_open *open) { __be32 status; dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", @@ -236,12 +238,12 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, break; case NFS4_OPEN_CLAIM_DELEGATE_PREV: open->op_stateowner->so_confirmed = 1; - printk("NFSD: unsupported OPEN claim type %d\n", + dprintk("NFSD: unsupported OPEN claim type %d\n", open->op_claim_type); status = nfserr_notsupp; goto out; default: - printk("NFSD: Invalid OPEN claim type %d\n", + dprintk("NFSD: Invalid OPEN claim type %d\n", open->op_claim_type); status = nfserr_inval; goto out; @@ -255,7 +257,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, out: if (open->op_stateowner) { nfs4_get_stateowner(open->op_stateowner); - *replay_owner = open->op_stateowner; + cstate->replay_owner = open->op_stateowner; } nfs4_unlock_state(); return status; @@ -264,8 +266,9 @@ out: /* * filehandle-manipulating ops. */ -static inline __be32 -nfsd4_getfh(struct nfsd4_compound_state *cstate, struct svc_fh **getfh) +static __be32 +nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct svc_fh **getfh) { if (!cstate->current_fh.fh_dentry) return nfserr_nofilehandle; @@ -274,7 +277,7 @@ nfsd4_getfh(struct nfsd4_compound_state *cstate, struct svc_fh **getfh) return nfs_ok; } -static inline __be32 +static __be32 nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_putfh *putfh) { @@ -285,19 +288,20 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); } -static inline __be32 -nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate) +static __be32 +nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + void *arg) { __be32 status; fh_put(&cstate->current_fh); - status = exp_pseudoroot(rqstp->rq_client, &cstate->current_fh, - &rqstp->rq_chandle); + status = exp_pseudoroot(rqstp, &cstate->current_fh); return status; } -static inline __be32 -nfsd4_restorefh(struct nfsd4_compound_state *cstate) +static __be32 +nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + void *arg) { if (!cstate->save_fh.fh_dentry) return nfserr_restorefh; @@ -306,8 +310,9 @@ nfsd4_restorefh(struct nfsd4_compound_state *cstate) return nfs_ok; } -static inline __be32 -nfsd4_savefh(struct nfsd4_compound_state *cstate) +static __be32 +nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + void *arg) { if (!cstate->current_fh.fh_dentry) return nfserr_nofilehandle; @@ -319,7 +324,7 @@ nfsd4_savefh(struct nfsd4_compound_state *cstate) /* * misc nfsv4 ops */ -static inline __be32 +static __be32 nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_access *access) { @@ -331,7 +336,7 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, &access->ac_supported); } -static inline __be32 +static __be32 nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_commit *commit) { @@ -434,7 +439,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return status; } -static inline __be32 +static __be32 nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_getattr *getattr) { @@ -454,7 +459,7 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return nfs_ok; } -static inline __be32 +static __be32 nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_link *link) { @@ -470,14 +475,15 @@ nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, } static __be32 -nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate) +nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + void *arg) { struct svc_fh tmp_fh; __be32 ret; fh_init(&tmp_fh, NFS4_FHSIZE); - if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh, - &rqstp->rq_chandle)) != 0) + ret = exp_pseudoroot(rqstp, &tmp_fh); + if (ret) return ret; if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) { fh_put(&tmp_fh); @@ -488,7 +494,7 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate) "..", 2, &cstate->current_fh); } -static inline __be32 +static __be32 nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_lookup *lookup) { @@ -497,7 +503,7 @@ nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, &cstate->current_fh); } -static inline __be32 +static __be32 nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_read *read) { @@ -527,7 +533,7 @@ out: return status; } -static inline __be32 +static __be32 nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_readdir *readdir) { @@ -551,7 +557,7 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return nfs_ok; } -static inline __be32 +static __be32 nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_readlink *readlink) { @@ -560,7 +566,7 @@ nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return nfs_ok; } -static inline __be32 +static __be32 nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_remove *remove) { @@ -579,7 +585,7 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return status; } -static inline __be32 +static __be32 nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_rename *rename) { @@ -612,7 +618,31 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return status; } -static inline __be32 +static __be32 +nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_secinfo *secinfo) +{ + struct svc_fh resfh; + struct svc_export *exp; + struct dentry *dentry; + __be32 err; + + fh_init(&resfh, NFS4_FHSIZE); + err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, + secinfo->si_name, secinfo->si_namelen, + &exp, &dentry); + if (err) + return err; + if (dentry->d_inode == NULL) { + exp_put(exp); + err = nfserr_noent; + } else + secinfo->si_exp = exp; + dput(dentry); + return err; +} + +static __be32 nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr) { @@ -639,7 +669,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, return status; } -static inline __be32 +static __be32 nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_write *write) { @@ -688,7 +718,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK. */ static __be32 -nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, +_nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_verify *verify) { __be32 *buf, *p; @@ -740,6 +770,26 @@ out_kfree: return status; } +static __be32 +nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_verify *verify) +{ + __be32 status; + + status = _nfsd4_verify(rqstp, cstate, verify); + return status == nfserr_not_same ? nfs_ok : status; +} + +static __be32 +nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_verify *verify) +{ + __be32 status; + + status = _nfsd4_verify(rqstp, cstate, verify); + return status == nfserr_same ? nfs_ok : status; +} + /* * NULL call. */ @@ -761,6 +811,7 @@ static void cstate_free(struct nfsd4_compound_state *cstate) return; fh_put(&cstate->current_fh); fh_put(&cstate->save_fh); + BUG_ON(cstate->replay_owner); kfree(cstate); } @@ -773,9 +824,24 @@ static struct nfsd4_compound_state *cstate_alloc(void) return NULL; fh_init(&cstate->current_fh, NFS4_FHSIZE); fh_init(&cstate->save_fh, NFS4_FHSIZE); + cstate->replay_owner = NULL; return cstate; } +typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, + void *); + +struct nfsd4_operation { + nfsd4op_func op_func; + u32 op_flags; +/* Most ops require a valid current filehandle; a few don't: */ +#define ALLOWED_WITHOUT_FH 1 +/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */ +#define ALLOWED_ON_ABSENT_FS 2 +}; + +static struct nfsd4_operation nfsd4_ops[]; + /* * COMPOUND call. */ @@ -785,8 +851,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, struct nfsd4_compoundres *resp) { struct nfsd4_op *op; + struct nfsd4_operation *opdesc; struct nfsd4_compound_state *cstate = NULL; - struct nfs4_stateowner *replay_owner = NULL; int slack_bytes; __be32 status; @@ -840,177 +906,36 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, goto encode_op; } - /* All operations except RENEW, SETCLIENTID, RESTOREFH - * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH - * require a valid current filehandle - */ + opdesc = &nfsd4_ops[op->opnum]; + if (!cstate->current_fh.fh_dentry) { - if (!((op->opnum == OP_PUTFH) || - (op->opnum == OP_PUTROOTFH) || - (op->opnum == OP_SETCLIENTID) || - (op->opnum == OP_SETCLIENTID_CONFIRM) || - (op->opnum == OP_RENEW) || - (op->opnum == OP_RESTOREFH) || - (op->opnum == OP_RELEASE_LOCKOWNER))) { + if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { op->status = nfserr_nofilehandle; goto encode_op; } - } - /* Check must be done at start of each operation, except - * for GETATTR and ops not listed as returning NFS4ERR_MOVED - */ - else if (cstate->current_fh.fh_export->ex_fslocs.migrated && - !((op->opnum == OP_GETATTR) || - (op->opnum == OP_PUTROOTFH) || - (op->opnum == OP_PUTPUBFH) || - (op->opnum == OP_RENEW) || - (op->opnum == OP_SETCLIENTID) || - (op->opnum == OP_RELEASE_LOCKOWNER))) { + } else if (cstate->current_fh.fh_export->ex_fslocs.migrated && + !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) { op->status = nfserr_moved; goto encode_op; } - switch (op->opnum) { - case OP_ACCESS: - op->status = nfsd4_access(rqstp, cstate, - &op->u.access); - break; - case OP_CLOSE: - op->status = nfsd4_close(rqstp, cstate, - &op->u.close, &replay_owner); - break; - case OP_COMMIT: - op->status = nfsd4_commit(rqstp, cstate, - &op->u.commit); - break; - case OP_CREATE: - op->status = nfsd4_create(rqstp, cstate, - &op->u.create); - break; - case OP_DELEGRETURN: - op->status = nfsd4_delegreturn(rqstp, cstate, - &op->u.delegreturn); - break; - case OP_GETATTR: - op->status = nfsd4_getattr(rqstp, cstate, - &op->u.getattr); - break; - case OP_GETFH: - op->status = nfsd4_getfh(cstate, &op->u.getfh); - break; - case OP_LINK: - op->status = nfsd4_link(rqstp, cstate, &op->u.link); - break; - case OP_LOCK: - op->status = nfsd4_lock(rqstp, cstate, &op->u.lock, - &replay_owner); - break; - case OP_LOCKT: - op->status = nfsd4_lockt(rqstp, cstate, &op->u.lockt); - break; - case OP_LOCKU: - op->status = nfsd4_locku(rqstp, cstate, &op->u.locku, - &replay_owner); - break; - case OP_LOOKUP: - op->status = nfsd4_lookup(rqstp, cstate, - &op->u.lookup); - break; - case OP_LOOKUPP: - op->status = nfsd4_lookupp(rqstp, cstate); - break; - case OP_NVERIFY: - op->status = nfsd4_verify(rqstp, cstate, - &op->u.nverify); - if (op->status == nfserr_not_same) - op->status = nfs_ok; - break; - case OP_OPEN: - op->status = nfsd4_open(rqstp, cstate, - &op->u.open, &replay_owner); - break; - case OP_OPEN_CONFIRM: - op->status = nfsd4_open_confirm(rqstp, cstate, - &op->u.open_confirm, - &replay_owner); - break; - case OP_OPEN_DOWNGRADE: - op->status = nfsd4_open_downgrade(rqstp, cstate, - &op->u.open_downgrade, - &replay_owner); - break; - case OP_PUTFH: - op->status = nfsd4_putfh(rqstp, cstate, &op->u.putfh); - break; - case OP_PUTROOTFH: - op->status = nfsd4_putrootfh(rqstp, cstate); - break; - case OP_READ: - op->status = nfsd4_read(rqstp, cstate, &op->u.read); - break; - case OP_READDIR: - op->status = nfsd4_readdir(rqstp, cstate, - &op->u.readdir); - break; - case OP_READLINK: - op->status = nfsd4_readlink(rqstp, cstate, - &op->u.readlink); - break; - case OP_REMOVE: - op->status = nfsd4_remove(rqstp, cstate, - &op->u.remove); - break; - case OP_RENAME: - op->status = nfsd4_rename(rqstp, cstate, - &op->u.rename); - break; - case OP_RENEW: - op->status = nfsd4_renew(&op->u.renew); - break; - case OP_RESTOREFH: - op->status = nfsd4_restorefh(cstate); - break; - case OP_SAVEFH: - op->status = nfsd4_savefh(cstate); - break; - case OP_SETATTR: - op->status = nfsd4_setattr(rqstp, cstate, - &op->u.setattr); - break; - case OP_SETCLIENTID: - op->status = nfsd4_setclientid(rqstp, &op->u.setclientid); - break; - case OP_SETCLIENTID_CONFIRM: - op->status = nfsd4_setclientid_confirm(rqstp, &op->u.setclientid_confirm); - break; - case OP_VERIFY: - op->status = nfsd4_verify(rqstp, cstate, - &op->u.verify); - if (op->status == nfserr_same) - op->status = nfs_ok; - break; - case OP_WRITE: - op->status = nfsd4_write(rqstp, cstate, &op->u.write); - break; - case OP_RELEASE_LOCKOWNER: - op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner); - break; - default: + + if (opdesc->op_func) + op->status = opdesc->op_func(rqstp, cstate, &op->u); + else BUG_ON(op->status == nfs_ok); - break; - } encode_op: if (op->status == nfserr_replay_me) { - op->replay = &replay_owner->so_replay; + op->replay = &cstate->replay_owner->so_replay; nfsd4_encode_replay(resp, op); status = op->status = op->replay->rp_status; } else { nfsd4_encode_operation(resp, op); status = op->status; } - if (replay_owner && (replay_owner != (void *)(-1))) { - nfs4_put_stateowner(replay_owner); - replay_owner = NULL; + if (cstate->replay_owner) { + nfs4_put_stateowner(cstate->replay_owner); + cstate->replay_owner = NULL; } /* XXX Ugh, we need to get rid of this kind of special case: */ if (op->opnum == OP_READ && op->u.read.rd_filp) @@ -1025,6 +950,123 @@ out: return status; } +static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = { + [OP_ACCESS] = { + .op_func = (nfsd4op_func)nfsd4_access, + }, + [OP_CLOSE] = { + .op_func = (nfsd4op_func)nfsd4_close, + }, + [OP_COMMIT] = { + .op_func = (nfsd4op_func)nfsd4_commit, + }, + [OP_CREATE] = { + .op_func = (nfsd4op_func)nfsd4_create, + }, + [OP_DELEGRETURN] = { + .op_func = (nfsd4op_func)nfsd4_delegreturn, + }, + [OP_GETATTR] = { + .op_func = (nfsd4op_func)nfsd4_getattr, + .op_flags = ALLOWED_ON_ABSENT_FS, + }, + [OP_GETFH] = { + .op_func = (nfsd4op_func)nfsd4_getfh, + }, + [OP_LINK] = { + .op_func = (nfsd4op_func)nfsd4_link, + }, + [OP_LOCK] = { + .op_func = (nfsd4op_func)nfsd4_lock, + }, + [OP_LOCKT] = { + .op_func = (nfsd4op_func)nfsd4_lockt, + }, + [OP_LOCKU] = { + .op_func = (nfsd4op_func)nfsd4_locku, + }, + [OP_LOOKUP] = { + .op_func = (nfsd4op_func)nfsd4_lookup, + }, + [OP_LOOKUPP] = { + .op_func = (nfsd4op_func)nfsd4_lookupp, + }, + [OP_NVERIFY] = { + .op_func = (nfsd4op_func)nfsd4_nverify, + }, + [OP_OPEN] = { + .op_func = (nfsd4op_func)nfsd4_open, + }, + [OP_OPEN_CONFIRM] = { + .op_func = (nfsd4op_func)nfsd4_open_confirm, + }, + [OP_OPEN_DOWNGRADE] = { + .op_func = (nfsd4op_func)nfsd4_open_downgrade, + }, + [OP_PUTFH] = { + .op_func = (nfsd4op_func)nfsd4_putfh, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_PUTPUBFH] = { + /* unsupported; just for future reference: */ + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_PUTROOTFH] = { + .op_func = (nfsd4op_func)nfsd4_putrootfh, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_READ] = { + .op_func = (nfsd4op_func)nfsd4_read, + }, + [OP_READDIR] = { + .op_func = (nfsd4op_func)nfsd4_readdir, + }, + [OP_READLINK] = { + .op_func = (nfsd4op_func)nfsd4_readlink, + }, + [OP_REMOVE] = { + .op_func = (nfsd4op_func)nfsd4_remove, + }, + [OP_RENAME] = { + .op_func = (nfsd4op_func)nfsd4_rename, + }, + [OP_RENEW] = { + .op_func = (nfsd4op_func)nfsd4_renew, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_RESTOREFH] = { + .op_func = (nfsd4op_func)nfsd4_restorefh, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_SAVEFH] = { + .op_func = (nfsd4op_func)nfsd4_savefh, + }, + [OP_SECINFO] = { + .op_func = (nfsd4op_func)nfsd4_secinfo, + }, + [OP_SETATTR] = { + .op_func = (nfsd4op_func)nfsd4_setattr, + }, + [OP_SETCLIENTID] = { + .op_func = (nfsd4op_func)nfsd4_setclientid, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_SETCLIENTID_CONFIRM] = { + .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_VERIFY] = { + .op_func = (nfsd4op_func)nfsd4_verify, + }, + [OP_WRITE] = { + .op_func = (nfsd4op_func)nfsd4_write, + }, + [OP_RELEASE_LOCKOWNER] = { + .op_func = (nfsd4op_func)nfsd4_release_lockowner, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, +}; + #define nfs4svc_decode_voidargs NULL #define nfs4svc_release_void NULL #define nfsd4_voidres nfsd4_voidargs