📄 nfs4state.c
字号:
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: 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); return nfs_ok;}static inline __be32nfs4_check_delegmode(struct nfs4_delegation *dp, int flags){ if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) return nfserr_openmode; else return nfs_ok;}static struct nfs4_delegation *find_delegation_file(struct nfs4_file *fp, stateid_t *stid){ struct nfs4_delegation *dp; list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) { if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) return dp; } return NULL;}static __be32nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_delegation **dp){ int flags; __be32 status = nfserr_bad_stateid; *dp = find_delegation_file(fp, &open->op_delegate_stateid); if (*dp == NULL) goto out; flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; status = nfs4_check_delegmode(*dp, flags); if (status) *dp = NULL;out: if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR) return nfs_ok; if (status) return status; open->op_stateowner->so_confirmed = 1; return nfs_ok;}static __be32nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp){ struct nfs4_stateid *local; __be32 status = nfserr_share_denied; struct nfs4_stateowner *sop = open->op_stateowner; list_for_each_entry(local, &fp->fi_stateids, st_perfile) { /* ignore lock owners */ if (local->st_stateowner->so_is_open_owner == 0) continue; /* remember if we have seen this open owner */ if (local->st_stateowner == sop) *stpp = local; /* check for conflicting share reservations */ if (!test_share(local, open)) goto out; } status = 0;out: return status;}static inline struct nfs4_stateid *nfs4_alloc_stateid(void){ return kmem_cache_alloc(stateid_slab, GFP_KERNEL);}static __be32nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, struct nfs4_delegation *dp, struct svc_fh *cur_fh, int flags){ struct nfs4_stateid *stp; stp = nfs4_alloc_stateid(); if (stp == NULL) return nfserr_resource; if (dp) { get_file(dp->dl_vfs_file); stp->st_vfs_file = dp->dl_vfs_file; } else { __be32 status; status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, &stp->st_vfs_file); if (status) { if (status == nfserr_dropit) status = nfserr_jukebox; kmem_cache_free(stateid_slab, stp); return status; } } *stpp = stp; return 0;}static inline __be32nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, struct nfsd4_open *open){ struct iattr iattr = { .ia_valid = ATTR_SIZE, .ia_size = 0, }; if (!open->op_truncate) return 0; if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) return nfserr_inval; return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);}static __be32nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open){ struct file *filp = stp->st_vfs_file; struct inode *inode = filp->f_path.dentry->d_inode; unsigned int share_access, new_writer; __be32 status; set_access(&share_access, stp->st_access_bmap); new_writer = (~share_access) & open->op_share_access & NFS4_SHARE_ACCESS_WRITE; if (new_writer) { int err = get_write_access(inode); if (err) return nfserrno(err); } status = nfsd4_truncate(rqstp, cur_fh, open); if (status) { if (new_writer) put_write_access(inode); return status; } /* remember the open */ 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); return nfs_ok;}static voidnfs4_set_claim_prev(struct nfsd4_open *open){ open->op_stateowner->so_confirmed = 1; open->op_stateowner->so_client->cl_firststate = 1;}/* * Attempt to hand out a delegation. */static voidnfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp){ struct nfs4_delegation *dp; struct nfs4_stateowner *sop = stp->st_stateowner; struct nfs4_callback *cb = &sop->so_client->cl_callback; struct file_lock fl, *flp = &fl; int status, flag = 0; flag = NFS4_OPEN_DELEGATE_NONE; open->op_recall = 0; switch (open->op_claim_type) { case NFS4_OPEN_CLAIM_PREVIOUS: if (!atomic_read(&cb->cb_set)) open->op_recall = 1; flag = open->op_delegate_type; if (flag == NFS4_OPEN_DELEGATE_NONE) goto out; break; case NFS4_OPEN_CLAIM_NULL: /* Let's not give out any delegations till everyone's * had the chance to reclaim theirs.... */ if (nfs4_in_grace()) goto out; if (!atomic_read(&cb->cb_set) || !sop->so_confirmed) goto out; if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) flag = NFS4_OPEN_DELEGATE_WRITE; else flag = NFS4_OPEN_DELEGATE_READ; break; default: goto out; } dp = alloc_init_deleg(sop->so_client, stp, fh, flag); if (dp == NULL) { flag = NFS4_OPEN_DELEGATE_NONE; goto out; } locks_init_lock(&fl); fl.fl_lmops = &nfsd_lease_mng_ops; fl.fl_flags = FL_LEASE; fl.fl_end = OFFSET_MAX; fl.fl_owner = (fl_owner_t)dp; fl.fl_file = stp->st_vfs_file; fl.fl_pid = current->tgid; /* vfs_setlease checks to see if delegation should be handed out. * the lock_manager callbacks fl_mylease and fl_change are used */ if ((status = vfs_setlease(stp->st_vfs_file, flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) { dprintk("NFSD: setlease failed [%d], no delegation\n", status); unhash_delegation(dp); flag = NFS4_OPEN_DELEGATE_NONE; goto out; } memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid)); dprintk("NFSD: delegation stateid=(%08x/%08x/%08x/%08x)\n\n", dp->dl_stateid.si_boot, dp->dl_stateid.si_stateownerid, dp->dl_stateid.si_fileid, dp->dl_stateid.si_generation);out: if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && flag == NFS4_OPEN_DELEGATE_NONE && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) dprintk("NFSD: WARNING: refusing delegation reclaim\n"); open->op_delegate_type = flag;}/* * called with nfs4_lock_state() held. */__be32nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open){ struct nfs4_file *fp = NULL; struct inode *ino = current_fh->fh_dentry->d_inode; struct nfs4_stateid *stp = NULL; struct nfs4_delegation *dp = NULL; __be32 status; status = nfserr_inval; if (!access_valid(open->op_share_access) || !deny_valid(open->op_share_deny)) goto out; /* * Lookup file; if found, lookup stateid and check open request, * and check for delegations in the process of being recalled. * If not found, create the nfs4_file struct */ fp = find_file(ino); if (fp) { if ((status = nfs4_check_open(fp, open, &stp))) goto out; status = nfs4_check_deleg(fp, open, &dp); if (status) goto out; } else { status = nfserr_bad_stateid; if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) goto out; status = nfserr_resource; fp = alloc_init_file(ino); if (fp == NULL) goto out; } /* * OPEN the file, or upgrade an existing OPEN. * If truncate fails, the OPEN fails. */ if (stp) { /* Stateid was found, this is an OPEN upgrade */ 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; if (open->op_share_access & NFS4_SHARE_ACCESS_READ) flags |= MAY_READ; if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) flags |= MAY_WRITE; status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags); if (status) goto out; init_stateid(stp, fp, open); status = nfsd4_truncate(rqstp, current_fh, open); if (status) { release_stateid(stp, OPEN_STATE); goto out; } } memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); /* * Attempt to hand out a delegation. No error return, because the * OPEN succeeds even if we fail. */ nfs4_open_delegation(current_fh, open, stp); status = nfs_ok; dprintk("nfs4_process_open2: stateid=(%08x/%08x/%08x/%08x)\n", stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid, stp->st_stateid.si_fileid, stp->st_stateid.si_generation);out: if (fp) put_nfs4_file(fp); 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. */ open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; if (!open->op_stateowner->so_confirmed) open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; return status;}static struct workqueue_struct *laundry_wq;static void laundromat_main(struct work_struct *);static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);__be32nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, clientid_t *clid){ struct nfs4_client *clp; __be32 status; nfs4_lock_state(); dprintk("process_renew(%08x/%08x): starting\n", clid->cl_boot, clid->cl_id); status = nfserr_stale_clientid; if (STALE_CLIENTID(clid)) goto out; clp = find_confirmed_client(clid); status = nfserr_expired; if (clp == NULL) { /* We assume the client took too long to RENEW. */ dprintk("nfsd4_renew: clientid not found!\n"); goto out; } renew_client(clp); status = nfserr_cb_path_down; if (!list_empty(&clp->cl_delegations) && !atomic_read(&clp->cl_callback.cb_set)) goto out; status = nfs_ok;out: nfs4_unlock_state(); return status;}static voidend_grace(void){ dprintk("NFSD: end of grace period\n"); nfsd4_recdir_purge_old(); in_grace = 0;}static time_tnfs4_laundromat(void){ struct nfs4_client *clp; struct nfs4_stateowner *sop; struct nfs4_delegation *dp; struct list_head *pos, *next, reaplist; time_t cutoff = get_seconds() - NFSD_LEASE_TIME; time_t t, clientid_val = NFSD_LEASE_TIME; time_t u, test_val = NFSD_LEASE_TIME; nfs4_lock_state(); dprintk("NFSD: laundromat service - starting\n"); if (in_grace) end_grace(); list_for_each_safe(pos, next, &client_lru) { clp = list_entry(pos, struct nfs4_client, cl_lru); if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { t = clp->cl_time - cutoff; if (clientid_val > t) clientid_val = t; break; } dprintk("NFSD: purging unused client (clientid %08x)\n", clp->cl_clientid.cl_id); nfsd4_remove_clid_dir(clp); expire_client(clp); } INIT_LIST_HEAD(&reaplist); spin_lock(&recall_lock); list_for_each_safe(pos, next, &del_recall_lru) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { u = dp->dl_time - cutoff; if (test_val > u) test_val = u; break; } dprintk("NFSD: purging unused delegation dp %p, fp %p\n", dp, dp->dl_flock); list_move(&dp->dl_recall_lru, &reaplist); } spin_unlock(&recall_lock); list_for_each_safe(pos, next, &reaplist) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); list_del_init(&dp->dl_recall_lru); unhash_delegation(dp); } test_val = NFSD_LEASE_TIME; list_for_each_safe(pos, next, &close_lru) { sop = list_entry(pos, struct nfs4_stateowner, so_close_lru); if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) { u = sop->so_time - cutoff; if (test_val > u) test_val = u; break; } dprintk("NFSD: purging unused open stateowner (so_id %d)\n", sop->so_id); release_stateowner(sop); } if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; nfs4_unlock_state(); return clientid_val;}voidlaundromat_main(struct work_struct *not_used){ time_t t; t = nfs4_laundromat(); dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);}static struct nfs4_stateowner *search_close_lru(u32 st_id, int flags){ struct nfs4_stateowner *local = NULL; if (flags & CLOSE_STATE) { list_for_each_entry(local, &close_lru, so_close_lru) { if (local->so_id == st_id) return local; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -