313 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			313 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| Index: sys/ufs/ffs/ffs_softdep.c
 | |
| ===================================================================
 | |
| --- sys/ufs/ffs/ffs_softdep.c	(revision 282245)
 | |
| +++ sys/ufs/ffs/ffs_softdep.c	(working copy)
 | |
| @@ -735,9 +735,10 @@ static struct malloc_type *memtype[] = {
 | |
|  static	void check_clear_deps(struct mount *);
 | |
|  static	void softdep_error(char *, int);
 | |
|  static	int softdep_process_worklist(struct mount *, int);
 | |
| -static	int softdep_waitidle(struct mount *);
 | |
| +static	int softdep_waitidle(struct mount *, int);
 | |
|  static	void drain_output(struct vnode *);
 | |
|  static	struct buf *getdirtybuf(struct buf *, struct rwlock *, int);
 | |
| +static	int check_inodedep_free(struct inodedep *);
 | |
|  static	void clear_remove(struct mount *);
 | |
|  static	void clear_inodedeps(struct mount *);
 | |
|  static	void unlinked_inodedep(struct mount *, struct inodedep *);
 | |
| @@ -1377,6 +1378,10 @@ softdep_flush(addr)
 | |
|  	mp = (struct mount *)addr;
 | |
|  	ump = VFSTOUFS(mp);
 | |
|  	atomic_add_int(&stat_flush_threads, 1);
 | |
| +	ACQUIRE_LOCK(ump);
 | |
| +	ump->softdep_flags &= ~FLUSH_STARTING;
 | |
| +	wakeup(&ump->softdep_flushtd);
 | |
| +	FREE_LOCK(ump);
 | |
|  	if (print_threads) {
 | |
|  		if (stat_flush_threads == 1)
 | |
|  			printf("Running %s at pid %d\n", bufdaemonproc->p_comm,
 | |
| @@ -1389,7 +1394,7 @@ softdep_flush(addr)
 | |
|  		    VFSTOUFS(mp)->softdep_jblocks->jb_suspended))
 | |
|  			kthread_suspend_check();
 | |
|  		ACQUIRE_LOCK(ump);
 | |
| -		if ((ump->softdep_flags & FLUSH_CLEANUP) == 0)
 | |
| +		if ((ump->softdep_flags & (FLUSH_CLEANUP | FLUSH_EXIT)) == 0)
 | |
|  			msleep(&ump->softdep_flushtd, LOCK_PTR(ump), PVM,
 | |
|  			    "sdflush", hz / 2);
 | |
|  		ump->softdep_flags &= ~FLUSH_CLEANUP;
 | |
| @@ -1419,11 +1424,9 @@ worklist_speedup(mp)
 | |
|  
 | |
|  	ump = VFSTOUFS(mp);
 | |
|  	LOCK_OWNED(ump);
 | |
| -	if ((ump->softdep_flags & (FLUSH_CLEANUP | FLUSH_EXIT)) == 0) {
 | |
| +	if ((ump->softdep_flags & (FLUSH_CLEANUP | FLUSH_EXIT)) == 0)
 | |
|  		ump->softdep_flags |= FLUSH_CLEANUP;
 | |
| -		if (ump->softdep_flushtd->td_wchan == &ump->softdep_flushtd)
 | |
| -			wakeup(&ump->softdep_flushtd);
 | |
| -	}
 | |
| +	wakeup(&ump->softdep_flushtd);
 | |
|  }
 | |
|  
 | |
|  static int
 | |
| @@ -1468,14 +1471,10 @@ softdep_speedup(ump)
 | |
|  			TAILQ_INSERT_TAIL(&softdepmounts, sdp, sd_next);
 | |
|  			FREE_GBLLOCK(&lk);
 | |
|  			if ((altump->softdep_flags &
 | |
| -			    (FLUSH_CLEANUP | FLUSH_EXIT)) == 0) {
 | |
| +			    (FLUSH_CLEANUP | FLUSH_EXIT)) == 0)
 | |
|  				altump->softdep_flags |= FLUSH_CLEANUP;
 | |
| -				altump->um_softdep->sd_cleanups++;
 | |
| -				if (altump->softdep_flushtd->td_wchan ==
 | |
| -				    &altump->softdep_flushtd) {
 | |
| -					wakeup(&altump->softdep_flushtd);
 | |
| -				}
 | |
| -			}
 | |
| +			altump->um_softdep->sd_cleanups++;
 | |
| +			wakeup(&altump->softdep_flushtd);
 | |
|  			FREE_LOCK(altump);
 | |
|  		}
 | |
|  	}
 | |
| @@ -1887,8 +1886,8 @@ softdep_flushworklist(oldmnt, countp, td
 | |
|  	struct thread *td;
 | |
|  {
 | |
|  	struct vnode *devvp;
 | |
| -	int count, error = 0;
 | |
|  	struct ufsmount *ump;
 | |
| +	int count, error;
 | |
|  
 | |
|  	/*
 | |
|  	 * Alternately flush the block device associated with the mount
 | |
| @@ -1897,6 +1896,7 @@ softdep_flushworklist(oldmnt, countp, td
 | |
|  	 * are found.
 | |
|  	 */
 | |
|  	*countp = 0;
 | |
| +	error = 0;
 | |
|  	ump = VFSTOUFS(oldmnt);
 | |
|  	devvp = ump->um_devvp;
 | |
|  	while ((count = softdep_process_worklist(oldmnt, 1)) > 0) {
 | |
| @@ -1904,36 +1904,47 @@ softdep_flushworklist(oldmnt, countp, td
 | |
|  		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
 | |
|  		error = VOP_FSYNC(devvp, MNT_WAIT, td);
 | |
|  		VOP_UNLOCK(devvp, 0);
 | |
| -		if (error)
 | |
| +		if (error != 0)
 | |
|  			break;
 | |
|  	}
 | |
|  	return (error);
 | |
|  }
 | |
|  
 | |
| +#define	SU_WAITIDLE_RETRIES	20
 | |
|  static int
 | |
| -softdep_waitidle(struct mount *mp)
 | |
| +softdep_waitidle(struct mount *mp, int flags __unused)
 | |
|  {
 | |
|  	struct ufsmount *ump;
 | |
| -	int error;
 | |
| -	int i;
 | |
| +	struct vnode *devvp;
 | |
| +	struct thread *td;
 | |
| +	int error, i;
 | |
|  
 | |
|  	ump = VFSTOUFS(mp);
 | |
| +	devvp = ump->um_devvp;
 | |
| +	td = curthread;
 | |
| +	error = 0;
 | |
|  	ACQUIRE_LOCK(ump);
 | |
| -	for (i = 0; i < 10 && ump->softdep_deps; i++) {
 | |
| +	for (i = 0; i < SU_WAITIDLE_RETRIES && ump->softdep_deps != 0; i++) {
 | |
|  		ump->softdep_req = 1;
 | |
| -		if (ump->softdep_on_worklist)
 | |
| -			panic("softdep_waitidle: work added after flush.");
 | |
| -		msleep(&ump->softdep_deps, LOCK_PTR(ump), PVM, "softdeps", 1);
 | |
| +		KASSERT((flags & FORCECLOSE) == 0 ||
 | |
| +		    ump->softdep_on_worklist == 0,
 | |
| +		    ("softdep_waitidle: work added after flush"));
 | |
| +		msleep(&ump->softdep_deps, LOCK_PTR(ump), PVM | PDROP,
 | |
| +		    "softdeps", 10 * hz);
 | |
| +		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
 | |
| +		error = VOP_FSYNC(devvp, MNT_WAIT, td);
 | |
| +		VOP_UNLOCK(devvp, 0);
 | |
| +		if (error != 0)
 | |
| +			break;
 | |
| +		ACQUIRE_LOCK(ump);
 | |
|  	}
 | |
|  	ump->softdep_req = 0;
 | |
| -	FREE_LOCK(ump);
 | |
| -	error = 0;
 | |
| -	if (i == 10) {
 | |
| +	if (i == SU_WAITIDLE_RETRIES && error == 0 && ump->softdep_deps != 0) {
 | |
|  		error = EBUSY;
 | |
|  		printf("softdep_waitidle: Failed to flush worklist for %p\n",
 | |
|  		    mp);
 | |
|  	}
 | |
| -
 | |
| +	FREE_LOCK(ump);
 | |
|  	return (error);
 | |
|  }
 | |
|  
 | |
| @@ -1990,7 +2001,7 @@ retry_flush:
 | |
|  		error = EBUSY;
 | |
|  	}
 | |
|  	if (!error)
 | |
| -		error = softdep_waitidle(oldmnt);
 | |
| +		error = softdep_waitidle(oldmnt, flags);
 | |
|  	if (!error) {
 | |
|  		if (oldmnt->mnt_kern_flag & MNTK_UNMOUNT) {
 | |
|  			retry = 0;
 | |
| @@ -2490,9 +2501,18 @@ softdep_mount(devvp, mp, fs, cred)
 | |
|  	/*
 | |
|  	 * Start our flushing thread in the bufdaemon process.
 | |
|  	 */
 | |
| +	ACQUIRE_LOCK(ump);
 | |
| +	ump->softdep_flags |= FLUSH_STARTING;
 | |
| +	FREE_LOCK(ump);
 | |
|  	kproc_kthread_add(&softdep_flush, mp, &bufdaemonproc,
 | |
|  	    &ump->softdep_flushtd, 0, 0, "softdepflush", "%s worker",
 | |
|  	    mp->mnt_stat.f_mntonname);
 | |
| +	ACQUIRE_LOCK(ump);
 | |
| +	while ((ump->softdep_flags & FLUSH_STARTING) != 0) {
 | |
| +		msleep(&ump->softdep_flushtd, LOCK_PTR(ump), PVM, "sdstart",
 | |
| +		    hz / 2);
 | |
| +	}
 | |
| +	FREE_LOCK(ump);
 | |
|  	/*
 | |
|  	 * When doing soft updates, the counters in the
 | |
|  	 * superblock may have gotten out of sync. Recomputation
 | |
| @@ -7629,17 +7649,13 @@ check_inode_unwritten(inodedep)
 | |
|  	return (1);
 | |
|  }
 | |
|  
 | |
| -/*
 | |
| - * Try to free an inodedep structure. Return 1 if it could be freed.
 | |
| - */
 | |
|  static int
 | |
| -free_inodedep(inodedep)
 | |
| +check_inodedep_free(inodedep)
 | |
|  	struct inodedep *inodedep;
 | |
|  {
 | |
|  
 | |
|  	LOCK_OWNED(VFSTOUFS(inodedep->id_list.wk_mp));
 | |
| -	if ((inodedep->id_state & (ONWORKLIST | UNLINKED)) != 0 ||
 | |
| -	    (inodedep->id_state & ALLCOMPLETE) != ALLCOMPLETE ||
 | |
| +	if ((inodedep->id_state & ALLCOMPLETE) != ALLCOMPLETE ||
 | |
|  	    !LIST_EMPTY(&inodedep->id_dirremhd) ||
 | |
|  	    !LIST_EMPTY(&inodedep->id_pendinghd) ||
 | |
|  	    !LIST_EMPTY(&inodedep->id_bufwait) ||
 | |
| @@ -7654,6 +7670,21 @@ free_inodedep(inodedep)
 | |
|  	    inodedep->id_nlinkdelta != 0 ||
 | |
|  	    inodedep->id_savedino1 != NULL)
 | |
|  		return (0);
 | |
| +	return (1);
 | |
| +}
 | |
| +
 | |
| +/*
 | |
| + * Try to free an inodedep structure. Return 1 if it could be freed.
 | |
| + */
 | |
| +static int
 | |
| +free_inodedep(inodedep)
 | |
| +	struct inodedep *inodedep;
 | |
| +{
 | |
| +
 | |
| +	LOCK_OWNED(VFSTOUFS(inodedep->id_list.wk_mp));
 | |
| +	if ((inodedep->id_state & (ONWORKLIST | UNLINKED)) != 0 ||
 | |
| +	    !check_inodedep_free(inodedep))
 | |
| +		return (0);
 | |
|  	if (inodedep->id_state & ONDEPLIST)
 | |
|  		LIST_REMOVE(inodedep, id_deps);
 | |
|  	LIST_REMOVE(inodedep, id_hash);
 | |
| @@ -13838,7 +13869,8 @@ softdep_check_suspend(struct mount *mp,
 | |
|  {
 | |
|  	struct bufobj *bo;
 | |
|  	struct ufsmount *ump;
 | |
| -	int error;
 | |
| +	struct inodedep *inodedep;
 | |
| +	int error, unlinked;
 | |
|  
 | |
|  	bo = &devvp->v_bufobj;
 | |
|  	ASSERT_BO_WLOCKED(bo);
 | |
| @@ -13899,6 +13931,20 @@ softdep_check_suspend(struct mount *mp,
 | |
|  		break;
 | |
|  	}
 | |
|  
 | |
| +	unlinked = 0;
 | |
| +	if (MOUNTEDSUJ(mp)) {
 | |
| +		for (inodedep = TAILQ_FIRST(&ump->softdep_unlinked);
 | |
| +		    inodedep != NULL;
 | |
| +		    inodedep = TAILQ_NEXT(inodedep, id_unlinked)) {
 | |
| +			if ((inodedep->id_state & (UNLINKED | UNLINKLINKS |
 | |
| +			    UNLINKONLIST)) != (UNLINKED | UNLINKLINKS |
 | |
| +			    UNLINKONLIST) ||
 | |
| +			    !check_inodedep_free(inodedep))
 | |
| +				continue;
 | |
| +			unlinked++;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
|  	/*
 | |
|  	 * Reasons for needing more work before suspend:
 | |
|  	 * - Dirty buffers on devvp.
 | |
| @@ -13908,8 +13954,8 @@ softdep_check_suspend(struct mount *mp,
 | |
|  	error = 0;
 | |
|  	if (bo->bo_numoutput > 0 ||
 | |
|  	    bo->bo_dirty.bv_cnt > 0 ||
 | |
| -	    softdep_depcnt != 0 ||
 | |
| -	    ump->softdep_deps != 0 ||
 | |
| +	    softdep_depcnt != unlinked ||
 | |
| +	    ump->softdep_deps != unlinked ||
 | |
|  	    softdep_accdepcnt != ump->softdep_accdeps ||
 | |
|  	    secondary_writes != 0 ||
 | |
|  	    mp->mnt_secondary_writes != 0 ||
 | |
| Index: sys/ufs/ffs/ffs_vfsops.c
 | |
| ===================================================================
 | |
| --- sys/ufs/ffs/ffs_vfsops.c	(revision 282245)
 | |
| +++ sys/ufs/ffs/ffs_vfsops.c	(working copy)
 | |
| @@ -1502,8 +1502,11 @@ ffs_sync(mp, waitfor)
 | |
|  	if (fs->fs_fmod != 0 && fs->fs_ronly != 0 && ump->um_fsckpid == 0)
 | |
|  		panic("%s: ffs_sync: modification on read-only filesystem",
 | |
|  		    fs->fs_fsmnt);
 | |
| -	if (waitfor == MNT_LAZY)
 | |
| -		return (ffs_sync_lazy(mp));
 | |
| +	if (waitfor == MNT_LAZY) {
 | |
| +		if (!rebooting)
 | |
| +			return (ffs_sync_lazy(mp));
 | |
| +		waitfor = MNT_NOWAIT;
 | |
| +	}
 | |
|  
 | |
|  	/*
 | |
|  	 * Write back each (modified) inode.
 | |
| @@ -1560,7 +1563,7 @@ loop:
 | |
|  	/*
 | |
|  	 * Force stale filesystem control information to be flushed.
 | |
|  	 */
 | |
| -	if (waitfor == MNT_WAIT) {
 | |
| +	if (waitfor == MNT_WAIT || rebooting) {
 | |
|  		if ((error = softdep_flushworklist(ump->um_mountp, &count, td)))
 | |
|  			allerror = error;
 | |
|  		/* Flushed work items may create new vnodes to clean */
 | |
| @@ -1577,9 +1580,12 @@ loop:
 | |
|  	if (bo->bo_numoutput > 0 || bo->bo_dirty.bv_cnt > 0) {
 | |
|  		BO_UNLOCK(bo);
 | |
|  		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
 | |
| -		if ((error = VOP_FSYNC(devvp, waitfor, td)) != 0)
 | |
| -			allerror = error;
 | |
| +		error = VOP_FSYNC(devvp, waitfor, td);
 | |
|  		VOP_UNLOCK(devvp, 0);
 | |
| +		if (MOUNTEDSOFTDEP(mp) && (error == 0 || error == EAGAIN))
 | |
| +			error = ffs_sbupdate(ump, waitfor, 0);
 | |
| +		if (error != 0)
 | |
| +			allerror = error;
 | |
|  		if (allerror == 0 && waitfor == MNT_WAIT)
 | |
|  			goto loop;
 | |
|  	} else if (suspend != 0) {
 | |
| Index: sys/ufs/ffs/softdep.h
 | |
| ===================================================================
 | |
| --- sys/ufs/ffs/softdep.h	(revision 282245)
 | |
| +++ sys/ufs/ffs/softdep.h	(working copy)
 | |
| @@ -1063,6 +1063,8 @@ struct mount_softdeps {
 | |
|   */
 | |
|  #define FLUSH_EXIT	0x0001	/* time to exit */
 | |
|  #define FLUSH_CLEANUP	0x0002	/* need to clear out softdep structures */
 | |
| +#define	FLUSH_STARTING	0x0004	/* flush thread not yet started */
 | |
| +
 | |
|  /*
 | |
|   * Keep the old names from when these were in the ufsmount structure.
 | |
|   */
 |