From 88400c43734051baef34b0d28b493fcaca6ec719 Mon Sep 17 00:00:00 2001 From: hannken Date: Fri, 22 Aug 2008 10:48:22 +0000 Subject: [PATCH] Add snapshot support for logging ffs file systems. - Add UFS_WAPBL_BEGIN() / UFS_WAPBL_END() where needed. - Expunge WAPBL log inodes from snapshots. - Ffs_copyonwrite() and ffs_snapblkfree() must run inside a WAPBL transaction. - Add ffs_gop_write() as a wrapper around genfs_gop_write() that makes sure genfs_gop_write() gets always called inside a WAPBL transaction. - Add VOP_PUTPAGES() flag PGO_JOURNALLOCKED to tag calls to VOP_PUTPAGES() inside a WAPBL transaction. Reviewed by: Simon Burge , Greg Oster PGO_JOURNALLOCKED / ffs_gop_write() part presented on tech-kern@. --- sys/ufs/ffs/ffs_extern.h | 3 +- sys/ufs/ffs/ffs_snapshot.c | 284 ++++++++++++++++++++++++++---------- sys/ufs/ffs/ffs_vfsops.c | 14 +- sys/ufs/ffs/ffs_vnops.c | 22 ++- sys/ufs/ufs/ufs_readwrite.c | 14 +- sys/uvm/uvm_pager.h | 3 +- 6 files changed, 240 insertions(+), 100 deletions(-) diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index 80bad58e5fcd..2de60f99a242 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_extern.h,v 1.68 2008/08/12 10:14:37 hannken Exp $ */ +/* $NetBSD: ffs_extern.h,v 1.69 2008/08/22 10:48:22 hannken Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 @@ -128,6 +128,7 @@ int ffs_fsync(void *); int ffs_reclaim(void *); int ffs_getpages(void *); void ffs_gop_size(struct vnode *, off_t, off_t *, int); +int ffs_gop_write(struct vnode *, struct vm_page **, int, int); int ffs_openextattr(void *); int ffs_closeextattr(void *); int ffs_getextattr(void *); diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index 42e81ddc8e6e..55e1411a6a71 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_snapshot.c,v 1.74 2008/08/12 10:14:37 hannken Exp $ */ +/* $NetBSD: ffs_snapshot.c,v 1.75 2008/08/22 10:48:22 hannken Exp $ */ /* * Copyright 2000 Marshall Kirk McKusick. All Rights Reserved. @@ -38,10 +38,11 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.74 2008/08/12 10:14:37 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.75 2008/08/22 10:48:22 hannken Exp $"); #if defined(_KERNEL_OPT) #include "opt_ffs.h" +#include "opt_wapbl.h" #endif #include @@ -60,6 +61,7 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.74 2008/08/12 10:14:37 hannken Ex #include #include #include +#include #include @@ -68,6 +70,7 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.74 2008/08/12 10:14:37 hannken Ex #include #include #include +#include #include #include @@ -117,7 +120,8 @@ static int mapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, static int ffs_copyonwrite(void *, struct buf *, bool); static int snapblkaddr(struct vnode *, daddr_t, daddr_t *); -static int readfsblk(struct vnode *, void *, ufs2_daddr_t); +static int rwfsblk(struct vnode *, int, void *, ufs2_daddr_t); +static int syncsnap(struct vnode *); static int wrsnapblk(struct vnode *, void *, ufs2_daddr_t); static inline ufs2_daddr_t db_get(struct inode *, int); static inline void db_assign(struct inode *, int, ufs2_daddr_t); @@ -199,16 +203,14 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, struct inode *ip, *xp; struct buf *bp, *ibp, *nbp; struct vattr vat; - struct vnode *xvp, *mvp, *devvp; + struct vnode *xvp, *mvp, *logvp, *devvp; struct snap_info *si; + bool suspended = false; bool snapshot_locked = false; ns = UFS_FSNEEDSWAP(fs); si = VFSTOUFS(mp)->um_snapinfo; - /* Snapshots do not work yet with WAPBL. */ - if ((mp->mnt_flag & MNT_LOG)) - return EOPNOTSUPP; /* * Need to serialize access to snapshot code per filesystem. */ @@ -249,6 +251,14 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, return (ENOSPC); ip = VTOI(vp); devvp = ip->i_devvp; + if ((fs->fs_flags & FS_DOWAPBL) && + fs->fs_journal_location == UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM) { + error = VFS_VGET(mp, + fs->fs_journallocs[UFS_WAPBL_INFS_INO], &logvp); + if (error) + return error; + } else + logvp = NULL; /* * Write an empty list of preallocated blocks to the end of * the snapshot to set size to at least that of the filesystem. @@ -272,31 +282,46 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, * Allocate all indirect blocks and mark all of them as not * needing to be copied. */ - for (blkno = NDADDR; blkno < numblks; blkno += NINDIR(fs)) { + error = UFS_WAPBL_BEGIN(mp); + if (error) + goto out; + for (blkno = NDADDR, i = 0; blkno < numblks; blkno += NINDIR(fs)) { error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno), fs->fs_bsize, l->l_cred, B_METAONLY, &ibp); - if (error) + if (error) { + UFS_WAPBL_END(mp); goto out; + } if (DOINGSOFTDEP(vp)) bawrite(ibp); else brelse(ibp, 0); + if ((++i % 16) == 0) { + UFS_WAPBL_END(mp); + error = UFS_WAPBL_BEGIN(mp); + if (error) + goto out; + } } /* * Allocate copies for the superblock and its summary information. */ error = ffs_balloc(vp, fs->fs_sblockloc, fs->fs_sbsize, KERNCRED, 0, &nbp); - if (error) + if (error) { + UFS_WAPBL_END(mp); goto out; + } bawrite(nbp); blkno = fragstoblks(fs, fs->fs_csaddr); len = howmany(fs->fs_cssize, fs->fs_bsize); for (loc = 0; loc < len; loc++) { error = ffs_balloc(vp, lblktosize(fs, (off_t)(blkno + loc)), fs->fs_bsize, KERNCRED, 0, &nbp); - if (error) + if (error) { + UFS_WAPBL_END(mp); goto out; + } bawrite(nbp); } /* @@ -312,12 +337,15 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, for (cg = 0; cg < fs->fs_ncg; cg++) { if ((error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)), fs->fs_bsize, KERNCRED, 0, &nbp)) != 0) - goto out; + break; error = cgaccount(cg, vp, nbp->b_data, 1); bawrite(nbp); if (error) - goto out; + break; } + UFS_WAPBL_END(mp); + if (error) + goto out; /* * Change inode to snapshot type file. */ @@ -341,8 +369,12 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); goto out; } + suspended = true; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); getmicrotime(&starttime); + error = UFS_WAPBL_BEGIN(mp); + if (error) + goto out; /* * First, copy all the cylinder group maps that have changed. */ @@ -352,11 +384,15 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, redo++; if ((error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)), fs->fs_bsize, KERNCRED, 0, &nbp)) != 0) - goto out1; + break; error = cgaccount(cg, vp, nbp->b_data, 2); bawrite(nbp); if (error) - goto out1; + break; + } + if (error) { + UFS_WAPBL_END(mp); + goto out; } /* * Grab a copy of the superblock and its summary information. @@ -387,7 +423,7 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, len, KERNCRED, 0, &bp)) != 0) { brelse(bp, 0); free(copy_fs->fs_csp, M_UFSMNT); - goto out1; + goto out; } bcopy(bp->b_data, space, (u_int)len); space = (char *)space + len; @@ -415,7 +451,7 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, /* Allocate a marker vnode */ if ((mvp = vnalloc(mp)) == NULL) { error = ENOMEM; - goto out1; + goto out; } MNT_ILOCK(mp); /* @@ -448,13 +484,14 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, if (snapdebug) vprint("ffs_snapshot: busy vnode", xvp); #endif - if (VOP_GETATTR(xvp, &vat, l->l_cred) == 0 && + if (xvp != logvp && VOP_GETATTR(xvp, &vat, l->l_cred) == 0 && vat.va_nlink > 0) { MNT_ILOCK(mp); continue; } xp = VTOI(xvp); - if (ffs_checkfreefile(copy_fs, vp, xp->i_number)) { + if (xvp != logvp && + ffs_checkfreefile(copy_fs, vp, xp->i_number)) { MNT_ILOCK(mp); continue; } @@ -474,11 +511,11 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, } snaplistsize += 1; if (xp->i_ump->um_fstype == UFS1) - error = expunge_ufs1(vp, xp, copy_fs, fullacct_ufs1, - BLK_NOCOPY); + error = expunge_ufs1(vp, xp, copy_fs, + fullacct_ufs1, BLK_NOCOPY); else - error = expunge_ufs2(vp, xp, copy_fs, fullacct_ufs2, - BLK_NOCOPY); + error = expunge_ufs2(vp, xp, copy_fs, + fullacct_ufs2, BLK_NOCOPY); if (blkno) db_assign(xp, loc, blkno); if (!error) @@ -487,12 +524,13 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, if (error) { free(copy_fs->fs_csp, M_UFSMNT); (void)vunmark(mvp); - goto out1; + goto out; } MNT_ILOCK(mp); } MNT_IUNLOCK(mp); vnfree(mvp); + UFS_WAPBL_END(mp); /* * Acquire the snapshot lock. */ @@ -542,11 +580,6 @@ ffs_snapshot(struct mount *mp, struct vnode *vp, si->si_gen++; mutex_exit(&si->si_lock); vp->v_vflag |= VV_SYSTEM; -out1: - /* - * Resume operation on filesystem. - */ - vfs_resume(vp->v_mount); /* * Set the mtime to the time the snapshot has been taken. */ @@ -556,18 +589,6 @@ out1: DIP_ASSIGN(ip, mtime, ts.tv_sec); DIP_ASSIGN(ip, mtimensec, ts.tv_nsec); ip->i_flag |= IN_CHANGE | IN_UPDATE; - -#ifdef DEBUG - if (starttime.tv_sec > 0) { - getmicrotime(&endtime); - timersub(&endtime, &starttime, &endtime); - printf("%s: suspended %ld.%03ld sec, redo %ld of %d\n", - vp->v_mount->mnt_stat.f_mntonname, (long)endtime.tv_sec, - endtime.tv_usec / 1000, redo, fs->fs_ncg); - } -#endif - if (error) - goto out; /* * Copy allocation information from all the snapshots in * this snapshot and then expunge them from its view. @@ -575,15 +596,18 @@ out1: TAILQ_FOREACH(xp, &si->si_snapshots, i_nextsnap) { if (xp == ip) break; - if (xp->i_ump->um_fstype == UFS1) - error = expunge_ufs1(vp, xp, fs, snapacct_ufs1, - BLK_SNAP); - else - error = expunge_ufs2(vp, xp, fs, snapacct_ufs2, - BLK_SNAP); - if (error == 0 && xp->i_ffs_effnlink == 0) - error = ffs_freefile(copy_fs, vp, - xp->i_number, xp->i_mode); + if ((error = UFS_WAPBL_BEGIN(mp)) == 0) { + if (xp->i_ump->um_fstype == UFS1) + error = expunge_ufs1(vp, xp, fs, snapacct_ufs1, + BLK_SNAP); + else + error = expunge_ufs2(vp, xp, fs, snapacct_ufs2, + BLK_SNAP); + if (error == 0 && xp->i_ffs_effnlink == 0) + error = ffs_freefile(copy_fs, vp, + xp->i_number, xp->i_mode); + UFS_WAPBL_END(mp); + } if (error) { fs->fs_snapinum[snaploc] = 0; goto done; @@ -600,10 +624,15 @@ out1: * blocks marked as used in the snapshot bitmaps. Also, collect * the list of allocated blocks in i_snapblklist. */ - if (ip->i_ump->um_fstype == UFS1) - error = expunge_ufs1(vp, ip, copy_fs, mapacct_ufs1, BLK_SNAP); - else - error = expunge_ufs2(vp, ip, copy_fs, mapacct_ufs2, BLK_SNAP); + if ((error = UFS_WAPBL_BEGIN(mp)) == 0) { + if (ip->i_ump->um_fstype == UFS1) + error = expunge_ufs1(vp, ip, copy_fs, mapacct_ufs1, + BLK_SNAP); + else + error = expunge_ufs2(vp, ip, copy_fs, mapacct_ufs2, + BLK_SNAP); + UFS_WAPBL_END(mp); + } if (error) { fs->fs_snapinum[snaploc] = 0; FREE(snapblklist, M_UFSMNT); @@ -642,8 +671,15 @@ out1: ffs_csum_swap(space, space, fs->fs_cssize); } #endif + error = UFS_WAPBL_BEGIN(mp); + if (error) { + fs->fs_snapinum[snaploc] = 0; + FREE(snapblklist, M_UFSMNT); + goto done; + } for (loc = 0; loc < len; loc++) { - error = bread(vp, blkno + loc, fs->fs_bsize, KERNCRED, 0, &nbp); + error = bread(vp, blkno + loc, fs->fs_bsize, KERNCRED, + B_MODIFY, &nbp); if (error) { brelse(nbp, 0); fs->fs_snapinum[snaploc] = 0; @@ -654,6 +690,27 @@ out1: space = (char *)space + fs->fs_bsize; bawrite(nbp); } + /* + * Copy the first NDADDR blocks to the snapshot so ffs_copyonwrite() + * and ffs_snapblkfree() will always work on indirect blocks. + */ + for (loc = 0; loc < NDADDR; loc++) { + if (db_get(ip, loc) != 0) + continue; + error = ffs_balloc(vp, lblktosize(fs, (off_t)loc), + fs->fs_bsize, KERNCRED, 0, &nbp); + if (error) + break; + error = rwfsblk(vp, B_READ, nbp->b_data, loc); + if (error) { + brelse(nbp, 0); + fs->fs_snapinum[snaploc] = 0; + FREE(snapblklist, M_UFSMNT); + goto done; + } + bawrite(nbp); + } + UFS_WAPBL_END(mp); /* * As this is the newest list, it is the most inclusive, so * should replace the previous list. If this is the first snapshot @@ -667,16 +724,24 @@ out1: si->si_gen++; mutex_exit(&si->si_lock); done: + if (mp->mnt_wapbl) + copy_fs->fs_flags &= ~FS_DOWAPBL; free(copy_fs->fs_csp, M_UFSMNT); if (!error) { - error = bread(vp, lblkno(fs, fs->fs_sblockloc), fs->fs_bsize, - KERNCRED, 0, &nbp); - if (error) { - brelse(nbp, 0); - fs->fs_snapinum[snaploc] = 0; + error = UFS_WAPBL_BEGIN(mp); + if (!error) { + error = bread(vp, lblkno(fs, fs->fs_sblockloc), + fs->fs_bsize, KERNCRED, B_MODIFY, &nbp); + if (error) { + brelse(nbp, 0); + } else { + bcopy(sbbuf, nbp->b_data, fs->fs_bsize); + bawrite(nbp); + } + UFS_WAPBL_END(mp); } - bcopy(sbbuf, nbp->b_data, fs->fs_bsize); - bawrite(nbp); + if (error) + fs->fs_snapinum[snaploc] = 0; } out: /* @@ -688,6 +753,23 @@ out: error = VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES|PGO_CLEANIT|PGO_SYNCIO|PGO_FREE); } +#ifdef WAPBL + if (!error && mp->mnt_wapbl) + error = wapbl_flush(mp->mnt_wapbl, 1); +#endif + if (suspended) { + vfs_resume(vp->v_mount); +#ifdef DEBUG + if (starttime.tv_sec > 0) { + getmicrotime(&endtime); + timersub(&endtime, &starttime, &endtime); + printf("%s: suspended %ld.%03ld sec, redo %ld of %d\n", + vp->v_mount->mnt_stat.f_mntonname, + (long)endtime.tv_sec, endtime.tv_usec / 1000, + redo, fs->fs_ncg); + } +#endif + } if (sbbuf) free(sbbuf, M_UFSMNT); if (fs->fs_active != 0) { @@ -695,9 +777,12 @@ out: fs->fs_active = 0; } mp->mnt_flag = flag; - if (error) - (void) ffs_truncate(vp, (off_t)0, 0, NOCRED); - else + if (error) { + if (!UFS_WAPBL_BEGIN(mp)) { + (void) ffs_truncate(vp, (off_t)0, 0, NOCRED); + UFS_WAPBL_END(mp); + } + } else vref(vp); if (snapshot_locked) mutex_exit(&si->si_snaplock); @@ -823,7 +908,7 @@ expunge_ufs1(struct vnode *snapvp, struct inode *cancelip, struct fs *fs, error = ffs_balloc(snapvp, lblktosize(fs, (off_t)lbn), fs->fs_bsize, KERNCRED, 0, &bp); if (! error) - error = readfsblk(snapvp, bp->b_data, lbn); + error = rwfsblk(snapvp, B_READ, bp->b_data, lbn); } if (error) return error; @@ -908,7 +993,7 @@ indiracct_ufs1(struct vnode *snapvp, struct vnode *cancelvp, int level, if (error) return error; if ((bp->b_oflags & (BO_DONE | BO_DELWRI)) == 0 && (error = - readfsblk(bp->b_vp, bp->b_data, fragstoblks(fs, blkno)))) { + rwfsblk(bp->b_vp, B_READ, bp->b_data, fragstoblks(fs, blkno)))) { brelse(bp, 0); return (error); } @@ -1081,7 +1166,7 @@ expunge_ufs2(struct vnode *snapvp, struct inode *cancelip, struct fs *fs, error = ffs_balloc(snapvp, lblktosize(fs, (off_t)lbn), fs->fs_bsize, KERNCRED, 0, &bp); if (! error) - error = readfsblk(snapvp, bp->b_data, lbn); + error = rwfsblk(snapvp, B_READ, bp->b_data, lbn); } if (error) return error; @@ -1166,7 +1251,7 @@ indiracct_ufs2(struct vnode *snapvp, struct vnode *cancelvp, int level, if (error) return error; if ((bp->b_oflags & (BO_DONE | BO_DELWRI)) == 0 && (error = - readfsblk(bp->b_vp, bp->b_data, fragstoblks(fs, blkno)))) { + rwfsblk(bp->b_vp, B_READ, bp->b_data, fragstoblks(fs, blkno)))) { brelse(bp, 0); return (error); } @@ -1588,8 +1673,12 @@ retry: } DIP_ADD(ip, blocks, btodb(size)); ip->i_flag |= IN_CHANGE | IN_UPDATE; + if (ip->i_ffs_effnlink > 0 && mp->mnt_wapbl) + error = syncsnap(vp); + else + error = 0; mutex_exit(&si->si_snaplock); - return (1); + return (error == 0); } if (lbn >= NDADDR) brelse(ibp, 0); @@ -1610,7 +1699,7 @@ retry: mutex_exit(&si->si_lock); if (saved_data == NULL) { saved_data = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK); - error = readfsblk(vp, saved_data, lbn); + error = rwfsblk(vp, B_READ, saved_data, lbn); if (error) { free(saved_data, M_UFSMNT); saved_data = NULL; @@ -1619,6 +1708,8 @@ retry: } } error = wrsnapblk(vp, saved_data, lbn); + if (error == 0 && ip->i_ffs_effnlink > 0 && mp->mnt_wapbl) + error = syncsnap(vp); mutex_enter(&si->si_lock); if (error) break; @@ -1862,12 +1953,17 @@ ffs_copyonwrite(void *v, struct buf *bp, bool data_valid) return 0; } /* - * First check to see if it is in the preallocated list. + * First check to see if it is after the file system or + * in the preallocated list. * By doing this check we avoid several potential deadlocks. */ fs = ip->i_fs; ns = UFS_FSNEEDSWAP(fs); lbn = fragstoblks(fs, dbtofsb(fs, bp->b_blkno)); + if (bp->b_blkno >= fsbtodb(fs, fs->fs_size)) { + mutex_exit(&si->si_lock); + return 0; + } snapblklist = si->si_snapblklist; upper = si->si_snapblklist[0] - 1; lower = 1; @@ -1987,7 +2083,7 @@ retry: mutex_exit(&si->si_lock); if (saved_data == NULL) { saved_data = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK); - error = readfsblk(vp, saved_data, lbn); + error = rwfsblk(vp, B_READ, saved_data, lbn); if (error) { free(saved_data, M_UFSMNT); saved_data = NULL; @@ -1996,6 +2092,8 @@ retry: } } error = wrsnapblk(vp, saved_data, lbn); + if (error == 0 && ip->i_ffs_effnlink > 0 && mp->mnt_wapbl) + error = syncsnap(vp); mutex_enter(&si->si_lock); if (error) break; @@ -2070,10 +2168,10 @@ ffs_snapshot_read(struct vnode *vp, struct uio *uio, int ioflag) error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio); if (error) break; - brelse(bp, BC_INVAL | BC_NOCACHE); + brelse(bp, BC_AGE); } if (bp != NULL) - brelse(bp, BC_INVAL | BC_NOCACHE); + brelse(bp, BC_AGE); mutex_exit(&si->si_snaplock); fstrans_done(vp->v_mount); @@ -2081,11 +2179,11 @@ ffs_snapshot_read(struct vnode *vp, struct uio *uio, int ioflag) } /* - * Read the specified block of the filesystem vp resides on - * from the disk bypassing the buffer cache. + * Read or write the specified block of the filesystem vp resides on + * from or to the disk bypassing the buffer cache. */ static int -readfsblk(struct vnode *vp, void *data, ufs2_daddr_t lbn) +rwfsblk(struct vnode *vp, int flags, void *data, ufs2_daddr_t lbn) { int error; struct inode *ip = VTOI(vp); @@ -2093,7 +2191,7 @@ readfsblk(struct vnode *vp, void *data, ufs2_daddr_t lbn) struct buf *nbp; nbp = getiobuf(NULL, true); - nbp->b_flags = B_READ; + nbp->b_flags = flags; nbp->b_bcount = nbp->b_bufsize = fs->fs_bsize; nbp->b_error = 0; nbp->b_data = data; @@ -2111,6 +2209,34 @@ readfsblk(struct vnode *vp, void *data, ufs2_daddr_t lbn) return error; } +/* + * Write all dirty buffers to disk and invalidate them. + */ +static int +syncsnap(struct vnode *vp) +{ + int error; + buf_t *bp; + struct fs *fs = VTOI(vp)->i_fs; + + mutex_enter(&bufcache_lock); + while ((bp = LIST_FIRST(&vp->v_dirtyblkhd))) { + KASSERT((bp->b_cflags & BC_BUSY) == 0); + KASSERT(bp->b_bcount == fs->fs_bsize); + bp->b_cflags |= BC_BUSY; + mutex_exit(&bufcache_lock); + error = rwfsblk(vp, B_WRITE, bp->b_data, + fragstoblks(fs, dbtofsb(fs, bp->b_blkno))); + brelse(bp, BC_INVAL | BC_VFLUSH); + if (error) + return error; + mutex_enter(&bufcache_lock); + } + mutex_exit(&bufcache_lock); + + return 0; +} + /* * Write the specified block to a snapshot. */ diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 82fbb641dae9..7accc25bc466 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_vfsops.c,v 1.233 2008/08/15 17:32:32 hannken Exp $ */ +/* $NetBSD: ffs_vfsops.c,v 1.234 2008/08/22 10:48:22 hannken Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -61,7 +61,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.233 2008/08/15 17:32:32 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.234 2008/08/22 10:48:22 hannken Exp $"); #if defined(_KERNEL_OPT) #include "opt_ffs.h" @@ -160,7 +160,7 @@ struct vfsops ffs_vfsops = { static const struct genfs_ops ffs_genfsops = { .gop_size = ffs_gop_size, .gop_alloc = ufs_gop_alloc, - .gop_write = genfs_gop_write, + .gop_write = ffs_gop_write, .gop_markupdate = ufs_gop_markupdate, }; @@ -1291,14 +1291,6 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l) goto out; } } - /* Snapshots do not work yet with WAPBL. */ - if (ronly == 0 && fs->fs_snapinum[0] != 0 && (mp->mnt_flag & MNT_LOG)) { - printf("%s fs has snapshots -- logging not supported yet\n", - fs->fs_fsmnt); - error = EINVAL; - free(fs->fs_csp, M_UFSMNT); - goto out; - } if (ronly == 0 && fs->fs_snapinum[0] != 0) ffs_snapshot_mount(mp); diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 37fc12bb6b59..4edc8bda668f 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_vnops.c,v 1.102 2008/08/12 10:14:37 hannken Exp $ */ +/* $NetBSD: ffs_vnops.c,v 1.103 2008/08/22 10:48:22 hannken Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -61,7 +61,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.102 2008/08/12 10:14:37 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.103 2008/08/22 10:48:22 hannken Exp $"); #if defined(_KERNEL_OPT) #include "opt_ffs.h" @@ -692,6 +692,24 @@ ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) } } +int +ffs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags) +{ + int error; + const bool need_wapbl = (curlwp != uvm.pagedaemon_lwp && + vp->v_mount->mnt_wapbl && (flags & PGO_JOURNALLOCKED) == 0); + + if (need_wapbl) { + error = UFS_WAPBL_BEGIN(vp->v_mount); + if (error) + return error; + } + error = genfs_gop_write(vp, pgs, npages, flags); + if (need_wapbl) + UFS_WAPBL_END(vp->v_mount); + return error; +} + int ffs_openextattr(void *v) { diff --git a/sys/ufs/ufs/ufs_readwrite.c b/sys/ufs/ufs/ufs_readwrite.c index 0960c6adb451..509bcbafcb4c 100644 --- a/sys/ufs/ufs/ufs_readwrite.c +++ b/sys/ufs/ufs/ufs_readwrite.c @@ -1,4 +1,4 @@ -/* $NetBSD: ufs_readwrite.c,v 1.90 2008/08/12 10:14:38 hannken Exp $ */ +/* $NetBSD: ufs_readwrite.c,v 1.91 2008/08/22 10:48:22 hannken Exp $ */ /*- * Copyright (c) 1993 @@ -32,7 +32,7 @@ */ #include -__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.90 2008/08/12 10:14:38 hannken Exp $"); +__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.91 2008/08/22 10:48:22 hannken Exp $"); #ifdef LFS_READWRITE #define FS struct lfs @@ -337,7 +337,8 @@ WRITE(void *v) if (flags & B_SYNC) { mutex_enter(&vp->v_interlock); VOP_PUTPAGES(vp, trunc_page(osize & fs->fs_bmask), - round_page(eob), PGO_CLEANIT | PGO_SYNCIO); + round_page(eob), + PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED); } } @@ -432,7 +433,8 @@ WRITE(void *v) if (!async && oldoff >> 16 != uio->uio_offset >> 16) { mutex_enter(&vp->v_interlock); error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16, - (uio->uio_offset >> 16) << 16, PGO_CLEANIT); + (uio->uio_offset >> 16) << 16, + PGO_CLEANIT | PGO_JOURNALLOCKED); if (error) break; } @@ -442,14 +444,14 @@ WRITE(void *v) mutex_enter(&vp->v_interlock); error = VOP_PUTPAGES(vp, trunc_page(origoff & fs->fs_bmask), round_page(blkroundup(fs, uio->uio_offset)), - PGO_CLEANIT | PGO_SYNCIO); + PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED); } goto out; bcache: mutex_enter(&vp->v_interlock); VOP_PUTPAGES(vp, trunc_page(origoff), round_page(origoff + resid), - PGO_CLEANIT | PGO_FREE | PGO_SYNCIO); + PGO_CLEANIT | PGO_FREE | PGO_SYNCIO | PGO_JOURNALLOCKED); while (uio->uio_resid > 0) { lbn = lblkno(fs, uio->uio_offset); blkoffset = blkoff(fs, uio->uio_offset); diff --git a/sys/uvm/uvm_pager.h b/sys/uvm/uvm_pager.h index 981e0d56d164..6c42f3c62057 100644 --- a/sys/uvm/uvm_pager.h +++ b/sys/uvm/uvm_pager.h @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_pager.h,v 1.37 2007/10/25 13:03:06 yamt Exp $ */ +/* $NetBSD: uvm_pager.h,v 1.38 2008/08/22 10:48:22 hannken Exp $ */ /* * @@ -156,6 +156,7 @@ struct uvm_pagerops { /* if PGO_FREE is not set then the pages stay where they are. */ #define PGO_ALLPAGES 0x010 /* flush whole object/get all pages */ +#define PGO_JOURNALLOCKED 0x020 /* journal is already locked [put] */ #define PGO_LOCKED 0x040 /* fault data structures are locked [get] */ #define PGO_BUSYFAIL 0x080 /* fail if a page is busy [put] */ #define PGO_OVERWRITE 0x200 /* pages will be overwritten before unlocked */