--- kernel/bsd/nfs/nfs_vnops.c 2018/04/24 18:26:01 1.1.1.1 +++ kernel/bsd/nfs/nfs_vnops.c 2018/04/24 18:27:50 1.1.1.2 @@ -583,10 +583,11 @@ nfs_close(ap) #if DIAGNOSTIC register struct sillyrename *sp = np->n_sillyrename; if (sp) - kprintf("nfs_close: %s, dvp=%x, vp=%x, ap=%x, np=%x, sp=%x\n", - &sp->s_name[0], (unsigned)(sp->s_dvp), (unsigned)vp, - (unsigned)ap, (unsigned)np, (unsigned)sp); #endif + NFS_DPF(SILLY, + ("nfs_close: %s, dvp=%x, vp=%x, ap=%x, np=%x, sp=%x\n", + &sp->s_name[0], (unsigned)(sp->s_dvp), (unsigned)vp, + (unsigned)ap, (unsigned)np, (unsigned)sp)); if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && (np->n_flag & NMODIFIED)) { if (NFS_ISV3(vp)) { @@ -1162,6 +1163,15 @@ nfs_readlinkrpc(vp, uiop, cred) nfsm_postop_attr(vp, attrflag); if (!error) { nfsm_strsiz(len, NFS_MAXPATHLEN); + if (len == NFS_MAXPATHLEN) { + struct nfsnode *np = VTONFS(vp); +#if DIAGNOSTIC + if (!np) + panic("nfs_readlinkrpc: null np\n"); +#endif + if (np->n_size && np->n_size < NFS_MAXPATHLEN) + len = np->n_size; + } nfsm_mtouio(uiop, len); } nfsm_reqdone; @@ -2576,7 +2586,7 @@ nfs_sillyrename(dvp, vp, cnp) struct nfsnode *np; int error; short pid; - struct cred *cred; + struct ucred *cred; cache_purge(dvp); np = VTONFS(vp); @@ -2607,10 +2617,9 @@ nfs_sillyrename(dvp, vp, cnp) goto bad; error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, cnp->cn_proc, &np); -#if DIAGNOSTIC - kprintf("sillyrename: %s, vp=%x, np=%x, dvp=%x\n", - &sp->s_name[0], (unsigned)vp, (unsigned)np, (unsigned)dvp); -#endif + NFS_DPF(SILLY, + ("nfs_sillyrename: %s, vp=%x, np=%x, dvp=%x\n", + &sp->s_name[0], (unsigned)vp, (unsigned)np, (unsigned)dvp)); np->n_sillyrename = sp; return (0); bad: @@ -3160,7 +3169,7 @@ nfs_advlock(ap) return (lf_advlock(ap, &(np->n_lockf), np->n_size)); #else #if DIAGNOSTIC - printf("nfs_advlock: unimplemented!!"); + printf("nfs_advlock: pid %d comm %s\n", current_proc()->p_pid, current_proc()->p_comm); #endif return (EOPNOTSUPP); #endif @@ -3283,6 +3292,43 @@ nfs_update(ap) return (EOPNOTSUPP); } +int nfs_aio_threads = 0; /* 1 per nfd (arbitrary) */ +struct slock nfs_aio_slock; +TAILQ_HEAD(bqueues, buf) nfs_aio_bufq; +int nfs_aio_bufq_len = 0; /* diagnostic only */ + +void +nfs_aio_thread() +{ /* see comment below in nfs_bwrite() for some rationale */ + struct buf *bp; + + for(;;) { + simple_lock(&nfs_aio_slock); + if ((bp = nfs_aio_bufq.tqh_first)) { + TAILQ_REMOVE(&nfs_aio_bufq, bp, b_freelist); + nfs_aio_bufq_len--; + simple_unlock(&nfs_aio_slock); + nfs_writebp(bp, 1); + } else { /* nothing to do - goodnight */ + assert_wait((event_t)&nfs_aio_bufq, FALSE); + simple_unlock(&nfs_aio_slock); + (void)tsleep((caddr_t)0, PRIBIO+1, "nfs_aio_bufq", 0); + } + } +} + + +void +nfs_aio_thread_init() +{ + if (nfs_aio_threads++ == 0) { + simple_lock_init(&nfs_aio_slock); + TAILQ_INIT(&nfs_aio_bufq); + } + kernel_thread(kernel_task, nfs_aio_thread, (void *)0); +} + + /* * Just call nfs_writebp() with the force argument set to 1. */ @@ -3292,7 +3338,33 @@ nfs_bwrite(ap) struct vnode *a_bp; } */ *ap; { + extern void wakeup_one(caddr_t chan); + /* + * nfs_writebp will issue a synchronous rpc to if B_ASYNC then + * to avoid distributed deadlocks we handoff the write to the + * nfs_aio threads. Doing so allows us to complete the + * current request, rather than blocking on a server which may + * be ourself (or blocked on ourself). + * + * Note the loopback deadlocks happened when the thread + * invoking us was nfsd, and also when it was the pagedaemon. + * + * This solution has one known problem. If *ALL* buffers get + * on the nfs_aio queue then no forward progress can be made + * until one of those writes complete. And if the current + * nfs_aio writes-in-progress block due to a non-responsive server we + * are in a deadlock circle. Probably the cure is to limit the + * async write concurrency in getnewbuf as in FreeBSD 3.2. + */ + if (nfs_aio_threads && (ap->a_bp->b_flags & B_ASYNC)) { + simple_lock(&nfs_aio_slock); + nfs_aio_bufq_len++; + TAILQ_INSERT_TAIL(&nfs_aio_bufq, ap->a_bp, b_freelist); + simple_unlock(&nfs_aio_slock); + wakeup_one((caddr_t)&nfs_aio_bufq); + return (0); + } return (nfs_writebp(ap->a_bp, 1)); } @@ -3625,6 +3697,7 @@ nfs_select(ap) */ return (1); } + /* Pagein */ nfs_pagein(ap) struct vop_pagein_args /* {