Skip to content

Commit 179b8c9

Browse files
committed
quota: Fix rcu annotations of inode dquot pointers
Dquot pointers in i_dquot array in the inode are protected by dquot_srcu. Annotate the array pointers with __rcu, perform the locked dereferences with srcu_dereference_check() instead of plain reads, and set the array elements with rcu_assign_pointer(). Fixes: b9ba6f9 ("quota: remove dqptr_sem") Reported-by: kernel test robot <lkp@intel.com> Closes: https://lore.kernel.org/oe-kbuild-all/202402061900.rTuYDlo6-lkp@intel.com/ Signed-off-by: Jan Kara <jack@suse.cz>
1 parent 4243bf8 commit 179b8c9

File tree

1 file changed

+39
-27
lines changed

1 file changed

+39
-27
lines changed

fs/quota/dquot.c

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
399399
EXPORT_SYMBOL(dquot_mark_dquot_dirty);
400400

401401
/* Dirtify all the dquots - this can block when journalling */
402-
static inline int mark_all_dquot_dirty(struct dquot * const *dquots)
402+
static inline int mark_all_dquot_dirty(struct dquot __rcu * const *dquots)
403403
{
404404
int ret, err, cnt;
405405
struct dquot *dquot;
@@ -996,14 +996,15 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid)
996996
}
997997
EXPORT_SYMBOL(dqget);
998998

999-
static inline struct dquot **i_dquot(struct inode *inode)
999+
static inline struct dquot __rcu **i_dquot(struct inode *inode)
10001000
{
1001-
return inode->i_sb->s_op->get_dquots(inode);
1001+
/* Force __rcu for now until filesystems are fixed */
1002+
return (struct dquot __rcu **)inode->i_sb->s_op->get_dquots(inode);
10021003
}
10031004

10041005
static int dqinit_needed(struct inode *inode, int type)
10051006
{
1006-
struct dquot * const *dquots;
1007+
struct dquot __rcu * const *dquots;
10071008
int cnt;
10081009

10091010
if (IS_NOQUOTA(inode))
@@ -1093,14 +1094,16 @@ static void remove_dquot_ref(struct super_block *sb, int type)
10931094
*/
10941095
spin_lock(&dq_data_lock);
10951096
if (!IS_NOQUOTA(inode)) {
1096-
struct dquot **dquots = i_dquot(inode);
1097-
struct dquot *dquot = dquots[type];
1097+
struct dquot __rcu **dquots = i_dquot(inode);
1098+
struct dquot *dquot = srcu_dereference_check(
1099+
dquots[type], &dquot_srcu,
1100+
lockdep_is_held(&dq_data_lock));
10981101

10991102
#ifdef CONFIG_QUOTA_DEBUG
11001103
if (unlikely(inode_get_rsv_space(inode) > 0))
11011104
reserved = 1;
11021105
#endif
1103-
dquots[type] = NULL;
1106+
rcu_assign_pointer(dquots[type], NULL);
11041107
if (dquot)
11051108
dqput(dquot);
11061109
}
@@ -1453,7 +1456,8 @@ static int inode_quota_active(const struct inode *inode)
14531456
static int __dquot_initialize(struct inode *inode, int type)
14541457
{
14551458
int cnt, init_needed = 0;
1456-
struct dquot **dquots, *got[MAXQUOTAS] = {};
1459+
struct dquot __rcu **dquots;
1460+
struct dquot *got[MAXQUOTAS] = {};
14571461
struct super_block *sb = inode->i_sb;
14581462
qsize_t rsv;
14591463
int ret = 0;
@@ -1528,20 +1532,24 @@ static int __dquot_initialize(struct inode *inode, int type)
15281532
if (!got[cnt])
15291533
continue;
15301534
if (!dquots[cnt]) {
1531-
dquots[cnt] = got[cnt];
1535+
rcu_assign_pointer(dquots[cnt], got[cnt]);
15321536
got[cnt] = NULL;
15331537
/*
15341538
* Make quota reservation system happy if someone
15351539
* did a write before quota was turned on
15361540
*/
15371541
rsv = inode_get_rsv_space(inode);
15381542
if (unlikely(rsv)) {
1543+
struct dquot *dquot = srcu_dereference_check(
1544+
dquots[cnt], &dquot_srcu,
1545+
lockdep_is_held(&dq_data_lock));
1546+
15391547
spin_lock(&inode->i_lock);
15401548
/* Get reservation again under proper lock */
15411549
rsv = __inode_get_rsv_space(inode);
1542-
spin_lock(&dquots[cnt]->dq_dqb_lock);
1543-
dquots[cnt]->dq_dqb.dqb_rsvspace += rsv;
1544-
spin_unlock(&dquots[cnt]->dq_dqb_lock);
1550+
spin_lock(&dquot->dq_dqb_lock);
1551+
dquot->dq_dqb.dqb_rsvspace += rsv;
1552+
spin_unlock(&dquot->dq_dqb_lock);
15451553
spin_unlock(&inode->i_lock);
15461554
}
15471555
}
@@ -1563,7 +1571,7 @@ EXPORT_SYMBOL(dquot_initialize);
15631571

15641572
bool dquot_initialize_needed(struct inode *inode)
15651573
{
1566-
struct dquot **dquots;
1574+
struct dquot __rcu **dquots;
15671575
int i;
15681576

15691577
if (!inode_quota_active(inode))
@@ -1588,21 +1596,22 @@ EXPORT_SYMBOL(dquot_initialize_needed);
15881596
static void __dquot_drop(struct inode *inode)
15891597
{
15901598
int cnt;
1591-
struct dquot **dquots = i_dquot(inode);
1599+
struct dquot __rcu **dquots = i_dquot(inode);
15921600
struct dquot *put[MAXQUOTAS];
15931601

15941602
spin_lock(&dq_data_lock);
15951603
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1596-
put[cnt] = dquots[cnt];
1597-
dquots[cnt] = NULL;
1604+
put[cnt] = srcu_dereference_check(dquots[cnt], &dquot_srcu,
1605+
lockdep_is_held(&dq_data_lock));
1606+
rcu_assign_pointer(dquots[cnt], NULL);
15981607
}
15991608
spin_unlock(&dq_data_lock);
16001609
dqput_all(put);
16011610
}
16021611

16031612
void dquot_drop(struct inode *inode)
16041613
{
1605-
struct dquot * const *dquots;
1614+
struct dquot __rcu * const *dquots;
16061615
int cnt;
16071616

16081617
if (IS_NOQUOTA(inode))
@@ -1675,7 +1684,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
16751684
int cnt, ret = 0, index;
16761685
struct dquot_warn warn[MAXQUOTAS];
16771686
int reserve = flags & DQUOT_SPACE_RESERVE;
1678-
struct dquot **dquots;
1687+
struct dquot __rcu **dquots;
16791688
struct dquot *dquot;
16801689

16811690
if (!inode_quota_active(inode)) {
@@ -1745,7 +1754,7 @@ int dquot_alloc_inode(struct inode *inode)
17451754
{
17461755
int cnt, ret = 0, index;
17471756
struct dquot_warn warn[MAXQUOTAS];
1748-
struct dquot * const *dquots;
1757+
struct dquot __rcu * const *dquots;
17491758
struct dquot *dquot;
17501759

17511760
if (!inode_quota_active(inode))
@@ -1790,7 +1799,7 @@ EXPORT_SYMBOL(dquot_alloc_inode);
17901799
*/
17911800
void dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
17921801
{
1793-
struct dquot **dquots;
1802+
struct dquot __rcu **dquots;
17941803
struct dquot *dquot;
17951804
int cnt, index;
17961805

@@ -1832,7 +1841,7 @@ EXPORT_SYMBOL(dquot_claim_space_nodirty);
18321841
*/
18331842
void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number)
18341843
{
1835-
struct dquot **dquots;
1844+
struct dquot __rcu **dquots;
18361845
struct dquot *dquot;
18371846
int cnt, index;
18381847

@@ -1876,7 +1885,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
18761885
{
18771886
unsigned int cnt;
18781887
struct dquot_warn warn[MAXQUOTAS];
1879-
struct dquot **dquots;
1888+
struct dquot __rcu **dquots;
18801889
struct dquot *dquot;
18811890
int reserve = flags & DQUOT_SPACE_RESERVE, index;
18821891

@@ -1933,7 +1942,7 @@ void dquot_free_inode(struct inode *inode)
19331942
{
19341943
unsigned int cnt;
19351944
struct dquot_warn warn[MAXQUOTAS];
1936-
struct dquot * const *dquots;
1945+
struct dquot __rcu * const *dquots;
19371946
struct dquot *dquot;
19381947
int index;
19391948

@@ -1980,6 +1989,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
19801989
qsize_t cur_space;
19811990
qsize_t rsv_space = 0;
19821991
qsize_t inode_usage = 1;
1992+
struct dquot __rcu **dquots;
19831993
struct dquot *transfer_from[MAXQUOTAS] = {};
19841994
int cnt, index, ret = 0;
19851995
char is_valid[MAXQUOTAS] = {};
@@ -2012,6 +2022,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
20122022
}
20132023
cur_space = __inode_get_bytes(inode);
20142024
rsv_space = __inode_get_rsv_space(inode);
2025+
dquots = i_dquot(inode);
20152026
/*
20162027
* Build the transfer_from list, check limits, and update usage in
20172028
* the target structures.
@@ -2026,7 +2037,8 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
20262037
if (!sb_has_quota_active(inode->i_sb, cnt))
20272038
continue;
20282039
is_valid[cnt] = 1;
2029-
transfer_from[cnt] = i_dquot(inode)[cnt];
2040+
transfer_from[cnt] = srcu_dereference_check(dquots[cnt],
2041+
&dquot_srcu, lockdep_is_held(&dq_data_lock));
20302042
ret = dquot_add_inodes(transfer_to[cnt], inode_usage,
20312043
&warn_to[cnt]);
20322044
if (ret)
@@ -2065,7 +2077,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
20652077
rsv_space);
20662078
spin_unlock(&transfer_from[cnt]->dq_dqb_lock);
20672079
}
2068-
i_dquot(inode)[cnt] = transfer_to[cnt];
2080+
rcu_assign_pointer(dquots[cnt], transfer_to[cnt]);
20692081
}
20702082
spin_unlock(&inode->i_lock);
20712083
spin_unlock(&dq_data_lock);
@@ -2076,8 +2088,8 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
20762088
* mark_all_dquot_dirty().
20772089
*/
20782090
index = srcu_read_lock(&dquot_srcu);
2079-
mark_all_dquot_dirty(transfer_from);
2080-
mark_all_dquot_dirty(transfer_to);
2091+
mark_all_dquot_dirty((struct dquot __rcu **)transfer_from);
2092+
mark_all_dquot_dirty((struct dquot __rcu **)transfer_to);
20812093
srcu_read_unlock(&dquot_srcu, index);
20822094

20832095
flush_warnings(warn_to);

0 commit comments

Comments
 (0)