Add snapshots to the fast filesystem. Most of the changes support

the gating of system calls that cause modifications to the underlying
filesystem. The gating can be enabled by any filesystem that needs
to consistently suspend operations by adding the vop_stdgetwritemount
to their set of vnops. Once gating is enabled, the function
vfs_write_suspend stops all new write operations to a filesystem,
allows any filesystem modifying system calls already in progress
to complete, then sync's the filesystem to disk and returns. The
function vfs_write_resume allows the suspended write operations to
begin again. Gating is not added by default for all filesystems as
for SMP systems it adds two extra locks to such critical kernel
paths as the write system call. Thus, gating should only be added
as needed.

Details on the use and current status of snapshots in FFS can be
found in /sys/ufs/ffs/README.snapshot so for brevity and timelyness
is not included here. Unless and until you create a snapshot file,
these changes should have no effect on your system (famous last words).
This commit is contained in:
Kirk McKusick 2000-07-11 22:07:57 +00:00
parent aa02fb5729
commit f2a2857bb3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=62976
52 changed files with 2541 additions and 451 deletions

View File

@ -247,6 +247,7 @@ fd_revoke(p, fd)
struct filedesc *fdp = p->p_fd;
struct file *fp;
struct vnode *vp;
struct mount *mp;
struct vattr vattr;
int error, *retval;
@ -271,8 +272,11 @@ fd_revoke(p, fd)
(error = suser(p)) != 0)
goto out;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
goto out;
if (vcount(vp) > 1)
VOP_REVOKE(vp, REVOKEALL);
vn_finished_write(mp);
out:
vrele(vp);
return error;

View File

@ -906,6 +906,8 @@ ufs/ffs/ffs_balloc.c optional ffs
ufs/ffs/ffs_balloc.c optional mfs
ufs/ffs/ffs_inode.c optional ffs
ufs/ffs/ffs_inode.c optional mfs
ufs/ffs/ffs_snapshot.c optional ffs
ufs/ffs/ffs_snapshot.c optional mfs
ufs/ffs/ffs_softdep.c optional softupdates
ufs/ffs/ffs_softdep_stub.c standard
ufs/ffs/ffs_subr.c optional ffs

View File

@ -276,7 +276,6 @@ vnstrategy(struct bio *bp)
int unit;
struct vn_softc *vn;
int error;
int isvplocked = 0;
unit = dkunit(bp->bio_dev);
vn = bp->bio_dev->si_drv1;
@ -360,6 +359,7 @@ vnstrategy(struct bio *bp)
*/
struct uio auio;
struct iovec aiov;
struct mount *mp;
bzero(&auio, sizeof(auio));
@ -375,18 +375,18 @@ vnstrategy(struct bio *bp)
auio.uio_rw = UIO_WRITE;
auio.uio_resid = bp->bio_bcount;
auio.uio_procp = curproc;
if (!VOP_ISLOCKED(vn->sc_vp, NULL)) {
isvplocked = 1;
if (VOP_ISLOCKED(vn->sc_vp, NULL))
vprint("unexpected vn driver lock", vn->sc_vp);
if (bp->bio_cmd == BIO_READ) {
vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, curproc);
}
if(bp->bio_cmd == BIO_READ)
error = VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred);
else
} else {
(void) vn_start_write(vn->sc_vp, &mp, V_WAIT);
vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, curproc);
error = VOP_WRITE(vn->sc_vp, &auio, 0, vn->sc_cred);
if (isvplocked) {
VOP_UNLOCK(vn->sc_vp, 0, curproc);
isvplocked = 0;
vn_finished_write(mp);
}
VOP_UNLOCK(vn->sc_vp, 0, curproc);
bp->bio_resid = auio.uio_resid;
if (error) {

View File

@ -383,6 +383,8 @@ fdesc_setattr(ap)
{
struct filedesc *fdp = ap->a_p->p_fd;
struct vattr *vap = ap->a_vap;
struct vnode *vp;
struct mount *mp;
struct file *fp;
unsigned fd;
int error;
@ -403,8 +405,11 @@ fdesc_setattr(ap)
switch (fp->f_type) {
case DTYPE_FIFO:
case DTYPE_VNODE:
error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap,
ap->a_cred, ap->a_p);
vp = (struct vnode *)fp->f_data;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
error = VOP_SETATTR(vp, ap->a_vap, ap->a_cred, ap->a_p);
vn_finished_write(mp);
break;
default:

View File

@ -107,6 +107,7 @@ static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
{ &vop_open_desc, (vop_t *) fifo_open },
{ &vop_pathconf_desc, (vop_t *) fifo_pathconf },
{ &vop_poll_desc, (vop_t *) fifo_poll },
{ &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount },
{ &vop_print_desc, (vop_t *) fifo_print },
{ &vop_read_desc, (vop_t *) fifo_read },
{ &vop_readdir_desc, (vop_t *) fifo_badop },

View File

@ -88,6 +88,7 @@ static struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
{ &vop_open_desc, (vop_t *) spec_open },
{ &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
{ &vop_poll_desc, (vop_t *) spec_poll },
{ &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount },
{ &vop_print_desc, (vop_t *) spec_print },
{ &vop_read_desc, (vop_t *) spec_read },
{ &vop_readdir_desc, (vop_t *) vop_panic },
@ -415,16 +416,29 @@ spec_strategy(ap)
struct buf *bp;
struct vnode *vp;
struct mount *mp;
int error;
bp = ap->a_bp;
if ((bp->b_iocmd == BIO_WRITE) && (LIST_FIRST(&bp->b_dep)) != NULL)
buf_start(bp);
vp = ap->a_vp;
if ((bp->b_iocmd == BIO_WRITE)) {
if (vp->v_mount != NULL &&
(vp->v_mount->mnt_kern_flag & MNTK_SUSPENDED) != 0)
panic("spec_strategy: bad I/O");
if (LIST_FIRST(&bp->b_dep) != NULL)
buf_start(bp);
if ((vp->v_flag & VCOPYONWRITE) &&
(error = VOP_COPYONWRITE(vp, bp)) != 0 &&
error != EOPNOTSUPP) {
bp->b_io.bio_error = error;
bp->b_io.bio_flags |= BIO_ERROR;
biodone(&bp->b_io);
return (0);
}
}
/*
* Collect statistics on synchronous and asynchronous read
* and write counts for disks that have associated filesystems.
*/
vp = ap->a_vp;
if (vn_isdisk(vp, NULL) && (mp = vp->v_specmountpoint) != NULL) {
if (bp->b_iocmd == BIO_WRITE) {
if (bp->b_lock.lk_lockholder == LK_KERNPROC)

View File

@ -747,6 +747,7 @@ union_copyup(un, docopy, cred, p)
struct proc *p;
{
int error;
struct mount *mp;
struct vnode *lvp, *uvp;
/*
@ -759,9 +760,12 @@ union_copyup(un, docopy, cred, p)
if (error)
return (error);
error = union_vn_create(&uvp, un, p);
if (error)
if ((error = vn_start_write(un->un_dirvp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
if ((error = union_vn_create(&uvp, un, p)) != 0) {
vn_finished_write(mp);
return (error);
}
lvp = un->un_lowervp;
@ -785,6 +789,7 @@ union_copyup(un, docopy, cred, p)
}
VOP_UNLOCK(uvp, 0, p);
vn_finished_write(mp);
union_newupper(un, uvp);
KASSERT(uvp->v_usecount > 0, ("copy: uvp refcount 0: %d", uvp->v_usecount));
union_vn_close(uvp, FWRITE, cred, p);
@ -910,11 +915,15 @@ union_mkshadow(um, dvp, cnp, vpp)
struct vattr va;
struct proc *p = cnp->cn_proc;
struct componentname cn;
struct mount *mp;
error = union_relookup(um, dvp, vpp, cnp, &cn,
cnp->cn_nameptr, cnp->cn_namelen);
if (error)
if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
if ((error = union_relookup(um, dvp, vpp, cnp, &cn,
cnp->cn_nameptr, cnp->cn_namelen)) != 0) {
vn_finished_write(mp);
return (error);
}
if (*vpp) {
if (cn.cn_flags & HASBUF) {
@ -925,6 +934,7 @@ union_mkshadow(um, dvp, cnp, vpp)
vrele(*vpp);
else
vput(*vpp);
vn_finished_write(mp);
*vpp = NULLVP;
return (EEXIST);
}
@ -950,6 +960,7 @@ union_mkshadow(um, dvp, cnp, vpp)
cn.cn_flags &= ~HASBUF;
}
/*vput(dvp);*/
vn_finished_write(mp);
return (error);
}
@ -973,10 +984,15 @@ union_mkwhiteout(um, dvp, cnp, path)
struct proc *p = cnp->cn_proc;
struct vnode *wvp;
struct componentname cn;
struct mount *mp;
error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path));
if (error)
if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path));
if (error) {
vn_finished_write(mp);
return (error);
}
if (wvp) {
if (cn.cn_flags & HASBUF) {
@ -987,6 +1003,7 @@ union_mkwhiteout(um, dvp, cnp, path)
vrele(wvp);
else
vput(wvp);
vn_finished_write(mp);
return (EEXIST);
}
@ -998,6 +1015,7 @@ union_mkwhiteout(um, dvp, cnp, path)
zfree(namei_zone, cn.cn_pnbuf);
cn.cn_flags &= ~HASBUF;
}
vn_finished_write(mp);
return (error);
}

View File

@ -93,6 +93,7 @@ static int union_print __P((struct vop_print_args *ap));
static int union_read __P((struct vop_read_args *ap));
static int union_readdir __P((struct vop_readdir_args *ap));
static int union_readlink __P((struct vop_readlink_args *ap));
static int union_getwritemount __P((struct vop_getwritemount_args *ap));
static int union_reclaim __P((struct vop_reclaim_args *ap));
static int union_remove __P((struct vop_remove_args *ap));
static int union_rename __P((struct vop_rename_args *ap));
@ -1681,6 +1682,20 @@ union_readlink(ap)
return (error);
}
static int
union_getwritemount(ap)
struct vop_getwritemount_args /* {
struct vnode *a_vp;
struct mount **a_mpp;
} */ *ap;
{
struct vnode *vp = UPPERVP(ap->a_vp);
if (vp == NULL)
panic("union: missing upper layer in getwritemount");
return(VOP_GETWRITEMOUNT(vp, ap->a_mpp));
}
/*
* union_inactive:
*
@ -1963,6 +1978,7 @@ static struct vnodeopv_entry_desc union_vnodeop_entries[] = {
{ &vop_read_desc, (vop_t *) union_read },
{ &vop_readdir_desc, (vop_t *) union_readdir },
{ &vop_readlink_desc, (vop_t *) union_readlink },
{ &vop_getwritemount_desc, (vop_t *) union_getwritemount },
{ &vop_reclaim_desc, (vop_t *) union_reclaim },
{ &vop_remove_desc, (vop_t *) union_remove },
{ &vop_rename_desc, (vop_t *) union_rename },

View File

@ -47,6 +47,7 @@
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/resourcevar.h>
#include <sys/stat.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
@ -115,7 +116,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
struct indir a[NIADDR+1], *xap;
ufs_daddr_t daddr;
long metalbn;
int error, maxrun, num;
int error, num, maxrun = 0;
ip = VTOI(vp);
mp = vp->v_mount;
@ -127,6 +128,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
#endif
if (runp) {
maxrun = mp->mnt_iosize_max / mp->mnt_stat.f_iosize - 1;
*runp = 0;
}
@ -134,7 +136,6 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
*runb = 0;
}
maxrun = mp->mnt_iosize_max / mp->mnt_stat.f_iosize - 1;
xap = ap == NULL ? a : ap;
if (!nump)
@ -146,9 +147,12 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
num = *nump;
if (num == 0) {
*bnp = blkptrtodb(ump, ip->i_db[bn]);
if (*bnp == 0)
*bnp = -1;
else if (runp) {
if (*bnp == 0) {
if (ip->i_flags & SF_SNAPSHOT)
*bnp = blkptrtodb(ump, bn * ump->um_seqinc);
else
*bnp = -1;
} else if (runp) {
daddr_t bnb = bn;
for (++bn; bn < NDADDR && *runp < maxrun &&
is_sequential(ump, ip->i_db[bn - 1], ip->i_db[bn]);
@ -226,8 +230,13 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
if (bp)
bqrelse(bp);
daddr = blkptrtodb(ump, daddr);
*bnp = daddr == 0 ? -1 : daddr;
*bnp = blkptrtodb(ump, daddr);
if (*bnp == 0) {
if (ip->i_flags & SF_SNAPSHOT)
*bnp = blkptrtodb(ump, bn * ump->um_seqinc);
else
*bnp = -1;
}
return (0);
}

View File

@ -84,6 +84,7 @@ struct inode {
struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
u_quad_t i_modrev; /* Revision level for NFS lease. */
struct lockf *i_lockf;/* Head of byte-level lock list. */
struct inode *i_copyonwrite; /* copy-on-write list */
/*
* Side effects; used during directory lookup.
*/

View File

@ -47,6 +47,7 @@
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/resourcevar.h>
#include <sys/stat.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
@ -115,7 +116,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
struct indir a[NIADDR+1], *xap;
ufs_daddr_t daddr;
long metalbn;
int error, maxrun, num;
int error, num, maxrun = 0;
ip = VTOI(vp);
mp = vp->v_mount;
@ -127,6 +128,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
#endif
if (runp) {
maxrun = mp->mnt_iosize_max / mp->mnt_stat.f_iosize - 1;
*runp = 0;
}
@ -134,7 +136,6 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
*runb = 0;
}
maxrun = mp->mnt_iosize_max / mp->mnt_stat.f_iosize - 1;
xap = ap == NULL ? a : ap;
if (!nump)
@ -146,9 +147,12 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
num = *nump;
if (num == 0) {
*bnp = blkptrtodb(ump, ip->i_db[bn]);
if (*bnp == 0)
*bnp = -1;
else if (runp) {
if (*bnp == 0) {
if (ip->i_flags & SF_SNAPSHOT)
*bnp = blkptrtodb(ump, bn * ump->um_seqinc);
else
*bnp = -1;
} else if (runp) {
daddr_t bnb = bn;
for (++bn; bn < NDADDR && *runp < maxrun &&
is_sequential(ump, ip->i_db[bn - 1], ip->i_db[bn]);
@ -226,8 +230,13 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
if (bp)
bqrelse(bp);
daddr = blkptrtodb(ump, daddr);
*bnp = daddr == 0 ? -1 : daddr;
*bnp = blkptrtodb(ump, daddr);
if (*bnp == 0) {
if (ip->i_flags & SF_SNAPSHOT)
*bnp = blkptrtodb(ump, bn * ump->um_seqinc);
else
*bnp = -1;
}
return (0);
}

View File

@ -84,6 +84,7 @@ struct inode {
struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
u_quad_t i_modrev; /* Revision level for NFS lease. */
struct lockf *i_lockf;/* Head of byte-level lock list. */
struct inode *i_copyonwrite; /* copy-on-write list */
/*
* Side effects; used during directory lookup.
*/

View File

@ -457,7 +457,8 @@ ktrwrite(vp, kth, uio)
{
struct uio auio;
struct iovec aiov[2];
register struct proc *p = curproc; /* XXX */
struct proc *p = curproc; /* XXX */
struct mount *mp;
int error;
if (vp == NULL)
@ -479,6 +480,7 @@ ktrwrite(vp, kth, uio)
if (uio != NULL)
kth->ktr_len += uio->uio_resid;
}
vn_start_write(vp, &mp, V_WAIT);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
(void)VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, p->p_ucred);
@ -487,6 +489,7 @@ ktrwrite(vp, kth, uio)
error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, p->p_ucred);
}
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
if (!error)
return;
/*

View File

@ -1599,6 +1599,7 @@ coredump(p)
struct nameidata nd;
struct vattr vattr;
int error, error1, flags;
struct mount *mp;
char *name; /* name of corefile */
off_t limit;
@ -1619,6 +1620,7 @@ coredump(p)
if (limit == 0)
return 0;
restart:
name = expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid);
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name, p);
flags = O_CREAT | FWRITE | O_NOFOLLOW;
@ -1628,6 +1630,14 @@ coredump(p)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
if (vn_start_write(vp, &mp, V_NOWAIT) != 0) {
VOP_UNLOCK(vp, 0, p);
if ((error = vn_close(vp, FWRITE, cred, p)) != 0)
return (error);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
/* Don't dump to non-regular files or files with links. */
if (vp->v_type != VREG ||
@ -1647,6 +1657,7 @@ coredump(p)
out:
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
error1 = vn_close(vp, FWRITE, cred, p);
if (error == 0)
error = error1;

View File

@ -133,13 +133,19 @@ cttywrite(dev, uio, flag)
{
struct proc *p = uio->uio_procp;
struct vnode *ttyvp = cttyvp(uio->uio_procp);
struct mount *mp;
int error;
if (ttyvp == NULL)
return (EIO);
mp = NULL;
if (ttyvp->v_type != VCHR &&
(error = vn_start_write(ttyvp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, p);
error = VOP_WRITE(ttyvp, uio, flag, NOCRED);
VOP_UNLOCK(ttyvp, 0, p);
vn_finished_write(mp);
return (error);
}

View File

@ -538,7 +538,8 @@ unp_bind(unp, nam, p)
struct proc *p;
{
struct sockaddr_un *soun = (struct sockaddr_un *)nam;
register struct vnode *vp;
struct vnode *vp;
struct mount *mp;
struct vattr vattr;
int error, namelen;
struct nameidata nd;
@ -552,6 +553,7 @@ unp_bind(unp, nam, p)
return EINVAL;
strncpy(buf, soun->sun_path, namelen);
buf[namelen] = 0; /* null-terminate the string */
restart:
NDINIT(&nd, CREATE, NOFOLLOW | LOCKPARENT, UIO_SYSSPACE,
buf, p);
/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
@ -559,14 +561,19 @@ unp_bind(unp, nam, p)
if (error)
return (error);
vp = nd.ni_vp;
if (vp != NULL) {
if (vp != NULL || vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
vrele(vp);
return (EADDRINUSE);
if (vp != NULL) {
vrele(vp);
return (EADDRINUSE);
}
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VATTR_NULL(&vattr);
vattr.va_type = VSOCK;
@ -582,6 +589,7 @@ unp_bind(unp, nam, p)
unp->unp_vnode = vp;
unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam, 1);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (0);
}

View File

@ -1165,6 +1165,8 @@ brelse(struct buf * bp)
BUF_UNLOCK(bp);
bp->b_flags &= ~(B_ASYNC | B_NOCACHE | B_AGE | B_RELBUF);
bp->b_ioflags &= ~BIO_ORDERED;
if ((bp->b_flags & B_DELWRI) == 0 && (bp->b_xflags & BX_VNDIRTY))
panic("brelse: not dirty");
splx(s);
}
@ -1225,6 +1227,8 @@ bqrelse(struct buf * bp)
BUF_UNLOCK(bp);
bp->b_flags &= ~(B_ASYNC | B_NOCACHE | B_AGE | B_RELBUF);
bp->b_ioflags &= ~BIO_ORDERED;
if ((bp->b_flags & B_DELWRI) == 0 && (bp->b_xflags & BX_VNDIRTY))
panic("bqrelse: not dirty");
splx(s);
}
@ -1420,7 +1424,7 @@ getnewbuf(int slpflag, int slptimeo, int size, int maxsize)
int isspecial;
static int flushingbufs;
if (curproc && (curproc->p_flag & P_BUFEXHAUST) == 0)
if (curproc && (curproc->p_flag & (P_COWINPROGRESS|P_BUFEXHAUST)) == 0)
isspecial = 0;
else
isspecial = 1;

View File

@ -500,6 +500,21 @@ vop_noislocked(ap)
return (lockstatus(vp->v_vnlock, ap->a_p));
}
/*
* Return our mount point, as we will take charge of the writes.
*/
int
vop_stdgetwritemount(ap)
struct vop_getwritemount_args /* {
struct vnode *a_vp;
struct mount **a_mpp;
} */ *ap;
{
*(ap->a_mpp) = ap->a_vp->v_mount;
return (0);
}
/*
* vfs default ops
* used to fill the vfs fucntion table to get reasonable default return values.

View File

@ -453,6 +453,7 @@ getnewvnode(tag, mp, vops, vpp)
int s, count;
struct proc *p = curproc; /* XXX */
struct vnode *vp = NULL;
struct mount *vnmp;
vm_object_t object;
/*
@ -491,7 +492,14 @@ getnewvnode(tag, mp, vops, vpp)
vp = NULL;
continue;
}
break;
/*
* Skip over it if its filesystem is being suspended.
*/
if (vn_start_write(vp, &vnmp, V_NOWAIT) == 0)
break;
simple_unlock(&vp->v_interlock);
TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
vp = NULL;
}
if (vp) {
vp->v_flag |= VDOOMED;
@ -504,6 +512,7 @@ getnewvnode(tag, mp, vops, vpp)
} else {
simple_unlock(&vp->v_interlock);
}
vn_finished_write(vnmp);
#ifdef INVARIANTS
{
@ -515,6 +524,8 @@ getnewvnode(tag, mp, vops, vpp)
if (vp->v_numoutput)
panic("Clean vnode has pending I/O's");
splx(s);
if (vp->v_writecount != 0)
panic("Non-zero write count");
}
#endif
vp->v_flag = 0;
@ -523,7 +534,6 @@ getnewvnode(tag, mp, vops, vpp)
vp->v_cstart = 0;
vp->v_clen = 0;
vp->v_socket = 0;
vp->v_writecount = 0; /* XXX */
} else {
simple_unlock(&vnode_free_list_slock);
vp = (struct vnode *) zalloc(vnode_zone);
@ -946,6 +956,7 @@ sched_sync(void)
{
struct synclist *slp;
struct vnode *vp;
struct mount *mp;
long starttime;
int s;
struct proc *p = updateproc;
@ -970,10 +981,12 @@ sched_sync(void)
splx(s);
while ((vp = LIST_FIRST(slp)) != NULL) {
if (VOP_ISLOCKED(vp, NULL) == 0) {
if (VOP_ISLOCKED(vp, NULL) == 0 &&
vn_start_write(vp, &mp, V_NOWAIT) == 0) {
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
(void) VOP_FSYNC(vp, p->p_ucred, MNT_LAZY, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
}
s = splbio();
if (LIST_FIRST(slp) == vp) {
@ -1386,6 +1399,7 @@ vrele(vp)
struct proc *p = curproc; /* XXX */
KASSERT(vp != NULL, ("vrele: null vp"));
KASSERT(vp->v_writecount < vp->v_usecount, ("vrele: missed vn_close"));
simple_lock(&vp->v_interlock);
@ -1427,6 +1441,7 @@ vput(vp)
struct proc *p = curproc; /* XXX */
KASSERT(vp != NULL, ("vput: null vp"));
KASSERT(vp->v_writecount < vp->v_usecount, ("vput: missed vn_close"));
simple_lock(&vp->v_interlock);
@ -1632,6 +1647,8 @@ vclean(vp, flags, p)
* If the flush fails, just toss the buffers.
*/
if (flags & DOCLOSE) {
if (TAILQ_FIRST(&vp->v_dirtyblkhd) != NULL)
(void) vn_write_suspend_wait(vp, V_WAIT);
if (vinvalbuf(vp, V_SAVE, NOCRED, p, 0, 0) != 0)
vinvalbuf(vp, 0, NOCRED, p, 0, 0);
}
@ -2785,12 +2802,18 @@ sync_fsync(ap)
simple_unlock(&mountlist_slock);
return (0);
}
if (vn_start_write(NULL, &mp, V_NOWAIT) != 0) {
vfs_unbusy(mp, p);
simple_unlock(&mountlist_slock);
return (0);
}
asyncflag = mp->mnt_flag & MNT_ASYNC;
mp->mnt_flag &= ~MNT_ASYNC;
vfs_msync(mp, MNT_NOWAIT);
VFS_SYNC(mp, MNT_LAZY, ap->a_cred, p);
if (asyncflag)
mp->mnt_flag |= MNT_ASYNC;
vn_finished_write(mp);
vfs_unbusy(mp, p);
return (0);
}

View File

@ -164,8 +164,8 @@ mount(p, uap)
vput(vp);
return (EOPNOTSUPP); /* Needs translation */
}
mp->mnt_flag |=
SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
mp->mnt_flag |= SCARG(uap, flags) &
(MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT);
/*
* Only root, or the user that did the original mount is
* permitted to update it.
@ -303,7 +303,8 @@ mount(p, uap)
vrele(vp);
if (mp->mnt_kern_flag & MNTK_WANTRDWR)
mp->mnt_flag &= ~MNT_RDONLY;
mp->mnt_flag &=~ (MNT_UPDATE | MNT_RELOAD | MNT_FORCE);
mp->mnt_flag &=~
(MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_SNAPSHOT);
mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
if (error) {
mp->mnt_flag = flag;
@ -458,7 +459,7 @@ unmount(p, uap)
*/
int
dounmount(mp, flags, p)
register struct mount *mp;
struct mount *mp;
int flags;
struct proc *p;
{
@ -469,6 +470,7 @@ dounmount(mp, flags, p)
simple_lock(&mountlist_slock);
mp->mnt_kern_flag |= MNTK_UNMOUNT;
lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p);
vn_start_write(NULL, &mp, V_WAIT);
if (mp->mnt_flag & MNT_EXPUBLIC)
vfs_setpublicfs(NULL, NULL, NULL);
@ -481,8 +483,10 @@ dounmount(mp, flags, p)
vrele(mp->mnt_syncer);
if (((mp->mnt_flag & MNT_RDONLY) ||
(error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
(flags & MNT_FORCE))
(flags & MNT_FORCE)) {
error = VFS_UNMOUNT(mp, flags, p);
}
vn_finished_write(mp);
simple_lock(&mountlist_slock);
if (error) {
if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
@ -530,7 +534,7 @@ sync(p, uap)
struct proc *p;
struct sync_args *uap;
{
register struct mount *mp, *nmp;
struct mount *mp, *nmp;
int asyncflag;
simple_lock(&mountlist_slock);
@ -539,13 +543,15 @@ sync(p, uap)
nmp = TAILQ_NEXT(mp, mnt_list);
continue;
}
if ((mp->mnt_flag & MNT_RDONLY) == 0) {
if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
asyncflag = mp->mnt_flag & MNT_ASYNC;
mp->mnt_flag &= ~MNT_ASYNC;
vfs_msync(mp, MNT_NOWAIT);
VFS_SYNC(mp, MNT_NOWAIT,
((p != NULL) ? p->p_ucred : NOCRED), p);
((p != NULL) ? p->p_ucred : NOCRED), p);
mp->mnt_flag |= asyncflag;
vn_finished_write(mp);
}
simple_lock(&mountlist_slock);
nmp = TAILQ_NEXT(mp, mnt_list);
@ -593,7 +599,7 @@ quotactl(p, uap)
syscallarg(caddr_t) arg;
} */ *uap;
{
register struct mount *mp;
struct mount *mp;
int error;
struct nameidata nd;
@ -602,11 +608,15 @@ quotactl(p, uap)
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
mp = nd.ni_vp->v_mount;
NDFREE(&nd, NDF_ONLY_PNBUF);
error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
vrele(nd.ni_vp);
return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
SCARG(uap, arg), p));
if (error)
return (error);
error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
SCARG(uap, arg), p);
vn_finished_write(mp);
return (error);
}
/*
@ -972,6 +982,7 @@ open(p, uap)
struct file *fp;
struct vnode *vp;
struct vattr vat;
struct mount *mp;
int cmode, flags, oflags;
struct file *nfp;
int type, indx, error;
@ -1029,12 +1040,15 @@ open(p, uap)
fp->f_flag |= FHASLOCK;
}
if (flags & O_TRUNC) {
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
goto bad;
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
VATTR_NULL(&vat);
vat.va_size = 0;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
error = VOP_SETATTR(vp, &vat, p->p_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
if (error)
goto bad;
}
@ -1101,7 +1115,8 @@ mknod(p, uap)
syscallarg(int) dev;
} */ *uap;
{
register struct vnode *vp;
struct vnode *vp;
struct mount *mp;
struct vattr vattr;
int error;
int whiteout = 0;
@ -1118,14 +1133,16 @@ mknod(p, uap)
}
if (error)
return (error);
restart:
bwillwrite();
NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
if (vp != NULL)
if (vp != NULL) {
vrele(vp);
error = EEXIST;
else {
} else {
VATTR_NULL(&vattr);
vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
vattr.va_rdev = SCARG(uap, dev);
@ -1149,6 +1166,13 @@ mknod(p, uap)
break;
}
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
if (!error) {
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
if (whiteout)
@ -1159,17 +1183,10 @@ mknod(p, uap)
if (error == 0)
vput(nd.ni_vp);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
} else {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
if (vp)
vrele(vp);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod");
return (error);
@ -1193,23 +1210,29 @@ mkfifo(p, uap)
syscallarg(int) mode;
} */ *uap;
{
struct mount *mp;
struct vattr vattr;
int error;
struct nameidata nd;
restart:
bwillwrite();
NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
if (nd.ni_vp != NULL) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == nd.ni_vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
vrele(nd.ni_vp);
vput(nd.ni_dvp);
return (EEXIST);
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VATTR_NULL(&vattr);
vattr.va_type = VFIFO;
vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
@ -1219,6 +1242,7 @@ mkfifo(p, uap)
vput(nd.ni_vp);
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
vn_finished_write(mp);
return (error);
}
@ -1240,7 +1264,8 @@ link(p, uap)
syscallarg(char *) link;
} */ *uap;
{
register struct vnode *vp;
struct vnode *vp;
struct mount *mp;
struct nameidata nd;
int error;
@ -1250,30 +1275,29 @@ link(p, uap)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
if (vp->v_type == VDIR)
error = EPERM; /* POSIX */
else {
NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p);
error = namei(&nd);
if (!error) {
if (nd.ni_vp != NULL) {
if (nd.ni_vp)
vrele(nd.ni_vp);
error = EEXIST;
} else {
VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
LEASE_WRITE);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == nd.ni_vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
if (vp->v_type == VDIR) {
vrele(vp);
return (EPERM); /* POSIX */
}
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
vrele(vp);
return (error);
}
NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p);
if ((error = namei(&nd)) == 0) {
if (nd.ni_vp != NULL) {
vrele(nd.ni_vp);
error = EEXIST;
} else {
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
}
vrele(vp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "link");
return (error);
@ -1297,6 +1321,7 @@ symlink(p, uap)
syscallarg(char *) link;
} */ *uap;
{
struct mount *mp;
struct vattr vattr;
char *path;
int error;
@ -1305,20 +1330,25 @@ symlink(p, uap)
path = zalloc(namei_zone);
if ((error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) != 0)
goto out;
restart:
bwillwrite();
NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p);
if ((error = namei(&nd)) != 0)
goto out;
if (nd.ni_vp) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == nd.ni_vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
vrele(nd.ni_vp);
vput(nd.ni_dvp);
error = EEXIST;
goto out;
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VATTR_NULL(&vattr);
vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
@ -1327,6 +1357,7 @@ symlink(p, uap)
if (error == 0)
vput(nd.ni_vp);
vput(nd.ni_dvp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink");
out:
@ -1346,8 +1377,10 @@ undelete(p, uap)
} */ *uap;
{
int error;
struct mount *mp;
struct nameidata nd;
restart:
bwillwrite();
NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
SCARG(uap, path), p);
@ -1357,19 +1390,23 @@ undelete(p, uap)
if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == nd.ni_vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
if (nd.ni_vp)
vrele(nd.ni_vp);
vput(nd.ni_dvp);
return (EEXIST);
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
return (error);
@ -1391,18 +1428,17 @@ unlink(p, uap)
syscallarg(char *) path;
} */ *uap;
{
register struct vnode *vp;
struct mount *mp;
struct vnode *vp;
int error;
struct nameidata nd;
restart:
bwillwrite();
NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
if (vp->v_type == VDIR)
error = EPERM; /* POSIX */
else {
@ -1414,18 +1450,24 @@ unlink(p, uap)
if (vp->v_flag & VROOT)
error = EBUSY;
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(vp);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
if (!error) {
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
if (vp != NULLVP)
vput(vp);
vput(nd.ni_dvp);
vput(vp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink");
return (error);
@ -1936,6 +1978,7 @@ setfflags(p, vp, flags)
int flags;
{
int error;
struct mount *mp;
struct vattr vattr;
/*
@ -1948,12 +1991,15 @@ setfflags(p, vp, flags)
((error = suser_xxx(p->p_ucred, p, PRISON_ROOT)) != 0))
return (error);
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
VATTR_NULL(&vattr);
vattr.va_flags = flags;
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
@ -2020,14 +2066,18 @@ setfmode(p, vp, mode)
int mode;
{
int error;
struct mount *mp;
struct vattr vattr;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
VATTR_NULL(&vattr);
vattr.va_mode = mode & ALLPERMS;
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return error;
}
@ -2125,8 +2175,11 @@ setfown(p, vp, uid, gid)
gid_t gid;
{
int error;
struct mount *mp;
struct vattr vattr;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
VATTR_NULL(&vattr);
@ -2134,6 +2187,7 @@ setfown(p, vp, uid, gid)
vattr.va_gid = gid;
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return error;
}
@ -2259,8 +2313,11 @@ setutimes(p, vp, ts, nullflag)
int nullflag;
{
int error;
struct mount *mp;
struct vattr vattr;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
VATTR_NULL(&vattr);
@ -2270,6 +2327,7 @@ setutimes(p, vp, ts, nullflag)
vattr.va_vaflags |= VA_UTIMES_NULL;
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return error;
}
@ -2394,7 +2452,8 @@ truncate(p, uap)
syscallarg(off_t) length;
} */ *uap;
{
register struct vnode *vp;
struct mount *mp;
struct vnode *vp;
struct vattr vattr;
int error;
struct nameidata nd;
@ -2405,6 +2464,10 @@ truncate(p, uap)
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
vrele(vp);
return (error);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
@ -2417,6 +2480,7 @@ truncate(p, uap)
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
}
vput(vp);
vn_finished_write(mp);
return (error);
}
@ -2440,6 +2504,7 @@ ftruncate(p, uap)
syscallarg(off_t) length;
} */ *uap;
{
struct mount *mp;
struct vattr vattr;
struct vnode *vp;
struct file *fp;
@ -2452,6 +2517,8 @@ ftruncate(p, uap)
if ((fp->f_flag & FWRITE) == 0)
return (EINVAL);
vp = (struct vnode *)fp->f_data;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
if (vp->v_type == VDIR)
@ -2462,6 +2529,7 @@ ftruncate(p, uap)
error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
}
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
@ -2541,13 +2609,16 @@ fsync(p, uap)
syscallarg(int) fd;
} */ *uap;
{
register struct vnode *vp;
struct vnode *vp;
struct mount *mp;
struct file *fp;
int error;
if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
vp = (struct vnode *)fp->f_data;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
if (vp->v_object)
vm_object_page_clean(vp->v_object, 0, 0, 0);
@ -2558,6 +2629,7 @@ fsync(p, uap)
#endif
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
@ -2580,7 +2652,8 @@ rename(p, uap)
syscallarg(char *) to;
} */ *uap;
{
register struct vnode *tvp, *fvp, *tdvp;
struct mount *mp;
struct vnode *tvp, *fvp, *tdvp;
struct nameidata fromnd, tond;
int error;
@ -2590,6 +2663,12 @@ rename(p, uap)
if ((error = namei(&fromnd)) != 0)
return (error);
fvp = fromnd.ni_vp;
if ((error = vn_start_write(fvp, &mp, V_WAIT | PCATCH)) != 0) {
NDFREE(&fromnd, NDF_ONLY_PNBUF);
vrele(fromnd.ni_dvp);
vrele(fvp);
goto out1;
}
NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ,
UIO_USERSPACE, SCARG(uap, to), p);
if (fromnd.ni_vp->v_type == VDIR)
@ -2652,6 +2731,7 @@ rename(p, uap)
vrele(fvp);
}
vrele(tond.ni_startdir);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename");
ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename");
ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename");
@ -2682,11 +2762,13 @@ mkdir(p, uap)
syscallarg(int) mode;
} */ *uap;
{
register struct vnode *vp;
struct mount *mp;
struct vnode *vp;
struct vattr vattr;
int error;
struct nameidata nd;
restart:
bwillwrite();
NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
nd.ni_cnd.cn_flags |= WILLBEDIR;
@ -2695,13 +2777,17 @@ mkdir(p, uap)
vp = nd.ni_vp;
if (vp != NULL) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
vrele(vp);
vput(nd.ni_dvp);
return (EEXIST);
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VATTR_NULL(&vattr);
vattr.va_type = VDIR;
vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
@ -2711,6 +2797,7 @@ mkdir(p, uap)
vput(nd.ni_dvp);
if (!error)
vput(nd.ni_vp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir");
return (error);
@ -2732,10 +2819,12 @@ rmdir(p, uap)
syscallarg(char *) path;
} */ *uap;
{
register struct vnode *vp;
struct mount *mp;
struct vnode *vp;
int error;
struct nameidata nd;
restart:
bwillwrite();
NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
SCARG(uap, path), p);
@ -2756,21 +2845,32 @@ rmdir(p, uap)
/*
* The root of a mounted filesystem cannot be deleted.
*/
if (vp->v_flag & VROOT)
if (vp->v_flag & VROOT) {
error = EBUSY;
else {
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
goto out;
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
vput(vp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
vn_finished_write(mp);
out:
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
if (vp != NULLVP)
vput(vp);
vput(vp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir");
return (error);
@ -3049,7 +3149,8 @@ revoke(p, uap)
syscallarg(char *) path;
} */ *uap;
{
register struct vnode *vp;
struct mount *mp;
struct vnode *vp;
struct vattr vattr;
int error;
struct nameidata nd;
@ -3068,8 +3169,11 @@ revoke(p, uap)
if (p->p_ucred->cr_uid != vattr.va_uid &&
(error = suser_xxx(0, p, PRISON_ROOT)))
goto out;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
goto out;
if (vcount(vp) > 1)
VOP_REVOKE(vp, REVOKEALL);
vn_finished_write(mp);
out:
vrele(vp);
return (error);
@ -3228,11 +3332,16 @@ fhopen(p, uap)
}
if (fmode & O_TRUNC) {
VOP_UNLOCK(vp, 0, p); /* XXX */
if ((error = vn_start_write(NULL, &mp, V_WAIT | PCATCH)) != 0) {
vrele(vp);
return (error);
}
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
VATTR_NULL(vap);
vap->va_size = 0;
error = VOP_SETATTR(vp, vap, p->p_ucred, p);
vn_finished_write(mp);
if (error)
goto bad;
}
@ -3407,10 +3516,15 @@ extattrctl(p, uap)
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
mp = nd.ni_vp->v_mount;
error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
NDFREE(&nd, 0);
return (VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname),
SCARG(uap, arg), p));
vrele(nd.ni_vp);
if (error)
return (error);
error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname),
SCARG(uap, arg), p);
vn_finished_write(mp);
return (error);
}
/*
@ -3425,6 +3539,7 @@ extattr_set_file(p, uap)
struct extattr_set_file_args *uap;
{
struct nameidata nd;
struct mount *mp;
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
char attrname[EXTATTR_MAXNAMELEN];
@ -3434,10 +3549,11 @@ extattr_set_file(p, uap)
error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
if (error)
return (error);
NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, SCARG(uap, path),
p);
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return(error);
if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0)
goto done;
iovlen = uap->iovcnt * sizeof(struct iovec);
if (uap->iovcnt > UIO_SMALLIOV) {
if (uap->iovcnt > UIO_MAXIOV) {
@ -3477,6 +3593,8 @@ extattr_set_file(p, uap)
if (needfree)
FREE(needfree, M_IOV);
NDFREE(&nd, 0);
vrele(nd.ni_vp);
vn_finished_write(mp);
return (error);
}
@ -3508,6 +3626,7 @@ extattr_get_file(p, uap)
if (uap->iovcnt > UIO_SMALLIOV) {
if (uap->iovcnt > UIO_MAXIOV) {
NDFREE(&nd, 0);
vrele(nd.ni_vp);
return (EINVAL);
}
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
@ -3545,6 +3664,7 @@ extattr_get_file(p, uap)
if (needfree)
FREE(needfree, M_IOV);
NDFREE(&nd, 0);
vrele(nd.ni_vp);
return(error);
}
@ -3557,6 +3677,7 @@ extattr_delete_file(p, uap)
struct proc *p;
struct extattr_delete_file_args *uap;
{
struct mount *mp;
struct nameidata nd;
char attrname[EXTATTR_MAXNAMELEN];
int error;
@ -3564,12 +3685,17 @@ extattr_delete_file(p, uap)
error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
if (error)
return(error);
NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, SCARG(uap, path),
p);
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return(error);
if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
vrele(nd.ni_vp);
return (error);
}
error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_cred->pc_ucred,
p);
NDFREE(&nd, 0);
vrele(nd.ni_vp);
vn_finished_write(mp);
return(error);
}

View File

@ -453,6 +453,7 @@ getnewvnode(tag, mp, vops, vpp)
int s, count;
struct proc *p = curproc; /* XXX */
struct vnode *vp = NULL;
struct mount *vnmp;
vm_object_t object;
/*
@ -491,7 +492,14 @@ getnewvnode(tag, mp, vops, vpp)
vp = NULL;
continue;
}
break;
/*
* Skip over it if its filesystem is being suspended.
*/
if (vn_start_write(vp, &vnmp, V_NOWAIT) == 0)
break;
simple_unlock(&vp->v_interlock);
TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
vp = NULL;
}
if (vp) {
vp->v_flag |= VDOOMED;
@ -504,6 +512,7 @@ getnewvnode(tag, mp, vops, vpp)
} else {
simple_unlock(&vp->v_interlock);
}
vn_finished_write(vnmp);
#ifdef INVARIANTS
{
@ -515,6 +524,8 @@ getnewvnode(tag, mp, vops, vpp)
if (vp->v_numoutput)
panic("Clean vnode has pending I/O's");
splx(s);
if (vp->v_writecount != 0)
panic("Non-zero write count");
}
#endif
vp->v_flag = 0;
@ -523,7 +534,6 @@ getnewvnode(tag, mp, vops, vpp)
vp->v_cstart = 0;
vp->v_clen = 0;
vp->v_socket = 0;
vp->v_writecount = 0; /* XXX */
} else {
simple_unlock(&vnode_free_list_slock);
vp = (struct vnode *) zalloc(vnode_zone);
@ -946,6 +956,7 @@ sched_sync(void)
{
struct synclist *slp;
struct vnode *vp;
struct mount *mp;
long starttime;
int s;
struct proc *p = updateproc;
@ -970,10 +981,12 @@ sched_sync(void)
splx(s);
while ((vp = LIST_FIRST(slp)) != NULL) {
if (VOP_ISLOCKED(vp, NULL) == 0) {
if (VOP_ISLOCKED(vp, NULL) == 0 &&
vn_start_write(vp, &mp, V_NOWAIT) == 0) {
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
(void) VOP_FSYNC(vp, p->p_ucred, MNT_LAZY, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
}
s = splbio();
if (LIST_FIRST(slp) == vp) {
@ -1386,6 +1399,7 @@ vrele(vp)
struct proc *p = curproc; /* XXX */
KASSERT(vp != NULL, ("vrele: null vp"));
KASSERT(vp->v_writecount < vp->v_usecount, ("vrele: missed vn_close"));
simple_lock(&vp->v_interlock);
@ -1427,6 +1441,7 @@ vput(vp)
struct proc *p = curproc; /* XXX */
KASSERT(vp != NULL, ("vput: null vp"));
KASSERT(vp->v_writecount < vp->v_usecount, ("vput: missed vn_close"));
simple_lock(&vp->v_interlock);
@ -1632,6 +1647,8 @@ vclean(vp, flags, p)
* If the flush fails, just toss the buffers.
*/
if (flags & DOCLOSE) {
if (TAILQ_FIRST(&vp->v_dirtyblkhd) != NULL)
(void) vn_write_suspend_wait(vp, V_WAIT);
if (vinvalbuf(vp, V_SAVE, NOCRED, p, 0, 0) != 0)
vinvalbuf(vp, 0, NOCRED, p, 0, 0);
}
@ -2785,12 +2802,18 @@ sync_fsync(ap)
simple_unlock(&mountlist_slock);
return (0);
}
if (vn_start_write(NULL, &mp, V_NOWAIT) != 0) {
vfs_unbusy(mp, p);
simple_unlock(&mountlist_slock);
return (0);
}
asyncflag = mp->mnt_flag & MNT_ASYNC;
mp->mnt_flag &= ~MNT_ASYNC;
vfs_msync(mp, MNT_NOWAIT);
VFS_SYNC(mp, MNT_LAZY, ap->a_cred, p);
if (asyncflag)
mp->mnt_flag |= MNT_ASYNC;
vn_finished_write(mp);
vfs_unbusy(mp, p);
return (0);
}

View File

@ -164,8 +164,8 @@ mount(p, uap)
vput(vp);
return (EOPNOTSUPP); /* Needs translation */
}
mp->mnt_flag |=
SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
mp->mnt_flag |= SCARG(uap, flags) &
(MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT);
/*
* Only root, or the user that did the original mount is
* permitted to update it.
@ -303,7 +303,8 @@ mount(p, uap)
vrele(vp);
if (mp->mnt_kern_flag & MNTK_WANTRDWR)
mp->mnt_flag &= ~MNT_RDONLY;
mp->mnt_flag &=~ (MNT_UPDATE | MNT_RELOAD | MNT_FORCE);
mp->mnt_flag &=~
(MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_SNAPSHOT);
mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
if (error) {
mp->mnt_flag = flag;
@ -458,7 +459,7 @@ unmount(p, uap)
*/
int
dounmount(mp, flags, p)
register struct mount *mp;
struct mount *mp;
int flags;
struct proc *p;
{
@ -469,6 +470,7 @@ dounmount(mp, flags, p)
simple_lock(&mountlist_slock);
mp->mnt_kern_flag |= MNTK_UNMOUNT;
lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p);
vn_start_write(NULL, &mp, V_WAIT);
if (mp->mnt_flag & MNT_EXPUBLIC)
vfs_setpublicfs(NULL, NULL, NULL);
@ -481,8 +483,10 @@ dounmount(mp, flags, p)
vrele(mp->mnt_syncer);
if (((mp->mnt_flag & MNT_RDONLY) ||
(error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
(flags & MNT_FORCE))
(flags & MNT_FORCE)) {
error = VFS_UNMOUNT(mp, flags, p);
}
vn_finished_write(mp);
simple_lock(&mountlist_slock);
if (error) {
if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
@ -530,7 +534,7 @@ sync(p, uap)
struct proc *p;
struct sync_args *uap;
{
register struct mount *mp, *nmp;
struct mount *mp, *nmp;
int asyncflag;
simple_lock(&mountlist_slock);
@ -539,13 +543,15 @@ sync(p, uap)
nmp = TAILQ_NEXT(mp, mnt_list);
continue;
}
if ((mp->mnt_flag & MNT_RDONLY) == 0) {
if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
asyncflag = mp->mnt_flag & MNT_ASYNC;
mp->mnt_flag &= ~MNT_ASYNC;
vfs_msync(mp, MNT_NOWAIT);
VFS_SYNC(mp, MNT_NOWAIT,
((p != NULL) ? p->p_ucred : NOCRED), p);
((p != NULL) ? p->p_ucred : NOCRED), p);
mp->mnt_flag |= asyncflag;
vn_finished_write(mp);
}
simple_lock(&mountlist_slock);
nmp = TAILQ_NEXT(mp, mnt_list);
@ -593,7 +599,7 @@ quotactl(p, uap)
syscallarg(caddr_t) arg;
} */ *uap;
{
register struct mount *mp;
struct mount *mp;
int error;
struct nameidata nd;
@ -602,11 +608,15 @@ quotactl(p, uap)
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
mp = nd.ni_vp->v_mount;
NDFREE(&nd, NDF_ONLY_PNBUF);
error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
vrele(nd.ni_vp);
return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
SCARG(uap, arg), p));
if (error)
return (error);
error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
SCARG(uap, arg), p);
vn_finished_write(mp);
return (error);
}
/*
@ -972,6 +982,7 @@ open(p, uap)
struct file *fp;
struct vnode *vp;
struct vattr vat;
struct mount *mp;
int cmode, flags, oflags;
struct file *nfp;
int type, indx, error;
@ -1029,12 +1040,15 @@ open(p, uap)
fp->f_flag |= FHASLOCK;
}
if (flags & O_TRUNC) {
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
goto bad;
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
VATTR_NULL(&vat);
vat.va_size = 0;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
error = VOP_SETATTR(vp, &vat, p->p_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
if (error)
goto bad;
}
@ -1101,7 +1115,8 @@ mknod(p, uap)
syscallarg(int) dev;
} */ *uap;
{
register struct vnode *vp;
struct vnode *vp;
struct mount *mp;
struct vattr vattr;
int error;
int whiteout = 0;
@ -1118,14 +1133,16 @@ mknod(p, uap)
}
if (error)
return (error);
restart:
bwillwrite();
NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
if (vp != NULL)
if (vp != NULL) {
vrele(vp);
error = EEXIST;
else {
} else {
VATTR_NULL(&vattr);
vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
vattr.va_rdev = SCARG(uap, dev);
@ -1149,6 +1166,13 @@ mknod(p, uap)
break;
}
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
if (!error) {
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
if (whiteout)
@ -1159,17 +1183,10 @@ mknod(p, uap)
if (error == 0)
vput(nd.ni_vp);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
} else {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
if (vp)
vrele(vp);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod");
return (error);
@ -1193,23 +1210,29 @@ mkfifo(p, uap)
syscallarg(int) mode;
} */ *uap;
{
struct mount *mp;
struct vattr vattr;
int error;
struct nameidata nd;
restart:
bwillwrite();
NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
if (nd.ni_vp != NULL) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == nd.ni_vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
vrele(nd.ni_vp);
vput(nd.ni_dvp);
return (EEXIST);
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VATTR_NULL(&vattr);
vattr.va_type = VFIFO;
vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
@ -1219,6 +1242,7 @@ mkfifo(p, uap)
vput(nd.ni_vp);
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
vn_finished_write(mp);
return (error);
}
@ -1240,7 +1264,8 @@ link(p, uap)
syscallarg(char *) link;
} */ *uap;
{
register struct vnode *vp;
struct vnode *vp;
struct mount *mp;
struct nameidata nd;
int error;
@ -1250,30 +1275,29 @@ link(p, uap)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
if (vp->v_type == VDIR)
error = EPERM; /* POSIX */
else {
NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p);
error = namei(&nd);
if (!error) {
if (nd.ni_vp != NULL) {
if (nd.ni_vp)
vrele(nd.ni_vp);
error = EEXIST;
} else {
VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
LEASE_WRITE);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == nd.ni_vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
if (vp->v_type == VDIR) {
vrele(vp);
return (EPERM); /* POSIX */
}
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
vrele(vp);
return (error);
}
NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p);
if ((error = namei(&nd)) == 0) {
if (nd.ni_vp != NULL) {
vrele(nd.ni_vp);
error = EEXIST;
} else {
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
}
vrele(vp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "link");
return (error);
@ -1297,6 +1321,7 @@ symlink(p, uap)
syscallarg(char *) link;
} */ *uap;
{
struct mount *mp;
struct vattr vattr;
char *path;
int error;
@ -1305,20 +1330,25 @@ symlink(p, uap)
path = zalloc(namei_zone);
if ((error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) != 0)
goto out;
restart:
bwillwrite();
NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p);
if ((error = namei(&nd)) != 0)
goto out;
if (nd.ni_vp) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == nd.ni_vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
vrele(nd.ni_vp);
vput(nd.ni_dvp);
error = EEXIST;
goto out;
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VATTR_NULL(&vattr);
vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
@ -1327,6 +1357,7 @@ symlink(p, uap)
if (error == 0)
vput(nd.ni_vp);
vput(nd.ni_dvp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink");
out:
@ -1346,8 +1377,10 @@ undelete(p, uap)
} */ *uap;
{
int error;
struct mount *mp;
struct nameidata nd;
restart:
bwillwrite();
NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
SCARG(uap, path), p);
@ -1357,19 +1390,23 @@ undelete(p, uap)
if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == nd.ni_vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
if (nd.ni_vp)
vrele(nd.ni_vp);
vput(nd.ni_dvp);
return (EEXIST);
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
return (error);
@ -1391,18 +1428,17 @@ unlink(p, uap)
syscallarg(char *) path;
} */ *uap;
{
register struct vnode *vp;
struct mount *mp;
struct vnode *vp;
int error;
struct nameidata nd;
restart:
bwillwrite();
NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
if (vp->v_type == VDIR)
error = EPERM; /* POSIX */
else {
@ -1414,18 +1450,24 @@ unlink(p, uap)
if (vp->v_flag & VROOT)
error = EBUSY;
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(vp);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
if (!error) {
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
if (vp != NULLVP)
vput(vp);
vput(nd.ni_dvp);
vput(vp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink");
return (error);
@ -1936,6 +1978,7 @@ setfflags(p, vp, flags)
int flags;
{
int error;
struct mount *mp;
struct vattr vattr;
/*
@ -1948,12 +1991,15 @@ setfflags(p, vp, flags)
((error = suser_xxx(p->p_ucred, p, PRISON_ROOT)) != 0))
return (error);
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
VATTR_NULL(&vattr);
vattr.va_flags = flags;
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
@ -2020,14 +2066,18 @@ setfmode(p, vp, mode)
int mode;
{
int error;
struct mount *mp;
struct vattr vattr;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
VATTR_NULL(&vattr);
vattr.va_mode = mode & ALLPERMS;
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return error;
}
@ -2125,8 +2175,11 @@ setfown(p, vp, uid, gid)
gid_t gid;
{
int error;
struct mount *mp;
struct vattr vattr;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
VATTR_NULL(&vattr);
@ -2134,6 +2187,7 @@ setfown(p, vp, uid, gid)
vattr.va_gid = gid;
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return error;
}
@ -2259,8 +2313,11 @@ setutimes(p, vp, ts, nullflag)
int nullflag;
{
int error;
struct mount *mp;
struct vattr vattr;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
VATTR_NULL(&vattr);
@ -2270,6 +2327,7 @@ setutimes(p, vp, ts, nullflag)
vattr.va_vaflags |= VA_UTIMES_NULL;
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return error;
}
@ -2394,7 +2452,8 @@ truncate(p, uap)
syscallarg(off_t) length;
} */ *uap;
{
register struct vnode *vp;
struct mount *mp;
struct vnode *vp;
struct vattr vattr;
int error;
struct nameidata nd;
@ -2405,6 +2464,10 @@ truncate(p, uap)
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
vrele(vp);
return (error);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
@ -2417,6 +2480,7 @@ truncate(p, uap)
error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
}
vput(vp);
vn_finished_write(mp);
return (error);
}
@ -2440,6 +2504,7 @@ ftruncate(p, uap)
syscallarg(off_t) length;
} */ *uap;
{
struct mount *mp;
struct vattr vattr;
struct vnode *vp;
struct file *fp;
@ -2452,6 +2517,8 @@ ftruncate(p, uap)
if ((fp->f_flag & FWRITE) == 0)
return (EINVAL);
vp = (struct vnode *)fp->f_data;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
if (vp->v_type == VDIR)
@ -2462,6 +2529,7 @@ ftruncate(p, uap)
error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
}
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
@ -2541,13 +2609,16 @@ fsync(p, uap)
syscallarg(int) fd;
} */ *uap;
{
register struct vnode *vp;
struct vnode *vp;
struct mount *mp;
struct file *fp;
int error;
if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
return (error);
vp = (struct vnode *)fp->f_data;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
if (vp->v_object)
vm_object_page_clean(vp->v_object, 0, 0, 0);
@ -2558,6 +2629,7 @@ fsync(p, uap)
#endif
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
@ -2580,7 +2652,8 @@ rename(p, uap)
syscallarg(char *) to;
} */ *uap;
{
register struct vnode *tvp, *fvp, *tdvp;
struct mount *mp;
struct vnode *tvp, *fvp, *tdvp;
struct nameidata fromnd, tond;
int error;
@ -2590,6 +2663,12 @@ rename(p, uap)
if ((error = namei(&fromnd)) != 0)
return (error);
fvp = fromnd.ni_vp;
if ((error = vn_start_write(fvp, &mp, V_WAIT | PCATCH)) != 0) {
NDFREE(&fromnd, NDF_ONLY_PNBUF);
vrele(fromnd.ni_dvp);
vrele(fvp);
goto out1;
}
NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ,
UIO_USERSPACE, SCARG(uap, to), p);
if (fromnd.ni_vp->v_type == VDIR)
@ -2652,6 +2731,7 @@ rename(p, uap)
vrele(fvp);
}
vrele(tond.ni_startdir);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename");
ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename");
ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename");
@ -2682,11 +2762,13 @@ mkdir(p, uap)
syscallarg(int) mode;
} */ *uap;
{
register struct vnode *vp;
struct mount *mp;
struct vnode *vp;
struct vattr vattr;
int error;
struct nameidata nd;
restart:
bwillwrite();
NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
nd.ni_cnd.cn_flags |= WILLBEDIR;
@ -2695,13 +2777,17 @@ mkdir(p, uap)
vp = nd.ni_vp;
if (vp != NULL) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
vrele(vp);
vput(nd.ni_dvp);
return (EEXIST);
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VATTR_NULL(&vattr);
vattr.va_type = VDIR;
vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
@ -2711,6 +2797,7 @@ mkdir(p, uap)
vput(nd.ni_dvp);
if (!error)
vput(nd.ni_vp);
vn_finished_write(mp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir");
return (error);
@ -2732,10 +2819,12 @@ rmdir(p, uap)
syscallarg(char *) path;
} */ *uap;
{
register struct vnode *vp;
struct mount *mp;
struct vnode *vp;
int error;
struct nameidata nd;
restart:
bwillwrite();
NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
SCARG(uap, path), p);
@ -2756,21 +2845,32 @@ rmdir(p, uap)
/*
* The root of a mounted filesystem cannot be deleted.
*/
if (vp->v_flag & VROOT)
if (vp->v_flag & VROOT) {
error = EBUSY;
else {
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
goto out;
}
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
vput(vp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
vn_finished_write(mp);
out:
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
if (vp != NULLVP)
vput(vp);
vput(vp);
ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir");
ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir");
return (error);
@ -3049,7 +3149,8 @@ revoke(p, uap)
syscallarg(char *) path;
} */ *uap;
{
register struct vnode *vp;
struct mount *mp;
struct vnode *vp;
struct vattr vattr;
int error;
struct nameidata nd;
@ -3068,8 +3169,11 @@ revoke(p, uap)
if (p->p_ucred->cr_uid != vattr.va_uid &&
(error = suser_xxx(0, p, PRISON_ROOT)))
goto out;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
goto out;
if (vcount(vp) > 1)
VOP_REVOKE(vp, REVOKEALL);
vn_finished_write(mp);
out:
vrele(vp);
return (error);
@ -3228,11 +3332,16 @@ fhopen(p, uap)
}
if (fmode & O_TRUNC) {
VOP_UNLOCK(vp, 0, p); /* XXX */
if ((error = vn_start_write(NULL, &mp, V_WAIT | PCATCH)) != 0) {
vrele(vp);
return (error);
}
VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
VATTR_NULL(vap);
vap->va_size = 0;
error = VOP_SETATTR(vp, vap, p->p_ucred, p);
vn_finished_write(mp);
if (error)
goto bad;
}
@ -3407,10 +3516,15 @@ extattrctl(p, uap)
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
mp = nd.ni_vp->v_mount;
error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
NDFREE(&nd, 0);
return (VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname),
SCARG(uap, arg), p));
vrele(nd.ni_vp);
if (error)
return (error);
error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname),
SCARG(uap, arg), p);
vn_finished_write(mp);
return (error);
}
/*
@ -3425,6 +3539,7 @@ extattr_set_file(p, uap)
struct extattr_set_file_args *uap;
{
struct nameidata nd;
struct mount *mp;
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
char attrname[EXTATTR_MAXNAMELEN];
@ -3434,10 +3549,11 @@ extattr_set_file(p, uap)
error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
if (error)
return (error);
NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, SCARG(uap, path),
p);
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return(error);
if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0)
goto done;
iovlen = uap->iovcnt * sizeof(struct iovec);
if (uap->iovcnt > UIO_SMALLIOV) {
if (uap->iovcnt > UIO_MAXIOV) {
@ -3477,6 +3593,8 @@ extattr_set_file(p, uap)
if (needfree)
FREE(needfree, M_IOV);
NDFREE(&nd, 0);
vrele(nd.ni_vp);
vn_finished_write(mp);
return (error);
}
@ -3508,6 +3626,7 @@ extattr_get_file(p, uap)
if (uap->iovcnt > UIO_SMALLIOV) {
if (uap->iovcnt > UIO_MAXIOV) {
NDFREE(&nd, 0);
vrele(nd.ni_vp);
return (EINVAL);
}
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
@ -3545,6 +3664,7 @@ extattr_get_file(p, uap)
if (needfree)
FREE(needfree, M_IOV);
NDFREE(&nd, 0);
vrele(nd.ni_vp);
return(error);
}
@ -3557,6 +3677,7 @@ extattr_delete_file(p, uap)
struct proc *p;
struct extattr_delete_file_args *uap;
{
struct mount *mp;
struct nameidata nd;
char attrname[EXTATTR_MAXNAMELEN];
int error;
@ -3564,12 +3685,17 @@ extattr_delete_file(p, uap)
error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
if (error)
return(error);
NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, SCARG(uap, path),
p);
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return(error);
if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
vrele(nd.ni_vp);
return (error);
}
error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_cred->pc_ucred,
p);
NDFREE(&nd, 0);
vrele(nd.ni_vp);
vn_finished_write(mp);
return(error);
}

View File

@ -103,12 +103,14 @@ vn_open(ndp, flagp, cmode)
int *flagp, cmode;
{
struct vnode *vp;
struct mount *mp;
struct proc *p = ndp->ni_cnd.cn_proc;
struct ucred *cred = p->p_ucred;
struct vattr vat;
struct vattr *vap = &vat;
int mode, fmode, error;
restart:
fmode = *flagp;
if (fmode & O_CREAT) {
ndp->ni_cnd.cn_nameiop = CREATE;
@ -124,10 +126,19 @@ vn_open(ndp, flagp, cmode)
vap->va_mode = cmode;
if (fmode & O_EXCL)
vap->va_vaflags |= VA_EXCLUSIVE;
if (vn_start_write(ndp->ni_dvp, &mp, V_NOWAIT) != 0) {
NDFREE(ndp, NDF_ONLY_PNBUF);
vput(ndp->ni_dvp);
if ((error = vn_start_write(NULL, &mp,
V_XSLEEP | PCATCH)) != 0)
return (error);
goto restart;
}
VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE);
error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
&ndp->ni_cnd, vap);
vput(ndp->ni_dvp);
vn_finished_write(mp);
if (error) {
NDFREE(ndp, NDF_ONLY_PNBUF);
return (error);
@ -293,10 +304,17 @@ vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
{
struct uio auio;
struct iovec aiov;
struct mount *mp;
int error;
if ((ioflg & IO_NODELOCKED) == 0)
if ((ioflg & IO_NODELOCKED) == 0) {
mp = NULL;
if (rw == UIO_WRITE &&
vp->v_type != VCHR && vp->v_type != VBLK &&
(error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
}
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
aiov.iov_base = base;
@ -316,8 +334,10 @@ vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
else
if (auio.uio_resid && error == 0)
error = EIO;
if ((ioflg & IO_NODELOCKED) == 0)
if ((ioflg & IO_NODELOCKED) == 0) {
vn_finished_write(mp);
VOP_UNLOCK(vp, 0, p);
}
return (error);
}
@ -368,6 +388,7 @@ vn_write(fp, uio, cred, flags, p)
int flags;
{
struct vnode *vp;
struct mount *mp;
int error, ioflag;
KASSERT(uio->uio_procp == p, ("uio_procp %p is not p %p",
@ -384,6 +405,10 @@ vn_write(fp, uio, cred, flags, p)
if ((fp->f_flag & O_FSYNC) ||
(vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
ioflag |= IO_SYNC;
mp = NULL;
if (vp->v_type != VCHR && vp->v_type != VBLK &&
(error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
VOP_LEASE(vp, p, cred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
if ((flags & FOF_OFFSET) == 0)
@ -394,6 +419,7 @@ vn_write(fp, uio, cred, flags, p)
fp->f_offset = uio->uio_offset;
fp->f_nextoff = uio->uio_offset;
VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
@ -649,6 +675,140 @@ vn_closefile(fp, p)
fp->f_cred, p));
}
/*
* Preparing to start a filesystem write operation. If the operation is
* permitted, then we bump the count of operations in progress and
* proceed. If a suspend request is in progress, we wait until the
* suspension is over, and then proceed.
*/
int
vn_start_write(vp, mpp, flags)
struct vnode *vp;
struct mount **mpp;
int flags;
{
struct mount *mp;
int error;
/*
* If a vnode is provided, get and return the mount point that
* to which it will write.
*/
if (vp != NULL) {
if ((error = VOP_GETWRITEMOUNT(vp, mpp)) != 0) {
*mpp = NULL;
if (error != EOPNOTSUPP)
return (error);
return (0);
}
}
if ((mp = *mpp) == NULL)
return (0);
/*
* Check on status of suspension.
*/
while ((mp->mnt_kern_flag & MNTK_SUSPEND) != 0) {
if (flags & V_NOWAIT)
return (EWOULDBLOCK);
error = tsleep(&mp->mnt_flag, (PUSER - 1) | (flags & PCATCH),
"suspfs", 0);
if (error)
return (error);
}
if (flags & V_XSLEEP)
return (0);
mp->mnt_writeopcount++;
return (0);
}
/*
* Secondary suspension. Used by operations such as vop_inactive
* routines that are needed by the higher level functions. These
* are allowed to proceed until all the higher level functions have
* completed (indicated by mnt_writeopcount dropping to zero). At that
* time, these operations are halted until the suspension is over.
*/
int
vn_write_suspend_wait(vp, flags)
struct vnode *vp;
int flags;
{
struct mount *mp;
int error;
if ((error = VOP_GETWRITEMOUNT(vp, &mp)) != 0) {
if (error != EOPNOTSUPP)
return (error);
return (0);
}
/*
* If we are not suspended or have not yet reached suspended
* mode, then let the operation proceed.
*/
if (mp == NULL || (mp->mnt_kern_flag & MNTK_SUSPENDED) == 0)
return (0);
if (flags & V_NOWAIT)
return (EWOULDBLOCK);
/*
* Wait for the suspension to finish.
*/
return (tsleep(&mp->mnt_flag, (PUSER - 1) | (flags & PCATCH),
"suspfs", 0));
}
/*
* Filesystem write operation has completed. If we are suspending and this
* operation is the last one, notify the suspender that the suspension is
* now in effect.
*/
void
vn_finished_write(mp)
struct mount *mp;
{
if (mp == NULL)
return;
mp->mnt_writeopcount--;
if (mp->mnt_writeopcount < 0)
panic("vn_finished_write: neg cnt");
if ((mp->mnt_kern_flag & MNTK_SUSPEND) != 0 &&
mp->mnt_writeopcount <= 0)
wakeup(&mp->mnt_writeopcount);
}
/*
* Request a filesystem to suspend write operations.
*/
void
vfs_write_suspend(mp)
struct mount *mp;
{
struct proc *p = curproc;
if (mp->mnt_kern_flag & MNTK_SUSPEND)
return;
mp->mnt_kern_flag |= MNTK_SUSPEND;
if (mp->mnt_writeopcount > 0)
(void) tsleep(&mp->mnt_writeopcount, PUSER - 1, "suspwt", 0);
VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p);
mp->mnt_kern_flag |= MNTK_SUSPENDED;
}
/*
* Request a filesystem to resume write operations.
*/
void
vfs_write_resume(mp)
struct mount *mp;
{
if ((mp->mnt_kern_flag & MNTK_SUSPEND) == 0)
return;
mp->mnt_kern_flag &= ~(MNTK_SUSPEND | MNTK_SUSPENDED);
wakeup(&mp->mnt_writeopcount);
wakeup(&mp->mnt_flag);
}
static int
filt_vnattach(struct knote *kn)
{

View File

@ -393,6 +393,22 @@ vop_strategy {
IN struct buf *bp;
};
#
#% getwritemount vp = = =
#
vop_getwritemount {
IN struct vnode *vp;
OUT struct mount **mpp;
};
#
#% copyonwrite vp L L L
#
vop_copyonwrite {
IN struct vnode *vp;
IN struct buf *bp;
};
#
#% print vp = = =
#

View File

@ -383,6 +383,8 @@ fdesc_setattr(ap)
{
struct filedesc *fdp = ap->a_p->p_fd;
struct vattr *vap = ap->a_vap;
struct vnode *vp;
struct mount *mp;
struct file *fp;
unsigned fd;
int error;
@ -403,8 +405,11 @@ fdesc_setattr(ap)
switch (fp->f_type) {
case DTYPE_FIFO:
case DTYPE_VNODE:
error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap,
ap->a_cred, ap->a_p);
vp = (struct vnode *)fp->f_data;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
error = VOP_SETATTR(vp, ap->a_vap, ap->a_cred, ap->a_p);
vn_finished_write(mp);
break;
default:

View File

@ -107,6 +107,7 @@ static struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
{ &vop_open_desc, (vop_t *) fifo_open },
{ &vop_pathconf_desc, (vop_t *) fifo_pathconf },
{ &vop_poll_desc, (vop_t *) fifo_poll },
{ &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount },
{ &vop_print_desc, (vop_t *) fifo_print },
{ &vop_read_desc, (vop_t *) fifo_read },
{ &vop_readdir_desc, (vop_t *) fifo_badop },

View File

@ -88,6 +88,7 @@ static struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
{ &vop_open_desc, (vop_t *) spec_open },
{ &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
{ &vop_poll_desc, (vop_t *) spec_poll },
{ &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount },
{ &vop_print_desc, (vop_t *) spec_print },
{ &vop_read_desc, (vop_t *) spec_read },
{ &vop_readdir_desc, (vop_t *) vop_panic },
@ -415,16 +416,29 @@ spec_strategy(ap)
struct buf *bp;
struct vnode *vp;
struct mount *mp;
int error;
bp = ap->a_bp;
if ((bp->b_iocmd == BIO_WRITE) && (LIST_FIRST(&bp->b_dep)) != NULL)
buf_start(bp);
vp = ap->a_vp;
if ((bp->b_iocmd == BIO_WRITE)) {
if (vp->v_mount != NULL &&
(vp->v_mount->mnt_kern_flag & MNTK_SUSPENDED) != 0)
panic("spec_strategy: bad I/O");
if (LIST_FIRST(&bp->b_dep) != NULL)
buf_start(bp);
if ((vp->v_flag & VCOPYONWRITE) &&
(error = VOP_COPYONWRITE(vp, bp)) != 0 &&
error != EOPNOTSUPP) {
bp->b_io.bio_error = error;
bp->b_io.bio_flags |= BIO_ERROR;
biodone(&bp->b_io);
return (0);
}
}
/*
* Collect statistics on synchronous and asynchronous read
* and write counts for disks that have associated filesystems.
*/
vp = ap->a_vp;
if (vn_isdisk(vp, NULL) && (mp = vp->v_specmountpoint) != NULL) {
if (bp->b_iocmd == BIO_WRITE) {
if (bp->b_lock.lk_lockholder == LK_KERNPROC)

View File

@ -747,6 +747,7 @@ union_copyup(un, docopy, cred, p)
struct proc *p;
{
int error;
struct mount *mp;
struct vnode *lvp, *uvp;
/*
@ -759,9 +760,12 @@ union_copyup(un, docopy, cred, p)
if (error)
return (error);
error = union_vn_create(&uvp, un, p);
if (error)
if ((error = vn_start_write(un->un_dirvp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
if ((error = union_vn_create(&uvp, un, p)) != 0) {
vn_finished_write(mp);
return (error);
}
lvp = un->un_lowervp;
@ -785,6 +789,7 @@ union_copyup(un, docopy, cred, p)
}
VOP_UNLOCK(uvp, 0, p);
vn_finished_write(mp);
union_newupper(un, uvp);
KASSERT(uvp->v_usecount > 0, ("copy: uvp refcount 0: %d", uvp->v_usecount));
union_vn_close(uvp, FWRITE, cred, p);
@ -910,11 +915,15 @@ union_mkshadow(um, dvp, cnp, vpp)
struct vattr va;
struct proc *p = cnp->cn_proc;
struct componentname cn;
struct mount *mp;
error = union_relookup(um, dvp, vpp, cnp, &cn,
cnp->cn_nameptr, cnp->cn_namelen);
if (error)
if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
if ((error = union_relookup(um, dvp, vpp, cnp, &cn,
cnp->cn_nameptr, cnp->cn_namelen)) != 0) {
vn_finished_write(mp);
return (error);
}
if (*vpp) {
if (cn.cn_flags & HASBUF) {
@ -925,6 +934,7 @@ union_mkshadow(um, dvp, cnp, vpp)
vrele(*vpp);
else
vput(*vpp);
vn_finished_write(mp);
*vpp = NULLVP;
return (EEXIST);
}
@ -950,6 +960,7 @@ union_mkshadow(um, dvp, cnp, vpp)
cn.cn_flags &= ~HASBUF;
}
/*vput(dvp);*/
vn_finished_write(mp);
return (error);
}
@ -973,10 +984,15 @@ union_mkwhiteout(um, dvp, cnp, path)
struct proc *p = cnp->cn_proc;
struct vnode *wvp;
struct componentname cn;
struct mount *mp;
error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path));
if (error)
if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path));
if (error) {
vn_finished_write(mp);
return (error);
}
if (wvp) {
if (cn.cn_flags & HASBUF) {
@ -987,6 +1003,7 @@ union_mkwhiteout(um, dvp, cnp, path)
vrele(wvp);
else
vput(wvp);
vn_finished_write(mp);
return (EEXIST);
}
@ -998,6 +1015,7 @@ union_mkwhiteout(um, dvp, cnp, path)
zfree(namei_zone, cn.cn_pnbuf);
cn.cn_flags &= ~HASBUF;
}
vn_finished_write(mp);
return (error);
}

View File

@ -93,6 +93,7 @@ static int union_print __P((struct vop_print_args *ap));
static int union_read __P((struct vop_read_args *ap));
static int union_readdir __P((struct vop_readdir_args *ap));
static int union_readlink __P((struct vop_readlink_args *ap));
static int union_getwritemount __P((struct vop_getwritemount_args *ap));
static int union_reclaim __P((struct vop_reclaim_args *ap));
static int union_remove __P((struct vop_remove_args *ap));
static int union_rename __P((struct vop_rename_args *ap));
@ -1681,6 +1682,20 @@ union_readlink(ap)
return (error);
}
static int
union_getwritemount(ap)
struct vop_getwritemount_args /* {
struct vnode *a_vp;
struct mount **a_mpp;
} */ *ap;
{
struct vnode *vp = UPPERVP(ap->a_vp);
if (vp == NULL)
panic("union: missing upper layer in getwritemount");
return(VOP_GETWRITEMOUNT(vp, ap->a_mpp));
}
/*
* union_inactive:
*
@ -1963,6 +1978,7 @@ static struct vnodeopv_entry_desc union_vnodeop_entries[] = {
{ &vop_read_desc, (vop_t *) union_read },
{ &vop_readdir_desc, (vop_t *) union_readdir },
{ &vop_readlink_desc, (vop_t *) union_readlink },
{ &vop_getwritemount_desc, (vop_t *) union_getwritemount },
{ &vop_reclaim_desc, (vop_t *) union_reclaim },
{ &vop_remove_desc, (vop_t *) union_remove },
{ &vop_rename_desc, (vop_t *) union_rename },

View File

@ -325,10 +325,18 @@ nfsrv_setattr(nfsd, slp, procp, mrq)
struct mbuf *mb, *mb2, *mreq;
u_quad_t frev;
struct timespec guard;
struct mount *mp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
VATTR_NULL(vap);
if (v3) {
nfsm_srvsattr(vap);
@ -440,6 +448,7 @@ nfsrv_setattr(nfsd, slp, procp, mrq)
nfsmout:
if (vp)
vput(vp);
vn_finished_write(mp);
return(error);
}
@ -1039,6 +1048,7 @@ nfsrv_write(nfsd, slp, procp, mrq)
struct uio io, *uiop = &io;
off_t off;
u_quad_t frev;
struct mount *mntp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
if (mrep == NULL) {
@ -1048,6 +1058,13 @@ nfsrv_write(nfsd, slp, procp, mrq)
}
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mntp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mntp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mntp, V_WAIT);
vput(vp);
vp = NULL;
if (v3) {
nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
off = fxdr_hyper(tl);
@ -1205,6 +1222,7 @@ nfsrv_write(nfsd, slp, procp, mrq)
nfsmout:
if (vp)
vput(vp);
vn_finished_write(mntp);
return(error);
}
@ -1241,6 +1259,7 @@ nfsrv_writegather(ndp, slp, procp, mrq)
struct vnode *vp = NULL;
struct uio io, *uiop = &io;
u_quad_t frev, cur_usec;
struct mount *mntp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
@ -1443,9 +1462,17 @@ nfsrv_writegather(ndp, slp, procp, mrq)
}
mp = mp->m_next;
}
if (!error) {
if (vn_start_write(vp, &mntp, V_NOWAIT) != 0) {
VOP_UNLOCK(vp, 0, procp);
error = vn_start_write(NULL, &mntp, V_WAIT);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp);
}
}
if (!error) {
error = VOP_WRITE(vp, uiop, ioflags, cred);
nfsstats.srvvop_writes++;
vn_finished_write(mntp);
}
FREE((caddr_t)iov, M_TEMP);
}
@ -1620,6 +1647,8 @@ nfsrv_create(nfsd, slp, procp, mrq)
fhandle_t *fhp;
u_quad_t frev, tempsize;
u_char cverf[NFSX_V3CREATEVERF];
struct mount *mp = NULL;
struct vnode *vp;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
@ -1629,6 +1658,12 @@ nfsrv_create(nfsd, slp, procp, mrq)
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
@ -1869,6 +1904,7 @@ nfsrv_create(nfsd, slp, procp, mrq)
}
if (nd.ni_vp)
vput(nd.ni_vp);
vn_finished_write(mp);
return (error);
}
@ -1901,12 +1937,20 @@ nfsrv_mknod(nfsd, slp, procp, mrq)
nfsfh_t nfh;
fhandle_t *fhp;
u_quad_t frev;
struct mount *mp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
@ -2030,6 +2074,7 @@ nfsrv_mknod(nfsd, slp, procp, mrq)
nfsm_srvpostop_attr(0, vap);
}
nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
vn_finished_write(mp);
return (0);
nfsmout:
if (dirp)
@ -2045,6 +2090,7 @@ nfsrv_mknod(nfsd, slp, procp, mrq)
}
if (nd.ni_vp)
vput(nd.ni_vp);
vn_finished_write(mp);
return (error);
}
@ -2075,12 +2121,21 @@ nfsrv_remove(nfsd, slp, procp, mrq)
nfsfh_t nfh;
fhandle_t *fhp;
u_quad_t frev;
struct mount *mp = NULL;
struct vnode *vp;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
@ -2137,6 +2192,7 @@ nfsrv_remove(nfsd, slp, procp, mrq)
}
if (nd.ni_vp)
vput(nd.ni_vp);
vn_finished_write(mp);
return(error);
}
@ -2170,6 +2226,8 @@ nfsrv_rename(nfsd, slp, procp, mrq)
fhandle_t *ffhp, *tfhp;
u_quad_t frev;
uid_t saved_uid;
struct mount *mp = NULL;
struct vnode *vp;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
@ -2186,6 +2244,13 @@ nfsrv_rename(nfsd, slp, procp, mrq)
ndclear(&tond);
nfsm_srvmtofh(ffhp);
if ((mp = vfs_getvfs(&ffhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &ffhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
/*
* Remember our original uid so that we can reset cr_uid before
@ -2360,6 +2425,7 @@ nfsrv_rename(nfsd, slp, procp, mrq)
if (fromnd.ni_vp)
vrele(fromnd.ni_vp);
vn_finished_write(mp);
return (error);
}
@ -2390,6 +2456,7 @@ nfsrv_link(nfsd, slp, procp, mrq)
nfsfh_t nfh, dnfh;
fhandle_t *fhp, *dfhp;
u_quad_t frev;
struct mount *mp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
@ -2397,6 +2464,13 @@ nfsrv_link(nfsd, slp, procp, mrq)
fhp = &nfh.fh_generic;
dfhp = &dnfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvmtofh(dfhp);
nfsm_srvnamesiz(len);
@ -2475,6 +2549,7 @@ nfsrv_link(nfsd, slp, procp, mrq)
}
if (nd.ni_vp)
vrele(nd.ni_vp);
vn_finished_write(mp);
return(error);
}
@ -2508,12 +2583,21 @@ nfsrv_symlink(nfsd, slp, procp, mrq)
nfsfh_t nfh;
fhandle_t *fhp;
u_quad_t frev;
struct mount *mp = NULL;
struct vnode *vp;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = CREATE;
@ -2651,6 +2735,7 @@ nfsrv_symlink(nfsd, slp, procp, mrq)
if (pathcp)
FREE(pathcp, M_TEMP);
vn_finished_write(mp);
return (error);
}
@ -2685,12 +2770,21 @@ nfsrv_mkdir(nfsd, slp, procp, mrq)
nfsfh_t nfh;
fhandle_t *fhp;
u_quad_t frev;
struct mount *mp = NULL;
struct vnode *vp;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = CREATE;
@ -2787,6 +2881,7 @@ nfsrv_mkdir(nfsd, slp, procp, mrq)
else
vrele(nd.ni_vp);
}
vn_finished_write(mp);
return (error);
}
@ -2817,12 +2912,20 @@ nfsrv_rmdir(nfsd, slp, procp, mrq)
fhandle_t *fhp;
struct nameidata nd;
u_quad_t frev;
struct mount *mp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = DELETE;
@ -2895,6 +2998,7 @@ nfsrv_rmdir(nfsd, slp, procp, mrq)
if (nd.ni_vp)
vput(nd.ni_vp);
vn_finished_write(mp);
return(error);
}
@ -3588,6 +3692,7 @@ nfsrv_commit(nfsd, slp, procp, mrq)
char *cp2;
struct mbuf *mb, *mb2, *mreq;
u_quad_t frev, off;
struct mount *mp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
@ -3595,6 +3700,13 @@ nfsrv_commit(nfsd, slp, procp, mrq)
#endif
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
/*
@ -3697,6 +3809,7 @@ nfsrv_commit(nfsd, slp, procp, mrq)
nfsmout:
if (vp)
vput(vp);
vn_finished_write(mp);
return(error);
}
@ -4065,4 +4178,3 @@ nfsrv_access(vp, flags, cred, rdonly, p, override)
return error;
}
#endif /* NFS_NOSERVER */

View File

@ -325,10 +325,18 @@ nfsrv_setattr(nfsd, slp, procp, mrq)
struct mbuf *mb, *mb2, *mreq;
u_quad_t frev;
struct timespec guard;
struct mount *mp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
VATTR_NULL(vap);
if (v3) {
nfsm_srvsattr(vap);
@ -440,6 +448,7 @@ nfsrv_setattr(nfsd, slp, procp, mrq)
nfsmout:
if (vp)
vput(vp);
vn_finished_write(mp);
return(error);
}
@ -1039,6 +1048,7 @@ nfsrv_write(nfsd, slp, procp, mrq)
struct uio io, *uiop = &io;
off_t off;
u_quad_t frev;
struct mount *mntp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
if (mrep == NULL) {
@ -1048,6 +1058,13 @@ nfsrv_write(nfsd, slp, procp, mrq)
}
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mntp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mntp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mntp, V_WAIT);
vput(vp);
vp = NULL;
if (v3) {
nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
off = fxdr_hyper(tl);
@ -1205,6 +1222,7 @@ nfsrv_write(nfsd, slp, procp, mrq)
nfsmout:
if (vp)
vput(vp);
vn_finished_write(mntp);
return(error);
}
@ -1241,6 +1259,7 @@ nfsrv_writegather(ndp, slp, procp, mrq)
struct vnode *vp = NULL;
struct uio io, *uiop = &io;
u_quad_t frev, cur_usec;
struct mount *mntp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
@ -1443,9 +1462,17 @@ nfsrv_writegather(ndp, slp, procp, mrq)
}
mp = mp->m_next;
}
if (!error) {
if (vn_start_write(vp, &mntp, V_NOWAIT) != 0) {
VOP_UNLOCK(vp, 0, procp);
error = vn_start_write(NULL, &mntp, V_WAIT);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp);
}
}
if (!error) {
error = VOP_WRITE(vp, uiop, ioflags, cred);
nfsstats.srvvop_writes++;
vn_finished_write(mntp);
}
FREE((caddr_t)iov, M_TEMP);
}
@ -1620,6 +1647,8 @@ nfsrv_create(nfsd, slp, procp, mrq)
fhandle_t *fhp;
u_quad_t frev, tempsize;
u_char cverf[NFSX_V3CREATEVERF];
struct mount *mp = NULL;
struct vnode *vp;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
@ -1629,6 +1658,12 @@ nfsrv_create(nfsd, slp, procp, mrq)
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
@ -1869,6 +1904,7 @@ nfsrv_create(nfsd, slp, procp, mrq)
}
if (nd.ni_vp)
vput(nd.ni_vp);
vn_finished_write(mp);
return (error);
}
@ -1901,12 +1937,20 @@ nfsrv_mknod(nfsd, slp, procp, mrq)
nfsfh_t nfh;
fhandle_t *fhp;
u_quad_t frev;
struct mount *mp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
@ -2030,6 +2074,7 @@ nfsrv_mknod(nfsd, slp, procp, mrq)
nfsm_srvpostop_attr(0, vap);
}
nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
vn_finished_write(mp);
return (0);
nfsmout:
if (dirp)
@ -2045,6 +2090,7 @@ nfsrv_mknod(nfsd, slp, procp, mrq)
}
if (nd.ni_vp)
vput(nd.ni_vp);
vn_finished_write(mp);
return (error);
}
@ -2075,12 +2121,21 @@ nfsrv_remove(nfsd, slp, procp, mrq)
nfsfh_t nfh;
fhandle_t *fhp;
u_quad_t frev;
struct mount *mp = NULL;
struct vnode *vp;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
@ -2137,6 +2192,7 @@ nfsrv_remove(nfsd, slp, procp, mrq)
}
if (nd.ni_vp)
vput(nd.ni_vp);
vn_finished_write(mp);
return(error);
}
@ -2170,6 +2226,8 @@ nfsrv_rename(nfsd, slp, procp, mrq)
fhandle_t *ffhp, *tfhp;
u_quad_t frev;
uid_t saved_uid;
struct mount *mp = NULL;
struct vnode *vp;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
@ -2186,6 +2244,13 @@ nfsrv_rename(nfsd, slp, procp, mrq)
ndclear(&tond);
nfsm_srvmtofh(ffhp);
if ((mp = vfs_getvfs(&ffhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &ffhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
/*
* Remember our original uid so that we can reset cr_uid before
@ -2360,6 +2425,7 @@ nfsrv_rename(nfsd, slp, procp, mrq)
if (fromnd.ni_vp)
vrele(fromnd.ni_vp);
vn_finished_write(mp);
return (error);
}
@ -2390,6 +2456,7 @@ nfsrv_link(nfsd, slp, procp, mrq)
nfsfh_t nfh, dnfh;
fhandle_t *fhp, *dfhp;
u_quad_t frev;
struct mount *mp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
@ -2397,6 +2464,13 @@ nfsrv_link(nfsd, slp, procp, mrq)
fhp = &nfh.fh_generic;
dfhp = &dnfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvmtofh(dfhp);
nfsm_srvnamesiz(len);
@ -2475,6 +2549,7 @@ nfsrv_link(nfsd, slp, procp, mrq)
}
if (nd.ni_vp)
vrele(nd.ni_vp);
vn_finished_write(mp);
return(error);
}
@ -2508,12 +2583,21 @@ nfsrv_symlink(nfsd, slp, procp, mrq)
nfsfh_t nfh;
fhandle_t *fhp;
u_quad_t frev;
struct mount *mp = NULL;
struct vnode *vp;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = CREATE;
@ -2651,6 +2735,7 @@ nfsrv_symlink(nfsd, slp, procp, mrq)
if (pathcp)
FREE(pathcp, M_TEMP);
vn_finished_write(mp);
return (error);
}
@ -2685,12 +2770,21 @@ nfsrv_mkdir(nfsd, slp, procp, mrq)
nfsfh_t nfh;
fhandle_t *fhp;
u_quad_t frev;
struct mount *mp = NULL;
struct vnode *vp;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = CREATE;
@ -2787,6 +2881,7 @@ nfsrv_mkdir(nfsd, slp, procp, mrq)
else
vrele(nd.ni_vp);
}
vn_finished_write(mp);
return (error);
}
@ -2817,12 +2912,20 @@ nfsrv_rmdir(nfsd, slp, procp, mrq)
fhandle_t *fhp;
struct nameidata nd;
u_quad_t frev;
struct mount *mp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = DELETE;
@ -2895,6 +2998,7 @@ nfsrv_rmdir(nfsd, slp, procp, mrq)
if (nd.ni_vp)
vput(nd.ni_vp);
vn_finished_write(mp);
return(error);
}
@ -3588,6 +3692,7 @@ nfsrv_commit(nfsd, slp, procp, mrq)
char *cp2;
struct mbuf *mb, *mb2, *mreq;
u_quad_t frev, off;
struct mount *mp = NULL;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
@ -3595,6 +3700,13 @@ nfsrv_commit(nfsd, slp, procp, mrq)
#endif
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != NULL)
return (error);
(void) vn_start_write(vp, &mp, V_WAIT);
vput(vp);
vp = NULL;
nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
/*
@ -3697,6 +3809,7 @@ nfsrv_commit(nfsd, slp, procp, mrq)
nfsmout:
if (vp)
vput(vp);
vn_finished_write(mp);
return(error);
}
@ -4065,4 +4178,3 @@ nfsrv_access(vp, flags, cred, rdonly, p, override)
return error;
}
#endif /* NFS_NOSERVER */

View File

@ -247,6 +247,7 @@ fd_revoke(p, fd)
struct filedesc *fdp = p->p_fd;
struct file *fp;
struct vnode *vp;
struct mount *mp;
struct vattr vattr;
int error, *retval;
@ -271,8 +272,11 @@ fd_revoke(p, fd)
(error = suser(p)) != 0)
goto out;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
goto out;
if (vcount(vp) > 1)
VOP_REVOKE(vp, REVOKEALL);
vn_finished_write(mp);
out:
vrele(vp);
return error;

View File

@ -466,6 +466,7 @@ buf_countdeps(struct buf *bp, int i)
/* Flags to low-level allocation routines. */
#define B_CLRBUF 0x01 /* Request allocated buffer be cleared. */
#define B_SYNC 0x02 /* Do all allocations synchronously. */
#define B_METAONLY 0x04 /* Return indirect block buffer. */
#ifdef _KERNEL
extern int nbuf; /* The number of buffer headers */

View File

@ -285,6 +285,7 @@ struct proc {
/* Marked a kernel thread */
#define P_BUFEXHAUST 0x100000 /* dirty buffers flush is in progress */
#define P_KTHREADP 0x200000 /* Process is really a kernel thread */
#define P_COWINPROGRESS 0x400000 /* Snapshot copy-on-write in progress */
#define P_DEADLKTREAT 0x800000 /* lock aquisition - deadlock treatment */

View File

@ -158,7 +158,7 @@ struct vnode {
/* open for business 0x00800 */
/* open for business 0x01000 */
#define VOBJBUF 0x02000 /* Allocate buffers in VM object */
/* open for business 0x04000 */
#define VCOPYONWRITE 0x04000 /* vnode is doing copy-on-write */
#define VAGE 0x08000 /* Insert vnode at head of free list */
#define VOLOCK 0x10000 /* vnode is locked waiting for an object */
#define VOWANT 0x20000 /* a process is waiting for VOLOCK */
@ -246,12 +246,15 @@ extern int vttoif_tab[];
/*
* Flags to various vnode functions.
*/
#define SKIPSYSTEM 0x0001 /* vflush: skip vnodes marked VSYSTEM */
#define FORCECLOSE 0x0002 /* vflush: force file closure */
#define WRITECLOSE 0x0004 /* vflush: only close writable files */
#define DOCLOSE 0x0008 /* vclean: close active files */
#define V_SAVE 0x0001 /* vinvalbuf: sync file first */
#define REVOKEALL 0x0001 /* vop_revoke: revoke all aliases */
#define SKIPSYSTEM 0x0001 /* vflush: skip vnodes marked VSYSTEM */
#define FORCECLOSE 0x0002 /* vflush: force file closure */
#define WRITECLOSE 0x0004 /* vflush: only close writable files */
#define DOCLOSE 0x0008 /* vclean: close active files */
#define V_SAVE 0x0001 /* vinvalbuf: sync file first */
#define REVOKEALL 0x0001 /* vop_revoke: revoke all aliases */
#define V_WAIT 0x0001 /* vn_start_write: sleep for suspend */
#define V_NOWAIT 0x0002 /* vn_start_write: don't sleep for suspend */
#define V_XSLEEP 0x0004 /* vn_start_write: just return after sleep */
#define VREF(vp) vref(vp)
@ -572,6 +575,7 @@ int vrecycle __P((struct vnode *vp, struct simplelock *inter_lkp,
struct proc *p));
int vn_close __P((struct vnode *vp,
int flags, struct ucred *cred, struct proc *p));
void vn_finished_write __P((struct mount *mp));
int vn_isdisk __P((struct vnode *vp, int *errp));
int vn_lock __P((struct vnode *vp, int flags, struct proc *p));
#ifdef DEBUG_LOCKS
@ -587,13 +591,18 @@ int vn_rdwr __P((enum uio_rw rw, struct vnode *vp, caddr_t base,
int len, off_t offset, enum uio_seg segflg, int ioflg,
struct ucred *cred, int *aresid, struct proc *p));
int vn_stat __P((struct vnode *vp, struct stat *sb, struct proc *p));
int vn_start_write __P((struct vnode *vp, struct mount **mpp, int flags));
dev_t vn_todev __P((struct vnode *vp));
int vn_write_suspend_wait __P((struct vnode *vp, int flags));
int vn_writechk __P((struct vnode *vp));
int vfs_cache_lookup __P((struct vop_lookup_args *ap));
int vfs_object_create __P((struct vnode *vp, struct proc *p,
struct ucred *cred));
void vfs_timestamp __P((struct timespec *));
int vn_writechk __P((struct vnode *vp));
void vfs_write_resume __P((struct mount *mp));
void vfs_write_suspend __P((struct mount *mp));
int vop_stdbwrite __P((struct vop_bwrite_args *ap));
int vop_stdgetwritemount __P((struct vop_getwritemount_args *));
int vop_stdislocked __P((struct vop_islocked_args *));
int vop_stdlock __P((struct vop_lock_args *));
int vop_stdunlock __P((struct vop_unlock_args *));

112
sys/ufs/ffs/README.snapshot Normal file
View File

@ -0,0 +1,112 @@
$FreeBSD$
Soft Updates Status
As is detailed in the operational information below, snapshots
are definitely alpha-test code and are NOT yet ready for production
use. Much remains to be done to make them really useful, but I
wanted to let folks get a chance to try it out and start reporting
bugs and other shortcomings. Such reports should be sent to
Kirk McKusick <mckusick@mckusick.com>.
Snapshot Copyright Restrictions
Snapshots have been introduced to FreeBSD with a `Berkeley-style'
copyright. The file implementing snapshots resides in the sys/ufs/ffs
directory and is compiled into the generic kernel by default.
Using Snapshots
To create a snapshot of your /var filesystem, run the command:
mount -u -o snapshot /var/snapshot/snap1 /var
This command will take a snapshot of your /var filesystem and
leave it in the file /var/snapshot/snap1. Note that snapshot
files must be created in the filesystem that is being snapshotted.
I use the convention of putting a `snapshot' directory at the
root of each filesystem into which I can place snapshots.
You may create up to 20 snapshots per filesystem. Active snapshots
are recorded in the superblock, so they persist across unmount
and remount operations and across system reboots. When your
are done with a snapshot, it can be removed with the `rm'
command. Snapshots may be removed in any order, however you
may not get back all the space contained in the snapshot as
another snapshot may claim some of the blocks that it is releasing.
Note that the `schg' flag is set on snapshots to ensure that
not even the root user can write to them. The unlink command
makes an exception for snapshot files in that it allows them
to be removed even though they have the `schg' flag set, so it
is not necessary to clear the `schg' flag before removing a
snapshot file.
Once you have taken a snapshot, there are three interesting
things that you can do with it:
1) Run fsck on the snapshot file. Assuming that the filesystem
was clean when it was mounted, you should always get a clean
(and unchanging) result from running fsck on the snapshot.
If you are running with soft updates and rebooted after a
crash without cleaning up the filesystem, then fsck of the
snapshot may find missing blocks and inodes or inodes with
link counts that are too high. I have not yet added the
system calls to allow fsck to add these missing resources
back to the filesystem - that will be added once the basic
snapshot code is working properly. So, view those reports
as informational for now.
2) Run dump on the snapshot. You will get a dump that is
consistent with the filesystem as of the timestamp of the
snapshot. Note that I have not yet changed dump to set the
dumpdates file correctly, so do not use this feature in
production until that fix is made.
3) Mount the snapshot as a frozen image of the filesystem.
To mount the snapshot /var/snapshot/snap1:
vnconfig -c vn0c /var/snapshot/snap1
mount -r /dev/vn0c /mnt
You can now cruise around your frozen /var filesystem
at /mnt. Everything will be in the same state that it
was at the time the snapshot was taken. The one exception
is that any earlier snapshots will appear as zero length
files. When you are done with the mounted snapshot:
umount /mnt
vnconfig -u vn0c
Note that under some circumstances, the process accessing
the frozen filesystem may deadlock. I am aware of this
problem, but the solution is not simple. It requires
using buffer read locks rather than exclusive locks when
traversing the inode indirect blocks. Until this problem
is fixed, you should avoid putting mounted snapshots into
production.
Performance
It takes about 30 seconds to create a snapshot of an 8Gb filesystem.
Of that time 25 seconds is spent in preparation; filesystem activity
is only suspended for the final 5 seconds of that period. Snapshot
removal of an 8Gb filesystem takes about two minutes. Filesystem
activity is never suspended during snapshot removal.
The suspend time may be expanded by several minutes if a process
is in the midst of removing many files as all the soft updates
backlog must be cleared. Generally snapshots do not slow the system
down appreciably except when removing many small files (i.e., any
file less than 96Kb whose last block is a fragment) that are claimed
by a snapshot. Here, the snapshot code must make a copy of every
released fragment which slows the rate of file removal to about
twenty files per second once the soft updates backlog limit is
reached.
How Snapshots Work
For more general information on snapshots, please see:
http://www.mckusick.com/softdep/

View File

@ -186,6 +186,8 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp)
*bpp = 0;
fs = ip->i_fs;
#ifdef DIAGNOSTIC
if (ITOV(ip)->v_mount->mnt_kern_flag & MNTK_SUSPENDED)
panic("ffs_realloccg: allocation on suspended filesystem");
if ((u_int)osize > fs->fs_bsize || fragoff(fs, osize) != 0 ||
(u_int)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) {
printf(
@ -763,6 +765,10 @@ ffs_hashalloc(ip, cg, pref, size, allocator)
long result; /* XXX why not same type as we return? */
int i, icg = cg;
#ifdef DIAGNOSTIC
if (ITOV(ip)->v_mount->mnt_kern_flag & MNTK_SUSPENDED)
panic("ffs_hashalloc: allocation on suspended filesystem");
#endif
fs = ip->i_fs;
/*
* 1: preferred cylinder group
@ -1311,9 +1317,13 @@ ffs_blkfree(ip, bno, size)
ufs_daddr_t blkno;
int i, error, cg, blk, frags, bbase;
u_int8_t *blksfree;
struct vnode *vp;
fs = ip->i_fs;
VOP_FREEBLKS(ip->i_devvp, fsbtodb(fs, bno), size);
#ifdef DIAGNOSTIC
if ((vp = ITOV(ip)) != NULL && vp->v_mount != NULL &&
(vp->v_mount->mnt_kern_flag & MNTK_SUSPENDED))
panic("ffs_blkfree: deallocation on suspended filesystem");
if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0 ||
fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) {
printf("dev=%s, bno = %ld, bsize = %ld, size = %ld, fs = %s\n",
@ -1321,6 +1331,11 @@ ffs_blkfree(ip, bno, size)
fs->fs_fsmnt);
panic("ffs_blkfree: bad size");
}
#endif
if ((ip->i_devvp->v_flag & VCOPYONWRITE) &&
ffs_snapblkfree(ip, bno, size))
return;
VOP_FREEBLKS(ip->i_devvp, fsbtodb(fs, bno), size);
cg = dtog(fs, bno);
if ((u_int)bno >= fs->fs_size) {
printf("bad block %ld, ino %lu\n",

View File

@ -125,6 +125,8 @@ ffs_balloc(ap)
* The first NDADDR blocks are direct blocks
*/
if (lbn < NDADDR) {
if (flags & B_METAONLY)
panic("ffs_balloc: B_METAONLY for direct block");
nb = ip->i_db[lbn];
if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) {
error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp);
@ -288,6 +290,13 @@ ffs_balloc(ap)
bdwrite(bp);
}
}
/*
* If asked only for the indirect block, then return it.
*/
if (flags & B_METAONLY) {
*ap->a_bpp = bp;
return (0);
}
/*
* Get the data block, allocating if necessary.
*/

View File

@ -67,6 +67,7 @@ struct vop_balloc_args;
struct vop_bmap_args;
struct vop_fsync_args;
struct vop_reallocblks_args;
struct vop_copyonwrite_args;
int ffs_alloc __P((struct inode *,
ufs_daddr_t, ufs_daddr_t, int, struct ucred *, ufs_daddr_t *));
@ -76,6 +77,7 @@ void ffs_blkfree __P((struct inode *, ufs_daddr_t, long));
ufs_daddr_t ffs_blkpref __P((struct inode *, ufs_daddr_t, int, ufs_daddr_t *));
int ffs_bmap __P((struct vop_bmap_args *));
void ffs_clrblock __P((struct fs *, u_char *, ufs_daddr_t));
int ffs_copyonwrite __P((struct vop_copyonwrite_args *ap));
int ffs_fhtovp __P((struct mount *, struct fid *, struct vnode **));
int ffs_flushfiles __P((struct mount *, int, struct proc *));
void ffs_fragacct __P((struct fs *, int, int32_t [], int));
@ -89,6 +91,10 @@ int ffs_reallocblks __P((struct vop_reallocblks_args *));
int ffs_realloccg __P((struct inode *,
ufs_daddr_t, ufs_daddr_t, int, int, struct ucred *, struct buf **));
void ffs_setblock __P((struct fs *, u_char *, ufs_daddr_t));
int ffs_snapblkfree __P((struct inode *freeip, ufs_daddr_t bno, long size));
int ffs_snapshot __P((struct mount *mp, char *snapfile));
void ffs_snapshot_mount __P((struct mount *mp));
void ffs_snapshot_unmount __P((struct mount *mp));
int ffs_statfs __P((struct mount *, struct statfs *, struct proc *));
int ffs_sync __P((struct mount *, int, struct ucred *, struct proc *));
int ffs_truncate __P((struct vnode *, off_t, int, struct ucred *, struct proc *));

1028
sys/ufs/ffs/ffs_snapshot.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -508,7 +508,7 @@ softdep_process_worklist(matchmnt)
{
struct proc *p = CURPROC;
struct worklist *wk;
struct fs *matchfs;
struct mount *mp;
int matchcnt, loopcount;
/*
@ -517,9 +517,6 @@ softdep_process_worklist(matchmnt)
*/
filesys_syncer = p;
matchcnt = 0;
matchfs = NULL;
if (matchmnt != NULL)
matchfs = VFSTOUFS(matchmnt)->um_fs;
/*
* There is no danger of having multiple processes run this
* code. It is single threaded solely so that softdep_flushfiles
@ -550,30 +547,42 @@ softdep_process_worklist(matchmnt)
case D_DIRREM:
/* removal of a directory entry */
if (WK_DIRREM(wk)->dm_mnt == matchmnt)
mp = WK_DIRREM(wk)->dm_mnt;
if (mp == matchmnt)
matchcnt += 1;
vn_start_write(NULL, &mp, V_WAIT);
handle_workitem_remove(WK_DIRREM(wk));
vn_finished_write(mp);
break;
case D_FREEBLKS:
/* releasing blocks and/or fragments from a file */
if (WK_FREEBLKS(wk)->fb_fs == matchfs)
mp = WK_FREEBLKS(wk)->fb_mnt;
if (mp == matchmnt)
matchcnt += 1;
vn_start_write(NULL, &mp, V_WAIT);
handle_workitem_freeblocks(WK_FREEBLKS(wk));
vn_finished_write(mp);
break;
case D_FREEFRAG:
/* releasing a fragment when replaced as a file grows */
if (WK_FREEFRAG(wk)->ff_fs == matchfs)
mp = WK_FREEFRAG(wk)->ff_mnt;
if (mp == matchmnt)
matchcnt += 1;
vn_start_write(NULL, &mp, V_WAIT);
handle_workitem_freefrag(WK_FREEFRAG(wk));
vn_finished_write(mp);
break;
case D_FREEFILE:
/* releasing an inode when its link count drops to 0 */
if (WK_FREEFILE(wk)->fx_fs == matchfs)
mp = WK_FREEFILE(wk)->fx_mnt;
if (mp == matchmnt)
matchcnt += 1;
vn_start_write(NULL, &mp, V_WAIT);
handle_workitem_freefile(WK_FREEFILE(wk));
vn_finished_write(mp);
break;
default:
@ -1316,7 +1325,7 @@ newfreefrag(ip, blkno, size)
freefrag->ff_list.wk_type = D_FREEFRAG;
freefrag->ff_state = ip->i_uid & ~ONWORKLIST; /* XXX - used below */
freefrag->ff_inum = ip->i_number;
freefrag->ff_fs = fs;
freefrag->ff_mnt = ITOV(ip)->v_mount;
freefrag->ff_devvp = ip->i_devvp;
freefrag->ff_blkno = blkno;
freefrag->ff_fragsize = size;
@ -1333,7 +1342,8 @@ handle_workitem_freefrag(freefrag)
{
struct inode tip;
tip.i_fs = freefrag->ff_fs;
tip.i_vnode = NULL;
tip.i_fs = VFSTOUFS(freefrag->ff_mnt)->um_fs;
tip.i_devvp = freefrag->ff_devvp;
tip.i_dev = freefrag->ff_devvp->v_rdev;
tip.i_number = freefrag->ff_inum;
@ -1601,7 +1611,7 @@ softdep_setup_freeblocks(ip, length)
freeblks->fb_uid = ip->i_uid;
freeblks->fb_previousinum = ip->i_number;
freeblks->fb_devvp = ip->i_devvp;
freeblks->fb_fs = fs;
freeblks->fb_mnt = ITOV(ip)->v_mount;
freeblks->fb_oldsize = ip->i_size;
freeblks->fb_newsize = length;
freeblks->fb_chkcnt = ip->i_blocks;
@ -1845,7 +1855,7 @@ softdep_freefile(pvp, ino, mode)
freefile->fx_mode = mode;
freefile->fx_oldinum = ino;
freefile->fx_devvp = ip->i_devvp;
freefile->fx_fs = ip->i_fs;
freefile->fx_mnt = ITOV(ip)->v_mount;
/*
* If the inodedep does not exist, then the zero'ed inode has
@ -1949,13 +1959,13 @@ handle_workitem_freeblocks(freeblks)
int error, allerror = 0;
ufs_lbn_t baselbns[NIADDR], tmpval;
tip.i_fs = fs = VFSTOUFS(freeblks->fb_mnt)->um_fs;
tip.i_number = freeblks->fb_previousinum;
tip.i_devvp = freeblks->fb_devvp;
tip.i_dev = freeblks->fb_devvp->v_rdev;
tip.i_fs = freeblks->fb_fs;
tip.i_size = freeblks->fb_oldsize;
tip.i_uid = freeblks->fb_uid;
fs = freeblks->fb_fs;
tip.i_vnode = NULL;
tmpval = 1;
baselbns[0] = NDADDR;
for (i = 1; i < NIADDR; i++) {
@ -2715,20 +2725,23 @@ static void
handle_workitem_freefile(freefile)
struct freefile *freefile;
{
struct fs *fs;
struct vnode vp;
struct inode tip;
struct inodedep *idp;
int error;
fs = VFSTOUFS(freefile->fx_mnt)->um_fs;
#ifdef DEBUG
ACQUIRE_LOCK(&lk);
if (inodedep_lookup(freefile->fx_fs, freefile->fx_oldinum, 0, &idp))
if (inodedep_lookup(fs, freefile->fx_oldinum, 0, &idp))
panic("handle_workitem_freefile: inodedep survived");
FREE_LOCK(&lk);
#endif
tip.i_devvp = freefile->fx_devvp;
tip.i_dev = freefile->fx_devvp->v_rdev;
tip.i_fs = freefile->fx_fs;
tip.i_fs = fs;
tip.i_vnode = &vp;
vp.v_data = &tip;
if ((error = ffs_freefile(&vp, freefile->fx_oldinum, freefile->fx_mode)) != 0)
softdep_error("handle_workitem_freefile", error);
@ -4419,14 +4432,18 @@ clear_remove(p)
mp = pagedep->pd_mnt;
ino = pagedep->pd_ino;
FREE_LOCK(&lk);
if (vn_start_write(NULL, &mp, V_WAIT | PCATCH) != 0)
return;
if ((error = VFS_VGET(mp, ino, &vp)) != 0) {
softdep_error("clear_remove: vget", error);
vn_finished_write(mp);
return;
}
if ((error = VOP_FSYNC(vp, p->p_ucred, MNT_NOWAIT, p)))
softdep_error("clear_remove: fsync", error);
drain_output(vp, 0);
vput(vp);
vn_finished_write(mp);
return;
}
}
@ -4486,8 +4503,11 @@ clear_inodedeps(p)
if (inodedep_lookup(fs, ino, 0, &inodedep) == 0)
continue;
FREE_LOCK(&lk);
if (vn_start_write(NULL, &mp, V_WAIT | PCATCH) != 0)
return;
if ((error = VFS_VGET(mp, ino, &vp)) != 0) {
softdep_error("clear_inodedeps: vget", error);
vn_finished_write(mp);
return;
}
if (ino == lastino) {
@ -4499,6 +4519,7 @@ clear_inodedeps(p)
drain_output(vp, 0);
}
vput(vp);
vn_finished_write(mp);
ACQUIRE_LOCK(&lk);
}
FREE_LOCK(&lk);

View File

@ -133,7 +133,7 @@ VFS_SET(ufs_vfsops, ufs, 0);
* namei() if it is a genuine NULL from the user.
*/
static int
ffs_mount( mp, path, data, ndp, p)
ffs_mount(mp, path, data, ndp, p)
struct mount *mp; /* mount struct pointer*/
char *path; /* path to mount point*/
caddr_t data; /* arguments to FS specific mount*/
@ -141,49 +141,34 @@ ffs_mount( mp, path, data, ndp, p)
struct proc *p; /* process requesting mount*/
{
size_t size;
int err = 0;
struct vnode *devvp;
struct ufs_args args;
struct ufsmount *ump = 0;
register struct fs *fs;
int error, flags, ronly = 0;
int error, flags;
mode_t accessmode;
/*
* Use NULL path to flag a root mount
* Use NULL path to indicate we are mounting the root file system.
*/
if( path == NULL) {
/*
***
* Mounting root file system
***
*/
if ((err = bdevvp(rootdev, &rootvp))) {
if (path == NULL) {
if ((error = bdevvp(rootdev, &rootvp))) {
printf("ffs_mountroot: can't find rootvp\n");
return (err);
return (error);
}
if( ( err = ffs_mountfs(rootvp, mp, p, M_FFSNODE)) != 0) {
/* fs specific cleanup (if any)*/
goto error_1;
}
goto dostatfs; /* success*/
if ((error = ffs_mountfs(rootvp, mp, p, M_FFSNODE)) != 0)
return (error);
(void)VFS_STATFS(mp, &mp->mnt_stat, p);
return (0);
}
/*
***
* Mounting non-root file system or updating a file system
***
*/
/* copy in user arguments*/
err = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
if (err)
goto error_1; /* can't get arguments*/
if ((error = copyin(data, (caddr_t)&args, sizeof(struct ufs_args)))!= 0)
return (error);
/*
* If updating, check whether changing from read-only to
@ -193,25 +178,36 @@ ffs_mount( mp, path, data, ndp, p)
ump = VFSTOUFS(mp);
fs = ump->um_fs;
devvp = ump->um_devvp;
err = 0;
ronly = fs->fs_ronly; /* MNT_RELOAD might change this */
if (ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
return (error);
flags = WRITECLOSE;
if (mp->mnt_flag & MNT_FORCE)
flags |= FORCECLOSE;
if (mp->mnt_flag & MNT_SOFTDEP) {
err = softdep_flushfiles(mp, flags, p);
error = softdep_flushfiles(mp, flags, p);
} else {
err = ffs_flushfiles(mp, flags, p);
error = ffs_flushfiles(mp, flags, p);
}
ronly = 1;
if (error) {
vn_finished_write(mp);
return (error);
}
fs->fs_ronly = 1;
if ((fs->fs_flags & FS_UNCLEAN) == 0)
fs->fs_clean = 1;
if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
fs->fs_ronly = 0;
fs->fs_clean = 0;
vn_finished_write(mp);
return (error);
}
vn_finished_write(mp);
}
if (!err && (mp->mnt_flag & MNT_RELOAD))
err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
if (err) {
goto error_1;
}
if (ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
if ((mp->mnt_flag & MNT_RELOAD) &&
(error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p)) != 0)
return (error);
if (fs->fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
/*
* If upgrade to read-write by non-root, then verify
* that user has necessary permissions on the device.
@ -225,31 +221,36 @@ ffs_mount( mp, path, data, ndp, p)
}
VOP_UNLOCK(devvp, 0, p);
}
fs->fs_flags &= ~FS_UNCLEAN;
if (fs->fs_clean == 0) {
fs->fs_flags |= FS_UNCLEAN;
if (mp->mnt_flag & MNT_FORCE) {
printf(
"WARNING: %s was not properly dismounted\n",
fs->fs_fsmnt);
printf("WARNING: %s was not %s\n",
fs->fs_fsmnt, "properly dismounted");
} else {
printf(
"WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n",
fs->fs_fsmnt);
err = EPERM;
goto error_1;
return (EPERM);
}
}
/* check to see if we need to start softdep */
if (fs->fs_flags & FS_DOSOFTDEP) {
err = softdep_mount(devvp, mp, fs, p->p_ucred);
if (err)
goto error_1;
if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
return (error);
fs->fs_ronly = 0;
fs->fs_clean = 0;
if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
vn_finished_write(mp);
return (error);
}
ronly = 0;
/* check to see if we need to start softdep */
if ((fs->fs_flags & FS_DOSOFTDEP) &&
(error = softdep_mount(devvp, mp, fs, p->p_ucred))){
vn_finished_write(mp);
return (error);
}
if (fs->fs_snapinum[0] != 0)
ffs_snapshot_mount(mp);
vn_finished_write(mp);
}
/*
* Soft updates is incompatible with "async",
@ -258,18 +259,18 @@ ffs_mount( mp, path, data, ndp, p)
* Softdep_mount() clears it in an initial mount
* or ro->rw remount.
*/
if (mp->mnt_flag & MNT_SOFTDEP) {
if (mp->mnt_flag & MNT_SOFTDEP)
mp->mnt_flag &= ~MNT_ASYNC;
}
/* if not updating name...*/
if (args.fspec == 0) {
/*
* Process export requests. Jumping to "success"
* will return the vfs_export() error code.
*/
err = vfs_export(mp, &ump->um_export, &args.export);
goto success;
}
/*
* If not updating name, process export requests.
*/
if (args.fspec == 0)
return (vfs_export(mp, &ump->um_export, &args.export));
/*
* If this is a snapshot request, take the snapshot.
*/
if (mp->mnt_flag & MNT_SNAPSHOT)
return (ffs_snapshot(mp, args.fspec));
}
/*
@ -277,17 +278,14 @@ ffs_mount( mp, path, data, ndp, p)
* and verify that it refers to a sensible block device.
*/
NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
err = namei(ndp);
if (err) {
/* can't get devvp!*/
goto error_1;
}
if ((error = namei(ndp)) != 0)
return (error);
NDFREE(ndp, NDF_ONLY_PNBUF);
devvp = ndp->ni_vp;
if (!vn_isdisk(devvp, &err))
goto error_2;
if (!vn_isdisk(devvp, &error)) {
vrele(devvp);
return (error);
}
/*
* If mount by non-root, then verify that user has necessary
@ -298,7 +296,7 @@ ffs_mount( mp, path, data, ndp, p)
if ((mp->mnt_flag & MNT_RDONLY) == 0)
accessmode |= VWRITE;
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
if ((error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) != 0) {
if ((error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p))!= 0){
vput(devvp);
return (error);
}
@ -307,96 +305,43 @@ ffs_mount( mp, path, data, ndp, p)
if (mp->mnt_flag & MNT_UPDATE) {
/*
********************
* UPDATE
* Update only
*
* If it's not the same vnode, or at least the same device
* then it's not correct.
********************
*/
if (devvp != ump->um_devvp) {
if ( devvp->v_rdev == ump->um_devvp->v_rdev) {
vrele(devvp);
} else {
err = EINVAL; /* needs translation */
}
} else
vrele(devvp);
/*
* Update device name only on success
*/
if( !err) {
/* Save "mounted from" info for mount point (NULL pad)*/
copyinstr( args.fspec,
mp->mnt_stat.f_mntfromname,
MNAMELEN - 1,
&size);
bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
}
if (devvp != ump->um_devvp &&
devvp->v_rdev != ump->um_devvp->v_rdev)
error = EINVAL; /* needs translation */
vrele(devvp);
if (error)
return (error);
} else {
/*
********************
* NEW MOUNT
********************
* New mount
*
* We need the name for the mount point (also used for
* "last mounted on") copied in. If an error occurs,
* the mount point is discarded by the upper level code.
*/
/*
* Since this is a new mount, we want the names for
* the device and the mount point copied in. If an
* error occurs, the mountpoint is discarded by the
* upper level code.
*/
/* Save "last mounted on" info for mount point (NULL pad)*/
copyinstr( path, /* mount point*/
mp->mnt_stat.f_mntonname, /* save area*/
MNAMELEN - 1, /* max size*/
&size); /* real size*/
copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
/* Save "mounted from" info for mount point (NULL pad)*/
copyinstr( args.fspec, /* device name*/
mp->mnt_stat.f_mntfromname, /* save area*/
MNAMELEN - 1, /* max size*/
&size); /* real size*/
bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
err = ffs_mountfs(devvp, mp, p, M_FFSNODE);
}
if (err) {
goto error_2;
}
dostatfs:
/*
* Initialize FS stat information in mount struct; uses both
* mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
*
* This code is common to root and non-root mounts
*/
(void)VFS_STATFS(mp, &mp->mnt_stat, p);
goto success;
error_2: /* error with devvp held*/
/* release devvp before failing*/
vrele(devvp);
error_1: /* no state to back out*/
success:
if (!err && path && (mp->mnt_flag & MNT_UPDATE)) {
/* Update clean flag after changing read-onlyness. */
fs = ump->um_fs;
if (ronly != fs->fs_ronly) {
fs->fs_ronly = ronly;
fs->fs_clean = ronly &&
(fs->fs_flags & FS_UNCLEAN) == 0 ? 1 : 0;
ffs_sbupdate(ump, MNT_WAIT);
if ((error = ffs_mountfs(devvp, mp, p, M_FFSNODE)) != 0) {
vrele(devvp);
return (error);
}
}
return (err);
/*
* Save "mounted from" device name info for mount point (NULL pad).
*/
copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
/*
* Initialize filesystem stat information in mount struct.
*/
(void)VFS_STATFS(mp, &mp->mnt_stat, p);
return (0);
}
/*
@ -478,7 +423,7 @@ ffs_reload(mp, cred, p)
newfs->fs_maxcluster = fs->fs_maxcluster;
bcopy(newfs, fs, (u_int)fs->fs_sbsize);
if (fs->fs_sbsize < SBSIZE)
bp->b_flags |= B_INVAL;
bp->b_flags |= B_INVAL | B_NOCACHE;
brelse(bp);
mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
ffs_oldfscompat(fs);
@ -670,7 +615,7 @@ ffs_mountfs(devvp, mp, p, malloctype)
ump->um_vfree = ffs_vfree;
bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
if (fs->fs_sbsize < SBSIZE)
bp->b_flags |= B_INVAL;
bp->b_flags |= B_INVAL | B_NOCACHE;
brelse(bp);
bp = NULL;
fs = ump->um_fs;
@ -750,6 +695,8 @@ ffs_mountfs(devvp, mp, p, malloctype)
free(base, M_UFSMNT);
goto out;
}
if (fs->fs_snapinum[0] != 0)
ffs_snapshot_mount(mp);
fs->fs_fmod = 1;
fs->fs_clean = 0;
(void) ffs_sbupdate(ump, MNT_WAIT);
@ -886,6 +833,15 @@ ffs_flushfiles(mp, flags, p)
*/
}
#endif
if (ump->um_devvp->v_flag & VCOPYONWRITE) {
if ((error = vflush(mp, NULL, SKIPSYSTEM | flags)) != 0)
return (error);
ffs_snapshot_unmount(mp);
/*
* Here we fall through to vflush again to ensure
* that we have gotten rid of all the system vnodes.
*/
}
/*
* Flush all the files.
*/

View File

@ -95,6 +95,7 @@ vop_t **ffs_specop_p;
static struct vnodeopv_entry_desc ffs_specop_entries[] = {
{ &vop_default_desc, (vop_t *) ufs_vnoperatespec },
{ &vop_fsync_desc, (vop_t *) ffs_fsync },
{ &vop_copyonwrite_desc, (vop_t *) ffs_copyonwrite },
{ NULL, NULL }
};
static struct vnodeopv_desc ffs_specop_opv_desc =
@ -129,11 +130,20 @@ ffs_fsync(ap)
} */ *ap;
{
struct vnode *vp = ap->a_vp;
struct inode *ip = VTOI(vp);
struct buf *bp;
struct buf *nbp;
int s, error, wait, passes, skipmeta;
daddr_t lbn;
/*
* Snapshots have to be unlocked so they do not deadlock
* checking whether they need to copy their written buffers.
* We always hold a reference, so they cannot be removed
* out from underneath us.
*/
if (ip->i_flags & SF_SNAPSHOT)
VOP_UNLOCK(vp, 0, ap->a_p);
wait = (ap->a_waitfor == MNT_WAIT);
if (vn_isdisk(vp, NULL)) {
lbn = INT_MAX;
@ -141,8 +151,6 @@ ffs_fsync(ap)
(vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP))
softdep_fsync_mountdev(vp);
} else {
struct inode *ip;
ip = VTOI(vp);
lbn = lblkno(ip->i_fs, (ip->i_size + ip->i_fs->fs_bsize - 1));
}
@ -279,5 +287,7 @@ ffs_fsync(ap)
}
splx(s);
error = UFS_UPDATE(vp, wait);
if (ip->i_flags & SF_SNAPSHOT)
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
return (error);
}

View File

@ -382,7 +382,7 @@ struct freefrag {
struct worklist ff_list; /* id_inowait or delayed worklist */
# define ff_state ff_list.wk_state /* owning user; should be uid_t */
struct vnode *ff_devvp; /* filesystem device vnode */
struct fs *ff_fs; /* addr of superblock */
struct mount *ff_mnt; /* associated mount point */
ufs_daddr_t ff_blkno; /* fragment physical block number */
long ff_fragsize; /* size of fragment being deleted */
ino_t ff_inum; /* owning inode number */
@ -398,7 +398,7 @@ struct freeblks {
struct worklist fb_list; /* id_inowait or delayed worklist */
ino_t fb_previousinum; /* inode of previous owner of blocks */
struct vnode *fb_devvp; /* filesystem device vnode */
struct fs *fb_fs; /* addr of superblock */
struct mount *fb_mnt; /* associated mount point */
off_t fb_oldsize; /* previous file size */
off_t fb_newsize; /* new file size */
int fb_chkcnt; /* used to check cnt of blks released */
@ -418,7 +418,7 @@ struct freefile {
mode_t fx_mode; /* mode of inode */
ino_t fx_oldinum; /* inum of the unlinked file */
struct vnode *fx_devvp; /* filesystem device vnode */
struct fs *fx_fs; /* addr of superblock */
struct mount *fx_mnt; /* associated mount point */
};
/*

View File

@ -84,6 +84,7 @@ struct inode {
struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
u_quad_t i_modrev; /* Revision level for NFS lease. */
struct lockf *i_lockf;/* Head of byte-level lock list. */
struct inode *i_copyonwrite; /* copy-on-write list */
/*
* Side effects; used during directory lookup.
*/

View File

@ -47,6 +47,7 @@
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/resourcevar.h>
#include <sys/stat.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
@ -115,7 +116,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
struct indir a[NIADDR+1], *xap;
ufs_daddr_t daddr;
long metalbn;
int error, maxrun, num;
int error, num, maxrun = 0;
ip = VTOI(vp);
mp = vp->v_mount;
@ -127,6 +128,7 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
#endif
if (runp) {
maxrun = mp->mnt_iosize_max / mp->mnt_stat.f_iosize - 1;
*runp = 0;
}
@ -134,7 +136,6 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
*runb = 0;
}
maxrun = mp->mnt_iosize_max / mp->mnt_stat.f_iosize - 1;
xap = ap == NULL ? a : ap;
if (!nump)
@ -146,9 +147,12 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
num = *nump;
if (num == 0) {
*bnp = blkptrtodb(ump, ip->i_db[bn]);
if (*bnp == 0)
*bnp = -1;
else if (runp) {
if (*bnp == 0) {
if (ip->i_flags & SF_SNAPSHOT)
*bnp = blkptrtodb(ump, bn * ump->um_seqinc);
else
*bnp = -1;
} else if (runp) {
daddr_t bnb = bn;
for (++bn; bn < NDADDR && *runp < maxrun &&
is_sequential(ump, ip->i_db[bn - 1], ip->i_db[bn]);
@ -226,8 +230,13 @@ ufs_bmaparray(vp, bn, bnp, ap, nump, runp, runb)
if (bp)
bqrelse(bp);
daddr = blkptrtodb(ump, daddr);
*bnp = daddr == 0 ? -1 : daddr;
*bnp = blkptrtodb(ump, daddr);
if (*bnp == 0) {
if (ip->i_flags & SF_SNAPSHOT)
*bnp = blkptrtodb(ump, bn * ump->um_seqinc);
else
*bnp = -1;
}
return (0);
}

View File

@ -87,6 +87,7 @@ int ufs_init __P((struct vfsconf *));
void ufs_itimes __P((struct vnode *vp));
int ufs_lookup __P((struct vop_cachedlookup_args *));
int ufs_reclaim __P((struct vop_reclaim_args *));
void ffs_snapremove __P((struct vnode *vp));
int ufs_root __P((struct mount *, struct vnode **));
int ufs_start __P((struct mount *, int, struct proc *));
int ufs_vinit __P((struct mount *, vop_t **, vop_t **, struct vnode **));

View File

@ -77,6 +77,7 @@ ufs_inactive(ap)
if (ip->i_mode == 0)
goto out;
if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
(void) vn_write_suspend_wait(vp, V_WAIT);
#ifdef QUOTA
if (!getinoquota(ip))
(void)chkiq(ip, -1, NOCRED, 0);
@ -91,8 +92,15 @@ ufs_inactive(ap)
ip->i_flag |= IN_CHANGE | IN_UPDATE;
UFS_VFREE(vp, ip->i_number, mode);
}
if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE))
UFS_UPDATE(vp, 0);
if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
if ((ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 &&
vn_write_suspend_wait(vp, V_NOWAIT)) {
ip->i_flag &= ~IN_ACCESS;
} else {
(void) vn_write_suspend_wait(vp, V_WAIT);
UFS_UPDATE(vp, 0);
}
}
out:
VOP_UNLOCK(vp, 0, p);
/*

View File

@ -889,6 +889,7 @@ dqsync(vp, dq)
struct vnode *dqvp;
struct iovec aiov;
struct uio auio;
struct mount *mp;
int error;
if (dq == NODQUOT)
@ -897,6 +898,7 @@ dqsync(vp, dq)
return (0);
if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)
panic("dqsync: file");
(void) vn_write_suspend_wait(dqvp, V_WAIT);
if (vp != dqvp)
vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY, p);
while (dq->dq_flags & DQ_LOCK) {

View File

@ -702,6 +702,8 @@ ufs_remove(ap)
int error;
ip = VTOI(vp);
if ((ip->i_flags & SF_SNAPSHOT) != 0)
ffs_snapremove(vp);
if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
(VTOI(dvp)->i_flags & APPEND)) {
error = EPERM;
@ -2215,6 +2217,7 @@ static struct vnodeopv_entry_desc ufs_vnodeop_entries[] = {
{ &vop_open_desc, (vop_t *) ufs_open },
{ &vop_pathconf_desc, (vop_t *) ufs_pathconf },
{ &vop_poll_desc, (vop_t *) vop_stdpoll },
{ &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount },
{ &vop_print_desc, (vop_t *) ufs_print },
{ &vop_readdir_desc, (vop_t *) ufs_readdir },
{ &vop_readlink_desc, (vop_t *) ufs_readlink },

View File

@ -777,6 +777,7 @@ vm_pageout_scan()
int written;
int swap_pageouts_ok;
struct vnode *vp = NULL;
struct mount *mp;
object = m->object;
@ -853,9 +854,13 @@ vm_pageout_scan()
if (object->type == OBJT_VNODE) {
vp = object->handle;
mp = NULL;
if (vp->v_type == VREG)
vn_start_write(vp, &mp, V_NOWAIT);
if (VOP_ISLOCKED(vp, NULL) ||
vp->v_data == NULL ||
vget(vp, LK_EXCLUSIVE|LK_NOOBJ, curproc)) {
vn_finished_write(mp);
if ((m->queue == PQ_INACTIVE) &&
(m->hold_count == 0) &&
(m->busy == 0) &&
@ -878,6 +883,7 @@ vm_pageout_scan()
if (object->flags & OBJ_MIGHTBEDIRTY)
vnodes_skipped++;
vput(vp);
vn_finished_write(mp);
continue;
}
@ -888,6 +894,7 @@ vm_pageout_scan()
*/
if (m->busy || (m->flags & PG_BUSY)) {
vput(vp);
vn_finished_write(mp);
continue;
}
@ -902,6 +909,7 @@ vm_pageout_scan()
if (object->flags & OBJ_MIGHTBEDIRTY)
vnodes_skipped++;
vput(vp);
vn_finished_write(mp);
continue;
}
}
@ -913,8 +921,10 @@ vm_pageout_scan()
* start the cleaning operation.
*/
written = vm_pageout_clean(m);
if (vp)
if (vp) {
vput(vp);
vn_finished_write(mp);
}
maxlaunder -= written;
}

View File

@ -850,6 +850,7 @@ vnode_pager_putpages(object, m, count, sync, rtvals)
{
int rtval;
struct vnode *vp;
struct mount *mp;
int bytes = count * PAGE_SIZE;
/*
@ -872,11 +873,15 @@ vnode_pager_putpages(object, m, count, sync, rtvals)
*/
vp = object->handle;
if (vp->v_type != VREG)
mp = NULL;
(void)vn_start_write(vp, &mp, V_WAIT);
rtval = VOP_PUTPAGES(vp, m, bytes, sync, rtvals, 0);
if (rtval == EOPNOTSUPP) {
printf("vnode_pager: *** WARNING *** stale FS putpages\n");
rtval = vnode_pager_generic_putpages( vp, m, bytes, sync, rtvals);
}
vn_finished_write(mp);
}