Skip to content

Commit 8ca118e

Browse files
committed
Merge tag 'realtime-quotas-6.13_2024-11-05' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into staging-merge
xfs: enable quota for realtime volumes [v5.5 08/10] At some point, I realized that I've refactored enough of the quota code in XFS that I should evaluate whether or not quota actually works on realtime volumes. It turns out that it nearly works: the only broken pieces are chown and delayed allocation, and reporting of project quotas in the statvfs output for projinherit+rtinherit directories. Fix these things and we can have realtime quotas again after 20 years. With a bit of luck, this should all go splendidly. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
2 parents 93c0f79 + edc038f commit 8ca118e

File tree

11 files changed

+182
-76
lines changed

11 files changed

+182
-76
lines changed

fs/xfs/xfs_dquot.c

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,25 @@ xfs_qm_init_dquot_blk(
277277
xfs_trans_log_buf(tp, bp, 0, BBTOB(q->qi_dqchunklen) - 1);
278278
}
279279

280+
static void
281+
xfs_dquot_set_prealloc(
282+
struct xfs_dquot_pre *pre,
283+
const struct xfs_dquot_res *res)
284+
{
285+
xfs_qcnt_t space;
286+
287+
pre->q_prealloc_hi_wmark = res->hardlimit;
288+
pre->q_prealloc_lo_wmark = res->softlimit;
289+
290+
space = div_u64(pre->q_prealloc_hi_wmark, 100);
291+
if (!pre->q_prealloc_lo_wmark)
292+
pre->q_prealloc_lo_wmark = space * 95;
293+
294+
pre->q_low_space[XFS_QLOWSP_1_PCNT] = space;
295+
pre->q_low_space[XFS_QLOWSP_3_PCNT] = space * 3;
296+
pre->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5;
297+
}
298+
280299
/*
281300
* Initialize the dynamic speculative preallocation thresholds. The lo/hi
282301
* watermarks correspond to the soft and hard limits by default. If a soft limit
@@ -285,22 +304,8 @@ xfs_qm_init_dquot_blk(
285304
void
286305
xfs_dquot_set_prealloc_limits(struct xfs_dquot *dqp)
287306
{
288-
uint64_t space;
289-
290-
dqp->q_prealloc_hi_wmark = dqp->q_blk.hardlimit;
291-
dqp->q_prealloc_lo_wmark = dqp->q_blk.softlimit;
292-
if (!dqp->q_prealloc_lo_wmark) {
293-
dqp->q_prealloc_lo_wmark = dqp->q_prealloc_hi_wmark;
294-
do_div(dqp->q_prealloc_lo_wmark, 100);
295-
dqp->q_prealloc_lo_wmark *= 95;
296-
}
297-
298-
space = dqp->q_prealloc_hi_wmark;
299-
300-
do_div(space, 100);
301-
dqp->q_low_space[XFS_QLOWSP_1_PCNT] = space;
302-
dqp->q_low_space[XFS_QLOWSP_3_PCNT] = space * 3;
303-
dqp->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5;
307+
xfs_dquot_set_prealloc(&dqp->q_blk_prealloc, &dqp->q_blk);
308+
xfs_dquot_set_prealloc(&dqp->q_rtb_prealloc, &dqp->q_rtb);
304309
}
305310

306311
/*

fs/xfs/xfs_dquot.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ xfs_dquot_res_over_limits(
5656
return false;
5757
}
5858

59+
struct xfs_dquot_pre {
60+
xfs_qcnt_t q_prealloc_lo_wmark;
61+
xfs_qcnt_t q_prealloc_hi_wmark;
62+
int64_t q_low_space[XFS_QLOWSP_MAX];
63+
};
64+
5965
/*
6066
* The incore dquot structure
6167
*/
@@ -76,9 +82,9 @@ struct xfs_dquot {
7682

7783
struct xfs_dq_logitem q_logitem;
7884

79-
xfs_qcnt_t q_prealloc_lo_wmark;
80-
xfs_qcnt_t q_prealloc_hi_wmark;
81-
int64_t q_low_space[XFS_QLOWSP_MAX];
85+
struct xfs_dquot_pre q_blk_prealloc;
86+
struct xfs_dquot_pre q_rtb_prealloc;
87+
8288
struct mutex q_qlock;
8389
struct completion q_flush;
8490
atomic_t q_pincount;
@@ -192,7 +198,11 @@ static inline bool xfs_dquot_lowsp(struct xfs_dquot *dqp)
192198
int64_t freesp;
193199

194200
freesp = dqp->q_blk.hardlimit - dqp->q_blk.reserved;
195-
if (freesp < dqp->q_low_space[XFS_QLOWSP_1_PCNT])
201+
if (freesp < dqp->q_blk_prealloc.q_low_space[XFS_QLOWSP_1_PCNT])
202+
return true;
203+
204+
freesp = dqp->q_rtb.hardlimit - dqp->q_rtb.reserved;
205+
if (freesp < dqp->q_rtb_prealloc.q_low_space[XFS_QLOWSP_1_PCNT])
196206
return true;
197207

198208
return false;

fs/xfs/xfs_iomap.c

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -353,16 +353,26 @@ xfs_quota_need_throttle(
353353
xfs_fsblock_t alloc_blocks)
354354
{
355355
struct xfs_dquot *dq = xfs_inode_dquot(ip, type);
356+
struct xfs_dquot_res *res;
357+
struct xfs_dquot_pre *pre;
356358

357359
if (!dq || !xfs_this_quota_on(ip->i_mount, type))
358360
return false;
359361

362+
if (XFS_IS_REALTIME_INODE(ip)) {
363+
res = &dq->q_rtb;
364+
pre = &dq->q_rtb_prealloc;
365+
} else {
366+
res = &dq->q_blk;
367+
pre = &dq->q_blk_prealloc;
368+
}
369+
360370
/* no hi watermark, no throttle */
361-
if (!dq->q_prealloc_hi_wmark)
371+
if (!pre->q_prealloc_hi_wmark)
362372
return false;
363373

364374
/* under the lo watermark, no throttle */
365-
if (dq->q_blk.reserved + alloc_blocks < dq->q_prealloc_lo_wmark)
375+
if (res->reserved + alloc_blocks < pre->q_prealloc_lo_wmark)
366376
return false;
367377

368378
return true;
@@ -377,22 +387,35 @@ xfs_quota_calc_throttle(
377387
int64_t *qfreesp)
378388
{
379389
struct xfs_dquot *dq = xfs_inode_dquot(ip, type);
390+
struct xfs_dquot_res *res;
391+
struct xfs_dquot_pre *pre;
380392
int64_t freesp;
381393
int shift = 0;
382394

395+
if (!dq) {
396+
res = NULL;
397+
pre = NULL;
398+
} else if (XFS_IS_REALTIME_INODE(ip)) {
399+
res = &dq->q_rtb;
400+
pre = &dq->q_rtb_prealloc;
401+
} else {
402+
res = &dq->q_blk;
403+
pre = &dq->q_blk_prealloc;
404+
}
405+
383406
/* no dq, or over hi wmark, squash the prealloc completely */
384-
if (!dq || dq->q_blk.reserved >= dq->q_prealloc_hi_wmark) {
407+
if (!res || res->reserved >= pre->q_prealloc_hi_wmark) {
385408
*qblocks = 0;
386409
*qfreesp = 0;
387410
return;
388411
}
389412

390-
freesp = dq->q_prealloc_hi_wmark - dq->q_blk.reserved;
391-
if (freesp < dq->q_low_space[XFS_QLOWSP_5_PCNT]) {
413+
freesp = pre->q_prealloc_hi_wmark - res->reserved;
414+
if (freesp < pre->q_low_space[XFS_QLOWSP_5_PCNT]) {
392415
shift = 2;
393-
if (freesp < dq->q_low_space[XFS_QLOWSP_3_PCNT])
416+
if (freesp < pre->q_low_space[XFS_QLOWSP_3_PCNT])
394417
shift += 2;
395-
if (freesp < dq->q_low_space[XFS_QLOWSP_1_PCNT])
418+
if (freesp < pre->q_low_space[XFS_QLOWSP_1_PCNT])
396419
shift += 2;
397420
}
398421

fs/xfs/xfs_qm.c

Lines changed: 47 additions & 25 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
@@ -1664,10 +1663,11 @@ xfs_qm_mount_quotas(
16641663
uint sbf;
16651664

16661665
/*
1667-
* If quotas on realtime volumes is not supported, we disable
1668-
* quotas immediately.
1666+
* If quotas on realtime volumes is not supported, disable quotas
1667+
* immediately. We only support rtquota if rtgroups are enabled to
1668+
* avoid problems with older kernels.
16691669
*/
1670-
if (mp->m_sb.sb_rextents) {
1670+
if (mp->m_sb.sb_rextents && !xfs_has_rtgroups(mp)) {
16711671
xfs_notice(mp, "Cannot turn on quotas for realtime filesystem");
16721672
mp->m_qflags = 0;
16731673
goto write_changes;
@@ -2043,9 +2043,8 @@ xfs_qm_vop_chown(
20432043
struct xfs_dquot *newdq)
20442044
{
20452045
struct xfs_dquot *prevdq;
2046-
uint bfield = XFS_IS_REALTIME_INODE(ip) ?
2047-
XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT;
2048-
2046+
xfs_filblks_t dblocks, rblocks;
2047+
bool isrt = XFS_IS_REALTIME_INODE(ip);
20492048

20502049
xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);
20512050
ASSERT(XFS_IS_QUOTA_ON(ip->i_mount));
@@ -2056,11 +2055,17 @@ xfs_qm_vop_chown(
20562055
ASSERT(prevdq);
20572056
ASSERT(prevdq != newdq);
20582057

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

20622066
/* the sparkling new dquot */
2063-
xfs_trans_mod_ino_dquot(tp, ip, newdq, bfield, ip->i_nblocks);
2067+
xfs_trans_mod_ino_dquot(tp, ip, newdq, XFS_TRANS_DQ_BCOUNT, dblocks);
2068+
xfs_trans_mod_ino_dquot(tp, ip, newdq, XFS_TRANS_DQ_RTBCOUNT, rblocks);
20642069
xfs_trans_mod_ino_dquot(tp, ip, newdq, XFS_TRANS_DQ_ICOUNT, 1);
20652070

20662071
/*
@@ -2070,7 +2075,8 @@ xfs_qm_vop_chown(
20702075
* (having already bumped up the real counter) so that we don't have
20712076
* any reservation to give back when we commit.
20722077
*/
2073-
xfs_trans_mod_dquot(tp, newdq, XFS_TRANS_DQ_RES_BLKS,
2078+
xfs_trans_mod_dquot(tp, newdq,
2079+
isrt ? XFS_TRANS_DQ_RES_RTBLKS : XFS_TRANS_DQ_RES_BLKS,
20742080
-ip->i_delayed_blks);
20752081

20762082
/*
@@ -2082,8 +2088,13 @@ xfs_qm_vop_chown(
20822088
*/
20832089
tp->t_flags |= XFS_TRANS_DIRTY;
20842090
xfs_dqlock(prevdq);
2085-
ASSERT(prevdq->q_blk.reserved >= ip->i_delayed_blks);
2086-
prevdq->q_blk.reserved -= ip->i_delayed_blks;
2091+
if (isrt) {
2092+
ASSERT(prevdq->q_rtb.reserved >= ip->i_delayed_blks);
2093+
prevdq->q_rtb.reserved -= ip->i_delayed_blks;
2094+
} else {
2095+
ASSERT(prevdq->q_blk.reserved >= ip->i_delayed_blks);
2096+
prevdq->q_blk.reserved -= ip->i_delayed_blks;
2097+
}
20872098
xfs_dqunlock(prevdq);
20882099

20892100
/*
@@ -2168,6 +2179,8 @@ xfs_inode_near_dquot_enforcement(
21682179
xfs_dqtype_t type)
21692180
{
21702181
struct xfs_dquot *dqp;
2182+
struct xfs_dquot_res *res;
2183+
struct xfs_dquot_pre *pre;
21712184
int64_t freesp;
21722185

21732186
/* We only care for quotas that are enabled and enforced. */
@@ -2176,21 +2189,30 @@ xfs_inode_near_dquot_enforcement(
21762189
return false;
21772190

21782191
if (xfs_dquot_res_over_limits(&dqp->q_ino) ||
2192+
xfs_dquot_res_over_limits(&dqp->q_blk) ||
21792193
xfs_dquot_res_over_limits(&dqp->q_rtb))
21802194
return true;
21812195

2196+
if (XFS_IS_REALTIME_INODE(ip)) {
2197+
res = &dqp->q_rtb;
2198+
pre = &dqp->q_rtb_prealloc;
2199+
} else {
2200+
res = &dqp->q_blk;
2201+
pre = &dqp->q_blk_prealloc;
2202+
}
2203+
21822204
/* For space on the data device, check the various thresholds. */
2183-
if (!dqp->q_prealloc_hi_wmark)
2205+
if (!pre->q_prealloc_hi_wmark)
21842206
return false;
21852207

2186-
if (dqp->q_blk.reserved < dqp->q_prealloc_lo_wmark)
2208+
if (res->reserved < pre->q_prealloc_lo_wmark)
21872209
return false;
21882210

2189-
if (dqp->q_blk.reserved >= dqp->q_prealloc_hi_wmark)
2211+
if (res->reserved >= pre->q_prealloc_hi_wmark)
21902212
return true;
21912213

2192-
freesp = dqp->q_prealloc_hi_wmark - dqp->q_blk.reserved;
2193-
if (freesp < dqp->q_low_space[XFS_QLOWSP_5_PCNT])
2214+
freesp = pre->q_prealloc_hi_wmark - res->reserved;
2215+
if (freesp < pre->q_low_space[XFS_QLOWSP_5_PCNT])
21942216
return true;
21952217

21962218
return false;

fs/xfs/xfs_qm_bhv.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,24 @@
1919
STATIC void
2020
xfs_fill_statvfs_from_dquot(
2121
struct kstatfs *statp,
22+
struct xfs_inode *ip,
2223
struct xfs_dquot *dqp)
2324
{
25+
struct xfs_dquot_res *blkres = &dqp->q_blk;
2426
uint64_t limit;
2527

26-
limit = dqp->q_blk.softlimit ?
27-
dqp->q_blk.softlimit :
28-
dqp->q_blk.hardlimit;
28+
if (XFS_IS_REALTIME_MOUNT(ip->i_mount) &&
29+
(ip->i_diflags & (XFS_DIFLAG_RTINHERIT | XFS_DIFLAG_REALTIME)))
30+
blkres = &dqp->q_rtb;
31+
32+
limit = blkres->softlimit ?
33+
blkres->softlimit :
34+
blkres->hardlimit;
2935
if (limit && statp->f_blocks > limit) {
3036
statp->f_blocks = limit;
3137
statp->f_bfree = statp->f_bavail =
32-
(statp->f_blocks > dqp->q_blk.reserved) ?
33-
(statp->f_blocks - dqp->q_blk.reserved) : 0;
38+
(statp->f_blocks > blkres->reserved) ?
39+
(statp->f_blocks - blkres->reserved) : 0;
3440
}
3541

3642
limit = dqp->q_ino.softlimit ?
@@ -61,7 +67,7 @@ xfs_qm_statvfs(
6167
struct xfs_dquot *dqp;
6268

6369
if (!xfs_qm_dqget(mp, ip->i_projid, XFS_DQTYPE_PROJ, false, &dqp)) {
64-
xfs_fill_statvfs_from_dquot(statp, dqp);
70+
xfs_fill_statvfs_from_dquot(statp, ip, dqp);
6571
xfs_qm_dqput(dqp);
6672
}
6773
}

fs/xfs/xfs_quota.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ extern void xfs_qm_mount_quotas(struct xfs_mount *);
130130
extern void xfs_qm_unmount(struct xfs_mount *);
131131
extern void xfs_qm_unmount_quotas(struct xfs_mount *);
132132
bool xfs_inode_near_dquot_enforcement(struct xfs_inode *ip, xfs_dqtype_t type);
133+
int xfs_quota_reserve_blkres(struct xfs_inode *ip, int64_t blocks);
133134

134135
# ifdef CONFIG_XFS_LIVE_HOOKS
135136
void xfs_trans_mod_ino_dquot(struct xfs_trans *tp, struct xfs_inode *ip,
@@ -209,19 +210,18 @@ xfs_trans_reserve_quota_icreate(struct xfs_trans *tp, struct xfs_dquot *udqp,
209210
#define xfs_qm_unmount_quotas(mp)
210211
#define xfs_inode_near_dquot_enforcement(ip, type) (false)
211212

213+
static inline int xfs_quota_reserve_blkres(struct xfs_inode *ip, int64_t blocks)
214+
{
215+
return 0;
216+
}
217+
212218
# ifdef CONFIG_XFS_LIVE_HOOKS
213219
# define xfs_dqtrx_hook_enable() ((void)0)
214220
# define xfs_dqtrx_hook_disable() ((void)0)
215221
# endif /* CONFIG_XFS_LIVE_HOOKS */
216222

217223
#endif /* CONFIG_XFS_QUOTA */
218224

219-
static inline int
220-
xfs_quota_reserve_blkres(struct xfs_inode *ip, int64_t blocks)
221-
{
222-
return xfs_trans_reserve_quota_nblks(NULL, ip, blocks, 0, false);
223-
}
224-
225225
static inline void
226226
xfs_quota_unreserve_blkres(struct xfs_inode *ip, uint64_t blocks)
227227
{

fs/xfs/xfs_rtalloc.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,9 @@ xfs_growfs_rt(
12651265

12661266
/* Unsupported realtime features. */
12671267
error = -EOPNOTSUPP;
1268-
if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp) || xfs_has_quota(mp))
1268+
if (xfs_has_quota(mp) && !xfs_has_rtgroups(mp))
1269+
goto out_unlock;
1270+
if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp))
12691271
goto out_unlock;
12701272

12711273
error = xfs_sb_validate_fsb_count(&mp->m_sb, in->newblocks);

0 commit comments

Comments
 (0)