nfs4state.c
字号:
if (close_val > u) close_val = u; break; } dprintk("NFSD: purging unused open stateowner (so_id %d)\n", sop->so_id); list_del(&sop->so_close_lru); free_stateowner(sop); } if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; nfs4_unlock_state(); return clientid_val;}voidlaundromat_main(void *not_used){ time_t t; t = nfs4_laundromat(); dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); schedule_delayed_work(&laundromat_work, t*HZ);}/* search ownerid_hashtbl[] and close_lru for stateid owner * (stateid->si_stateownerid) */struct nfs4_stateowner *find_openstateowner_id(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) return local; } } return NULL;}static inline intnfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp){ return (stp->st_vfs_set == 0 || fhp->fh_dentry->d_inode != stp->st_vfs_file->f_dentry->d_inode);}static intSTALE_STATEID(stateid_t *stateid){ if (stateid->si_boot == boot_time) return 0; printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, stateid->si_generation); return 1;}/** Checks for stateid operations*/intnfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct nfs4_stateid **stpp){ struct nfs4_stateid *stp; int status; dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n", stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, stateid->si_generation); *stpp = NULL; /* STALE STATEID */ status = nfserr_stale_stateid; if (STALE_STATEID(stateid)) goto out; /* BAD STATEID */ status = nfserr_bad_stateid; if (!(stp = find_stateid(stateid, flags))) { dprintk("NFSD: preprocess_stateid_op: no open stateid!\n"); goto out; } if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { dprintk("NFSD: preprocess_stateid_op: fh-stateid mismatch!\n"); stp->st_vfs_set = 0; goto out; } if (!stp->st_stateowner->so_confirmed) { dprintk("preprocess_stateid_op: lockowner not confirmed yet!\n"); goto out; } if (stateid->si_generation > stp->st_stateid.si_generation) { dprintk("preprocess_stateid_op: future stateid?!\n"); goto out; } /* OLD STATEID */ status = nfserr_old_stateid; if (stateid->si_generation < stp->st_stateid.si_generation) { dprintk("preprocess_stateid_op: old stateid!\n"); goto out; } *stpp = stp; status = nfs_ok; renew_client(stp->st_stateowner->so_client);out: return status;}/* * Checks for sequence id mutating operations. */intnfs4_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){ int status; 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; status = nfserr_bad_stateid; if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { printk("NFSD: preprocess_seqid_op: magic stateid!\n"); goto out; } status = nfserr_stale_stateid; if (STALE_STATEID(stateid)) goto out; /* * 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; /* 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) { struct nfs4_stateowner *sop = stp->st_stateowner; struct nfs4_client *clp = sop->so_client; 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"); stp->st_vfs_set = 0; goto out; } *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 + 1) goto check_replay; if (sop->so_confirmed) { if (flags & CONFIRM) { printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n"); goto out; } } else { if (!(flags & CONFIRM)) { printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n"); goto out; } } if (stateid->si_generation > stp->st_stateid.si_generation) { printk("NFSD: preprocess_seqid_op: future stateid?!\n"); goto out; } 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; } *sopp = sop;check_replay: if (seqid == sop->so_seqid) { printk("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; } goto out;}/* * eventually, this will perform an upcall to the 'state daemon' as well as * set the cl_first_state field. */voidfirst_state(struct nfs4_client *clp){ if (!clp->cl_first_state) clp->cl_first_state = get_seconds();}/* * nfs4_unlock_state(); called in encode */intnfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc){ int status; struct nfs4_stateowner *sop; struct nfs4_stateid *stp; dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", (int)current_fh->fh_dentry->d_name.len, current_fh->fh_dentry->d_name.name); if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) goto out; oc->oc_stateowner = NULL; nfs4_lock_state(); if ((status = nfs4_preprocess_seqid_op(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); status = nfs_ok; first_state(sop->so_client);out: 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); }}/* * nfs4_unlock_state(); called in encode */intnfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od){ int status; struct nfs4_stateid *stp; unsigned int share_access; dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", (int)current_fh->fh_dentry->d_name.len, current_fh->fh_dentry->d_name.name); od->od_stateowner = NULL; status = nfserr_inval; if (!TEST_ACCESS(od->od_share_access) || !TEST_DENY(od->od_share_deny)) goto out; nfs4_lock_state(); if ((status = nfs4_preprocess_seqid_op(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: return status;}/* * nfs4_unlock_state() called after encode */intnfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close){ int status; struct nfs4_stateid *stp; dprintk("NFSD: nfsd4_close on file %.*s\n", (int)current_fh->fh_dentry->d_name.len, current_fh->fh_dentry->d_name.name); close->cl_stateowner = NULL; nfs4_lock_state(); /* check close_lru for replay */ if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid, &close->cl_stateid, 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, &close->cl_stateowner, OPEN_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)#define lock_ownerstr_hashval(x, clientid, ownername) \ ((file_hashval(x) + (clientid) + opaque_hashval((ownername.data), (ownername.len))) & LOCK_HASH_MASK)static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE];static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];struct nfs4_stateid *find_stateid(stateid_t *stid, int flags){ struct nfs4_stateid *local = NULL; u32 st_id = stid->si_stateownerid; u32 f_id = stid->si_fileid; unsigned int hashval; dprintk("NFSD: find_stateid flags 0x%x\n",flags); if ((flags & LOCK_STATE) || (flags & RDWR_STATE)) { hashval = stateid_hashval(st_id, f_id); list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) { if ((local->st_stateid.si_stateownerid == st_id) && (local->st_stateid.si_fileid == f_id)) return local; } } if ((flags & OPEN_STATE) || (flags & RDWR_STATE)) { hashval = stateid_hashval(st_id, f_id); list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) { if ((local->st_stateid.si_stateownerid == st_id) && (local->st_stateid.si_fileid == f_id)) return local; } } else printk("NFSD: find_stateid: ERROR: no state flag\n"); return NULL;}/* * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that * we can't properly handle lock requests that go beyond the (2^63 - 1)-th * byte, because of sign extension problems. Since NFSv4 calls for 64-bit * locking, this prevents us from being completely protocol-compliant. The * real solution to this problem is to start using unsigned file offsets in * the VFS, but this is a very deep change! */static inline voidnfs4_transform_lock_offset(struct file_lock *lock){ if (lock->fl_start < 0) lock->fl_start = OFFSET_MAX; if (lock->fl_end < 0) lock->fl_end = OFFSET_MAX;}intnfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval){ struct nfs4_stateowner *local = NULL; int status = 0; if (hashval >= LOCK_HASH_SIZE) goto out; list_for_each_entry(local, &lock_ownerid_hashtbl[hashval], so_idhash) { if (local == sop) { status = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -