Skip to content

Commit 7bce48f

Browse files
LiBaokun96jankara
authored andcommitted
quota: simplify drop_dquot_ref()
As Honza said, remove_inode_dquot_ref() currently does not release the last dquot reference but instead adds the dquot to tofree_head list. This is because dqput() can sleep while dropping of the last dquot reference (writing back the dquot and calling ->release_dquot()) and that must not happen under dq_list_lock. Now that dqput() queues the final dquot cleanup into a workqueue, remove_inode_dquot_ref() can call dqput() unconditionally and we can significantly simplify it. Here we open code the simplified code of remove_inode_dquot_ref() into remove_dquot_ref() and remove the function put_dquot_list() which is no longer used. Signed-off-by: Baokun Li <libaokun1@huawei.com> Signed-off-by: Jan Kara <jack@suse.cz> Message-Id: <20230630110822.3881712-6-libaokun1@huawei.com>
1 parent dabc8b2 commit 7bce48f

1 file changed

Lines changed: 9 additions & 61 deletions

File tree

fs/quota/dquot.c

Lines changed: 9 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,59 +1072,7 @@ static int add_dquot_ref(struct super_block *sb, int type)
10721072
return err;
10731073
}
10741074

1075-
/*
1076-
* Remove references to dquots from inode and add dquot to list for freeing
1077-
* if we have the last reference to dquot
1078-
*/
1079-
static void remove_inode_dquot_ref(struct inode *inode, int type,
1080-
struct list_head *tofree_head)
1081-
{
1082-
struct dquot **dquots = i_dquot(inode);
1083-
struct dquot *dquot = dquots[type];
1084-
1085-
if (!dquot)
1086-
return;
1087-
1088-
dquots[type] = NULL;
1089-
if (list_empty(&dquot->dq_free)) {
1090-
/*
1091-
* The inode still has reference to dquot so it can't be in the
1092-
* free list
1093-
*/
1094-
spin_lock(&dq_list_lock);
1095-
list_add(&dquot->dq_free, tofree_head);
1096-
spin_unlock(&dq_list_lock);
1097-
} else {
1098-
/*
1099-
* Dquot is already in a list to put so we won't drop the last
1100-
* reference here.
1101-
*/
1102-
dqput(dquot);
1103-
}
1104-
}
1105-
1106-
/*
1107-
* Free list of dquots
1108-
* Dquots are removed from inodes and no new references can be got so we are
1109-
* the only ones holding reference
1110-
*/
1111-
static void put_dquot_list(struct list_head *tofree_head)
1112-
{
1113-
struct list_head *act_head;
1114-
struct dquot *dquot;
1115-
1116-
act_head = tofree_head->next;
1117-
while (act_head != tofree_head) {
1118-
dquot = list_entry(act_head, struct dquot, dq_free);
1119-
act_head = act_head->next;
1120-
/* Remove dquot from the list so we won't have problems... */
1121-
list_del_init(&dquot->dq_free);
1122-
dqput(dquot);
1123-
}
1124-
}
1125-
1126-
static void remove_dquot_ref(struct super_block *sb, int type,
1127-
struct list_head *tofree_head)
1075+
static void remove_dquot_ref(struct super_block *sb, int type)
11281076
{
11291077
struct inode *inode;
11301078
#ifdef CONFIG_QUOTA_DEBUG
@@ -1141,11 +1089,16 @@ static void remove_dquot_ref(struct super_block *sb, int type,
11411089
*/
11421090
spin_lock(&dq_data_lock);
11431091
if (!IS_NOQUOTA(inode)) {
1092+
struct dquot **dquots = i_dquot(inode);
1093+
struct dquot *dquot = dquots[type];
1094+
11441095
#ifdef CONFIG_QUOTA_DEBUG
11451096
if (unlikely(inode_get_rsv_space(inode) > 0))
11461097
reserved = 1;
11471098
#endif
1148-
remove_inode_dquot_ref(inode, type, tofree_head);
1099+
dquots[type] = NULL;
1100+
if (dquot)
1101+
dqput(dquot);
11491102
}
11501103
spin_unlock(&dq_data_lock);
11511104
}
@@ -1162,13 +1115,8 @@ static void remove_dquot_ref(struct super_block *sb, int type,
11621115
/* Gather all references from inodes and drop them */
11631116
static void drop_dquot_ref(struct super_block *sb, int type)
11641117
{
1165-
LIST_HEAD(tofree_head);
1166-
1167-
if (sb->dq_op) {
1168-
remove_dquot_ref(sb, type, &tofree_head);
1169-
synchronize_srcu(&dquot_srcu);
1170-
put_dquot_list(&tofree_head);
1171-
}
1118+
if (sb->dq_op)
1119+
remove_dquot_ref(sb, type);
11721120
}
11731121

11741122
static inline

0 commit comments

Comments
 (0)