summaryrefslogtreecommitdiff
path: root/sys/ufs
diff options
context:
space:
mode:
authorConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>1997-12-02 17:11:14 +0000
committerConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>1997-12-02 17:11:14 +0000
commit6f7ac56ccd19416ad8f2dae8788acfabc298f11a (patch)
tree6988d3dc3a47ce62c11a78a50b5dd6ab855209d5 /sys/ufs
parent82232fad242af9b522d3f55e8ebda456f534f59d (diff)
Unlock child temporarily while truncating directory. This prevents
a double locking bug in the soft updates code.
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ufs/ufs_extern.h4
-rw-r--r--sys/ufs/ufs/ufs_lookup.c22
-rw-r--r--sys/ufs/ufs/ufs_vnops.c17
3 files changed, 32 insertions, 11 deletions
diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h
index 6c49d78717c..8a20bbbac48 100644
--- a/sys/ufs/ufs/ufs_extern.h
+++ b/sys/ufs/ufs/ufs_extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ufs_extern.h,v 1.5 1997/11/06 05:59:26 csapuntz Exp $ */
+/* $OpenBSD: ufs_extern.h,v 1.6 1997/12/02 17:11:10 csapuntz Exp $ */
/* $NetBSD: ufs_extern.h,v 1.5 1996/02/09 22:36:03 christos Exp $ */
/*-
@@ -127,7 +127,7 @@ void ufs_dirbad __P((struct inode *, doff_t, char *));
int ufs_dirbadentry __P((struct vnode *, struct direct *, int));
void ufs_makedirentry __P((struct inode *, struct componentname *,
struct direct *));
-int ufs_direnter __P((struct vnode *, struct direct *,
+int ufs_direnter __P((struct vnode *, struct vnode *, struct direct *,
struct componentname *, struct buf *));
int ufs_dirremove __P((struct vnode *, struct inode *, int, int));
int ufs_dirrewrite __P((struct inode *, struct inode *,
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index 31a7a5fd169..c89d4b7ee0c 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ufs_lookup.c,v 1.7 1997/11/06 05:59:27 csapuntz Exp $ */
+/* $OpenBSD: ufs_lookup.c,v 1.8 1997/12/02 17:11:11 csapuntz Exp $ */
/* $NetBSD: ufs_lookup.c,v 1.7 1996/02/09 22:36:06 christos Exp $ */
/*
@@ -721,8 +721,9 @@ ufs_makedirentry(ip, cnp, newdirp)
* soft dependency code).
*/
int
-ufs_direnter(dvp, dirp, cnp, newdirbp)
+ufs_direnter(dvp, tvp, dirp, cnp, newdirbp)
struct vnode *dvp;
+ struct vnode *tvp;
struct direct *dirp;
struct componentname *cnp;
struct buf *newdirbp;
@@ -877,8 +878,23 @@ ufs_direnter(dvp, dirp, cnp, newdirbp)
error = VOP_BWRITE(bp);
}
dp->i_flag |= IN_CHANGE | IN_UPDATE;
- if (error == 0 && dp->i_endoff && dp->i_endoff < dp->i_ffs_size)
+
+ /*
+ * If all went well, and the directory can be shortened, proceed
+ * with the truncation. Note that we have to unlock the inode for
+ * the entry that we just entered, as the truncation may need to
+ * lock other inodes which can lead to deadlock if we also hold a
+ * lock on the newly entered node.
+ */
+
+ if (error == 0 && dp->i_endoff && dp->i_endoff < dp->i_ffs_size) {
+ if (tvp != NULL)
+ VOP_UNLOCK(tvp, 0, p);
+
error = VOP_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr, p);
+ if (tvp != NULL)
+ vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p);
+ }
return (error);
}
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index a261a24c54f..1f71e54da9d 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ufs_vnops.c,v 1.16 1997/11/06 23:07:24 csapuntz Exp $ */
+/* $OpenBSD: ufs_vnops.c,v 1.17 1997/12/02 17:11:13 csapuntz Exp $ */
/* $NetBSD: ufs_vnops.c,v 1.18 1996/05/11 18:28:04 mycroft Exp $ */
/*
@@ -737,7 +737,7 @@ ufs_link(v)
TIMEVAL_TO_TIMESPEC(&time, &ts);
if ((error = VOP_UPDATE(vp, &ts, &ts, !DOINGSOFTDEP(vp))) == 0) {
ufs_makedirentry(ip, cnp, &newdir);
- error = ufs_direnter(dvp, &newdir, cnp, NULL);
+ error = ufs_direnter(dvp, vp, &newdir, cnp, NULL);
}
if (error) {
ip->i_effnlink--;
@@ -790,7 +790,7 @@ ufs_whiteout(v)
newdir.d_namlen = cnp->cn_namelen;
bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1);
newdir.d_type = DT_WHT;
- error = ufs_direnter(dvp, &newdir, cnp, NULL);
+ error = ufs_direnter(dvp, NULL, &newdir, cnp, NULL);
break;
case DELETE:
@@ -1042,7 +1042,7 @@ abortit:
goto bad;
}
ufs_makedirentry(ip, tcnp, &newdir);
- if ((error = ufs_direnter(tdvp, &newdir, tcnp, NULL)) != 0) {
+ if ((error = ufs_direnter(tdvp, fvp, &newdir, tcnp, NULL)) != 0) {
if (doingdirectory && newparent) {
dp->i_effnlink--;
dp->i_ffs_nlink--;
@@ -1313,7 +1313,7 @@ ufs_mkdir(v)
if (!DOINGSOFTDEP(dvp) && ((error = VOP_BWRITE(bp)) != 0))
goto bad;
ufs_makedirentry(ip, cnp, &newdir);
- error = ufs_direnter(dvp, &newdir, cnp, bp);
+ error = ufs_direnter(dvp, tvp, &newdir, cnp, bp);
bad:
if (error == 0) {
@@ -1728,6 +1728,11 @@ ufs_print(v)
printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number,
major(ip->i_dev), minor(ip->i_dev));
+ printf(" flags 0x%x, effnlink %d, nlink %d\n",
+ ip->i_flag, ip->i_effnlink, ip->i_ffs_nlink);
+ printf("\tmode 0%o, owner %d, group %d, size %qd",
+ ip->i_ffs_mode, ip->i_ffs_uid, ip->i_ffs_gid, ip->i_ffs_size);
+
#ifdef FIFO
if (vp->v_type == VFIFO)
fifo_printinfo(vp);
@@ -2064,7 +2069,7 @@ ufs_makeinode(mode, dvp, vpp, cnp)
goto bad;
ufs_makedirentry(ip, cnp, &newdir);
- if ((error = ufs_direnter(dvp, &newdir, cnp, NULL)) != 0)
+ if ((error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL)) != 0)
goto bad;
if ((cnp->cn_flags & SAVESTART) == 0)