summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ufs
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2001-05-17 07:24:03 +0000
committermckusick <mckusick@FreeBSD.org>2001-05-17 07:24:03 +0000
commit5411edc0fbb52100d0c701ae4710b831a88fe7d5 (patch)
treeef00c14c553e974c0b7c3e9011071fac33d5d4ea /sys/ufs/ufs
parent61d50b9b55a5fc77050b39ecc315d05d9e0aa462 (diff)
downloadFreeBSD-src-5411edc0fbb52100d0c701ae4710b831a88fe7d5.zip
FreeBSD-src-5411edc0fbb52100d0c701ae4710b831a88fe7d5.tar.gz
When a new block is allocated to a directory, an fsync of a file
whose name is within that block must ensure not only that the block containing the file name has been written, but also that the on-disk directory inode references that block. When a new directory block is created, we allocate a newdirblk structure which is linked to the associated allocdirect (on its ad_newdirblk list). When the allocdirect has been satisfied, the newdirblk structure is moved to the inodedep id_bufwait list of its directory to await the inode being written. When the inode is written, the directory entries are fully committed and can be deleted from their pagedep->id_pendinghd and inodedep->id_pendinghd lists.
Diffstat (limited to 'sys/ufs/ufs')
-rw-r--r--sys/ufs/ufs/ufs_extern.h4
-rw-r--r--sys/ufs/ufs/ufs_lookup.c32
2 files changed, 28 insertions, 8 deletions
diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h
index e08ee8d..d95013b 100644
--- a/sys/ufs/ufs/ufs_extern.h
+++ b/sys/ufs/ufs/ufs_extern.h
@@ -95,8 +95,8 @@ int ufs_vinit __P((struct mount *, vop_t **, vop_t **, struct vnode **));
/*
* Soft update function prototypes.
*/
-void softdep_setup_directory_add __P((struct buf *, struct inode *, off_t,
- long, struct buf *));
+int softdep_setup_directory_add __P((struct buf *, struct inode *, off_t,
+ long, struct buf *, int));
void softdep_change_directoryentry_offset __P((struct inode *, caddr_t,
caddr_t, caddr_t, int));
void softdep_setup_remove __P((struct buf *,struct inode *, struct inode *,
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index 5acc85d..61a620d 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -745,10 +745,29 @@ ufs_direnter(dvp, tvp, dirp, cnp, newdirbp)
(bp->b_data + blkoff))->d_reclen = DIRBLKSIZ;
blkoff += DIRBLKSIZ;
}
- softdep_setup_directory_add(bp, dp, dp->i_offset,
- dirp->d_ino, newdirbp);
- bdwrite(bp);
- return (UFS_UPDATE(dvp, 0));
+ if (softdep_setup_directory_add(bp, dp, dp->i_offset,
+ dirp->d_ino, newdirbp, 1) == 0) {
+ bdwrite(bp);
+ return (UFS_UPDATE(dvp, 0));
+ }
+ /* We have just allocated a directory block in an
+ * indirect block. Rather than tracking when it gets
+ * claimed by the inode, we simply do a VOP_FSYNC
+ * now to ensure that it is there (in case the user
+ * does a future fsync). Note that we have to unlock
+ * the inode for the entry that we just entered, as
+ * the VOP_FSYNC may need to lock other inodes which
+ * can lead to deadlock if we also hold a lock on
+ * the newly entered node.
+ */
+ if ((error = BUF_WRITE(bp)))
+ return (error);
+ if (tvp != NULL)
+ VOP_UNLOCK(tvp, 0, p);
+ error = VOP_FSYNC(dvp, p->p_ucred, MNT_WAIT, p);
+ if (tvp != NULL)
+ vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p);
+ return (error);
}
if (DOINGASYNC(dvp)) {
bdwrite(bp);
@@ -836,8 +855,9 @@ ufs_direnter(dvp, tvp, dirp, cnp, newdirbp)
bcopy((caddr_t)dirp, (caddr_t)ep, (u_int)newentrysize);
if (DOINGSOFTDEP(dvp)) {
- softdep_setup_directory_add(bp, dp,
- dp->i_offset + (caddr_t)ep - dirbuf, dirp->d_ino, newdirbp);
+ (void) softdep_setup_directory_add(bp, dp,
+ dp->i_offset + (caddr_t)ep - dirbuf,
+ dirp->d_ino, newdirbp, 0);
bdwrite(bp);
} else {
if (DOINGASYNC(dvp)) {
OpenPOWER on IntegriCloud