aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2002-01-15 07:17:12 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2002-01-15 07:17:12 +0000
commitcd6005961fd92a23918aac7c0c887ee9602e2ad4 (patch)
tree45f779b07dad926c32bb99b3e69a99ca2b14be36
parent7a852c22ced010188e7a158b587a61440a777b19 (diff)
downloadsrc-cd6005961fd92a23918aac7c0c887ee9602e2ad4.tar.gz
src-cd6005961fd92a23918aac7c0c887ee9602e2ad4.zip
When downgrading a filesystem from read-write to read-only, operations
involving file removal or file update were not always being fully committed to disk. The result was lost files or corrupted file data. This change ensures that the filesystem is properly synced to disk before the filesystem is down-graded. This delta also fixes a long standing bug in which a file open for reading has been unlinked. When the last open reference to the file is closed, the inode is reclaimed by the filesystem. Previously, if the filesystem had been down-graded to read-only, the inode could not be reclaimed, and thus was lost and had to be later recovered by fsck. With this change, such files are found at the time of the down-grade. Normally they will result in the filesystem down-grade failing with `device busy'. If a forcible down-grade is done, then the affected files will be revoked causing the inode to be released and the open file descriptors to begin failing on attempts to read. Submitted by: "Sam Leffler" <sam@errno.com>
Notes
Notes: svn path=/head/; revision=89384
-rw-r--r--sys/kern/vfs_subr.c9
-rw-r--r--sys/ufs/ffs/ffs_inode.c6
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c8
-rw-r--r--sys/ufs/ufs/ufs_inode.c2
-rw-r--r--sys/ufs/ufs/ufs_vnops.c9
5 files changed, 24 insertions, 10 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 8f0b4cfd23d4..41a3530a6052 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -1863,6 +1863,7 @@ vflush(mp, rootrefs, flags)
{
struct thread *td = curthread; /* XXX */
struct vnode *vp, *nvp, *rootvp = NULL;
+ struct vattr vattr;
int busy = 0, error;
if (rootrefs > 0) {
@@ -1898,10 +1899,14 @@ loop:
continue;
}
/*
- * If WRITECLOSE is set, only flush out regular file vnodes
- * open for writing.
+ * If WRITECLOSE is set, flush out unlinked but still open
+ * files (even if open only for reading) and regular file
+ * vnodes open for writing.
*/
if ((flags & WRITECLOSE) &&
+ (vp->v_type == VNON ||
+ (VOP_GETATTR(vp, &vattr, td->td_proc->p_ucred, td) == 0 &&
+ vattr.va_nlink > 0)) &&
(vp->v_writecount == 0 || vp->v_type != VREG)) {
mtx_unlock(&vp->v_interlock);
mtx_lock(&mntvnode_mtx);
diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c
index 9014a6098828..6dcf2ccb507c 100644
--- a/sys/ufs/ffs/ffs_inode.c
+++ b/sys/ufs/ffs/ffs_inode.c
@@ -87,9 +87,9 @@ ffs_update(vp, waitfor)
if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0)
return (0);
ip->i_flag &= ~(IN_LAZYMOD | IN_MODIFIED);
- if (vp->v_mount->mnt_flag & MNT_RDONLY)
- return (0);
fs = ip->i_fs;
+ if (fs->fs_ronly)
+ return (0);
/*
* Ensure that uid and gid are correct. This is a temporary
* fix until fsck has been changed to do the update.
@@ -152,6 +152,8 @@ ffs_truncate(vp, length, flags, cred, td)
oip = VTOI(ovp);
fs = oip->i_fs;
+ if (fs->fs_ronly)
+ panic("ffs_truncate: read-only filesystem");
if (length < 0)
return (EINVAL);
if (length > fs->fs_maxfilesize)
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index a9985d5c751a..902576777f64 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -180,6 +180,14 @@ ffs_mount(mp, path, data, ndp, td)
if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
return (error);
+ /*
+ * Flush any dirty data.
+ */
+ VFS_SYNC(mp, MNT_WAIT, td->td_proc->p_ucred, td);
+ /*
+ * Check for and optionally get rid of files open
+ * for writing.
+ */
flags = WRITECLOSE;
if (mp->mnt_flag & MNT_FORCE)
flags |= FORCECLOSE;
diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c
index c841c392679b..f7c7884fcf60 100644
--- a/sys/ufs/ufs/ufs_inode.c
+++ b/sys/ufs/ufs/ufs_inode.c
@@ -84,7 +84,7 @@ ufs_inactive(ap)
goto out;
if (ip->i_effnlink == 0 && DOINGSOFTDEP(vp))
softdep_releasefile(ip);
- if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
+ if (ip->i_nlink <= 0) {
(void) vn_write_suspend_wait(vp, NULL, V_WAIT);
#ifdef QUOTA
if (!getinoquota(ip))
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index d5df52e6d18e..4b52d1e4d076 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -158,13 +158,12 @@ ufs_itimes(vp)
ip = VTOI(vp);
if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
return;
+ if ((vp->v_type == VBLK || vp->v_type == VCHR) && !DOINGSOFTDEP(vp))
+ ip->i_flag |= IN_LAZYMOD;
+ else
+ ip->i_flag |= IN_MODIFIED;
if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
vfs_timestamp(&ts);
- if ((vp->v_type == VBLK || vp->v_type == VCHR) &&
- !DOINGSOFTDEP(vp))
- ip->i_flag |= IN_LAZYMOD;
- else
- ip->i_flag |= IN_MODIFIED;
if (ip->i_flag & IN_ACCESS) {
ip->i_atime = ts.tv_sec;
ip->i_atimensec = ts.tv_nsec;