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:
parent
aa02fb5729
commit
f2a2857bb3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=62976
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
@ -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 },
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 },
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 = = =
|
||||
#
|
||||
|
@ -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:
|
||||
|
@ -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 },
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 },
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
112
sys/ufs/ffs/README.snapshot
Normal 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/
|
@ -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",
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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
1028
sys/ufs/ffs/ffs_snapshot.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 **));
|
||||
|
@ -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);
|
||||
/*
|
||||
|
@ -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) {
|
||||
|
@ -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 },
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user