NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/60531: looping "vflushbuf: dirty" message



The following reply was made to PR kern/60531; it has been noted by GNATS.

From: "J. Hannken-Illjes" <hannken%netbsd.org@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc: 
Subject: Re: kern/60531: looping "vflushbuf: dirty" message
Date: Fri, 7 Aug 2026 16:39:33 +0000

 --ItY42kjenHJt4ZkN
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 The FIX will not work, it is not ok to replace 'vp->v_numoutput == 0' with
 'LIST_EMPTY(&vp->v_dirtyblkhd)'.
 
 Buffers are removed from v_dirtyblkhd through reassignbuf() when bwrite()
 initiates the write while v_numoutput gets decremented through
 biodone()->vwakekup() when the I/O has completed.
 
 With your patch VOP_FSYNC(vp, FSYNC_WAIT) would return before all buffers
 are written to disk.
 
 The first part should be sufficient to prevent looping here, an updfated
 patch is attached.
 
 -- 
 J. Hannken-Illjes - hannken%netbsd.org@localhost
 
 --ItY42kjenHJt4ZkN
 Content-Type: text/x-diff; charset=us-ascii
 Content-Disposition: attachment; filename=pr60531.patch
 
 diff -r 983d69604667 sys/kern/vfs_subr.c
 --- sys/kern/vfs_subr.c	Fri Aug 07 13:18:45 2026 +0200
 +++ sys/kern/vfs_subr.c	Fri Aug 07 18:28:00 2026 +0200
 @@ -171,6 +171,8 @@ const int	vttoif_tab[9] = {
  	(bp)->b_vnbufs.le_next = NOLIST;				\
  }
  
 +static uint64_t bufcache_flushgen = 1;
 +
  int doforce = 1;		/* 1 => permit forcible unmounting */
  
  /*
 @@ -329,19 +331,19 @@ restart:
  
  /*
   * Flush all dirty buffers from a vnode.
 - * Called with the underlying vnode locked, which should prevent new dirty
 - * buffers from being queued.
 + * Called with the underlying vnode locked.
   */
  int
  vflushbuf(struct vnode *vp, int flags)
  {
  	struct buf *bp, *nbp;
  	int error, pflags;
 -	bool dirty, sync;
 -#ifdef DEBUG
 -	bool warned = false;
 -#endif
 +	bool sync;
 +	uint64_t flushgen;
  
 +	KASSERT(VOP_ISLOCKED(vp));
 +
 +	flushgen = 0;
  	sync = (flags & FSYNC_WAIT) != 0;
  	pflags = PGO_CLEANIT | PGO_ALLPAGES |
  	    (sync ? PGO_SYNCIO : 0) |
 @@ -349,12 +351,20 @@ vflushbuf(struct vnode *vp, int flags)
  	rw_enter(vp->v_uobj.vmobjlock, RW_WRITER);
  	(void) VOP_PUTPAGES(vp, 0, 0, pflags);
  
 +	/*
 +	 * Ensure every dirty block associated with this vnode has
 +	 * begun to be written out (BC_BUSY, I/O in progress) -- any
 +	 * delayed writes must delay no longer.
 +	 */
  loop:
  	mutex_enter(&bufcache_lock);
 +	if (flushgen == 0)
 +		flushgen = bufcache_flushgen++;
  	for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
  		KASSERT(bp->b_vp == vp);
 +		KASSERT((bp->b_flags & B_PHYS) == 0);
  		nbp = LIST_NEXT(bp, b_vnbufs);
 -		if ((bp->b_cflags & BC_BUSY))
 +		if ((bp->b_cflags & BC_BUSY) != 0 || bp->b_flushgen > flushgen)
  			continue;
  		if ((bp->b_oflags & BO_DELWRI) == 0)
  			panic("vflushbuf: not dirty, bp %p", bp);
 @@ -378,28 +388,17 @@ loop:
  	if (!sync)
  		return 0;
  
 +	/*
 +	 * Wait until all pending writes issued before we incremented
 +	 * bufcache_flushgen have completed.
 +	 */
  	mutex_enter(vp->v_interlock);
  	while (vp->v_numoutput != 0)
  		cv_wait(&vp->v_cv, vp->v_interlock);
 -	dirty = !LIST_EMPTY(&vp->v_dirtyblkhd);
 +	KASSERT((vp->v_type == VBLK && spec_node_getmountedfs(vp)) ||
 +	    LIST_EMPTY(&vp->v_dirtyblkhd));
  	mutex_exit(vp->v_interlock);
  
 -	if (dirty) {
 -#ifdef DEBUG
 -		if (!warned) {
 -			static struct timeval vflushbuf_warntime;
 -			const struct timeval interval = {60,0};
 -
 -			mutex_enter(&bufcache_lock);
 -			if (ratecheck(&vflushbuf_warntime, &interval))
 -				vprint("vflushbuf: dirty", vp);
 -			mutex_exit(&bufcache_lock);
 -			warned = true;
 -		}
 -#endif
 -		goto loop;
 -	}
 -
  	return 0;
  }
  
 @@ -511,6 +510,7 @@ reassignbuf(struct buf *bp, struct vnode
  	KASSERT(bp->b_objlock == vp->v_interlock);
  	KASSERT(mutex_owned(vp->v_interlock));
  	KASSERT((bp->b_cflags & BC_BUSY) != 0);
 +	KASSERT((bp->b_flags & B_PHYS) == 0);
  
  	/*
  	 * Delete from old vnode list, if on one.
 @@ -549,6 +549,7 @@ reassignbuf(struct buf *bp, struct vnode
  			    (vp->v_mount->mnt_flag & MNT_ASYNC) == 0)
  				vn_syncer_add_to_worklist(vp, delayx);
  		}
 +		bp->b_flushgen = bufcache_flushgen;
  	}
  	bufinsvn(bp, listheadp);
  }
 diff -r 983d69604667 sys/sys/buf.h
 --- sys/sys/buf.h	Fri Aug 07 13:18:45 2026 +0200
 +++ sys/sys/buf.h	Fri Aug 07 18:28:00 2026 +0200
 @@ -135,8 +135,15 @@ struct buf {
  						      (partition relative) */
  	daddr_t			b_rawblkno;	/* b: raw physical block number
  						      (volume relative) */
 -	struct proc		*b_proc;	/* b: proc if BB_PHYS */
 -	void			*b_saveaddr;	/* b: saved b_data for physio */
 +	union {
 +		/* B_PHYS */
 +		struct {
 +			struct proc *b_proc;	/* b: proc if B_PHYS */
 +			void	*b_saveaddr;	/* b: saved b_data for physio */
 +		};
 +		/* !B_PHYS */
 +		uint64_t	b_flushgen;	/* b: flush generation */
 +	};
  	struct cpu_info		*b_ci;		/* b: originating CPU */
  
  	/*
 
 --ItY42kjenHJt4ZkN--
 



Home | Main Index | Thread Index | Old Index