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>
This commit is contained in:
Kirk McKusick 2002-01-15 07:17:12 +00:00
parent 7a852c22ce
commit cd6005961f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=89384
5 changed files with 24 additions and 10 deletions

View file

@ -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 @@ vflush(mp, rootrefs, flags)
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);

View file

@ -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)

View file

@ -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;

View file

@ -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))

View file

@ -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;