X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Fnfsd%2Fnfs4state.c;h=f6ab762bea991f1289063e47aa771bb3a1c69a8e;hb=8dc7c3115b611c00006eac3ee5b108296432aab7;hp=e388c9070de454ba88c1d8ccaeb8698a8ac61643;hpb=0fa822e452084032b8495ca0d8e0199329847815;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e388c90..f6ab762 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -624,7 +624,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) cb->cb_ident = se->se_callback_ident; return; out_err: - printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " + dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " "will not receive delegations\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); @@ -678,13 +678,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) int status; char dname[HEXDIR_LEN]; - status = nfserr_inval; if (!check_name(clname)) - goto out; + return nfserr_inval; status = nfs4_make_rec_clidname(dname, &clname); if (status) - goto out; + return status; /* * XXX The Duplicate Request Cache (DRC) has been checked (??) @@ -1089,7 +1088,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str sop->so_seqid = open->op_seqid; sop->so_confirmed = 0; rp = &sop->so_replay; - rp->rp_status = NFSERR_SERVERFAULT; + rp->rp_status = nfserr_serverfault; rp->rp_buflen = 0; rp->rp_buf = rp->rp_ibuf; return sop; @@ -1160,6 +1159,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * stp->st_deny_bmap = 0; __set_bit(open->op_share_access, &stp->st_access_bmap); __set_bit(open->op_share_deny, &stp->st_deny_bmap); + stp->st_openstp = NULL; } static void @@ -1178,7 +1178,6 @@ release_stateid(struct nfs4_stateid *stp, int flags) locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner); put_nfs4_file(stp->st_file); kmem_cache_free(stateid_slab, stp); - stp = NULL; } static void @@ -1191,22 +1190,6 @@ move_to_close_lru(struct nfs4_stateowner *sop) sop->so_time = get_seconds(); } -static void -release_state_owner(struct nfs4_stateid *stp, int flag) -{ - struct nfs4_stateowner *sop = stp->st_stateowner; - - dprintk("NFSD: release_state_owner\n"); - release_stateid(stp, flag); - - /* place unused nfs4_stateowners on so_close_lru list to be - * released by the laundromat service after the lease period - * to enable us to handle CLOSE replay - */ - if (sop->so_confirmed && list_empty(&sop->so_stateids)) - move_to_close_lru(sop); -} - static int cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) { return ((sop->so_owner.len == owner->len) && @@ -1295,7 +1278,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) fp = find_file(ino); if (!fp) return nfs_ok; - ret = nfserr_share_denied; + ret = nfserr_locked; /* Search for conflicting share reservations */ list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { if (test_bit(deny_type, &stp->st_deny_bmap) || @@ -1446,94 +1429,61 @@ static struct lock_manager_operations nfsd_lease_mng_ops = { }; -/* - * nfsd4_process_open1() - * lookup stateowner. - * found: - * check confirmed - * confirmed: - * check seqid - * not confirmed: - * delete owner - * create new owner - * notfound: - * verify clientid - * create new owner - * - * called with nfs4_lock_state() held. - */ int nfsd4_process_open1(struct nfsd4_open *open) { - int status; clientid_t *clientid = &open->op_clientid; struct nfs4_client *clp = NULL; unsigned int strhashval; struct nfs4_stateowner *sop = NULL; - status = nfserr_inval; if (!check_name(open->op_owner)) - goto out; + return nfserr_inval; if (STALE_CLIENTID(&open->op_clientid)) return nfserr_stale_clientid; strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner); sop = find_openstateowner_str(strhashval, open); - if (sop) { - open->op_stateowner = sop; - /* check for replay */ - if (open->op_seqid == sop->so_seqid){ - if (sop->so_replay.rp_buflen) - return NFSERR_REPLAY_ME; - else { - /* The original OPEN failed so spectacularly - * that we don't even have replay data saved! - * Therefore, we have no choice but to continue - * processing this OPEN; presumably, we'll - * fail again for the same reason. - */ - dprintk("nfsd4_process_open1:" - " replay with no replay cache\n"); - goto renew; - } - } else if (sop->so_confirmed) { - if (open->op_seqid == sop->so_seqid + 1) - goto renew; - status = nfserr_bad_seqid; - goto out; - } else { - /* If we get here, we received an OPEN for an - * unconfirmed nfs4_stateowner. Since the seqid's are - * different, purge the existing nfs4_stateowner, and - * instantiate a new one. - */ - clp = sop->so_client; - release_stateowner(sop); - } - } else { - /* nfs4_stateowner not found. - * Verify clientid and instantiate new nfs4_stateowner. - * If verify fails this is presumably the result of the - * client's lease expiring. - */ - status = nfserr_expired; + open->op_stateowner = sop; + if (!sop) { + /* Make sure the client's lease hasn't expired. */ clp = find_confirmed_client(clientid); if (clp == NULL) - goto out; + return nfserr_expired; + goto renew; } - status = nfserr_resource; - sop = alloc_init_open_stateowner(strhashval, clp, open); - if (sop == NULL) - goto out; - open->op_stateowner = sop; + if (!sop->so_confirmed) { + /* Replace unconfirmed owners without checking for replay. */ + clp = sop->so_client; + release_stateowner(sop); + open->op_stateowner = NULL; + goto renew; + } + if (open->op_seqid == sop->so_seqid - 1) { + if (sop->so_replay.rp_buflen) + return NFSERR_REPLAY_ME; + /* The original OPEN failed so spectacularly + * that we don't even have replay data saved! + * Therefore, we have no choice but to continue + * processing this OPEN; presumably, we'll + * fail again for the same reason. + */ + dprintk("nfsd4_process_open1: replay with no replay cache\n"); + goto renew; + } + if (open->op_seqid != sop->so_seqid) + return nfserr_bad_seqid; renew: - status = nfs_ok; + if (open->op_stateowner == NULL) { + sop = alloc_init_open_stateowner(strhashval, clp, open); + if (sop == NULL) + return nfserr_resource; + open->op_stateowner = sop; + } + list_del_init(&sop->so_close_lru); renew_client(sop->so_client); -out: - if (status && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) - status = nfserr_reclaim_bad; - return status; + return nfs_ok; } static inline int @@ -1650,7 +1600,7 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, if (!open->op_truncate) return 0; if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) - return -EINVAL; + return nfserr_inval; return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); } @@ -1659,26 +1609,26 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta { struct file *filp = stp->st_vfs_file; struct inode *inode = filp->f_dentry->d_inode; - unsigned int share_access; + unsigned int share_access, new_writer; int status; set_access(&share_access, stp->st_access_bmap); - share_access = ~share_access; - share_access &= open->op_share_access; + new_writer = (~share_access) & open->op_share_access + & NFS4_SHARE_ACCESS_WRITE; - if (!(share_access & NFS4_SHARE_ACCESS_WRITE)) - return nfsd4_truncate(rqstp, cur_fh, open); - - status = get_write_access(inode); - if (status) - return nfserrno(status); + if (new_writer) { + status = get_write_access(inode); + if (status) + return nfserrno(status); + } status = nfsd4_truncate(rqstp, cur_fh, open); if (status) { - put_write_access(inode); + if (new_writer) + put_write_access(inode); return status; } /* remember the open */ - filp->f_mode = (filp->f_mode | FMODE_WRITE) & ~FMODE_READ; + filp->f_mode |= open->op_share_access; set_bit(open->op_share_access, &stp->st_access_bmap); set_bit(open->op_share_deny, &stp->st_deny_bmap); @@ -1686,19 +1636,11 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta } -/* decrement seqid on successful reclaim, it will be bumped in encode_open */ static void -nfs4_set_claim_prev(struct nfsd4_open *open, int *status) +nfs4_set_claim_prev(struct nfsd4_open *open) { - if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) { - if (*status) - *status = nfserr_reclaim_bad; - else { - open->op_stateowner->so_confirmed = 1; - open->op_stateowner->so_client->cl_firststate = 1; - open->op_stateowner->so_seqid--; - } - } + open->op_stateowner->so_confirmed = 1; + open->op_stateowner->so_client->cl_firststate = 1; } /* @@ -1824,6 +1766,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf status = nfs4_upgrade_open(rqstp, current_fh, stp, open); if (status) goto out; + update_stateid(&stp->st_stateid); } else { /* Stateid was not found, this is a new OPEN */ int flags = 0; @@ -1857,8 +1800,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf out: if (fp) put_nfs4_file(fp); - /* CLAIM_PREVIOUS has different error returns */ - nfs4_set_claim_prev(open, &status); + if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) + nfs4_set_claim_prev(open); /* * To finish the open response, we just need to set the rflags. */ @@ -1991,14 +1934,11 @@ laundromat_main(void *not_used) queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); } -/* search ownerid_hashtbl[] and close_lru for stateid owner - * (stateid->si_stateownerid) - */ static struct nfs4_stateowner * -find_openstateowner_id(u32 st_id, int flags) { +search_close_lru(u32 st_id, int flags) +{ struct nfs4_stateowner *local = NULL; - dprintk("NFSD: find_openstateowner_id %d\n", st_id); if (flags & CLOSE_STATE) { list_for_each_entry(local, &close_lru, so_close_lru) { if (local->so_id == st_id) @@ -2019,7 +1959,7 @@ STALE_STATEID(stateid_t *stateid) { if (stateid->si_boot == boot_time) return 0; - printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", + dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, stateid->si_generation); return 1; @@ -2164,14 +2104,19 @@ out: return status; } +static inline int +setlkflg (int type) +{ + return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? + RD_STATE : WR_STATE; +} /* * Checks for sequence id mutating operations. */ static int -nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid) +nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock) { - int status; struct nfs4_stateid *stp; struct nfs4_stateowner *sop; @@ -2179,53 +2124,65 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei "stateid = (%08x/%08x/%08x/%08x)\n", seqid, stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, stateid->si_generation); - + *stpp = NULL; *sopp = NULL; - status = nfserr_bad_stateid; if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { printk("NFSD: preprocess_seqid_op: magic stateid!\n"); - goto out; + return nfserr_bad_stateid; } - status = nfserr_stale_stateid; if (STALE_STATEID(stateid)) - goto out; + return nfserr_stale_stateid; /* * We return BAD_STATEID if filehandle doesn't match stateid, * the confirmed flag is incorrecly set, or the generation * number is incorrect. - * If there is no entry in the openfile table for this id, - * we can't always return BAD_STATEID; - * this might be a retransmitted CLOSE which has arrived after - * the openfile has been released. */ - if (!(stp = find_stateid(stateid, flags))) - goto no_nfs4_stateid; - - status = nfserr_bad_stateid; + stp = find_stateid(stateid, flags); + if (stp == NULL) { + /* + * Also, we should make sure this isn't just the result of + * a replayed close: + */ + sop = search_close_lru(stateid->si_stateownerid, flags); + if (sop == NULL) + return nfserr_bad_stateid; + *sopp = sop; + goto check_replay; + } - /* for new lock stateowners: - * check that the lock->v.new.open_stateid - * refers to an open stateowner - * - * check that the lockclid (nfs4_lock->v.new.clientid) is the same - * as the open_stateid->st_stateowner->so_client->clientid - */ - if (lockclid) { + if (lock) { struct nfs4_stateowner *sop = stp->st_stateowner; + clientid_t *lockclid = &lock->v.new.clientid; struct nfs4_client *clp = sop->so_client; + int lkflg = 0; + int status; + + lkflg = setlkflg(lock->lk_type); + + if (lock->lk_is_new) { + if (!sop->so_is_open_owner) + return nfserr_bad_stateid; + if (!cmp_clid(&clp->cl_clientid, lockclid)) + return nfserr_bad_stateid; + /* stp is the open stateid */ + status = nfs4_check_openmode(stp, lkflg); + if (status) + return status; + } else { + /* stp is the lock stateid */ + status = nfs4_check_openmode(stp->st_openstp, lkflg); + if (status) + return status; + } - if (!sop->so_is_open_owner) - goto out; - if (!cmp_clid(&clp->cl_clientid, lockclid)) - goto out; } if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); - goto out; + return nfserr_bad_stateid; } *stpp = stp; @@ -2236,67 +2193,45 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei * For the moment, we ignore the possibility of * generation number wraparound. */ - if (seqid != sop->so_seqid + 1) + if (seqid != sop->so_seqid) goto check_replay; - if (sop->so_confirmed) { - if (flags & CONFIRM) { - printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n"); - goto out; - } + if (sop->so_confirmed && flags & CONFIRM) { + printk("NFSD: preprocess_seqid_op: expected" + " unconfirmed stateowner!\n"); + return nfserr_bad_stateid; } - else { - if (!(flags & CONFIRM)) { - printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n"); - goto out; - } + if (!sop->so_confirmed && !(flags & CONFIRM)) { + printk("NFSD: preprocess_seqid_op: stateowner not" + " confirmed yet!\n"); + return nfserr_bad_stateid; } if (stateid->si_generation > stp->st_stateid.si_generation) { printk("NFSD: preprocess_seqid_op: future stateid?!\n"); - goto out; + return nfserr_bad_stateid; } - status = nfserr_old_stateid; if (stateid->si_generation < stp->st_stateid.si_generation) { printk("NFSD: preprocess_seqid_op: old stateid!\n"); - goto out; - } - /* XXX renew the client lease here */ - status = nfs_ok; - -out: - return status; - -no_nfs4_stateid: - - /* - * We determine whether this is a bad stateid or a replay, - * starting by trying to look up the stateowner. - * If stateowner is not found - stateid is bad. - */ - if (!(sop = find_openstateowner_id(stateid->si_stateownerid, flags))) { - printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n"); - status = nfserr_bad_stateid; - goto out; + return nfserr_old_stateid; } - *sopp = sop; + renew_client(sop->so_client); + return nfs_ok; check_replay: - if (seqid == sop->so_seqid) { - printk("NFSD: preprocess_seqid_op: retransmission?\n"); + if (seqid == sop->so_seqid - 1) { + dprintk("NFSD: preprocess_seqid_op: retransmission?\n"); /* indicate replay to calling function */ - status = NFSERR_REPLAY_ME; - } else { - printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid); - - *sopp = NULL; - status = nfserr_bad_seqid; + return NFSERR_REPLAY_ME; } - goto out; + printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n", + sop->so_seqid, seqid); + *sopp = NULL; + return nfserr_bad_seqid; } int -nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc) +nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner) { int status; struct nfs4_stateowner *sop; @@ -2330,8 +2265,10 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs nfsd4_create_clid_dir(sop->so_client); out: - if (oc->oc_stateowner) + if (oc->oc_stateowner) { nfs4_get_stateowner(oc->oc_stateowner); + *replay_owner = oc->oc_stateowner; + } nfs4_unlock_state(); return status; } @@ -2362,7 +2299,7 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) } int -nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od) +nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner) { int status; struct nfs4_stateid *stp; @@ -2404,8 +2341,10 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t)); status = nfs_ok; out: - if (od->od_stateowner) + if (od->od_stateowner) { nfs4_get_stateowner(od->od_stateowner); + *replay_owner = od->od_stateowner; + } nfs4_unlock_state(); return status; } @@ -2414,7 +2353,7 @@ out: * nfs4_unlock_state() called after encode */ int -nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close) +nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner) { int status; struct nfs4_stateid *stp; @@ -2430,18 +2369,24 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos CHECK_FH | OPEN_STATE | CLOSE_STATE, &close->cl_stateowner, &stp, NULL))) goto out; - /* - * Return success, but first update the stateid. - */ status = nfs_ok; update_stateid(&stp->st_stateid); memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t)); - /* release_state_owner() calls nfsd_close() if needed */ - release_state_owner(stp, OPEN_STATE); + /* release_stateid() calls nfsd_close() if needed */ + release_stateid(stp, OPEN_STATE); + + /* place unused nfs4_stateowners on so_close_lru list to be + * released by the laundromat service after the lease period + * to enable us to handle CLOSE replay + */ + if (list_empty(&close->cl_stateowner->so_stateids)) + move_to_close_lru(close->cl_stateowner); out: - if (close->cl_stateowner) + if (close->cl_stateowner) { nfs4_get_stateowner(close->cl_stateowner); + *replay_owner = close->cl_stateowner; + } nfs4_unlock_state(); return status; } @@ -2510,8 +2455,7 @@ find_stateid(stateid_t *stid, int flags) (local->st_stateid.si_fileid == f_id)) return local; } - } else - printk("NFSD: find_stateid: ERROR: no state flag\n"); + } return NULL; } @@ -2610,7 +2554,6 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid, * occured. * * strhashval = lock_ownerstr_hashval - * so_seqid = lock->lk_new_lock_seqid - 1: it gets bumped in encode */ static struct nfs4_stateowner * @@ -2635,10 +2578,12 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str sop->so_is_open_owner = 0; sop->so_id = current_ownerid++; sop->so_client = clp; - sop->so_seqid = lock->lk_new_lock_seqid - 1; + /* It is the openowner seqid that will be incremented in encode in the + * case of new lockowners; so increment the lock seqid manually: */ + sop->so_seqid = lock->lk_new_lock_seqid + 1; sop->so_confirmed = 1; rp = &sop->so_replay; - rp->rp_status = NFSERR_SERVERFAULT; + rp->rp_status = nfserr_serverfault; rp->rp_buflen = 0; rp->rp_buf = rp->rp_ibuf; return sop; @@ -2670,6 +2615,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */ stp->st_access_bmap = open_stp->st_access_bmap; stp->st_deny_bmap = open_stp->st_deny_bmap; + stp->st_openstp = open_stp; out: return stp; @@ -2686,13 +2632,14 @@ check_lock_length(u64 offset, u64 length) * LOCK operation */ int -nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock) +nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner) { struct nfs4_stateowner *open_sop = NULL; + struct nfs4_stateowner *lock_sop = NULL; struct nfs4_stateid *lock_stp; struct file *filp; struct file_lock file_lock; - struct file_lock *conflock; + struct file_lock conflock; int status = 0; unsigned int strhashval; @@ -2700,34 +2647,27 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock (long long) lock->lk_offset, (long long) lock->lk_length); - if (nfs4_in_grace() && !lock->lk_reclaim) - return nfserr_grace; - if (!nfs4_in_grace() && lock->lk_reclaim) - return nfserr_no_grace; - if (check_lock_length(lock->lk_offset, lock->lk_length)) return nfserr_inval; + if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) { + dprintk("NFSD: nfsd4_lock: permission denied!\n"); + return status; + } + nfs4_lock_state(); if (lock->lk_is_new) { - /* - * Client indicates that this is a new lockowner. - * Use open owner and open stateid to create lock owner and lock - * stateid. - */ + /* + * Client indicates that this is a new lockowner. + * Use open owner and open stateid to create lock owner and + * lock stateid. + */ struct nfs4_stateid *open_stp = NULL; struct nfs4_file *fp; status = nfserr_stale_clientid; - if (STALE_CLIENTID(&lock->lk_new_clientid)) { - printk("NFSD: nfsd4_lock: clientid is stale!\n"); - goto out; - } - - /* is the new lock seqid presented by the client zero? */ - status = nfserr_bad_seqid; - if (lock->v.new.lock_seqid != 0) + if (STALE_CLIENTID(&lock->lk_new_clientid)) goto out; /* validate and update open stateid and open seqid */ @@ -2735,13 +2675,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock lock->lk_new_open_seqid, &lock->lk_new_open_stateid, CHECK_FH | OPEN_STATE, - &open_sop, &open_stp, - &lock->v.new.clientid); - if (status) { - if (lock->lk_reclaim) - status = nfserr_reclaim_bad; + &lock->lk_replay_owner, &open_stp, + lock); + if (status) goto out; - } + open_sop = lock->lk_replay_owner; /* create lockowner and lock stateid */ fp = open_stp->st_file; strhashval = lock_ownerstr_hashval(fp->fi_inode, @@ -2751,33 +2689,33 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock * the same file, or should they just be allowed (and * create new stateids)? */ status = nfserr_resource; - if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock))) + lock_sop = alloc_init_lock_stateowner(strhashval, + open_sop->so_client, open_stp, lock); + if (lock_sop == NULL) goto out; - if ((lock_stp = alloc_init_lock_stateid(lock->lk_stateowner, - fp, open_stp)) == NULL) { - release_stateowner(lock->lk_stateowner); - lock->lk_stateowner = NULL; + lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); + if (lock_stp == NULL) goto out; - } - /* bump the open seqid used to create the lock */ - open_sop->so_seqid++; } else { /* lock (lock owner + lock stateid) already exists */ status = nfs4_preprocess_seqid_op(current_fh, lock->lk_old_lock_seqid, &lock->lk_old_lock_stateid, CHECK_FH | LOCK_STATE, - &lock->lk_stateowner, &lock_stp, NULL); + &lock->lk_replay_owner, &lock_stp, lock); if (status) goto out; + lock_sop = lock->lk_replay_owner; } - /* lock->lk_stateowner and lock_stp have been created or found */ + /* lock->lk_replay_owner and lock_stp have been created or found */ filp = lock_stp->st_vfs_file; - if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) { - printk("NFSD: nfsd4_lock: permission denied!\n"); + status = nfserr_grace; + if (nfs4_in_grace() && !lock->lk_reclaim) + goto out; + status = nfserr_no_grace; + if (!nfs4_in_grace() && lock->lk_reclaim) goto out; - } locks_init_lock(&file_lock); switch (lock->lk_type) { @@ -2793,7 +2731,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock status = nfserr_inval; goto out; } - file_lock.fl_owner = (fl_owner_t) lock->lk_stateowner; + file_lock.fl_owner = (fl_owner_t)lock_sop; file_lock.fl_pid = current->tgid; file_lock.fl_file = filp; file_lock.fl_flags = FL_POSIX; @@ -2812,8 +2750,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock */ status = posix_lock_file(filp, &file_lock); - if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) - file_lock.fl_ops->fl_release_private(&file_lock); dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status); switch (-status) { case 0: /* success! */ @@ -2825,9 +2761,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock goto conflicting_lock; case (EDEADLK): status = nfserr_deadlock; + dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status); + goto out; default: + status = nfserrno(status); dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status); - goto out_destroy_new_stateid; + goto out; } conflicting_lock: @@ -2836,27 +2775,18 @@ conflicting_lock: /* XXX There is a race here. Future patch needed to provide * an atomic posix_lock_and_test_file */ - if (!(conflock = posix_test_lock(filp, &file_lock))) { + if (!posix_test_lock(filp, &file_lock, &conflock)) { status = nfserr_serverfault; goto out; } - nfs4_set_lock_denied(conflock, &lock->lk_denied); - -out_destroy_new_stateid: - if (lock->lk_is_new) { - dprintk("NFSD: nfsd4_lock: destroy new stateid!\n"); - /* - * An error encountered after instantiation of the new - * stateid has forced us to destroy it. - */ - if (!seqid_mutating_err(status)) - open_sop->so_seqid--; - - release_state_owner(lock_stp, LOCK_STATE); - } + nfs4_set_lock_denied(&conflock, &lock->lk_denied); out: - if (lock->lk_stateowner) - nfs4_get_stateowner(lock->lk_stateowner); + if (status && lock->lk_is_new && lock_sop) + release_stateowner(lock_sop); + if (lock->lk_replay_owner) { + nfs4_get_stateowner(lock->lk_replay_owner); + *replay_owner = lock->lk_replay_owner; + } nfs4_unlock_state(); return status; } @@ -2870,7 +2800,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock struct inode *inode; struct file file; struct file_lock file_lock; - struct file_lock *conflicting_lock; + struct file_lock conflock; int status; if (nfs4_in_grace()) @@ -2883,13 +2813,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock nfs4_lock_state(); status = nfserr_stale_clientid; - if (STALE_CLIENTID(&lockt->lt_clientid)) { - printk("NFSD: nfsd4_lockt: clientid is stale!\n"); + if (STALE_CLIENTID(&lockt->lt_clientid)) goto out; - } if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) { - printk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); + dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); if (status == nfserr_symlink) status = nfserr_inval; goto out; @@ -2936,10 +2864,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock file.f_dentry = current_fh->fh_dentry; status = nfs_ok; - conflicting_lock = posix_test_lock(&file, &file_lock); - if (conflicting_lock) { + if (posix_test_lock(&file, &file_lock, &conflock)) { status = nfserr_denied; - nfs4_set_lock_denied(conflicting_lock, &lockt->lt_denied); + nfs4_set_lock_denied(&conflock, &lockt->lt_denied); } out: nfs4_unlock_state(); @@ -2947,7 +2874,7 @@ out: } int -nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku) +nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner) { struct nfs4_stateid *stp; struct file *filp = NULL; @@ -2990,10 +2917,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock * Try to unlock the file in the VFS. */ status = posix_lock_file(filp, &file_lock); - if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) - file_lock.fl_ops->fl_release_private(&file_lock); if (status) { - printk("NFSD: nfs4_locku: posix_lock_file failed!\n"); + dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); goto out_nfserr; } /* @@ -3003,8 +2928,10 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t)); out: - if (locku->lu_stateowner) + if (locku->lu_stateowner) { nfs4_get_stateowner(locku->lu_stateowner); + *replay_owner = locku->lu_stateowner; + } nfs4_unlock_state(); return status; @@ -3027,9 +2954,10 @@ check_for_locks(struct file *filp, struct nfs4_stateowner *lowner) lock_kernel(); for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { - if ((*flpp)->fl_owner == (fl_owner_t)lowner) + if ((*flpp)->fl_owner == (fl_owner_t)lowner) { status = 1; goto out; + } } out: unlock_kernel(); @@ -3053,10 +2981,8 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner * /* XXX check for lease expiration */ status = nfserr_stale_clientid; - if (STALE_CLIENTID(clid)) { - printk("NFSD: nfsd4_release_lockowner: clientid is stale!\n"); + if (STALE_CLIENTID(clid)) return status; - } nfs4_lock_state();