File remove problem

Bruce Evans brde at optusnet.com.au
Sat Dec 1 03:34:50 PST 2007


On Sat, 1 Dec 2007, Kostik Belousov wrote:

> On Fri, Nov 30, 2007 at 11:15:47PM -0800, Don Lewis wrote:
>> On 30 Nov, Kostik Belousov wrote:

>>> As a speculation, it might be that ufs_inactive() should conditionalize on
>>> fs_ronly instead of MNT_RDONLY. Then, VOP_INACTIVE() would set up the
>>> IN_CHANGE|IN_UPDATE and finally call the ffs_update() ?
>>
>> That sounds reasonable to me.  I see that ffs_update(), which is called
>> by ufs_inactive(), looks at fs_ronly.
> The patch (compile-tested only) is below.
>
> diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
> index cbccc62..687011d 100644
> --- a/sys/ufs/ffs/ffs_vfsops.c
> +++ b/sys/ufs/ffs/ffs_vfsops.c
> @@ -79,6 +79,7 @@ static void	ffs_oldfscompat_read(struct fs *, struct ufsmount *,
> 		    ufs2_daddr_t);
> static void	ffs_oldfscompat_write(struct fs *, struct ufsmount *);
> static void	ffs_ifree(struct ufsmount *ump, struct inode *ip);
> +static int	ffs_isronly(struct ufsmount *ump);
> static vfs_init_t ffs_init;
> static vfs_uninit_t ffs_uninit;
> static vfs_extattrctl_t ffs_extattrctl;
> @@ -748,6 +749,7 @@ ffs_mountfs(devvp, mp, td)
> 	ump->um_valloc = ffs_valloc;
> 	ump->um_vfree = ffs_vfree;
> 	ump->um_ifree = ffs_ifree;
> +	ump->um_isronly = ffs_isronly;
> 	mtx_init(UFS_MTX(ump), "FFS", "FFS Lock", MTX_DEF);
> 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
> 	if (fs->fs_sbsize < SBLOCKSIZE)

I don't like these indirections.  The layering provided by them is pseudo.

> @@ -1862,3 +1864,12 @@ ffs_geom_strategy(struct bufobj *bo, struct buf *bp)
> 	}
> 	g_vfs_strategy(bo, bp);
> }
> +
> +static int
> +ffs_isronly(struct ufsmount *ump)
> +{
> +	struct fs *fs = ump->um_fs;
> +
> +	return (fs->fs_ronly);
> +}
> +

Could be ump->um_fs->fs_ronly.

> diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c
> index 448f436..a9abbeb 100644
> --- a/sys/ufs/ufs/ufs_inode.c
> +++ b/sys/ufs/ufs/ufs_inode.c
> @@ -90,8 +90,7 @@ ufs_inactive(ap)
> 	ufs_gjournal_close(vp);
> #endif
> 	if ((ip->i_effnlink == 0 && DOINGSOFTDEP(vp)) ||
> -	    (ip->i_nlink <= 0 &&
> -	     (vp->v_mount->mnt_flag & MNT_RDONLY) == 0)) {
> +	    (ip->i_nlink <= 0 && !UFS_ISRONLY(ip->i_ump))) {
> 	loop:
> 		if (vn_start_secondary_write(vp, &mp, V_NOWAIT) != 0) {
> 			/* Cannot delete file while file system is suspended */

This might help for non-soft updates, but with soft updates I also see
the problem in ~5.2 which doesn't have any r/o check here (5.2 doesn't
have this loop at all).  I haven't seen the problem in ~5.2 without
soft updates.

> @@ -121,7 +120,7 @@ ufs_inactive(ap)
> 	}
> 	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 && !UFS_ISRONLY(ip->i_ump)) {
> #ifdef QUOTA
> 		if (!getinoquota(ip))
> 			(void)chkiq(ip, -1, NOCRED, FORCE);

5.2 only has this i_nlink check, before a v_write_suspend_wait() call, and
without any r/o check.

With the MNT_RDONLY check here, the truncation isn't done, which is
clearly wrong.  However, I think this isn't the main problem here.
The truncation always does get done in simple test cases like
"rm /f/a; mount -u -o ro /f" which show the problem.  Then there
is no race between the rm and the mount -- ufs_inactive() completes
normally in the rm process before the mount process sets MNT_RDONLY.
I think soft updates (or just sync?) calls ufs_inactive again later
when MNT_RDONLY is set, but it should find nothing more to do then.

Anyway, doesn't the vn_start_write() in ffs_mount() wait for all writers
like the rm process to complete?  Mount sets MNT_RDONLY before that,
so there may be a problem before that.  There is only a single
vn_start_write() call in vfs_mount.c.  It is interesting that this
wraps ffs_unmount() which seems to work.  Mount-update may need to wait
for writers to go away before it does things even more than unmount,
since it changes active mount flags like MNT_RDONLY.

Bruce


More information about the freebsd-fs mailing list