📄 nfs4state.c
字号:
return NULL;}static inline intnfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp){ return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode;}static intSTALE_STATEID(stateid_t *stateid){ if (stateid->si_boot == boot_time) return 0; dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, stateid->si_generation); return 1;}static inline intaccess_permit_read(unsigned long access_bmap){ return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) || test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap) || test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap);}static inline intaccess_permit_write(unsigned long access_bmap){ return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) || test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);}static__be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags){ __be32 status = nfserr_openmode; if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) goto out; if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) goto out; status = nfs_ok;out: return status;}static inline __be32check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags){ /* Trying to call delegreturn with a special stateid? Yuch: */ if (!(flags & (RD_STATE | WR_STATE))) return nfserr_bad_stateid; else if (ONE_STATEID(stateid) && (flags & RD_STATE)) return nfs_ok; else if (nfs4_in_grace()) { /* Answer in remaining cases depends on existance of * conflicting state; so we must wait out the grace period. */ return nfserr_grace; } else if (flags & WR_STATE) return nfs4_share_conflict(current_fh, NFS4_SHARE_DENY_WRITE); else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ return nfs4_share_conflict(current_fh, NFS4_SHARE_DENY_READ);}/* * Allow READ/WRITE during grace period on recovered state only for files * that are not able to provide mandatory locking. */static inline intio_during_grace_disallowed(struct inode *inode, int flags){ return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE)) && mandatory_lock(inode);}/** Checks for stateid operations*/__be32nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filpp){ struct nfs4_stateid *stp = NULL; struct nfs4_delegation *dp = NULL; stateid_t *stidp; struct inode *ino = current_fh->fh_dentry->d_inode; __be32 status; dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n", stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, stateid->si_generation); if (filpp) *filpp = NULL; if (io_during_grace_disallowed(ino, flags)) return nfserr_grace; if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) return check_special_stateids(current_fh, stateid, flags); /* STALE STATEID */ status = nfserr_stale_stateid; if (STALE_STATEID(stateid)) goto out; /* BAD STATEID */ status = nfserr_bad_stateid; if (!stateid->si_fileid) { /* delegation stateid */ if(!(dp = find_delegation_stateid(ino, stateid))) { dprintk("NFSD: delegation stateid not found\n"); goto out; } stidp = &dp->dl_stateid; } else { /* open or lock stateid */ if (!(stp = find_stateid(stateid, flags))) { dprintk("NFSD: open or lock stateid not found\n"); goto out; } if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) goto out; if (!stp->st_stateowner->so_confirmed) goto out; stidp = &stp->st_stateid; } if (stateid->si_generation > stidp->si_generation) goto out; /* OLD STATEID */ status = nfserr_old_stateid; if (stateid->si_generation < stidp->si_generation) goto out; if (stp) { if ((status = nfs4_check_openmode(stp,flags))) goto out; renew_client(stp->st_stateowner->so_client); if (filpp) *filpp = stp->st_vfs_file; } else if (dp) { if ((status = nfs4_check_delegmode(dp, flags))) goto out; renew_client(dp->dl_client); if (flags & DELEG_RET) unhash_delegation(dp); if (filpp) *filpp = dp->dl_vfs_file; } status = nfs_ok;out: return status;}static inline intsetlkflg (int type){ return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? RD_STATE : WR_STATE;}/* * Checks for sequence id mutating operations. */static __be32nfs4_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){ struct nfs4_stateid *stp; struct nfs4_stateowner *sop; dprintk("NFSD: preprocess_seqid_op: seqid=%d " "stateid = (%08x/%08x/%08x/%08x)\n", seqid, stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, stateid->si_generation); *stpp = NULL; *sopp = NULL; if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { dprintk("NFSD: preprocess_seqid_op: magic stateid!\n"); return nfserr_bad_stateid; } if (STALE_STATEID(stateid)) 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. */ 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; } 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; __be32 status; lkflg = setlkflg(lock->lk_type); if (lock->lk_is_new) { if (!sop->so_is_open_owner) return nfserr_bad_stateid; if (!same_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 ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); return nfserr_bad_stateid; } *stpp = stp; *sopp = sop = stp->st_stateowner; /* * We now validate the seqid and stateid generation numbers. * For the moment, we ignore the possibility of * generation number wraparound. */ if (seqid != sop->so_seqid) goto check_replay; if (sop->so_confirmed && flags & CONFIRM) { dprintk("NFSD: preprocess_seqid_op: expected" " unconfirmed stateowner!\n"); return nfserr_bad_stateid; } if (!sop->so_confirmed && !(flags & CONFIRM)) { dprintk("NFSD: preprocess_seqid_op: stateowner not" " confirmed yet!\n"); return nfserr_bad_stateid; } if (stateid->si_generation > stp->st_stateid.si_generation) { dprintk("NFSD: preprocess_seqid_op: future stateid?!\n"); return nfserr_bad_stateid; } if (stateid->si_generation < stp->st_stateid.si_generation) { dprintk("NFSD: preprocess_seqid_op: old stateid!\n"); return nfserr_old_stateid; } renew_client(sop->so_client); return nfs_ok;check_replay: if (seqid == sop->so_seqid - 1) { dprintk("NFSD: preprocess_seqid_op: retransmission?\n"); /* indicate replay to calling function */ return nfserr_replay_me; } dprintk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n", sop->so_seqid, seqid); *sopp = NULL; return nfserr_bad_seqid;}__be32nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open_confirm *oc){ __be32 status; struct nfs4_stateowner *sop; struct nfs4_stateid *stp; dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", (int)cstate->current_fh.fh_dentry->d_name.len, cstate->current_fh.fh_dentry->d_name.name); status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); if (status) return status; nfs4_lock_state(); if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, oc->oc_seqid, &oc->oc_req_stateid, CHECK_FH | CONFIRM | OPEN_STATE, &oc->oc_stateowner, &stp, NULL))) goto out; sop = oc->oc_stateowner; sop->so_confirmed = 1; update_stateid(&stp->st_stateid); memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t)); dprintk("NFSD: nfsd4_open_confirm: success, seqid=%d " "stateid=(%08x/%08x/%08x/%08x)\n", oc->oc_seqid, stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid, stp->st_stateid.si_fileid, stp->st_stateid.si_generation); nfsd4_create_clid_dir(sop->so_client);out: if (oc->oc_stateowner) { nfs4_get_stateowner(oc->oc_stateowner); cstate->replay_owner = oc->oc_stateowner; } nfs4_unlock_state(); return status;}/* * unset all bits in union bitmap (bmap) that * do not exist in share (from successful OPEN_DOWNGRADE) */static voidreset_union_bmap_access(unsigned long access, unsigned long *bmap){ int i; for (i = 1; i < 4; i++) { if ((i & access) != i) __clear_bit(i, bmap); }}static voidreset_union_bmap_deny(unsigned long deny, unsigned long *bmap){ int i; for (i = 0; i < 4; i++) { if ((i & deny) != i) __clear_bit(i, bmap); }}__be32nfsd4_open_downgrade(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *od){ __be32 status; struct nfs4_stateid *stp; unsigned int share_access; dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", (int)cstate->current_fh.fh_dentry->d_name.len, cstate->current_fh.fh_dentry->d_name.name); if (!access_valid(od->od_share_access) || !deny_valid(od->od_share_deny)) return nfserr_inval; nfs4_lock_state(); if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, od->od_seqid, &od->od_stateid, CHECK_FH | OPEN_STATE, &od->od_stateowner, &stp, NULL))) goto out; status = nfserr_inval; if (!test_bit(od->od_share_access, &stp->st_access_bmap)) { dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n", stp->st_access_bmap, od->od_share_access); goto out; } if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) { dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", stp->st_deny_bmap, od->od_share_deny); goto out; } set_access(&share_access, stp->st_access_bmap); nfs4_file_downgrade(stp->st_vfs_file, share_access & ~od->od_share_access); reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); update_stateid(&stp->st_stateid); memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t)); status = nfs_ok;out: if (od->od_stateowner) { nfs4_get_stateowner(od->od_stateowner); cstate->replay_owner = od->od_stateowner; } nfs4_unlock_state(); return status;}/* * nfs4_unlock_state() called after encode */__be32nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_close *close){ __be32 status; struct nfs4_stateid *stp; dprintk("NFSD: nfsd4_close on file %.*s\n", (int)cstate->current_fh.fh_dentry->d_name.len, cstate->current_fh.fh_dentry->d_name.name); nfs4_lock_state(); /* check close_lru for replay */ if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, close->cl_seqid, &close->cl_stateid, CHECK_FH | OPEN_STATE | CLOSE_STATE, &close->cl_stateowner, &stp, NULL))) goto out; status = nfs_ok; update_stateid(&stp->st_stateid); memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t)); /* 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) { nfs4_get_stateowner(close->cl_stateowner); cstate->replay_owner = close->cl_stateowner; } nfs4_unlock_state(); return status;}__be32nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *dr){ __be32 status; if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) goto out; nfs4_lock_state(); status = nfs4_preprocess_stateid_op(&cstate->current_fh, &dr->dr_stateid, DELEG_RET, NULL); nfs4_unlock_state();out: return status;}/* * Lock owner state (byte-range locks) */#define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start))#define LOCK_HASH_BITS 8#define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS)#define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1)#define lockownerid_hashval(id) \ ((id) & LOCK_HASH_MASK)static inline unsigned intlock_ownerstr_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername){ return (file_hashval(inode) + cl_id + opaque_hashval(ownername->data, ownername->len)) & LOCK_HASH_MASK;}static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];static struct lis
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -