linux/fs/xfs/libxfs
Darrick J. Wong 78bba5c812 xfs: use ordered buffers to initialize dquot buffers during quotacheck
While QAing the new xfs_repair quotacheck code, I uncovered a quota
corruption bug resulting from a bad interaction between dquot buffer
initialization and quotacheck.  The bug can be reproduced with the
following sequence:

# mkfs.xfs -f /dev/sdf
# mount /dev/sdf /opt -o usrquota
# su nobody -s /bin/bash -c 'touch /opt/barf'
# sync
# xfs_quota -x -c 'report -ahi' /opt
User quota on /opt (/dev/sdf)
                        Inodes
User ID      Used   Soft   Hard Warn/Grace
---------- ---------------------------------
root            3      0      0  00 [------]
nobody          1      0      0  00 [------]

# xfs_io -x -c 'shutdown' /opt
# umount /opt
# mount /dev/sdf /opt -o usrquota
# touch /opt/man2
# xfs_quota -x -c 'report -ahi' /opt
User quota on /opt (/dev/sdf)
                        Inodes
User ID      Used   Soft   Hard Warn/Grace
---------- ---------------------------------
root            1      0      0  00 [------]
nobody          1      0      0  00 [------]

# umount /opt

Notice how the initial quotacheck set the root dquot icount to 3
(rootino, rbmino, rsumino), but after shutdown -> remount -> recovery,
xfs_quota reports that the root dquot has only 1 icount.  We haven't
deleted anything from the filesystem, which means that quota is now
under-counting.  This behavior is not limited to icount or the root
dquot, but this is the shortest reproducer.

I traced the cause of this discrepancy to the way that we handle ondisk
dquot updates during quotacheck vs. regular fs activity.  Normally, when
we allocate a disk block for a dquot, we log the buffer as a regular
(dquot) buffer.  Subsequent updates to the dquots backed by that block
are done via separate dquot log item updates, which means that they
depend on the logged buffer update being written to disk before the
dquot items.  Because individual dquots have their own LSN fields, that
initial dquot buffer must always be recovered.

However, the story changes for quotacheck, which can cause dquot block
allocations but persists the final dquot counter values via a delwri
list.  Because recovery doesn't gate dquot buffer replay on an LSN, this
means that the initial dquot buffer can be replayed over the (newer)
contents that were delwritten at the end of quotacheck.  In effect, this
re-initializes the dquot counters after they've been updated.  If the
log does not contain any other dquot items to recover, the obsolete
dquot contents will not be corrected by log recovery.

Because quotacheck uses a transaction to log the setting of the CHKD
flags in the superblock, we skip quotacheck during the second mount
call, which allows the incorrect icount to remain.

Fix this by changing the ondisk dquot initialization function to use
ordered buffers to write out fresh dquot blocks if it detects that we're
running quotacheck.  If the system goes down before quotacheck can
complete, the CHKD flags will not be set in the superblock and the next
mount will run quotacheck again, which can fix uninitialized dquot
buffers.  This requires amending the defer code to maintaine ordered
buffer state across defer rolls for the sake of the dquot allocation
code.

For regular operations we preserve the current behavior since the dquot
items require properly initialized ondisk dquot records.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
2020-05-19 09:40:56 -07:00
..
xfs_ag_resv.c xfs: fix missing header includes 2019-11-07 13:00:53 -08:00
xfs_ag_resv.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_ag.c xfs: remove XFS_BUF_TO_SBP 2020-03-11 09:11:39 -07:00
xfs_ag.h xfs: add a new ioctl to describe allocation group geometry 2019-04-14 18:15:57 -07:00
xfs_alloc_btree.c xfs: add support for free space btree staging cursors 2020-03-18 08:12:23 -07:00
xfs_alloc_btree.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_alloc.c xfs: fix incorrect test in xfs_alloc_ag_vextent_lastblock 2020-03-17 07:32:46 -07:00
xfs_alloc.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_attr_leaf.c xfs: don't fail verifier on empty attr3 leaf block 2020-05-19 09:05:24 -07:00
xfs_attr_leaf.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_attr_remote.c xfs: remove ATTR_KERNOVAL 2020-03-02 20:55:53 -08:00
xfs_attr_remote.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_attr_sf.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_attr.c xfs: remove XFS_DA_OP_INCOMPLETE 2020-03-02 20:55:55 -08:00
xfs_attr.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_bit.c xfs: fix missing header includes 2019-11-07 13:00:53 -08:00
xfs_bit.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_bmap_btree.c xfs: rename btree cursor private btree member flags 2020-03-13 10:37:14 -07:00
xfs_bmap_btree.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_bmap.c xfs: only check the superblock version for dinode size calculation 2020-03-19 08:48:47 -07:00
xfs_bmap.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_btree_staging.c xfs: support bulk loading of staged btrees 2020-03-18 08:12:23 -07:00
xfs_btree_staging.h xfs: support bulk loading of staged btrees 2020-03-18 08:12:23 -07:00
xfs_btree.c xfs: support bulk loading of staged btrees 2020-03-18 08:12:23 -07:00
xfs_btree.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_cksum.h
xfs_da_btree.c xfs: xfs_dabuf_map should return ENOMEM when map allocation fails 2020-03-15 09:22:35 -07:00
xfs_da_btree.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_da_format.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_defer.c xfs: use ordered buffers to initialize dquot buffers during quotacheck 2020-05-19 09:40:56 -07:00
xfs_defer.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_dir2_block.c xfs: check owner of dir3 blocks 2020-03-12 07:58:13 -07:00
xfs_dir2_data.c xfs: check owner of dir3 data blocks 2020-03-12 07:58:12 -07:00
xfs_dir2_leaf.c xfs: add a function to deal with corrupt buffers post-verifiers 2020-03-12 07:58:12 -07:00
xfs_dir2_node.c xfs: check owner of dir3 free blocks 2020-03-12 07:58:12 -07:00
xfs_dir2_priv.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_dir2_sf.c libxfs: resync with the userspace libxfs 2019-12-19 07:53:47 -08:00
xfs_dir2.c libxfs: resync with the userspace libxfs 2019-12-19 07:53:47 -08:00
xfs_dir2.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_dquot_buf.c xfs: remove the xfs_disk_dquot_t and xfs_dquot_t 2019-11-13 11:13:45 -08:00
xfs_errortag.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_format.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_fs.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_health.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_ialloc_btree.c xfs: add support for inode btree staging cursors 2020-03-18 08:12:23 -07:00
xfs_ialloc_btree.h xfs: add support for inode btree staging cursors 2020-03-18 08:12:23 -07:00
xfs_ialloc.c xfs: only check the superblock version for dinode size calculation 2020-03-19 08:48:47 -07:00
xfs_ialloc.h xfs: don't commit sunit/swidth updates to disk if that would cause repair failures 2019-12-19 07:53:48 -08:00
xfs_iext_tree.c xfs: fix inode fork extent count overflow 2019-10-21 09:04:58 -07:00
xfs_inode_buf.c xfs: remove unused iget_flags param from xfs_imap_to_bp() 2020-05-07 08:27:49 -07:00
xfs_inode_buf.h xfs: remove unused iget_flags param from xfs_imap_to_bp() 2020-05-07 08:27:49 -07:00
xfs_inode_fork.c xfs: remove the xfs_inode_log_item_t typedef 2020-05-04 09:03:16 -07:00
xfs_inode_fork.h xfs: only check the superblock version for dinode size calculation 2020-03-19 08:48:47 -07:00
xfs_log_format.h xfs: only check the superblock version for dinode size calculation 2020-03-19 08:48:47 -07:00
xfs_log_recover.h xfs: move log recovery buffer cancellation code to xfs_buf_item_recover.c 2020-05-08 08:50:01 -07:00
xfs_log_rlimit.c xfs: remove unused header files 2019-06-28 19:30:43 -07:00
xfs_quota_defs.h xfs: change some error-less functions to void types 2019-05-01 20:26:30 -07:00
xfs_refcount_btree.c xfs: add support for refcount btree staging cursors 2020-03-18 08:12:23 -07:00
xfs_refcount_btree.h xfs: add support for refcount btree staging cursors 2020-03-18 08:12:23 -07:00
xfs_refcount.c xfs: make the btree ag cursor private union anonymous 2020-03-13 10:37:15 -07:00
xfs_refcount.h xfs: remove unnecessary int returns from deferred refcount functions 2019-08-28 08:31:02 -07:00
xfs_rmap_btree.c xfs: add support for rmap btree staging cursors 2020-03-18 08:12:23 -07:00
xfs_rmap_btree.h xfs: add support for rmap btree staging cursors 2020-03-18 08:12:23 -07:00
xfs_rmap.c xfs: convert btree cursor ag-private member name 2020-03-13 10:37:14 -07:00
xfs_rmap.h xfs: reinitialize rm_flags when unpacking an offset into an rmap irec 2019-08-28 08:31:02 -07:00
xfs_rtbitmap.c xfs: convert open coded corruption check to use XFS_IS_CORRUPT 2019-11-13 11:08:01 -08:00
xfs_sb.c xfs: validate the realtime geometry in xfs_validate_sb_common 2020-03-27 08:32:53 -07:00
xfs_sb.h xfs: change some error-less functions to void types 2019-05-01 20:26:30 -07:00
xfs_shared.h xfs: remove all *_ITER_CONTINUE values 2019-08-30 22:43:56 -07:00
xfs_symlink_remote.c xfs: remove unused header files 2019-06-28 19:30:43 -07:00
xfs_trans_inode.c xfs: remove the xfs_inode_log_item_t typedef 2020-05-04 09:03:16 -07:00
xfs_trans_resv.c xfs: add a new xfs_sb_version_has_v3inode helper 2020-03-19 08:47:34 -07:00
xfs_trans_resv.h xfs: convert to SPDX license tags 2018-06-06 14:17:53 -07:00
xfs_trans_space.h xfs: separate inode geometry 2019-06-12 08:37:40 -07:00
xfs_types.c xfs: remove unused header files 2019-06-28 19:30:43 -07:00
xfs_types.h xfs: remove unused structure members & simple typedefs 2019-11-13 18:22:41 -08:00