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

"J. Hannken-Illjes via gnats" <[email protected]>
Newsgroups gmane.os.netbsd.bugs
Message-ID <[email protected]>
The following reply was made to PR kern/60531; it has been noted by GNATS.

From: "J. Hannken-Illjes" <[email protected]>
To: [email protected]
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 - [email protected]
 
 --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--
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.