summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_syscalls.c
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2000-07-11 22:07:57 +0000
committermckusick <mckusick@FreeBSD.org>2000-07-11 22:07:57 +0000
commita3d0c189ea25a7af3dfab30112f5d8d65e214e1c (patch)
treec84458dcf49aaf90ff010ebc108cb3b6ca3c2f4a /sys/kern/vfs_syscalls.c
parentc8c04452402a28eabd1ed8a1a06e0a14ac3d22c6 (diff)
downloadFreeBSD-src-a3d0c189ea25a7af3dfab30112f5d8d65e214e1c.zip
FreeBSD-src-a3d0c189ea25a7af3dfab30112f5d8d65e214e1c.tar.gz
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).
Diffstat (limited to 'sys/kern/vfs_syscalls.c')
-rw-r--r--sys/kern/vfs_syscalls.c316
1 files changed, 221 insertions, 95 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 65a297ca..404114a 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -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 @@ update:
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 @@ out:
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 @@ done:
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 @@ done:
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);
}
OpenPOWER on IntegriCloud