Skip to content

Commit 4016448

Browse files
committed
Merge tag 'fs_for_v6.6-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull quota regression fix from Jan Kara. * tag 'fs_for_v6.6-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: quota: Fix slow quotaoff
2 parents 759d1b6 + 869b6ea commit 4016448

File tree

3 files changed

+43
-29
lines changed

3 files changed

+43
-29
lines changed

fs/quota/dquot.c

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -233,19 +233,18 @@ static void put_quota_format(struct quota_format_type *fmt)
233233
* All dquots are placed to the end of inuse_list when first created, and this
234234
* list is used for invalidate operation, which must look at every dquot.
235235
*
236-
* When the last reference of a dquot will be dropped, the dquot will be
237-
* added to releasing_dquots. We'd then queue work item which would call
236+
* When the last reference of a dquot is dropped, the dquot is added to
237+
* releasing_dquots. We'll then queue work item which will call
238238
* synchronize_srcu() and after that perform the final cleanup of all the
239-
* dquots on the list. Both releasing_dquots and free_dquots use the
240-
* dq_free list_head in the dquot struct. When a dquot is removed from
241-
* releasing_dquots, a reference count is always subtracted, and if
242-
* dq_count == 0 at that point, the dquot will be added to the free_dquots.
239+
* dquots on the list. Each cleaned up dquot is moved to free_dquots list.
240+
* Both releasing_dquots and free_dquots use the dq_free list_head in the dquot
241+
* struct.
243242
*
244-
* Unused dquots (dq_count == 0) are added to the free_dquots list when freed,
245-
* and this list is searched whenever we need an available dquot. Dquots are
246-
* removed from the list as soon as they are used again, and
247-
* dqstats.free_dquots gives the number of dquots on the list. When
248-
* dquot is invalidated it's completely released from memory.
243+
* Unused and cleaned up dquots are in the free_dquots list and this list is
244+
* searched whenever we need an available dquot. Dquots are removed from the
245+
* list as soon as they are used again and dqstats.free_dquots gives the number
246+
* of dquots on the list. When dquot is invalidated it's completely released
247+
* from memory.
249248
*
250249
* Dirty dquots are added to the dqi_dirty_list of quota_info when mark
251250
* dirtied, and this list is searched when writing dirty dquots back to
@@ -321,15 +320,18 @@ static inline void put_dquot_last(struct dquot *dquot)
321320
static inline void put_releasing_dquots(struct dquot *dquot)
322321
{
323322
list_add_tail(&dquot->dq_free, &releasing_dquots);
323+
set_bit(DQ_RELEASING_B, &dquot->dq_flags);
324324
}
325325

326326
static inline void remove_free_dquot(struct dquot *dquot)
327327
{
328328
if (list_empty(&dquot->dq_free))
329329
return;
330330
list_del_init(&dquot->dq_free);
331-
if (!atomic_read(&dquot->dq_count))
331+
if (!test_bit(DQ_RELEASING_B, &dquot->dq_flags))
332332
dqstats_dec(DQST_FREE_DQUOTS);
333+
else
334+
clear_bit(DQ_RELEASING_B, &dquot->dq_flags);
333335
}
334336

335337
static inline void put_inuse(struct dquot *dquot)
@@ -581,12 +583,6 @@ static void invalidate_dquots(struct super_block *sb, int type)
581583
continue;
582584
/* Wait for dquot users */
583585
if (atomic_read(&dquot->dq_count)) {
584-
/* dquot in releasing_dquots, flush and retry */
585-
if (!list_empty(&dquot->dq_free)) {
586-
spin_unlock(&dq_list_lock);
587-
goto restart;
588-
}
589-
590586
atomic_inc(&dquot->dq_count);
591587
spin_unlock(&dq_list_lock);
592588
/*
@@ -605,6 +601,15 @@ static void invalidate_dquots(struct super_block *sb, int type)
605601
* restart. */
606602
goto restart;
607603
}
604+
/*
605+
* The last user already dropped its reference but dquot didn't
606+
* get fully cleaned up yet. Restart the scan which flushes the
607+
* work cleaning up released dquots.
608+
*/
609+
if (test_bit(DQ_RELEASING_B, &dquot->dq_flags)) {
610+
spin_unlock(&dq_list_lock);
611+
goto restart;
612+
}
608613
/*
609614
* Quota now has no users and it has been written on last
610615
* dqput()
@@ -696,6 +701,13 @@ int dquot_writeback_dquots(struct super_block *sb, int type)
696701
dq_dirty);
697702

698703
WARN_ON(!dquot_active(dquot));
704+
/* If the dquot is releasing we should not touch it */
705+
if (test_bit(DQ_RELEASING_B, &dquot->dq_flags)) {
706+
spin_unlock(&dq_list_lock);
707+
flush_delayed_work(&quota_release_work);
708+
spin_lock(&dq_list_lock);
709+
continue;
710+
}
699711

700712
/* Now we have active dquot from which someone is
701713
* holding reference so we can safely just increase
@@ -809,18 +821,18 @@ static void quota_release_workfn(struct work_struct *work)
809821
/* Exchange the list head to avoid livelock. */
810822
list_replace_init(&releasing_dquots, &rls_head);
811823
spin_unlock(&dq_list_lock);
824+
synchronize_srcu(&dquot_srcu);
812825

813826
restart:
814-
synchronize_srcu(&dquot_srcu);
815827
spin_lock(&dq_list_lock);
816828
while (!list_empty(&rls_head)) {
817829
dquot = list_first_entry(&rls_head, struct dquot, dq_free);
818-
/* Dquot got used again? */
819-
if (atomic_read(&dquot->dq_count) > 1) {
820-
remove_free_dquot(dquot);
821-
atomic_dec(&dquot->dq_count);
822-
continue;
823-
}
830+
WARN_ON_ONCE(atomic_read(&dquot->dq_count));
831+
/*
832+
* Note that DQ_RELEASING_B protects us from racing with
833+
* invalidate_dquots() calls so we are safe to work with the
834+
* dquot even after we drop dq_list_lock.
835+
*/
824836
if (dquot_dirty(dquot)) {
825837
spin_unlock(&dq_list_lock);
826838
/* Commit dquot before releasing */
@@ -834,7 +846,6 @@ static void quota_release_workfn(struct work_struct *work)
834846
}
835847
/* Dquot is inactive and clean, now move it to free list */
836848
remove_free_dquot(dquot);
837-
atomic_dec(&dquot->dq_count);
838849
put_dquot_last(dquot);
839850
}
840851
spin_unlock(&dq_list_lock);
@@ -875,6 +886,7 @@ void dqput(struct dquot *dquot)
875886
BUG_ON(!list_empty(&dquot->dq_free));
876887
#endif
877888
put_releasing_dquots(dquot);
889+
atomic_dec(&dquot->dq_count);
878890
spin_unlock(&dq_list_lock);
879891
queue_delayed_work(system_unbound_wq, &quota_release_work, 1);
880892
}
@@ -963,7 +975,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid)
963975
dqstats_inc(DQST_LOOKUPS);
964976
}
965977
/* Wait for dq_lock - after this we know that either dquot_release() is
966-
* already finished or it will be canceled due to dq_count > 1 test */
978+
* already finished or it will be canceled due to dq_count > 0 test */
967979
wait_on_dquot(dquot);
968980
/* Read the dquot / allocate space in quota file */
969981
if (!dquot_active(dquot)) {

include/linux/quota.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,9 @@ static inline void dqstats_dec(unsigned int type)
285285
#define DQ_FAKE_B 3 /* no limits only usage */
286286
#define DQ_READ_B 4 /* dquot was read into memory */
287287
#define DQ_ACTIVE_B 5 /* dquot is active (dquot_release not called) */
288-
#define DQ_LASTSET_B 6 /* Following 6 bits (see QIF_) are reserved\
288+
#define DQ_RELEASING_B 6 /* dquot is in releasing_dquots list waiting
289+
* to be cleaned up */
290+
#define DQ_LASTSET_B 7 /* Following 6 bits (see QIF_) are reserved\
289291
* for the mask of entries set via SETQUOTA\
290292
* quotactl. They are set under dq_data_lock\
291293
* and the quota format handling dquot can\

include/linux/quotaops.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static inline bool dquot_is_busy(struct dquot *dquot)
5757
{
5858
if (test_bit(DQ_MOD_B, &dquot->dq_flags))
5959
return true;
60-
if (atomic_read(&dquot->dq_count) > 1)
60+
if (atomic_read(&dquot->dq_count) > 0)
6161
return true;
6262
return false;
6363
}

0 commit comments

Comments
 (0)