diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 80e4d107726..945d95d9a7a 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -318,7 +318,7 @@ bufspacewakeup(void) * runningbufwakeup() - in-progress I/O accounting. * */ -static __inline void +void runningbufwakeup(struct buf *bp) { @@ -847,8 +847,7 @@ bufwrite(struct buf *bp) * or syncer daemon trying to clean up as that can lead * to deadlock. */ - if (curthread->td_proc != bufdaemonproc && - curthread->td_proc != updateproc) + if ((curthread->td_pflags & TDP_NORUNNINGBUF) == 0) waitrunningbufspace(); } @@ -1964,6 +1963,7 @@ buf_daemon() /* * This process is allowed to take the buffer cache to the limit */ + curthread->td_pflags |= TDP_NORUNNINGBUF; mtx_lock(&bdlock); for (;;) { bd_request = 0; diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 3486b0c1c66..26d5b9f0e90 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1524,7 +1524,7 @@ sysctl_vfs_worklist_len(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_vfs, OID_AUTO, worklist_len, CTLTYPE_INT | CTLFLAG_RD, NULL, 0, sysctl_vfs_worklist_len, "I", "Syncer thread worklist length"); -struct proc *updateproc; +static struct proc *updateproc; static void sched_sync(void); static struct kproc_desc up_kp = { "syncer", @@ -1601,6 +1601,7 @@ sched_sync(void) first_printf = 1; syncer_state = SYNCER_RUNNING; starttime = time_uptime; + td->td_pflags |= TDP_NORUNNINGBUF; EVENTHANDLER_REGISTER(shutdown_pre_sync, syncer_shutdown, td->td_proc, SHUTDOWN_PRI_LAST); diff --git a/sys/sys/buf.h b/sys/sys/buf.h index 63405122deb..6ef4f0f8655 100644 --- a/sys/sys/buf.h +++ b/sys/sys/buf.h @@ -477,6 +477,7 @@ extern int nswbuf; /* Number of swap I/O buffer headers. */ extern int cluster_pbuf_freecnt; /* Number of pbufs for clusters */ extern int vnode_pbuf_freecnt; /* Number of pbufs for vnode pager */ +void runningbufwakeup(struct buf *); caddr_t kern_vfs_bio_buffer_alloc(caddr_t v, long physmem_est); void bufinit(void); void bwillwrite(void); diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 40275bc8c6b..1006b9b8735 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -378,6 +378,7 @@ struct thread { #define TDP_SCHED4 0x00008000 /* Reserved for scheduler private use */ #define TDP_GEOM 0x00010000 /* Settle GEOM before finishing syscall */ #define TDP_SOFTDEP 0x00020000 /* Stuck processing softdep worklist */ +#define TDP_NORUNNINGBUF 0x00040000 /* Ignore runningbufspace check */ /* * Reasons that the current thread can not be run yet. @@ -833,7 +834,6 @@ TAILQ_HEAD(threadqueue, thread); extern struct proclist allproc; /* List of all processes. */ extern struct proclist zombproc; /* List of zombie processes. */ extern struct proc *initproc, *pageproc; /* Process slots for init, pager. */ -extern struct proc *updateproc; /* Process slot for syncer (sic). */ extern struct uma_zone *proc_zone; diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index c1344611e7d..3e7e2311f0e 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -1997,6 +1997,12 @@ ffs_copyonwrite(devvp, bp) VI_UNLOCK(devvp); return (0); } + /* + * Since I/O on bp isn't yet in progress and it may be blocked + * for a long time waiting on snaplk, back it out of + * runningbufspace, possibly waking other threads waiting for space. + */ + runningbufwakeup(bp); /* * Not in the precomputed list, so check the snapshots. */ @@ -2028,7 +2034,7 @@ retry: goto retry; } snapshot_locked = 1; - td->td_pflags |= TDP_COWINPROGRESS; + td->td_pflags |= TDP_COWINPROGRESS | TDP_NORUNNINGBUF; error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), fs->fs_bsize, KERNCRED, BA_METAONLY, &ibp); td->td_pflags &= ~TDP_COWINPROGRESS; @@ -2065,7 +2071,7 @@ retry: goto retry; } snapshot_locked = 1; - td->td_pflags |= TDP_COWINPROGRESS; + td->td_pflags |= TDP_COWINPROGRESS | TDP_NORUNNINGBUF; error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), fs->fs_bsize, KERNCRED, 0, &cbp); td->td_pflags &= ~TDP_COWINPROGRESS; @@ -2120,10 +2126,16 @@ retry: if (dopersistence && VTOI(vp)->i_effnlink > 0) (void) ffs_syncvnode(vp, MNT_WAIT); } - if (snapshot_locked) + if (snapshot_locked) { lockmgr(vp->v_vnlock, LK_RELEASE, NULL, td); - else + td->td_pflags &= ~TDP_NORUNNINGBUF; + } else VI_UNLOCK(devvp); + /* + * I/O on bp will now be started, so count it in runningbufspace. + */ + if (bp->b_runningbufspace) + atomic_add_int(&runningbufspace, bp->b_runningbufspace); return (error); }