release 6.12.4 (preliminary)
This commit is contained in:
178
debian/patches/patchset-pf/xfs/0001-xfs-fix-chown-with-rt-quota.patch
vendored
Normal file
178
debian/patches/patchset-pf/xfs/0001-xfs-fix-chown-with-rt-quota.patch
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
From 6fe0d820b76da3a4f1f8d1fd605b2afc9edcb3f8 Mon Sep 17 00:00:00 2001
|
||||
From: "Darrick J. Wong" <djwong@kernel.org>
|
||||
Date: Sun, 3 Nov 2024 20:19:39 -0800
|
||||
Subject: xfs: fix chown with rt quota
|
||||
|
||||
Make chown's quota adjustments work with realtime files. This is mostly
|
||||
a matter of calling xfs_inode_count_blocks on a given file to figure out
|
||||
the number of blocks allocated to the data device and to the realtime
|
||||
device, and using those quantities to update the quota accounting when
|
||||
the id changes. Delayed allocation reservations are moved from the old
|
||||
dquot's incore reservation to the new dquot's incore reservation.
|
||||
|
||||
Note that there was a missing ILOCK bug in xfs_qm_dqusage_adjust that we
|
||||
must fix before calling xfs_iread_extents. Prior to 2.6.37 the locking
|
||||
was correct, but then someone removed the ILOCK as part of a cleanup.
|
||||
Nobody noticed because nowhere in the git history have we ever supported
|
||||
rt+quota so nobody can use this.
|
||||
|
||||
I'm leaving git breadcrumbs in case anyone is desperate enough to try to
|
||||
backport the rtquota code to old kernels.
|
||||
|
||||
Not-Cc: <stable@vger.kernel.org> # v2.6.37
|
||||
Fixes: 52fda114249578 ("xfs: simplify xfs_qm_dqusage_adjust")
|
||||
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
|
||||
Reviewed-by: Christoph Hellwig <hch@lst.de>
|
||||
---
|
||||
fs/xfs/xfs_qm.c | 44 +++++++++++++++++++++++++++-----------------
|
||||
fs/xfs/xfs_trans.c | 31 +++++++++++++++++++++++++++++--
|
||||
2 files changed, 56 insertions(+), 19 deletions(-)
|
||||
|
||||
--- a/fs/xfs/xfs_qm.c
|
||||
+++ b/fs/xfs/xfs_qm.c
|
||||
@@ -1153,8 +1153,8 @@ xfs_qm_dqusage_adjust(
|
||||
void *data)
|
||||
{
|
||||
struct xfs_inode *ip;
|
||||
- xfs_qcnt_t nblks;
|
||||
- xfs_filblks_t rtblks = 0; /* total rt blks */
|
||||
+ xfs_filblks_t nblks, rtblks;
|
||||
+ unsigned int lock_mode;
|
||||
int error;
|
||||
|
||||
ASSERT(XFS_IS_QUOTA_ON(mp));
|
||||
@@ -1191,18 +1191,17 @@ xfs_qm_dqusage_adjust(
|
||||
|
||||
ASSERT(ip->i_delayed_blks == 0);
|
||||
|
||||
+ lock_mode = xfs_ilock_data_map_shared(ip);
|
||||
if (XFS_IS_REALTIME_INODE(ip)) {
|
||||
- struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
|
||||
-
|
||||
error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);
|
||||
- if (error)
|
||||
+ if (error) {
|
||||
+ xfs_iunlock(ip, lock_mode);
|
||||
goto error0;
|
||||
-
|
||||
- xfs_bmap_count_leaves(ifp, &rtblks);
|
||||
+ }
|
||||
}
|
||||
-
|
||||
- nblks = (xfs_qcnt_t)ip->i_nblocks - rtblks;
|
||||
+ xfs_inode_count_blocks(tp, ip, &nblks, &rtblks);
|
||||
xfs_iflags_clear(ip, XFS_IQUOTAUNCHECKED);
|
||||
+ xfs_iunlock(ip, lock_mode);
|
||||
|
||||
/*
|
||||
* Add the (disk blocks and inode) resources occupied by this
|
||||
@@ -1858,9 +1857,8 @@ xfs_qm_vop_chown(
|
||||
struct xfs_dquot *newdq)
|
||||
{
|
||||
struct xfs_dquot *prevdq;
|
||||
- uint bfield = XFS_IS_REALTIME_INODE(ip) ?
|
||||
- XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT;
|
||||
-
|
||||
+ xfs_filblks_t dblocks, rblocks;
|
||||
+ bool isrt = XFS_IS_REALTIME_INODE(ip);
|
||||
|
||||
xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);
|
||||
ASSERT(XFS_IS_QUOTA_ON(ip->i_mount));
|
||||
@@ -1870,11 +1868,17 @@ xfs_qm_vop_chown(
|
||||
ASSERT(prevdq);
|
||||
ASSERT(prevdq != newdq);
|
||||
|
||||
- xfs_trans_mod_ino_dquot(tp, ip, prevdq, bfield, -(ip->i_nblocks));
|
||||
+ xfs_inode_count_blocks(tp, ip, &dblocks, &rblocks);
|
||||
+
|
||||
+ xfs_trans_mod_ino_dquot(tp, ip, prevdq, XFS_TRANS_DQ_BCOUNT,
|
||||
+ -(xfs_qcnt_t)dblocks);
|
||||
+ xfs_trans_mod_ino_dquot(tp, ip, prevdq, XFS_TRANS_DQ_RTBCOUNT,
|
||||
+ -(xfs_qcnt_t)rblocks);
|
||||
xfs_trans_mod_ino_dquot(tp, ip, prevdq, XFS_TRANS_DQ_ICOUNT, -1);
|
||||
|
||||
/* the sparkling new dquot */
|
||||
- xfs_trans_mod_ino_dquot(tp, ip, newdq, bfield, ip->i_nblocks);
|
||||
+ xfs_trans_mod_ino_dquot(tp, ip, newdq, XFS_TRANS_DQ_BCOUNT, dblocks);
|
||||
+ xfs_trans_mod_ino_dquot(tp, ip, newdq, XFS_TRANS_DQ_RTBCOUNT, rblocks);
|
||||
xfs_trans_mod_ino_dquot(tp, ip, newdq, XFS_TRANS_DQ_ICOUNT, 1);
|
||||
|
||||
/*
|
||||
@@ -1884,7 +1888,8 @@ xfs_qm_vop_chown(
|
||||
* (having already bumped up the real counter) so that we don't have
|
||||
* any reservation to give back when we commit.
|
||||
*/
|
||||
- xfs_trans_mod_dquot(tp, newdq, XFS_TRANS_DQ_RES_BLKS,
|
||||
+ xfs_trans_mod_dquot(tp, newdq,
|
||||
+ isrt ? XFS_TRANS_DQ_RES_RTBLKS : XFS_TRANS_DQ_RES_BLKS,
|
||||
-ip->i_delayed_blks);
|
||||
|
||||
/*
|
||||
@@ -1896,8 +1901,13 @@ xfs_qm_vop_chown(
|
||||
*/
|
||||
tp->t_flags |= XFS_TRANS_DIRTY;
|
||||
xfs_dqlock(prevdq);
|
||||
- ASSERT(prevdq->q_blk.reserved >= ip->i_delayed_blks);
|
||||
- prevdq->q_blk.reserved -= ip->i_delayed_blks;
|
||||
+ if (isrt) {
|
||||
+ ASSERT(prevdq->q_rtb.reserved >= ip->i_delayed_blks);
|
||||
+ prevdq->q_rtb.reserved -= ip->i_delayed_blks;
|
||||
+ } else {
|
||||
+ ASSERT(prevdq->q_blk.reserved >= ip->i_delayed_blks);
|
||||
+ prevdq->q_blk.reserved -= ip->i_delayed_blks;
|
||||
+ }
|
||||
xfs_dqunlock(prevdq);
|
||||
|
||||
/*
|
||||
--- a/fs/xfs/xfs_trans.c
|
||||
+++ b/fs/xfs/xfs_trans.c
|
||||
@@ -1262,11 +1262,26 @@ retry:
|
||||
gdqp = (new_gdqp != ip->i_gdquot) ? new_gdqp : NULL;
|
||||
pdqp = (new_pdqp != ip->i_pdquot) ? new_pdqp : NULL;
|
||||
if (udqp || gdqp || pdqp) {
|
||||
+ xfs_filblks_t dblocks, rblocks;
|
||||
unsigned int qflags = XFS_QMOPT_RES_REGBLKS;
|
||||
+ bool isrt = XFS_IS_REALTIME_INODE(ip);
|
||||
|
||||
if (force)
|
||||
qflags |= XFS_QMOPT_FORCE_RES;
|
||||
|
||||
+ if (isrt) {
|
||||
+ error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);
|
||||
+ if (error)
|
||||
+ goto out_cancel;
|
||||
+ }
|
||||
+
|
||||
+ xfs_inode_count_blocks(tp, ip, &dblocks, &rblocks);
|
||||
+
|
||||
+ if (isrt)
|
||||
+ rblocks += ip->i_delayed_blks;
|
||||
+ else
|
||||
+ dblocks += ip->i_delayed_blks;
|
||||
+
|
||||
/*
|
||||
* Reserve enough quota to handle blocks on disk and reserved
|
||||
* for a delayed allocation. We'll actually transfer the
|
||||
@@ -1274,8 +1289,20 @@ retry:
|
||||
* though that part is only semi-transactional.
|
||||
*/
|
||||
error = xfs_trans_reserve_quota_bydquots(tp, mp, udqp, gdqp,
|
||||
- pdqp, ip->i_nblocks + ip->i_delayed_blks,
|
||||
- 1, qflags);
|
||||
+ pdqp, dblocks, 1, qflags);
|
||||
+ if ((error == -EDQUOT || error == -ENOSPC) && !retried) {
|
||||
+ xfs_trans_cancel(tp);
|
||||
+ xfs_blockgc_free_dquots(mp, udqp, gdqp, pdqp, 0);
|
||||
+ retried = true;
|
||||
+ goto retry;
|
||||
+ }
|
||||
+ if (error)
|
||||
+ goto out_cancel;
|
||||
+
|
||||
+ /* Do the same for realtime. */
|
||||
+ qflags = XFS_QMOPT_RES_RTBLKS | (qflags & XFS_QMOPT_FORCE_RES);
|
||||
+ error = xfs_trans_reserve_quota_bydquots(tp, mp, udqp, gdqp,
|
||||
+ pdqp, rblocks, 0, qflags);
|
||||
if ((error == -EDQUOT || error == -ENOSPC) && !retried) {
|
||||
xfs_trans_cancel(tp);
|
||||
xfs_blockgc_free_dquots(mp, udqp, gdqp, pdqp, 0);
|
Reference in New Issue
Block a user