X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnfsd%2Fnfs4proc.c;h=ee4eff27aedc80d9faac58a7dc208929551d36ef;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=55835414fa411f28a6f90531216afe3d16c9e5f7;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 55835414f..ee4eff27a 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -117,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, @@ -153,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); @@ -161,28 +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_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 */ @@ -201,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 @@ -232,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; } /* @@ -267,8 +288,6 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh) fh_put(current_fh); status = exp_pseudoroot(rqstp->rq_client, current_fh, &rqstp->rq_chandle); - if (!status) - status = nfsd_setuser(rqstp, current_fh->fh_export); return status; } @@ -461,64 +480,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(); @@ -563,6 +544,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; @@ -581,6 +564,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); @@ -606,106 +592,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"); - goto out; - } - 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_unlock; - } - status = nfserr_openmode; - if (!access_bits_permit_write(stp->st_access_bmap)) { - dprintk("NFSD: nfsd4_setattr: not opened for write!\n"); - goto out_unlock; - } + 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; + } } status = nfs_ok; if (setattr->sa_acl != NULL) status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl); if (status) - goto out; + return status; status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, 0, (time_t)0); -out: - return status; -out_unlock: - nfs4_unlock_state(); 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,6 +721,12 @@ nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) return nfs_ok; } +static inline void nfsd4_increment_op_stats(u32 opnum) +{ + if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP) + nfsdstats.nfs4_opcount[opnum]++; +} + /* * COMPOUND call. @@ -785,6 +739,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, struct nfsd4_op *op; 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; @@ -820,6 +775,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 @@ -844,17 +801,13 @@ 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) && !((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; } @@ -863,10 +816,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, op->status = nfsd4_access(rqstp, current_fh, &op->u.access); break; case OP_CLOSE: - op->status = nfsd4_close(rqstp, current_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, current_fh, &op->u.commit); @@ -874,6 +824,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, case OP_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, current_fh, &op->u.getattr); break; @@ -884,19 +837,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link); break; case OP_LOCK: - op->status = nfsd4_lock(rqstp, current_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, current_fh, &op->u.lockt); break; case OP_LOCKU: - op->status = nfsd4_locku(rqstp, current_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, current_fh, &op->u.lookup); @@ -910,22 +857,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, op->status = nfs_ok; break; case OP_OPEN: - op->status = nfsd4_open(rqstp, current_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, current_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, current_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, current_fh, &op->u.putfh); @@ -984,12 +922,22 @@ 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); + + nfsd4_increment_op_stats(op->opnum); } out: @@ -1033,7 +981,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 = {