diff options
author | mckusick <mckusick@FreeBSD.org> | 2001-05-17 07:24:03 +0000 |
---|---|---|
committer | mckusick <mckusick@FreeBSD.org> | 2001-05-17 07:24:03 +0000 |
commit | 5411edc0fbb52100d0c701ae4710b831a88fe7d5 (patch) | |
tree | ef00c14c553e974c0b7c3e9011071fac33d5d4ea /sys/ufs/ufs | |
parent | 61d50b9b55a5fc77050b39ecc315d05d9e0aa462 (diff) | |
download | FreeBSD-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.h | 4 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_lookup.c | 32 |
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)) { |