Skip to content

Commit b28564c

Browse files
author
Darrick J. Wong
committed
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: <[email protected]> # v2.6.37 Fixes: 52fda11 ("xfs: simplify xfs_qm_dqusage_adjust") Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent d5d9dd5 commit b28564c

File tree

2 files changed

+56
-19
lines changed

2 files changed

+56
-19
lines changed

fs/xfs/xfs_qm.c

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,8 +1351,8 @@ xfs_qm_dqusage_adjust(
13511351
void *data)
13521352
{
13531353
struct xfs_inode *ip;
1354-
xfs_qcnt_t nblks;
1355-
xfs_filblks_t rtblks = 0; /* total rt blks */
1354+
xfs_filblks_t nblks, rtblks;
1355+
unsigned int lock_mode;
13561356
int error;
13571357

13581358
ASSERT(XFS_IS_QUOTA_ON(mp));
@@ -1393,18 +1393,17 @@ xfs_qm_dqusage_adjust(
13931393

13941394
ASSERT(ip->i_delayed_blks == 0);
13951395

1396+
lock_mode = xfs_ilock_data_map_shared(ip);
13961397
if (XFS_IS_REALTIME_INODE(ip)) {
1397-
struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
1398-
13991398
error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);
1400-
if (error)
1399+
if (error) {
1400+
xfs_iunlock(ip, lock_mode);
14011401
goto error0;
1402-
1403-
xfs_bmap_count_leaves(ifp, &rtblks);
1402+
}
14041403
}
1405-
1406-
nblks = (xfs_qcnt_t)ip->i_nblocks - rtblks;
1404+
xfs_inode_count_blocks(tp, ip, &nblks, &rtblks);
14071405
xfs_iflags_clear(ip, XFS_IQUOTAUNCHECKED);
1406+
xfs_iunlock(ip, lock_mode);
14081407

14091408
/*
14101409
* Add the (disk blocks and inode) resources occupied by this
@@ -2043,9 +2042,8 @@ xfs_qm_vop_chown(
20432042
struct xfs_dquot *newdq)
20442043
{
20452044
struct xfs_dquot *prevdq;
2046-
uint bfield = XFS_IS_REALTIME_INODE(ip) ?
2047-
XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT;
2048-
2045+
xfs_filblks_t dblocks, rblocks;
2046+
bool isrt = XFS_IS_REALTIME_INODE(ip);
20492047

20502048
xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);
20512049
ASSERT(XFS_IS_QUOTA_ON(ip->i_mount));
@@ -2056,11 +2054,17 @@ xfs_qm_vop_chown(
20562054
ASSERT(prevdq);
20572055
ASSERT(prevdq != newdq);
20582056

2059-
xfs_trans_mod_ino_dquot(tp, ip, prevdq, bfield, -(ip->i_nblocks));
2057+
xfs_inode_count_blocks(tp, ip, &dblocks, &rblocks);
2058+
2059+
xfs_trans_mod_ino_dquot(tp, ip, prevdq, XFS_TRANS_DQ_BCOUNT,
2060+
-(xfs_qcnt_t)dblocks);
2061+
xfs_trans_mod_ino_dquot(tp, ip, prevdq, XFS_TRANS_DQ_RTBCOUNT,
2062+
-(xfs_qcnt_t)rblocks);
20602063
xfs_trans_mod_ino_dquot(tp, ip, prevdq, XFS_TRANS_DQ_ICOUNT, -1);
20612064

20622065
/* the sparkling new dquot */
2063-
xfs_trans_mod_ino_dquot(tp, ip, newdq, bfield, ip->i_nblocks);
2066+
xfs_trans_mod_ino_dquot(tp, ip, newdq, XFS_TRANS_DQ_BCOUNT, dblocks);
2067+
xfs_trans_mod_ino_dquot(tp, ip, newdq, XFS_TRANS_DQ_RTBCOUNT, rblocks);
20642068
xfs_trans_mod_ino_dquot(tp, ip, newdq, XFS_TRANS_DQ_ICOUNT, 1);
20652069

20662070
/*
@@ -2070,7 +2074,8 @@ xfs_qm_vop_chown(
20702074
* (having already bumped up the real counter) so that we don't have
20712075
* any reservation to give back when we commit.
20722076
*/
2073-
xfs_trans_mod_dquot(tp, newdq, XFS_TRANS_DQ_RES_BLKS,
2077+
xfs_trans_mod_dquot(tp, newdq,
2078+
isrt ? XFS_TRANS_DQ_RES_RTBLKS : XFS_TRANS_DQ_RES_BLKS,
20742079
-ip->i_delayed_blks);
20752080

20762081
/*
@@ -2082,8 +2087,13 @@ xfs_qm_vop_chown(
20822087
*/
20832088
tp->t_flags |= XFS_TRANS_DIRTY;
20842089
xfs_dqlock(prevdq);
2085-
ASSERT(prevdq->q_blk.reserved >= ip->i_delayed_blks);
2086-
prevdq->q_blk.reserved -= ip->i_delayed_blks;
2090+
if (isrt) {
2091+
ASSERT(prevdq->q_rtb.reserved >= ip->i_delayed_blks);
2092+
prevdq->q_rtb.reserved -= ip->i_delayed_blks;
2093+
} else {
2094+
ASSERT(prevdq->q_blk.reserved >= ip->i_delayed_blks);
2095+
prevdq->q_blk.reserved -= ip->i_delayed_blks;
2096+
}
20872097
xfs_dqunlock(prevdq);
20882098

20892099
/*

fs/xfs/xfs_trans.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,20 +1288,47 @@ xfs_trans_alloc_ichange(
12881288
gdqp = (new_gdqp != ip->i_gdquot) ? new_gdqp : NULL;
12891289
pdqp = (new_pdqp != ip->i_pdquot) ? new_pdqp : NULL;
12901290
if (udqp || gdqp || pdqp) {
1291+
xfs_filblks_t dblocks, rblocks;
12911292
unsigned int qflags = XFS_QMOPT_RES_REGBLKS;
1293+
bool isrt = XFS_IS_REALTIME_INODE(ip);
12921294

12931295
if (force)
12941296
qflags |= XFS_QMOPT_FORCE_RES;
12951297

1298+
if (isrt) {
1299+
error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);
1300+
if (error)
1301+
goto out_cancel;
1302+
}
1303+
1304+
xfs_inode_count_blocks(tp, ip, &dblocks, &rblocks);
1305+
1306+
if (isrt)
1307+
rblocks += ip->i_delayed_blks;
1308+
else
1309+
dblocks += ip->i_delayed_blks;
1310+
12961311
/*
12971312
* Reserve enough quota to handle blocks on disk and reserved
12981313
* for a delayed allocation. We'll actually transfer the
12991314
* delalloc reservation between dquots at chown time, even
13001315
* though that part is only semi-transactional.
13011316
*/
13021317
error = xfs_trans_reserve_quota_bydquots(tp, mp, udqp, gdqp,
1303-
pdqp, ip->i_nblocks + ip->i_delayed_blks,
1304-
1, qflags);
1318+
pdqp, dblocks, 1, qflags);
1319+
if ((error == -EDQUOT || error == -ENOSPC) && !retried) {
1320+
xfs_trans_cancel(tp);
1321+
xfs_blockgc_free_dquots(mp, udqp, gdqp, pdqp, 0);
1322+
retried = true;
1323+
goto retry;
1324+
}
1325+
if (error)
1326+
goto out_cancel;
1327+
1328+
/* Do the same for realtime. */
1329+
qflags = XFS_QMOPT_RES_RTBLKS | (qflags & XFS_QMOPT_FORCE_RES);
1330+
error = xfs_trans_reserve_quota_bydquots(tp, mp, udqp, gdqp,
1331+
pdqp, rblocks, 0, qflags);
13051332
if ((error == -EDQUOT || error == -ENOSPC) && !retried) {
13061333
xfs_trans_cancel(tp);
13071334
xfs_blockgc_free_dquots(mp, udqp, gdqp, pdqp, 0);

0 commit comments

Comments
 (0)