Further evaluation of the POSIX spec for fdatasync() shows that it

requires that new data on growing files be accessible. Thus, the
the fsyncdata() system call must update the on-disk inode when the
size of the file has changed.

This commit adds another inode update flag, IN_SIZEMOD, that gets
set any time that the file size changes. If either the IN_IBLKDATA
or the IN_SIZEMOD flag is set when fdatasync() is called, the
associated inode is synchronously written to disk. We could have
overloaded the IN_IBLKDATA flag to also track size changes since
the only (current) use case for these flags are for fsyncdata(),
but it does seem useful for possible future uses to separately
track the file size changes and the inode block pointer changes.

Reviewed by: kib
MFC with: -r361785
Differential revision:  https://reviews.freebsd.org/D25072
This commit is contained in:
Kirk McKusick 2020-06-05 01:00:55 +00:00
parent a6ca7ce3c2
commit 52488b5148
9 changed files with 36 additions and 21 deletions

View File

@ -3306,7 +3306,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS)
break;
ip = VTOI(vp);
DIP_SET(ip, i_size, cmd.size);
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_MODIFIED);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE | IN_MODIFIED);
error = ffs_update(vp, 1);
vput(vp);
break;

View File

@ -155,7 +155,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
dp->di_size = ip->i_size;
dp->di_db[nb] = dbtofsb(fs, bp->b_blkno);
UFS_INODE_SET_FLAG(ip,
IN_CHANGE | IN_UPDATE | IN_IBLKDATA);
IN_SIZEMOD | IN_CHANGE | IN_UPDATE | IN_IBLKDATA);
if (flags & IO_SYNC)
bwrite(bp);
else if (DOINGASYNC(vp))
@ -648,7 +648,8 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
dp->di_extsize = smalllblktosize(fs, nb + 1);
dp->di_extb[nb] = dbtofsb(fs, bp->b_blkno);
bp->b_xflags |= BX_ALTDATA;
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_IBLKDATA);
UFS_INODE_SET_FLAG(ip,
IN_SIZEMOD | IN_CHANGE | IN_IBLKDATA);
if (flags & IO_SYNC)
bwrite(bp);
else
@ -751,8 +752,8 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
ip->i_size = smalllblktosize(fs, nb + 1);
dp->di_size = ip->i_size;
dp->di_db[nb] = dbtofsb(fs, bp->b_blkno);
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE |
IN_IBLKDATA);
UFS_INODE_SET_FLAG(ip,
IN_SIZEMOD |IN_CHANGE | IN_UPDATE | IN_IBLKDATA);
if (flags & IO_SYNC)
bwrite(bp);
else

View File

@ -279,7 +279,7 @@ ffs_truncate(vp, length, flags, cred)
oldblks[i] = ip->i_din2->di_extb[i];
ip->i_din2->di_extb[i] = 0;
}
UFS_INODE_SET_FLAG(ip, IN_CHANGE);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE);
if ((error = ffs_update(vp, waitforupdate)))
return (error);
for (i = 0; i < UFS_NXADDR; i++) {
@ -303,7 +303,7 @@ ffs_truncate(vp, length, flags, cred)
bzero(SHORTLINK(ip), (u_int)ip->i_size);
ip->i_size = 0;
DIP_SET(ip, i_size, 0);
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
if (needextclean)
goto extclean;
return (ffs_update(vp, waitforupdate));
@ -343,7 +343,7 @@ ffs_truncate(vp, length, flags, cred)
bdwrite(bp);
else
bawrite(bp);
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
return (ffs_update(vp, waitforupdate));
}
/*
@ -429,6 +429,7 @@ ffs_truncate(vp, length, flags, cred)
if (blkno != 0 && offset == 0) {
ip->i_size = length;
DIP_SET(ip, i_size, length);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
} else {
lbn = lblkno(fs, length);
flags |= BA_CLRBUF;
@ -463,6 +464,7 @@ ffs_truncate(vp, length, flags, cred)
bdwrite(bp);
else
bawrite(bp);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
}
/*
* Calculate index into inode's block list of
@ -512,6 +514,7 @@ ffs_truncate(vp, length, flags, cred)
}
ip->i_size = osize;
DIP_SET(ip, i_size, osize);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
error = vtruncbuf(vp, length, fs->fs_bsize);
if (error && (allerror == 0))
@ -578,6 +581,7 @@ ffs_truncate(vp, length, flags, cred)
oldspace = blksize(fs, ip, lastblock);
ip->i_size = length;
DIP_SET(ip, i_size, length);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
newspace = blksize(fs, ip, lastblock);
if (newspace == 0)
panic("ffs_truncate: newspace");
@ -623,7 +627,7 @@ done:
DIP_SET(ip, i_blocks, DIP(ip, i_blocks) - blocksreleased);
else /* sanity */
DIP_SET(ip, i_blocks, 0);
UFS_INODE_SET_FLAG(ip, IN_CHANGE);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE);
#ifdef QUOTA
(void) chkdq(ip, -blocksreleased, NOCRED, FORCE);
#endif

View File

@ -319,7 +319,7 @@ restart:
goto out;
ip->i_size = lblktosize(fs, (off_t)numblks);
DIP_SET(ip, i_size, ip->i_size);
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
error = readblock(vp, bp, numblks - 1);
bawrite(bp);
if (error != 0)

View File

@ -6709,6 +6709,7 @@ softdep_journal_freeblocks(ip, cred, length, flags)
}
ip->i_size = length;
DIP_SET(ip, i_size, ip->i_size);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE);
datablocks = DIP(ip, i_blocks) - extblocks;
if (length != 0)
datablocks = blkcount(fs, datablocks, length);
@ -6719,6 +6720,7 @@ softdep_journal_freeblocks(ip, cred, length, flags)
setup_freeext(freeblks, ip, i, needj);
ip->i_din2->di_extsize = 0;
datablocks += extblocks;
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE);
}
#ifdef QUOTA
/* Reference the quotas in case the block count is wrong in the end. */
@ -6829,7 +6831,7 @@ softdep_journal_freeblocks(ip, cred, length, flags)
}
ip->i_size = length;
DIP_SET(ip, i_size, length);
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
allocbuf(bp, frags);
ffs_update(vp, 0);
bawrite(bp);
@ -6976,6 +6978,7 @@ softdep_setup_freeblocks(ip, length, flags)
setup_freeindir(freeblks, ip, i, -lbn -i, 0);
ip->i_size = 0;
DIP_SET(ip, i_size, 0);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE);
datablocks = DIP(ip, i_blocks) - extblocks;
}
if ((flags & IO_EXT) != 0) {
@ -6983,6 +6986,7 @@ softdep_setup_freeblocks(ip, length, flags)
setup_freeext(freeblks, ip, i, 0);
ip->i_din2->di_extsize = 0;
datablocks += extblocks;
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE);
}
#ifdef QUOTA
/* Reference the quotas in case the block count is wrong in the end. */

View File

@ -416,7 +416,7 @@ next:
error = ffs_update(vp, 1);
if (DOINGSUJ(vp))
softdep_journal_fsync(VTOI(vp));
} else if ((ip->i_flags & IN_IBLKDATA) != 0) {
} else if ((ip->i_flags & (IN_SIZEMOD | IN_IBLKDATA)) != 0) {
error = ffs_update(vp, 1);
}
return (error);
@ -825,6 +825,7 @@ ffs_write(ap)
if (uio->uio_offset + xfersize > ip->i_size) {
ip->i_size = uio->uio_offset + xfersize;
DIP_SET(ip, i_size, ip->i_size);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE);
}
size = blksize(fs, ip, lbn) - bp->b_resid;
@ -1108,8 +1109,10 @@ ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *ucred)
if ((bp->b_flags & B_CACHE) == 0 && fs->fs_bsize <= xfersize)
vfs_bio_clrbuf(bp);
if (uio->uio_offset + xfersize > dp->di_extsize)
if (uio->uio_offset + xfersize > dp->di_extsize) {
dp->di_extsize = uio->uio_offset + xfersize;
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE);
}
size = sblksize(fs, dp->di_extsize, lbn) - bp->b_resid;
if (size < xfersize)

View File

@ -127,19 +127,21 @@ struct inode {
#define IN_LAZYMOD 0x0020 /* Modified, but don't write yet. */
#define IN_LAZYACCESS 0x0040 /* Process IN_ACCESS after the
suspension finished */
#define IN_EA_LOCKED 0x0080
#define IN_EA_LOCKWAIT 0x0100
#define IN_EA_LOCKED 0x0080 /* Extended attributes locked */
#define IN_EA_LOCKWAIT 0x0100 /* Want extended attributes lock */
#define IN_TRUNCATED 0x0200 /* Journaled truncation pending. */
#define IN_UFS2 0x0400 /* UFS2 vs UFS1 */
#define IN_IBLKDATA 0x0800 /* datasync requires inode block
update */
#define IN_SIZEMOD 0x1000 /* Inode size has been modified */
#define PRINT_INODE_FLAGS "\20\20b16\17b15\16b14\15b13" \
#define PRINT_INODE_FLAGS "\20\20b16\17b15\16b14\15sizemod" \
"\14iblkdata\13is_ufs2\12truncated\11ea_lockwait\10ea_locked" \
"\7lazyaccess\6lazymod\5needsync\4modified\3update\2change\1access"
#define UFS_INODE_FLAG_LAZY_MASK \
(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE | IN_LAZYMOD | IN_LAZYACCESS)
(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE | IN_LAZYMOD | \
IN_LAZYACCESS)
/*
* Some flags can persist a vnode transitioning to 0 hold count and being tkaen
* off the list.

View File

@ -556,7 +556,7 @@ found:
ufs_dirbad(dp, i_offset, "i_size too small");
dp->i_size = i_offset + DIRSIZ(OFSFMT(vdp), ep);
DIP_SET(dp, i_size, dp->i_size);
UFS_INODE_SET_FLAG(dp, IN_CHANGE | IN_UPDATE);
UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
}
brelse(bp);
@ -918,7 +918,7 @@ ufs_direnter(dvp, tvp, dirp, cnp, newdirbp, isrename)
dp->i_size = dp->i_offset + DIRBLKSIZ;
DIP_SET(dp, i_size, dp->i_size);
dp->i_endoff = dp->i_size;
UFS_INODE_SET_FLAG(dp, IN_CHANGE | IN_UPDATE);
UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
dirp->d_reclen = DIRBLKSIZ;
blkoff = dp->i_offset &
(VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1);
@ -1004,6 +1004,7 @@ ufs_direnter(dvp, tvp, dirp, cnp, newdirbp, isrename)
if (dp->i_offset + dp->i_count > dp->i_size) {
dp->i_size = dp->i_offset + dp->i_count;
DIP_SET(dp, i_size, dp->i_size);
UFS_INODE_SET_FLAG(dp, IN_SIZEMOD | IN_MODIFIED);
}
/*
* Get the block containing the space for the new directory entry.

View File

@ -1932,7 +1932,7 @@ ufs_mkdir(ap)
goto bad;
ip->i_size = DIRBLKSIZ;
DIP_SET(ip, i_size, DIRBLKSIZ);
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
bcopy((caddr_t)&dirtemplate, (caddr_t)bp->b_data, sizeof dirtemplate);
if (DOINGSOFTDEP(tvp)) {
/*
@ -2119,7 +2119,7 @@ ufs_symlink(ap)
bcopy(ap->a_target, SHORTLINK(ip), len);
ip->i_size = len;
DIP_SET(ip, i_size, len);
UFS_INODE_SET_FLAG(ip, IN_CHANGE | IN_UPDATE);
UFS_INODE_SET_FLAG(ip, IN_SIZEMOD | IN_CHANGE | IN_UPDATE);
error = UFS_UPDATE(vp, 0);
} else
error = vn_rdwr(UIO_WRITE, vp, __DECONST(void *, ap->a_target),