X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnfsd%2Fnfs4proc.c;h=ca8a4c410de338e8935073d21d724a6cd67a2627;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=d54c85adef89b0750ce7a126a7dcd09a7ca1b9a9;hpb=39b607ac274a09883c7fe5f03a7eff28960a1190;p=linux-2.6.git diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index d54c85ade..ca8a4c410 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_PROC @@ -116,7 +118,6 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o /* set reply cache */ fh_dup2(current_fh, &resfh); - /* XXXJBF: keep a saved svc_fh struct instead?? */ open->op_stateowner->so_replay.rp_openfh_len = resfh.fh_handle.fh_size; memcpy(open->op_stateowner->so_replay.rp_openfh, @@ -135,9 +136,11 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ { int status; - dprintk("NFSD: do_open_fhandle\n"); + /* Only reclaims from previously confirmed clients are valid */ + if ((status = nfs4_check_open_reclaim(&open->op_clientid))) + return status; - /* we don't know the target directory, and therefore can not + /* We don't know the target directory, and therefore can not * set the change info */ @@ -150,7 +153,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ current_fh->fh_handle.fh_size); open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && - !open->op_iattr.ia_size; + (open->op_iattr.ia_size == 0); status = do_open_permission(rqstp, current_fh, open); @@ -158,29 +161,18 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ } -/* - * nfs4_unlock_state() called in encode - */ static inline int -nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) +nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner) { int status; dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", (int)open->op_fname.len, open->op_fname.data, open->op_stateowner); - if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) - return nfserr_grace; - - if (nfs4_in_no_grace() && - open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) - return nfserr_no_grace; - /* This check required by spec. */ if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) return nfserr_inval; - open->op_stateowner = NULL; nfs4_lock_state(); /* check seqid for replay. set nfs4_owner */ @@ -199,30 +191,57 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open status = NFSERR_REPLAY_ME; } if (status) - return status; - if (open->op_claim_type == NFS4_OPEN_CLAIM_NULL) { - /* - * This block of code will (1) set CURRENT_FH to the file being opened, - * creating it if necessary, (2) set open->op_cinfo, - * (3) set open->op_truncate if the file is to be truncated - * after opening, (4) do permission checking. - */ - status = do_open_lookup(rqstp, current_fh, open); - if (status) - return status; - } else if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) { - /* - * The CURRENT_FH is already set to the file being opened. This - * block of code will (1) set open->op_cinfo, (2) set - * open->op_truncate if the file is to be truncated after opening, - * (3) do permission checking. - */ - status = do_open_fhandle(rqstp, current_fh, open); - if (status) - return status; - } else { - printk("NFSD: unsupported OPEN claim type\n"); - return nfserr_inval; + goto out; + + /* Openowner is now set, so sequence id will get bumped. Now we need + * these checks before we do any creates: */ + status = nfserr_grace; + if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) + goto out; + status = nfserr_no_grace; + if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) + goto out; + + switch (open->op_claim_type) { + case NFS4_OPEN_CLAIM_DELEGATE_CUR: + status = nfserr_inval; + if (open->op_create) + goto out; + /* fall through */ + case NFS4_OPEN_CLAIM_NULL: + /* + * (1) set CURRENT_FH to the file being opened, + * creating it if necessary, (2) set open->op_cinfo, + * (3) set open->op_truncate if the file is to be + * truncated after opening, (4) do permission checking. + */ + status = do_open_lookup(rqstp, current_fh, open); + if (status) + goto out; + break; + case NFS4_OPEN_CLAIM_PREVIOUS: + open->op_stateowner->so_confirmed = 1; + /* + * The CURRENT_FH is already set to the file being + * opened. (1) set open->op_cinfo, (2) set + * open->op_truncate if the file is to be truncated + * after opening, (3) do permission checking. + */ + status = do_open_fhandle(rqstp, current_fh, open); + if (status) + goto out; + break; + case NFS4_OPEN_CLAIM_DELEGATE_PREV: + open->op_stateowner->so_confirmed = 1; + printk("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", + open->op_claim_type); + status = nfserr_inval; + goto out; } /* * nfsd4_process_open2() does the actual opening of the file. If @@ -230,9 +249,13 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open * set, (2) sets open->op_stateid, (3) sets open->op_delegation. */ status = nfsd4_process_open2(rqstp, current_fh, open); - if (status) - return status; - return 0; +out: + if (open->op_stateowner) { + nfs4_get_stateowner(open->op_stateowner); + *replay_owner = open->op_stateowner; + } + nfs4_unlock_state(); + return status; } /* @@ -266,7 +289,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh) status = exp_pseudoroot(rqstp->rq_client, current_fh, &rqstp->rq_chandle); if (!status) - status = nfsd_setuser(rqstp, current_fh->fh_export); + status = nfserrno(nfsd_setuser(rqstp, current_fh->fh_export)); return status; } @@ -318,7 +341,7 @@ nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_com return status; } -static inline int +static int nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create) { struct svc_fh resfh; @@ -435,7 +458,7 @@ nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh, return status; } -static inline int +static int nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh) { struct svc_fh tmp_fh; @@ -459,64 +482,26 @@ nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_loo return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh); } -static inline int -access_bits_permit_read(unsigned long access_bmap) -{ - return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) || - test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap); -} - -static inline int -access_bits_permit_write(unsigned long access_bmap) -{ - return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) || - test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap); -} - static inline int nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read) { - struct nfs4_stateid *stp; int status; /* no need to check permission - this will be done in nfsd_read() */ - if (nfs4_in_grace()) - return nfserr_grace; + read->rd_filp = NULL; if (read->rd_offset >= OFFSET_MAX) return nfserr_inval; nfs4_lock_state(); - status = nfs_ok; - /* For stateid -1, we don't check share reservations. */ - if (ONE_STATEID(&read->rd_stateid)) { - dprintk("NFSD: nfsd4_read: -1 stateid...\n"); - goto out; - } - /* - * For stateid 0, the client doesn't have to have the file open, but - * we still check for share reservation conflicts. - */ - if (ZERO_STATEID(&read->rd_stateid)) { - dprintk("NFSD: nfsd4_read: zero stateid...\n"); - if ((status = nfs4_share_conflict(current_fh, NFS4_SHARE_DENY_READ))) { - dprintk("NFSD: nfsd4_read: conflicting share reservation!\n"); - goto out; - } - status = nfs_ok; - goto out; - } /* check stateid */ - if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, - CHECK_FH | RDWR_STATE, &stp))) { + if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, + CHECK_FH | RD_STATE, &read->rd_filp))) { dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); goto out; } - status = nfserr_openmode; - if (!access_bits_permit_read(stp->st_access_bmap)) { - dprintk("NFSD: nfsd4_read: file not opened for read!\n"); - goto out; - } + if (read->rd_filp) + get_file(read->rd_filp); status = nfs_ok; out: nfs4_unlock_state(); @@ -561,6 +546,8 @@ nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_rem { int status; + if (nfs4_in_grace()) + return nfserr_grace; status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen); if (status == nfserr_symlink) return nfserr_notdir; @@ -579,6 +566,9 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, if (!save_fh->fh_dentry) return status; + if (nfs4_in_grace() && !(save_fh->fh_export->ex_flags + & NFSEXP_NOSUBTREECHECK)) + return nfserr_grace; status = nfsd_rename(rqstp, save_fh, rename->rn_sname, rename->rn_snamelen, current_fh, rename->rn_tname, rename->rn_tnamelen); @@ -604,98 +594,68 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, static inline int nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr) { - struct nfs4_stateid *stp; int status = nfs_ok; - if (nfs4_in_grace()) - return nfserr_grace; - - if (!current_fh->fh_dentry) - return nfserr_nofilehandle; - - status = nfs_ok; if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { - - status = nfserr_bad_stateid; - if (ZERO_STATEID(&setattr->sa_stateid) || ONE_STATEID(&setattr->sa_stateid)) { - dprintk("NFSD: nfsd4_setattr: magic stateid!\n"); - return status; - } - nfs4_lock_state(); - if ((status = nfs4_preprocess_stateid_op(current_fh, - &setattr->sa_stateid, - CHECK_FH | RDWR_STATE, &stp))) { - dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); - goto out; - } - status = nfserr_openmode; - if (!access_bits_permit_write(stp->st_access_bmap)) { - dprintk("NFSD: nfsd4_setattr: not opened for write!\n"); - goto out; - } + status = nfs4_preprocess_stateid_op(current_fh, + &setattr->sa_stateid, CHECK_FH | WR_STATE, NULL); nfs4_unlock_state(); + if (status) { + dprintk("NFSD: nfsd4_setattr: couldn't process stateid!"); + return status; + } } - return (nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, 0, (time_t)0)); -out: - nfs4_unlock_state(); + status = nfs_ok; + if (setattr->sa_acl != NULL) + status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl); + if (status) + return status; + status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, + 0, (time_t)0); return status; } static inline int nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write) { - struct nfs4_stateid *stp; stateid_t *stateid = &write->wr_stateid; + struct file *filp = NULL; u32 *p; int status = nfs_ok; - if (nfs4_in_grace()) - return nfserr_grace; - /* no need to check permission - this will be done in nfsd_write() */ if (write->wr_offset >= OFFSET_MAX) return nfserr_inval; nfs4_lock_state(); - if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { - dprintk("NFSD: nfsd4_write: zero stateid...\n"); - if ((status = nfs4_share_conflict(current_fh, NFS4_SHARE_DENY_WRITE))) { - dprintk("NFSD: nfsd4_write: conflicting share reservation!\n"); - goto out; - } - goto zero_stateid; - } - if ((status = nfs4_preprocess_stateid_op(current_fh, stateid, - CHECK_FH | RDWR_STATE, &stp))) { - dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); - goto out; - } + status = nfs4_preprocess_stateid_op(current_fh, stateid, + CHECK_FH | WR_STATE, &filp); + if (filp) + get_file(filp); + nfs4_unlock_state(); - status = nfserr_openmode; - if (!access_bits_permit_write(stp->st_access_bmap)) { - dprintk("NFSD: nfsd4_write: file not open for write!\n"); - goto out; + if (status) { + dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); + return status; } -zero_stateid: - nfs4_unlock_state(); write->wr_bytes_written = write->wr_buflen; write->wr_how_written = write->wr_stable_how; p = (u32 *)write->wr_verifier.data; *p++ = nfssvc_boot.tv_sec; *p++ = nfssvc_boot.tv_usec; - status = nfsd_write(rqstp, current_fh, write->wr_offset, - write->wr_vec, write->wr_vlen, write->wr_buflen, - &write->wr_how_written); + status = nfsd_write(rqstp, current_fh, filp, write->wr_offset, + write->wr_vec, write->wr_vlen, write->wr_buflen, + &write->wr_how_written); + if (filp) + fput(filp); + if (status == nfserr_symlink) status = nfserr_inval; return status; -out: - nfs4_unlock_state(); - return status; } /* This routine never returns NFS_OK! If there are no other errors, it @@ -773,13 +733,21 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, struct nfsd4_compoundres *resp) { struct nfsd4_op *op; - struct svc_fh current_fh; - struct svc_fh save_fh; + struct svc_fh *current_fh = NULL; + struct svc_fh *save_fh = NULL; + struct nfs4_stateowner *replay_owner = NULL; int slack_space; /* in words, not bytes! */ int status; - fh_init(¤t_fh, NFS4_FHSIZE); - fh_init(&save_fh, NFS4_FHSIZE); + status = nfserr_resource; + current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL); + if (current_fh == NULL) + goto out; + fh_init(current_fh, NFS4_FHSIZE); + save_fh = kmalloc(sizeof(*save_fh), GFP_KERNEL); + if (save_fh == NULL) + goto out; + fh_init(save_fh, NFS4_FHSIZE); resp->xbuf = &rqstp->rq_res; resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; @@ -803,6 +771,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, while (!status && resp->opcnt < args->opcnt) { op = &args->ops[resp->opcnt++]; + dprintk("nfsv4 compound op #%d: %d\n", resp->opcnt, op->opnum); + /* * The XDR decode routines may have pre-set op->status; * for example, if there is a miscellaneous XDR error @@ -827,121 +797,102 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, /* All operations except RENEW, SETCLIENTID, RESTOREFH * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH * require a valid current filehandle - * - * SETATTR NOFILEHANDLE error handled in nfsd4_setattr - * due to required returned bitmap argument */ - if ((!current_fh.fh_dentry) && + if ((!current_fh->fh_dentry) && !((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) || - (op->opnum == OP_SETATTR))) { + (op->opnum == OP_RELEASE_LOCKOWNER))) { op->status = nfserr_nofilehandle; goto encode_op; } switch (op->opnum) { case OP_ACCESS: - op->status = nfsd4_access(rqstp, ¤t_fh, &op->u.access); + op->status = nfsd4_access(rqstp, current_fh, &op->u.access); break; case OP_CLOSE: - op->status = nfsd4_close(rqstp, ¤t_fh, &op->u.close); - if (op->u.close.cl_stateowner) - op->replay = - &op->u.close.cl_stateowner->so_replay; + op->status = nfsd4_close(rqstp, current_fh, &op->u.close, &replay_owner); break; case OP_COMMIT: - op->status = nfsd4_commit(rqstp, ¤t_fh, &op->u.commit); + op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit); break; case OP_CREATE: - op->status = nfsd4_create(rqstp, ¤t_fh, &op->u.create); + op->status = nfsd4_create(rqstp, current_fh, &op->u.create); + break; + case OP_DELEGRETURN: + op->status = nfsd4_delegreturn(rqstp, current_fh, &op->u.delegreturn); break; case OP_GETATTR: - op->status = nfsd4_getattr(rqstp, ¤t_fh, &op->u.getattr); + op->status = nfsd4_getattr(rqstp, current_fh, &op->u.getattr); break; case OP_GETFH: - op->status = nfsd4_getfh(¤t_fh, &op->u.getfh); + op->status = nfsd4_getfh(current_fh, &op->u.getfh); break; case OP_LINK: - op->status = nfsd4_link(rqstp, ¤t_fh, &save_fh, &op->u.link); + op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link); break; case OP_LOCK: - op->status = nfsd4_lock(rqstp, ¤t_fh, &op->u.lock); - if (op->u.lock.lk_stateowner) - op->replay = - &op->u.lock.lk_stateowner->so_replay; + op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock, &replay_owner); break; case OP_LOCKT: - op->status = nfsd4_lockt(rqstp, ¤t_fh, &op->u.lockt); + op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt); break; case OP_LOCKU: - op->status = nfsd4_locku(rqstp, ¤t_fh, &op->u.locku); - if (op->u.locku.lu_stateowner) - op->replay = - &op->u.locku.lu_stateowner->so_replay; + op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku, &replay_owner); break; case OP_LOOKUP: - op->status = nfsd4_lookup(rqstp, ¤t_fh, &op->u.lookup); + op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup); break; case OP_LOOKUPP: - op->status = nfsd4_lookupp(rqstp, ¤t_fh); + op->status = nfsd4_lookupp(rqstp, current_fh); break; case OP_NVERIFY: - op->status = nfsd4_verify(rqstp, ¤t_fh, &op->u.nverify); + op->status = nfsd4_verify(rqstp, current_fh, &op->u.nverify); if (op->status == nfserr_not_same) op->status = nfs_ok; break; case OP_OPEN: - op->status = nfsd4_open(rqstp, ¤t_fh, &op->u.open); - if (op->u.open.op_stateowner) - op->replay = - &op->u.open.op_stateowner->so_replay; + op->status = nfsd4_open(rqstp, current_fh, &op->u.open, &replay_owner); break; case OP_OPEN_CONFIRM: - op->status = nfsd4_open_confirm(rqstp, ¤t_fh, &op->u.open_confirm); - if (op->u.open_confirm.oc_stateowner) - op->replay = - &op->u.open_confirm.oc_stateowner->so_replay; + op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm, &replay_owner); break; case OP_OPEN_DOWNGRADE: - op->status = nfsd4_open_downgrade(rqstp, ¤t_fh, &op->u.open_downgrade); - if (op->u.open_downgrade.od_stateowner) - op->replay = - &op->u.open_downgrade.od_stateowner->so_replay; + op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade, &replay_owner); break; case OP_PUTFH: - op->status = nfsd4_putfh(rqstp, ¤t_fh, &op->u.putfh); + op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh); break; case OP_PUTROOTFH: - op->status = nfsd4_putrootfh(rqstp, ¤t_fh); + op->status = nfsd4_putrootfh(rqstp, current_fh); break; case OP_READ: - op->status = nfsd4_read(rqstp, ¤t_fh, &op->u.read); + op->status = nfsd4_read(rqstp, current_fh, &op->u.read); break; case OP_READDIR: - op->status = nfsd4_readdir(rqstp, ¤t_fh, &op->u.readdir); + op->status = nfsd4_readdir(rqstp, current_fh, &op->u.readdir); break; case OP_READLINK: - op->status = nfsd4_readlink(rqstp, ¤t_fh, &op->u.readlink); + op->status = nfsd4_readlink(rqstp, current_fh, &op->u.readlink); break; case OP_REMOVE: - op->status = nfsd4_remove(rqstp, ¤t_fh, &op->u.remove); + op->status = nfsd4_remove(rqstp, current_fh, &op->u.remove); break; case OP_RENAME: - op->status = nfsd4_rename(rqstp, ¤t_fh, &save_fh, &op->u.rename); + op->status = nfsd4_rename(rqstp, current_fh, save_fh, &op->u.rename); break; case OP_RENEW: op->status = nfsd4_renew(&op->u.renew); break; case OP_RESTOREFH: - op->status = nfsd4_restorefh(¤t_fh, &save_fh); + op->status = nfsd4_restorefh(current_fh, save_fh); break; case OP_SAVEFH: - op->status = nfsd4_savefh(¤t_fh, &save_fh); + op->status = nfsd4_savefh(current_fh, save_fh); break; case OP_SETATTR: - op->status = nfsd4_setattr(rqstp, ¤t_fh, &op->u.setattr); + op->status = nfsd4_setattr(rqstp, current_fh, &op->u.setattr); break; case OP_SETCLIENTID: op->status = nfsd4_setclientid(rqstp, &op->u.setclientid); @@ -950,12 +901,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, op->status = nfsd4_setclientid_confirm(rqstp, &op->u.setclientid_confirm); break; case OP_VERIFY: - op->status = nfsd4_verify(rqstp, ¤t_fh, &op->u.verify); + op->status = nfsd4_verify(rqstp, current_fh, &op->u.verify); if (op->status == nfserr_same) op->status = nfs_ok; break; case OP_WRITE: - op->status = nfsd4_write(rqstp, ¤t_fh, &op->u.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); @@ -967,31 +918,30 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, encode_op: if (op->status == NFSERR_REPLAY_ME) { + op->replay = &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; + } + /* XXX Ugh, we need to get rid of this kind of special case: */ + if (op->opnum == OP_READ && op->u.read.rd_filp) + fput(op->u.read.rd_filp); } out: - if (args->ops != args->iops) { - kfree(args->ops); - args->ops = args->iops; - } - if (args->tmpp) { - kfree(args->tmpp); - args->tmpp = NULL; - } - while (args->to_free) { - struct tmpbuf *tb = args->to_free; - args->to_free = tb->next; - kfree(tb->buf); - kfree(tb); - } - fh_put(¤t_fh); - fh_put(&save_fh); + nfsd4_release_compoundargs(args); + if (current_fh) + fh_put(current_fh); + kfree(current_fh); + if (save_fh) + fh_put(save_fh); + kfree(save_fh); return status; } @@ -1025,7 +975,7 @@ struct nfsd4_voidargs { int dummy; }; */ static struct svc_procedure nfsd_procedures4[2] = { PROC(null, void, void, void, RC_NOCACHE, 1), - PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE) + PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE/4) }; struct svc_version nfsd_version4 = {