Over NFS, an open() call could result in multiple over-the-wire
GETATTRs being generated - one from lookup()/namei() and the other from nfs_open() (for cto consistency). This change eliminates the GETATTR in nfs_open() if an otw GETATTR was done from the namei() path. Instead of extending the vop interface, we timestamp each attr load, and use this to detect whether a GETATTR was done from namei() for this syscall. Introduces a thread-local variable that counts the syscalls made by the thread and uses <pid, tid, thread syscalls> as the attrload timestamp. Thanks to jhb@ and peter@ for a discussion on thread state that could be used as the timestamp with minimal overhead.
This commit is contained in:
parent
0c4a1ef8dc
commit
f9bb753844
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=167352
@ -813,6 +813,8 @@ syscall(struct trapframe *frame)
|
||||
CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
|
||||
td->td_proc->p_pid, td->td_proc->p_comm, code);
|
||||
|
||||
td->td_syscalls++;
|
||||
|
||||
if (error == 0) {
|
||||
td->td_retval[0] = 0;
|
||||
td->td_retval[1] = frame->tf_rdx;
|
||||
|
@ -996,6 +996,8 @@ syscall(struct trapframe *frame)
|
||||
CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
|
||||
td->td_proc->p_pid, td->td_proc->p_comm, code);
|
||||
|
||||
td->td_syscalls++;
|
||||
|
||||
if (error == 0) {
|
||||
td->td_retval[0] = 0;
|
||||
td->td_retval[1] = frame->tf_edx;
|
||||
|
@ -1044,6 +1044,8 @@ syscall(struct trapframe *tf)
|
||||
}
|
||||
}
|
||||
|
||||
td->td_syscalls++;
|
||||
|
||||
/*
|
||||
* Check for misbehavior.
|
||||
*/
|
||||
|
@ -116,6 +116,7 @@ thread_ctor(void *mem, int size, void *arg, int flags)
|
||||
td->td_oncpu = NOCPU;
|
||||
|
||||
td->td_tid = alloc_unr(tid_unrhdr);
|
||||
td->td_syscalls = 0;
|
||||
|
||||
/*
|
||||
* Note that td_critnest begins life as 1 because the thread is not
|
||||
|
@ -1412,7 +1412,7 @@ nfs_timer(void *arg)
|
||||
}
|
||||
if (rep->r_rtt >= 0) {
|
||||
rep->r_rtt++;
|
||||
if (nmp->nm_flag & NFSMNT_DUMBTIMR)
|
||||
if ((nmp->nm_flag & NFSMNT_DUMBTIMR) || (nmp->nm_sotype == SOCK_STREAM))
|
||||
timeo = nmp->nm_timeo;
|
||||
else
|
||||
timeo = nfs_estimate_rto(nmp, rep->r_procnum);
|
||||
|
@ -548,6 +548,7 @@ nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
|
||||
u_short vmode;
|
||||
struct timespec mtime;
|
||||
int v3 = NFS_ISV3(vp);
|
||||
struct thread *td = curthread;
|
||||
|
||||
md = *mdp;
|
||||
t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
|
||||
@ -647,6 +648,14 @@ nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
|
||||
vap->va_filerev = 0;
|
||||
}
|
||||
np->n_attrstamp = time_second;
|
||||
/* Timestamp the NFS otw getattr fetch */
|
||||
if (td->td_proc) {
|
||||
np->n_ac_ts_tid = td->td_tid;
|
||||
np->n_ac_ts_pid = td->td_proc->p_pid;
|
||||
np->n_ac_ts_syscalls = td->td_syscalls;
|
||||
} else
|
||||
bzero(&np->n_ac_ts, sizeof(struct nfs_attrcache_timestamp));
|
||||
|
||||
if (vap->va_size != np->n_size) {
|
||||
if (vap->va_type == VREG) {
|
||||
if (dontshrink && vap->va_size < np->n_size) {
|
||||
|
@ -432,6 +432,8 @@ nfs_access(struct vop_access_args *ap)
|
||||
}
|
||||
}
|
||||
|
||||
int nfs_otw_getattr_avoid = 0;
|
||||
|
||||
/*
|
||||
* nfs open vnode op
|
||||
* Check to see if the type is ok
|
||||
@ -471,7 +473,14 @@ nfs_open(struct vop_open_args *ap)
|
||||
np->n_mtime = vattr.va_mtime;
|
||||
mtx_unlock(&np->n_mtx);
|
||||
} else {
|
||||
np->n_attrstamp = 0;
|
||||
struct thread *td = curthread;
|
||||
|
||||
if (np->n_ac_ts_syscalls != td->td_syscalls ||
|
||||
np->n_ac_ts_tid != td->td_tid ||
|
||||
td->td_proc == NULL ||
|
||||
np->n_ac_ts_pid != td->td_proc->p_pid) {
|
||||
np->n_attrstamp = 0;
|
||||
}
|
||||
mtx_unlock(&np->n_mtx);
|
||||
error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td);
|
||||
if (error)
|
||||
|
@ -74,6 +74,16 @@ struct nfsdmap {
|
||||
#define ndm_cookies ndm_un1.ndmu3_cookies
|
||||
#define ndm4_cookies ndm_un1.ndmu4_cookies
|
||||
|
||||
#define n_ac_ts_tid n_ac_ts.nfs_ac_ts_tid
|
||||
#define n_ac_ts_pid n_ac_ts.nfs_ac_ts_pid
|
||||
#define n_ac_ts_syscalls n_ac_ts.nfs_ac_ts_syscalls
|
||||
|
||||
struct nfs_attrcache_timestamp {
|
||||
lwpid_t nfs_ac_ts_tid;
|
||||
pid_t nfs_ac_ts_pid;
|
||||
unsigned long nfs_ac_ts_syscalls;
|
||||
};
|
||||
|
||||
/*
|
||||
* The nfsnode is the nfs equivalent to ufs's inode. Any similarity
|
||||
* is purely coincidental.
|
||||
@ -127,6 +137,7 @@ struct nfsnode {
|
||||
uint32_t n_namelen;
|
||||
int n_directio_opens;
|
||||
int n_directio_asyncwr;
|
||||
struct nfs_attrcache_timestamp n_ac_ts;
|
||||
};
|
||||
|
||||
#define n_atim n_un1.nf_atim
|
||||
|
@ -414,6 +414,8 @@ syscall(struct trapframe *frame)
|
||||
ktrsyscall(code, narg, (register_t *)params);
|
||||
#endif
|
||||
|
||||
td->td_syscalls++;
|
||||
|
||||
if (error == 0) {
|
||||
td->td_retval[0] = 0;
|
||||
td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
|
||||
|
@ -414,6 +414,8 @@ syscall(struct trapframe *frame)
|
||||
ktrsyscall(code, narg, (register_t *)params);
|
||||
#endif
|
||||
|
||||
td->td_syscalls++;
|
||||
|
||||
if (error == 0) {
|
||||
td->td_retval[0] = 0;
|
||||
td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
|
||||
|
@ -584,6 +584,9 @@ syscall(struct trapframe *tf)
|
||||
if (KTRPOINT(td, KTR_SYSCALL))
|
||||
ktrsyscall(code, narg, argp);
|
||||
#endif
|
||||
|
||||
td->td_syscalls++;
|
||||
|
||||
if (error == 0) {
|
||||
td->td_retval[0] = 0;
|
||||
td->td_retval[1] = 0;
|
||||
|
@ -307,6 +307,7 @@ struct thread {
|
||||
struct mdthread td_md; /* (k) Any machine-dependent fields. */
|
||||
struct td_sched *td_sched; /* (*) Scheduler-specific data. */
|
||||
struct kaudit_record *td_ar; /* (k) Active audit record, if any. */
|
||||
int td_syscalls; /* per-thread syscall count (used by NFS :)) */
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user