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 <simonb@netbsd.org>, Greg Oster <oster@netbsd.org> PGO_JOURNALLOCKED / ffs_gop_write() part presented on tech-kern@.
This commit is contained in:
parent
6523980087
commit
88400c4373
@ -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
|
* Copyright (c) 1991, 1993, 1994
|
||||||
@ -128,6 +128,7 @@ int ffs_fsync(void *);
|
|||||||
int ffs_reclaim(void *);
|
int ffs_reclaim(void *);
|
||||||
int ffs_getpages(void *);
|
int ffs_getpages(void *);
|
||||||
void ffs_gop_size(struct vnode *, off_t, off_t *, int);
|
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_openextattr(void *);
|
||||||
int ffs_closeextattr(void *);
|
int ffs_closeextattr(void *);
|
||||||
int ffs_getextattr(void *);
|
int ffs_getextattr(void *);
|
||||||
|
@ -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.
|
* Copyright 2000 Marshall Kirk McKusick. All Rights Reserved.
|
||||||
@ -38,10 +38,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__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)
|
#if defined(_KERNEL_OPT)
|
||||||
#include "opt_ffs.h"
|
#include "opt_ffs.h"
|
||||||
|
#include "opt_wapbl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
@ -60,6 +61,7 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.74 2008/08/12 10:14:37 hannken Ex
|
|||||||
#include <sys/vnode.h>
|
#include <sys/vnode.h>
|
||||||
#include <sys/kauth.h>
|
#include <sys/kauth.h>
|
||||||
#include <sys/fstrans.h>
|
#include <sys/fstrans.h>
|
||||||
|
#include <sys/wapbl.h>
|
||||||
|
|
||||||
#include <miscfs/specfs/specdev.h>
|
#include <miscfs/specfs/specdev.h>
|
||||||
|
|
||||||
@ -68,6 +70,7 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.74 2008/08/12 10:14:37 hannken Ex
|
|||||||
#include <ufs/ufs/inode.h>
|
#include <ufs/ufs/inode.h>
|
||||||
#include <ufs/ufs/ufs_extern.h>
|
#include <ufs/ufs/ufs_extern.h>
|
||||||
#include <ufs/ufs/ufs_bswap.h>
|
#include <ufs/ufs/ufs_bswap.h>
|
||||||
|
#include <ufs/ufs/ufs_wapbl.h>
|
||||||
|
|
||||||
#include <ufs/ffs/fs.h>
|
#include <ufs/ffs/fs.h>
|
||||||
#include <ufs/ffs/ffs_extern.h>
|
#include <ufs/ffs/ffs_extern.h>
|
||||||
@ -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 ffs_copyonwrite(void *, struct buf *, bool);
|
||||||
static int snapblkaddr(struct vnode *, daddr_t, daddr_t *);
|
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 int wrsnapblk(struct vnode *, void *, ufs2_daddr_t);
|
||||||
static inline ufs2_daddr_t db_get(struct inode *, int);
|
static inline ufs2_daddr_t db_get(struct inode *, int);
|
||||||
static inline void db_assign(struct inode *, int, ufs2_daddr_t);
|
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 inode *ip, *xp;
|
||||||
struct buf *bp, *ibp, *nbp;
|
struct buf *bp, *ibp, *nbp;
|
||||||
struct vattr vat;
|
struct vattr vat;
|
||||||
struct vnode *xvp, *mvp, *devvp;
|
struct vnode *xvp, *mvp, *logvp, *devvp;
|
||||||
struct snap_info *si;
|
struct snap_info *si;
|
||||||
|
bool suspended = false;
|
||||||
bool snapshot_locked = false;
|
bool snapshot_locked = false;
|
||||||
|
|
||||||
ns = UFS_FSNEEDSWAP(fs);
|
ns = UFS_FSNEEDSWAP(fs);
|
||||||
si = VFSTOUFS(mp)->um_snapinfo;
|
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.
|
* Need to serialize access to snapshot code per filesystem.
|
||||||
*/
|
*/
|
||||||
@ -249,6 +251,14 @@ ffs_snapshot(struct mount *mp, struct vnode *vp,
|
|||||||
return (ENOSPC);
|
return (ENOSPC);
|
||||||
ip = VTOI(vp);
|
ip = VTOI(vp);
|
||||||
devvp = ip->i_devvp;
|
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
|
* Write an empty list of preallocated blocks to the end of
|
||||||
* the snapshot to set size to at least that of the filesystem.
|
* 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
|
* Allocate all indirect blocks and mark all of them as not
|
||||||
* needing to be copied.
|
* 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),
|
error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
|
||||||
fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
|
fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
|
||||||
if (error)
|
if (error) {
|
||||||
|
UFS_WAPBL_END(mp);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
if (DOINGSOFTDEP(vp))
|
if (DOINGSOFTDEP(vp))
|
||||||
bawrite(ibp);
|
bawrite(ibp);
|
||||||
else
|
else
|
||||||
brelse(ibp, 0);
|
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.
|
* Allocate copies for the superblock and its summary information.
|
||||||
*/
|
*/
|
||||||
error = ffs_balloc(vp, fs->fs_sblockloc, fs->fs_sbsize, KERNCRED,
|
error = ffs_balloc(vp, fs->fs_sblockloc, fs->fs_sbsize, KERNCRED,
|
||||||
0, &nbp);
|
0, &nbp);
|
||||||
if (error)
|
if (error) {
|
||||||
|
UFS_WAPBL_END(mp);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
bawrite(nbp);
|
bawrite(nbp);
|
||||||
blkno = fragstoblks(fs, fs->fs_csaddr);
|
blkno = fragstoblks(fs, fs->fs_csaddr);
|
||||||
len = howmany(fs->fs_cssize, fs->fs_bsize);
|
len = howmany(fs->fs_cssize, fs->fs_bsize);
|
||||||
for (loc = 0; loc < len; loc++) {
|
for (loc = 0; loc < len; loc++) {
|
||||||
error = ffs_balloc(vp, lblktosize(fs, (off_t)(blkno + loc)),
|
error = ffs_balloc(vp, lblktosize(fs, (off_t)(blkno + loc)),
|
||||||
fs->fs_bsize, KERNCRED, 0, &nbp);
|
fs->fs_bsize, KERNCRED, 0, &nbp);
|
||||||
if (error)
|
if (error) {
|
||||||
|
UFS_WAPBL_END(mp);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
bawrite(nbp);
|
bawrite(nbp);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -312,12 +337,15 @@ ffs_snapshot(struct mount *mp, struct vnode *vp,
|
|||||||
for (cg = 0; cg < fs->fs_ncg; cg++) {
|
for (cg = 0; cg < fs->fs_ncg; cg++) {
|
||||||
if ((error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
|
if ((error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
|
||||||
fs->fs_bsize, KERNCRED, 0, &nbp)) != 0)
|
fs->fs_bsize, KERNCRED, 0, &nbp)) != 0)
|
||||||
goto out;
|
break;
|
||||||
error = cgaccount(cg, vp, nbp->b_data, 1);
|
error = cgaccount(cg, vp, nbp->b_data, 1);
|
||||||
bawrite(nbp);
|
bawrite(nbp);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
break;
|
||||||
}
|
}
|
||||||
|
UFS_WAPBL_END(mp);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
/*
|
/*
|
||||||
* Change inode to snapshot type file.
|
* 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);
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
suspended = true;
|
||||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
||||||
getmicrotime(&starttime);
|
getmicrotime(&starttime);
|
||||||
|
error = UFS_WAPBL_BEGIN(mp);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
/*
|
/*
|
||||||
* First, copy all the cylinder group maps that have changed.
|
* First, copy all the cylinder group maps that have changed.
|
||||||
*/
|
*/
|
||||||
@ -352,11 +384,15 @@ ffs_snapshot(struct mount *mp, struct vnode *vp,
|
|||||||
redo++;
|
redo++;
|
||||||
if ((error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
|
if ((error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
|
||||||
fs->fs_bsize, KERNCRED, 0, &nbp)) != 0)
|
fs->fs_bsize, KERNCRED, 0, &nbp)) != 0)
|
||||||
goto out1;
|
break;
|
||||||
error = cgaccount(cg, vp, nbp->b_data, 2);
|
error = cgaccount(cg, vp, nbp->b_data, 2);
|
||||||
bawrite(nbp);
|
bawrite(nbp);
|
||||||
if (error)
|
if (error)
|
||||||
goto out1;
|
break;
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
UFS_WAPBL_END(mp);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Grab a copy of the superblock and its summary information.
|
* 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) {
|
len, KERNCRED, 0, &bp)) != 0) {
|
||||||
brelse(bp, 0);
|
brelse(bp, 0);
|
||||||
free(copy_fs->fs_csp, M_UFSMNT);
|
free(copy_fs->fs_csp, M_UFSMNT);
|
||||||
goto out1;
|
goto out;
|
||||||
}
|
}
|
||||||
bcopy(bp->b_data, space, (u_int)len);
|
bcopy(bp->b_data, space, (u_int)len);
|
||||||
space = (char *)space + len;
|
space = (char *)space + len;
|
||||||
@ -415,7 +451,7 @@ ffs_snapshot(struct mount *mp, struct vnode *vp,
|
|||||||
/* Allocate a marker vnode */
|
/* Allocate a marker vnode */
|
||||||
if ((mvp = vnalloc(mp)) == NULL) {
|
if ((mvp = vnalloc(mp)) == NULL) {
|
||||||
error = ENOMEM;
|
error = ENOMEM;
|
||||||
goto out1;
|
goto out;
|
||||||
}
|
}
|
||||||
MNT_ILOCK(mp);
|
MNT_ILOCK(mp);
|
||||||
/*
|
/*
|
||||||
@ -448,13 +484,14 @@ ffs_snapshot(struct mount *mp, struct vnode *vp,
|
|||||||
if (snapdebug)
|
if (snapdebug)
|
||||||
vprint("ffs_snapshot: busy vnode", xvp);
|
vprint("ffs_snapshot: busy vnode", xvp);
|
||||||
#endif
|
#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) {
|
vat.va_nlink > 0) {
|
||||||
MNT_ILOCK(mp);
|
MNT_ILOCK(mp);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
xp = VTOI(xvp);
|
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);
|
MNT_ILOCK(mp);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -474,11 +511,11 @@ ffs_snapshot(struct mount *mp, struct vnode *vp,
|
|||||||
}
|
}
|
||||||
snaplistsize += 1;
|
snaplistsize += 1;
|
||||||
if (xp->i_ump->um_fstype == UFS1)
|
if (xp->i_ump->um_fstype == UFS1)
|
||||||
error = expunge_ufs1(vp, xp, copy_fs, fullacct_ufs1,
|
error = expunge_ufs1(vp, xp, copy_fs,
|
||||||
BLK_NOCOPY);
|
fullacct_ufs1, BLK_NOCOPY);
|
||||||
else
|
else
|
||||||
error = expunge_ufs2(vp, xp, copy_fs, fullacct_ufs2,
|
error = expunge_ufs2(vp, xp, copy_fs,
|
||||||
BLK_NOCOPY);
|
fullacct_ufs2, BLK_NOCOPY);
|
||||||
if (blkno)
|
if (blkno)
|
||||||
db_assign(xp, loc, blkno);
|
db_assign(xp, loc, blkno);
|
||||||
if (!error)
|
if (!error)
|
||||||
@ -487,12 +524,13 @@ ffs_snapshot(struct mount *mp, struct vnode *vp,
|
|||||||
if (error) {
|
if (error) {
|
||||||
free(copy_fs->fs_csp, M_UFSMNT);
|
free(copy_fs->fs_csp, M_UFSMNT);
|
||||||
(void)vunmark(mvp);
|
(void)vunmark(mvp);
|
||||||
goto out1;
|
goto out;
|
||||||
}
|
}
|
||||||
MNT_ILOCK(mp);
|
MNT_ILOCK(mp);
|
||||||
}
|
}
|
||||||
MNT_IUNLOCK(mp);
|
MNT_IUNLOCK(mp);
|
||||||
vnfree(mvp);
|
vnfree(mvp);
|
||||||
|
UFS_WAPBL_END(mp);
|
||||||
/*
|
/*
|
||||||
* Acquire the snapshot lock.
|
* Acquire the snapshot lock.
|
||||||
*/
|
*/
|
||||||
@ -542,11 +580,6 @@ ffs_snapshot(struct mount *mp, struct vnode *vp,
|
|||||||
si->si_gen++;
|
si->si_gen++;
|
||||||
mutex_exit(&si->si_lock);
|
mutex_exit(&si->si_lock);
|
||||||
vp->v_vflag |= VV_SYSTEM;
|
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.
|
* 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, mtime, ts.tv_sec);
|
||||||
DIP_ASSIGN(ip, mtimensec, ts.tv_nsec);
|
DIP_ASSIGN(ip, mtimensec, ts.tv_nsec);
|
||||||
ip->i_flag |= IN_CHANGE | IN_UPDATE;
|
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
|
* Copy allocation information from all the snapshots in
|
||||||
* this snapshot and then expunge them from its view.
|
* this snapshot and then expunge them from its view.
|
||||||
@ -575,15 +596,18 @@ out1:
|
|||||||
TAILQ_FOREACH(xp, &si->si_snapshots, i_nextsnap) {
|
TAILQ_FOREACH(xp, &si->si_snapshots, i_nextsnap) {
|
||||||
if (xp == ip)
|
if (xp == ip)
|
||||||
break;
|
break;
|
||||||
if (xp->i_ump->um_fstype == UFS1)
|
if ((error = UFS_WAPBL_BEGIN(mp)) == 0) {
|
||||||
error = expunge_ufs1(vp, xp, fs, snapacct_ufs1,
|
if (xp->i_ump->um_fstype == UFS1)
|
||||||
BLK_SNAP);
|
error = expunge_ufs1(vp, xp, fs, snapacct_ufs1,
|
||||||
else
|
BLK_SNAP);
|
||||||
error = expunge_ufs2(vp, xp, fs, snapacct_ufs2,
|
else
|
||||||
BLK_SNAP);
|
error = expunge_ufs2(vp, xp, fs, snapacct_ufs2,
|
||||||
if (error == 0 && xp->i_ffs_effnlink == 0)
|
BLK_SNAP);
|
||||||
error = ffs_freefile(copy_fs, vp,
|
if (error == 0 && xp->i_ffs_effnlink == 0)
|
||||||
xp->i_number, xp->i_mode);
|
error = ffs_freefile(copy_fs, vp,
|
||||||
|
xp->i_number, xp->i_mode);
|
||||||
|
UFS_WAPBL_END(mp);
|
||||||
|
}
|
||||||
if (error) {
|
if (error) {
|
||||||
fs->fs_snapinum[snaploc] = 0;
|
fs->fs_snapinum[snaploc] = 0;
|
||||||
goto done;
|
goto done;
|
||||||
@ -600,10 +624,15 @@ out1:
|
|||||||
* blocks marked as used in the snapshot bitmaps. Also, collect
|
* blocks marked as used in the snapshot bitmaps. Also, collect
|
||||||
* the list of allocated blocks in i_snapblklist.
|
* the list of allocated blocks in i_snapblklist.
|
||||||
*/
|
*/
|
||||||
if (ip->i_ump->um_fstype == UFS1)
|
if ((error = UFS_WAPBL_BEGIN(mp)) == 0) {
|
||||||
error = expunge_ufs1(vp, ip, copy_fs, mapacct_ufs1, BLK_SNAP);
|
if (ip->i_ump->um_fstype == UFS1)
|
||||||
else
|
error = expunge_ufs1(vp, ip, copy_fs, mapacct_ufs1,
|
||||||
error = expunge_ufs2(vp, ip, copy_fs, mapacct_ufs2, BLK_SNAP);
|
BLK_SNAP);
|
||||||
|
else
|
||||||
|
error = expunge_ufs2(vp, ip, copy_fs, mapacct_ufs2,
|
||||||
|
BLK_SNAP);
|
||||||
|
UFS_WAPBL_END(mp);
|
||||||
|
}
|
||||||
if (error) {
|
if (error) {
|
||||||
fs->fs_snapinum[snaploc] = 0;
|
fs->fs_snapinum[snaploc] = 0;
|
||||||
FREE(snapblklist, M_UFSMNT);
|
FREE(snapblklist, M_UFSMNT);
|
||||||
@ -642,8 +671,15 @@ out1:
|
|||||||
ffs_csum_swap(space, space, fs->fs_cssize);
|
ffs_csum_swap(space, space, fs->fs_cssize);
|
||||||
}
|
}
|
||||||
#endif
|
#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++) {
|
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) {
|
if (error) {
|
||||||
brelse(nbp, 0);
|
brelse(nbp, 0);
|
||||||
fs->fs_snapinum[snaploc] = 0;
|
fs->fs_snapinum[snaploc] = 0;
|
||||||
@ -654,6 +690,27 @@ out1:
|
|||||||
space = (char *)space + fs->fs_bsize;
|
space = (char *)space + fs->fs_bsize;
|
||||||
bawrite(nbp);
|
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
|
* As this is the newest list, it is the most inclusive, so
|
||||||
* should replace the previous list. If this is the first snapshot
|
* should replace the previous list. If this is the first snapshot
|
||||||
@ -667,16 +724,24 @@ out1:
|
|||||||
si->si_gen++;
|
si->si_gen++;
|
||||||
mutex_exit(&si->si_lock);
|
mutex_exit(&si->si_lock);
|
||||||
done:
|
done:
|
||||||
|
if (mp->mnt_wapbl)
|
||||||
|
copy_fs->fs_flags &= ~FS_DOWAPBL;
|
||||||
free(copy_fs->fs_csp, M_UFSMNT);
|
free(copy_fs->fs_csp, M_UFSMNT);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = bread(vp, lblkno(fs, fs->fs_sblockloc), fs->fs_bsize,
|
error = UFS_WAPBL_BEGIN(mp);
|
||||||
KERNCRED, 0, &nbp);
|
if (!error) {
|
||||||
if (error) {
|
error = bread(vp, lblkno(fs, fs->fs_sblockloc),
|
||||||
brelse(nbp, 0);
|
fs->fs_bsize, KERNCRED, B_MODIFY, &nbp);
|
||||||
fs->fs_snapinum[snaploc] = 0;
|
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);
|
if (error)
|
||||||
bawrite(nbp);
|
fs->fs_snapinum[snaploc] = 0;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
/*
|
/*
|
||||||
@ -688,6 +753,23 @@ out:
|
|||||||
error = VOP_PUTPAGES(vp, 0, 0,
|
error = VOP_PUTPAGES(vp, 0, 0,
|
||||||
PGO_ALLPAGES|PGO_CLEANIT|PGO_SYNCIO|PGO_FREE);
|
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)
|
if (sbbuf)
|
||||||
free(sbbuf, M_UFSMNT);
|
free(sbbuf, M_UFSMNT);
|
||||||
if (fs->fs_active != 0) {
|
if (fs->fs_active != 0) {
|
||||||
@ -695,9 +777,12 @@ out:
|
|||||||
fs->fs_active = 0;
|
fs->fs_active = 0;
|
||||||
}
|
}
|
||||||
mp->mnt_flag = flag;
|
mp->mnt_flag = flag;
|
||||||
if (error)
|
if (error) {
|
||||||
(void) ffs_truncate(vp, (off_t)0, 0, NOCRED);
|
if (!UFS_WAPBL_BEGIN(mp)) {
|
||||||
else
|
(void) ffs_truncate(vp, (off_t)0, 0, NOCRED);
|
||||||
|
UFS_WAPBL_END(mp);
|
||||||
|
}
|
||||||
|
} else
|
||||||
vref(vp);
|
vref(vp);
|
||||||
if (snapshot_locked)
|
if (snapshot_locked)
|
||||||
mutex_exit(&si->si_snaplock);
|
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),
|
error = ffs_balloc(snapvp, lblktosize(fs, (off_t)lbn),
|
||||||
fs->fs_bsize, KERNCRED, 0, &bp);
|
fs->fs_bsize, KERNCRED, 0, &bp);
|
||||||
if (! error)
|
if (! error)
|
||||||
error = readfsblk(snapvp, bp->b_data, lbn);
|
error = rwfsblk(snapvp, B_READ, bp->b_data, lbn);
|
||||||
}
|
}
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
@ -908,7 +993,7 @@ indiracct_ufs1(struct vnode *snapvp, struct vnode *cancelvp, int level,
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
if ((bp->b_oflags & (BO_DONE | BO_DELWRI)) == 0 && (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);
|
brelse(bp, 0);
|
||||||
return (error);
|
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),
|
error = ffs_balloc(snapvp, lblktosize(fs, (off_t)lbn),
|
||||||
fs->fs_bsize, KERNCRED, 0, &bp);
|
fs->fs_bsize, KERNCRED, 0, &bp);
|
||||||
if (! error)
|
if (! error)
|
||||||
error = readfsblk(snapvp, bp->b_data, lbn);
|
error = rwfsblk(snapvp, B_READ, bp->b_data, lbn);
|
||||||
}
|
}
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
@ -1166,7 +1251,7 @@ indiracct_ufs2(struct vnode *snapvp, struct vnode *cancelvp, int level,
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
if ((bp->b_oflags & (BO_DONE | BO_DELWRI)) == 0 && (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);
|
brelse(bp, 0);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
@ -1588,8 +1673,12 @@ retry:
|
|||||||
}
|
}
|
||||||
DIP_ADD(ip, blocks, btodb(size));
|
DIP_ADD(ip, blocks, btodb(size));
|
||||||
ip->i_flag |= IN_CHANGE | IN_UPDATE;
|
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);
|
mutex_exit(&si->si_snaplock);
|
||||||
return (1);
|
return (error == 0);
|
||||||
}
|
}
|
||||||
if (lbn >= NDADDR)
|
if (lbn >= NDADDR)
|
||||||
brelse(ibp, 0);
|
brelse(ibp, 0);
|
||||||
@ -1610,7 +1699,7 @@ retry:
|
|||||||
mutex_exit(&si->si_lock);
|
mutex_exit(&si->si_lock);
|
||||||
if (saved_data == NULL) {
|
if (saved_data == NULL) {
|
||||||
saved_data = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK);
|
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) {
|
if (error) {
|
||||||
free(saved_data, M_UFSMNT);
|
free(saved_data, M_UFSMNT);
|
||||||
saved_data = NULL;
|
saved_data = NULL;
|
||||||
@ -1619,6 +1708,8 @@ retry:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
error = wrsnapblk(vp, saved_data, lbn);
|
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);
|
mutex_enter(&si->si_lock);
|
||||||
if (error)
|
if (error)
|
||||||
break;
|
break;
|
||||||
@ -1862,12 +1953,17 @@ ffs_copyonwrite(void *v, struct buf *bp, bool data_valid)
|
|||||||
return 0;
|
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.
|
* By doing this check we avoid several potential deadlocks.
|
||||||
*/
|
*/
|
||||||
fs = ip->i_fs;
|
fs = ip->i_fs;
|
||||||
ns = UFS_FSNEEDSWAP(fs);
|
ns = UFS_FSNEEDSWAP(fs);
|
||||||
lbn = fragstoblks(fs, dbtofsb(fs, bp->b_blkno));
|
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;
|
snapblklist = si->si_snapblklist;
|
||||||
upper = si->si_snapblklist[0] - 1;
|
upper = si->si_snapblklist[0] - 1;
|
||||||
lower = 1;
|
lower = 1;
|
||||||
@ -1987,7 +2083,7 @@ retry:
|
|||||||
mutex_exit(&si->si_lock);
|
mutex_exit(&si->si_lock);
|
||||||
if (saved_data == NULL) {
|
if (saved_data == NULL) {
|
||||||
saved_data = malloc(fs->fs_bsize, M_UFSMNT, M_WAITOK);
|
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) {
|
if (error) {
|
||||||
free(saved_data, M_UFSMNT);
|
free(saved_data, M_UFSMNT);
|
||||||
saved_data = NULL;
|
saved_data = NULL;
|
||||||
@ -1996,6 +2092,8 @@ retry:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
error = wrsnapblk(vp, saved_data, lbn);
|
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);
|
mutex_enter(&si->si_lock);
|
||||||
if (error)
|
if (error)
|
||||||
break;
|
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);
|
error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
|
||||||
if (error)
|
if (error)
|
||||||
break;
|
break;
|
||||||
brelse(bp, BC_INVAL | BC_NOCACHE);
|
brelse(bp, BC_AGE);
|
||||||
}
|
}
|
||||||
if (bp != NULL)
|
if (bp != NULL)
|
||||||
brelse(bp, BC_INVAL | BC_NOCACHE);
|
brelse(bp, BC_AGE);
|
||||||
|
|
||||||
mutex_exit(&si->si_snaplock);
|
mutex_exit(&si->si_snaplock);
|
||||||
fstrans_done(vp->v_mount);
|
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
|
* Read or write the specified block of the filesystem vp resides on
|
||||||
* from the disk bypassing the buffer cache.
|
* from or to the disk bypassing the buffer cache.
|
||||||
*/
|
*/
|
||||||
static int
|
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;
|
int error;
|
||||||
struct inode *ip = VTOI(vp);
|
struct inode *ip = VTOI(vp);
|
||||||
@ -2093,7 +2191,7 @@ readfsblk(struct vnode *vp, void *data, ufs2_daddr_t lbn)
|
|||||||
struct buf *nbp;
|
struct buf *nbp;
|
||||||
|
|
||||||
nbp = getiobuf(NULL, true);
|
nbp = getiobuf(NULL, true);
|
||||||
nbp->b_flags = B_READ;
|
nbp->b_flags = flags;
|
||||||
nbp->b_bcount = nbp->b_bufsize = fs->fs_bsize;
|
nbp->b_bcount = nbp->b_bufsize = fs->fs_bsize;
|
||||||
nbp->b_error = 0;
|
nbp->b_error = 0;
|
||||||
nbp->b_data = data;
|
nbp->b_data = data;
|
||||||
@ -2111,6 +2209,34 @@ readfsblk(struct vnode *vp, void *data, ufs2_daddr_t lbn)
|
|||||||
return error;
|
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.
|
* Write the specified block to a snapshot.
|
||||||
*/
|
*/
|
||||||
|
@ -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.
|
* Copyright (c) 2008 The NetBSD Foundation, Inc.
|
||||||
@ -61,7 +61,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__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)
|
#if defined(_KERNEL_OPT)
|
||||||
#include "opt_ffs.h"
|
#include "opt_ffs.h"
|
||||||
@ -160,7 +160,7 @@ struct vfsops ffs_vfsops = {
|
|||||||
static const struct genfs_ops ffs_genfsops = {
|
static const struct genfs_ops ffs_genfsops = {
|
||||||
.gop_size = ffs_gop_size,
|
.gop_size = ffs_gop_size,
|
||||||
.gop_alloc = ufs_gop_alloc,
|
.gop_alloc = ufs_gop_alloc,
|
||||||
.gop_write = genfs_gop_write,
|
.gop_write = ffs_gop_write,
|
||||||
.gop_markupdate = ufs_gop_markupdate,
|
.gop_markupdate = ufs_gop_markupdate,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1291,14 +1291,6 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
|
|||||||
goto out;
|
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)
|
if (ronly == 0 && fs->fs_snapinum[0] != 0)
|
||||||
ffs_snapshot_mount(mp);
|
ffs_snapshot_mount(mp);
|
||||||
|
|
||||||
|
@ -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.
|
* Copyright (c) 2008 The NetBSD Foundation, Inc.
|
||||||
@ -61,7 +61,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__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)
|
#if defined(_KERNEL_OPT)
|
||||||
#include "opt_ffs.h"
|
#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
|
int
|
||||||
ffs_openextattr(void *v)
|
ffs_openextattr(void *v)
|
||||||
{
|
{
|
||||||
|
@ -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
|
* Copyright (c) 1993
|
||||||
@ -32,7 +32,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__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
|
#ifdef LFS_READWRITE
|
||||||
#define FS struct lfs
|
#define FS struct lfs
|
||||||
@ -337,7 +337,8 @@ WRITE(void *v)
|
|||||||
if (flags & B_SYNC) {
|
if (flags & B_SYNC) {
|
||||||
mutex_enter(&vp->v_interlock);
|
mutex_enter(&vp->v_interlock);
|
||||||
VOP_PUTPAGES(vp, trunc_page(osize & fs->fs_bmask),
|
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) {
|
if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
|
||||||
mutex_enter(&vp->v_interlock);
|
mutex_enter(&vp->v_interlock);
|
||||||
error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16,
|
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)
|
if (error)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -442,14 +444,14 @@ WRITE(void *v)
|
|||||||
mutex_enter(&vp->v_interlock);
|
mutex_enter(&vp->v_interlock);
|
||||||
error = VOP_PUTPAGES(vp, trunc_page(origoff & fs->fs_bmask),
|
error = VOP_PUTPAGES(vp, trunc_page(origoff & fs->fs_bmask),
|
||||||
round_page(blkroundup(fs, uio->uio_offset)),
|
round_page(blkroundup(fs, uio->uio_offset)),
|
||||||
PGO_CLEANIT | PGO_SYNCIO);
|
PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
|
||||||
}
|
}
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
bcache:
|
bcache:
|
||||||
mutex_enter(&vp->v_interlock);
|
mutex_enter(&vp->v_interlock);
|
||||||
VOP_PUTPAGES(vp, trunc_page(origoff), round_page(origoff + resid),
|
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) {
|
while (uio->uio_resid > 0) {
|
||||||
lbn = lblkno(fs, uio->uio_offset);
|
lbn = lblkno(fs, uio->uio_offset);
|
||||||
blkoffset = blkoff(fs, uio->uio_offset);
|
blkoffset = blkoff(fs, uio->uio_offset);
|
||||||
|
@ -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. */
|
/* 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_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_LOCKED 0x040 /* fault data structures are locked [get] */
|
||||||
#define PGO_BUSYFAIL 0x080 /* fail if a page is busy [put] */
|
#define PGO_BUSYFAIL 0x080 /* fail if a page is busy [put] */
|
||||||
#define PGO_OVERWRITE 0x200 /* pages will be overwritten before unlocked */
|
#define PGO_OVERWRITE 0x200 /* pages will be overwritten before unlocked */
|
||||||
|
Loading…
Reference in New Issue
Block a user