Skip to content

Commit ae8ac6b

Browse files
committed
Merge branch 'quota_scaling' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull quota scaling updates from Jan Kara: "This contains changes to make the quota subsystem more scalable. Reportedly it improves number of files created per second on ext4 filesystem on fast storage by about a factor of 2x" * 'quota_scaling' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: (28 commits) quota: Add lock annotations to struct members quota: Reduce contention on dq_data_lock fs: Provide __inode_get_bytes() quota: Inline dquot_[re]claim_reserved_space() into callsite quota: Inline inode_{incr,decr}_space() into callsites quota: Inline functions into their callsites ext4: Disable dirty list tracking of dquots when journalling quotas quota: Allow disabling tracking of dirty dquots in a list quota: Remove dq_wait_unused from dquot quota: Move locking into clear_dquot_dirty() quota: Do not dirty bad dquots quota: Fix possible corruption of dqi_flags quota: Propagate ->quota_read errors from v2_read_file_info() quota: Fix error codes in v2_read_file_info() quota: Push dqio_sem down to ->read_file_info() quota: Push dqio_sem down to ->write_file_info() quota: Push dqio_sem down to ->get_next_id() quota: Push dqio_sem down to ->release_dqblk() quota: Remove locking for writing to the old quota format quota: Do not acquire dqio_sem for dquot overwrites in v2 format ...
2 parents 460352c + 6c83fd5 commit ae8ac6b

File tree

12 files changed

+413
-330
lines changed

12 files changed

+413
-330
lines changed

fs/ext4/super.c

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5215,7 +5215,7 @@ static int ext4_statfs_project(struct super_block *sb,
52155215
dquot = dqget(sb, qid);
52165216
if (IS_ERR(dquot))
52175217
return PTR_ERR(dquot);
5218-
spin_lock(&dq_data_lock);
5218+
spin_lock(&dquot->dq_dqb_lock);
52195219

52205220
limit = (dquot->dq_dqb.dqb_bsoftlimit ?
52215221
dquot->dq_dqb.dqb_bsoftlimit :
@@ -5238,7 +5238,7 @@ static int ext4_statfs_project(struct super_block *sb,
52385238
(buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0;
52395239
}
52405240

5241-
spin_unlock(&dq_data_lock);
5241+
spin_unlock(&dquot->dq_dqb_lock);
52425242
dqput(dquot);
52435243
return 0;
52445244
}
@@ -5284,18 +5284,13 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
52845284
return 0;
52855285
}
52865286

5287-
/* Helper function for writing quotas on sync - we need to start transaction
5288-
* before quota file is locked for write. Otherwise the are possible deadlocks:
5289-
* Process 1 Process 2
5290-
* ext4_create() quota_sync()
5291-
* jbd2_journal_start() write_dquot()
5292-
* dquot_initialize() down(dqio_mutex)
5293-
* down(dqio_mutex) jbd2_journal_start()
5294-
*
5295-
*/
52965287

52975288
#ifdef CONFIG_QUOTA
52985289

5290+
/*
5291+
* Helper functions so that transaction is started before we acquire dqio_sem
5292+
* to keep correct lock ordering of transaction > dqio_sem
5293+
*/
52995294
static inline struct inode *dquot_to_inode(struct dquot *dquot)
53005295
{
53015296
return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type];
@@ -5430,6 +5425,13 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
54305425
ext4_msg(sb, KERN_WARNING,
54315426
"Quota file not on filesystem root. "
54325427
"Journaled quota will not work");
5428+
sb_dqopt(sb)->flags |= DQUOT_NOLIST_DIRTY;
5429+
} else {
5430+
/*
5431+
* Clear the flag just in case mount options changed since
5432+
* last time.
5433+
*/
5434+
sb_dqopt(sb)->flags &= ~DQUOT_NOLIST_DIRTY;
54335435
}
54345436

54355437
/*
@@ -5526,7 +5528,7 @@ static int ext4_enable_quotas(struct super_block *sb)
55265528
test_opt(sb, PRJQUOTA),
55275529
};
55285530

5529-
sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
5531+
sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NOLIST_DIRTY;
55305532
for (type = 0; type < EXT4_MAXQUOTAS; type++) {
55315533
if (qf_inums[type]) {
55325534
err = ext4_quota_enable(sb, type, QFMT_VFS_V1,

fs/ocfs2/quota_global.c

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
* Locking of quotas with OCFS2 is rather complex. Here are rules that
3434
* should be obeyed by all the functions:
3535
* - any write of quota structure (either to local or global file) is protected
36-
* by dqio_mutex or dquot->dq_lock.
36+
* by dqio_sem or dquot->dq_lock.
3737
* - any modification of global quota file holds inode cluster lock, i_mutex,
3838
* and ip_alloc_sem of the global quota file (achieved by
3939
* ocfs2_lock_global_qf). It also has to hold qinfo_lock.
@@ -42,9 +42,9 @@
4242
*
4343
* A rough sketch of locking dependencies (lf = local file, gf = global file):
4444
* Normal filesystem operation:
45-
* start_trans -> dqio_mutex -> write to lf
45+
* start_trans -> dqio_sem -> write to lf
4646
* Syncing of local and global file:
47-
* ocfs2_lock_global_qf -> start_trans -> dqio_mutex -> qinfo_lock ->
47+
* ocfs2_lock_global_qf -> start_trans -> dqio_sem -> qinfo_lock ->
4848
* write to gf
4949
* -> write to lf
5050
* Acquire dquot for the first time:
@@ -60,7 +60,7 @@
6060
* Recovery:
6161
* inode cluster lock of recovered lf
6262
* -> read bitmaps -> ip_alloc_sem of lf
63-
* -> ocfs2_lock_global_qf -> start_trans -> dqio_mutex -> qinfo_lock ->
63+
* -> ocfs2_lock_global_qf -> start_trans -> dqio_sem -> qinfo_lock ->
6464
* write to gf
6565
*/
6666

@@ -443,13 +443,17 @@ static int __ocfs2_global_write_info(struct super_block *sb, int type)
443443
int ocfs2_global_write_info(struct super_block *sb, int type)
444444
{
445445
int err;
446-
struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
446+
struct quota_info *dqopt = sb_dqopt(sb);
447+
struct ocfs2_mem_dqinfo *info = dqopt->info[type].dqi_priv;
447448

449+
down_write(&dqopt->dqio_sem);
448450
err = ocfs2_qinfo_lock(info, 1);
449451
if (err < 0)
450-
return err;
452+
goto out_sem;
451453
err = __ocfs2_global_write_info(sb, type);
452454
ocfs2_qinfo_unlock(info, 1);
455+
out_sem:
456+
up_write(&dqopt->dqio_sem);
453457
return err;
454458
}
455459

@@ -500,7 +504,7 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
500504
/* Update space and inode usage. Get also other information from
501505
* global quota file so that we don't overwrite any changes there.
502506
* We are */
503-
spin_lock(&dq_data_lock);
507+
spin_lock(&dquot->dq_dqb_lock);
504508
spacechange = dquot->dq_dqb.dqb_curspace -
505509
OCFS2_DQUOT(dquot)->dq_origspace;
506510
inodechange = dquot->dq_dqb.dqb_curinodes -
@@ -556,7 +560,7 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
556560
__clear_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags);
557561
OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
558562
OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
559-
spin_unlock(&dq_data_lock);
563+
spin_unlock(&dquot->dq_dqb_lock);
560564
err = ocfs2_qinfo_lock(info, freeing);
561565
if (err < 0) {
562566
mlog(ML_ERROR, "Failed to lock quota info, losing quota write"
@@ -611,15 +615,15 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
611615
mlog_errno(status);
612616
goto out_ilock;
613617
}
614-
mutex_lock(&sb_dqopt(sb)->dqio_mutex);
618+
down_write(&sb_dqopt(sb)->dqio_sem);
615619
status = ocfs2_sync_dquot(dquot);
616620
if (status < 0)
617621
mlog_errno(status);
618622
/* We have to write local structure as well... */
619623
status = ocfs2_local_write_dquot(dquot);
620624
if (status < 0)
621625
mlog_errno(status);
622-
mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
626+
up_write(&sb_dqopt(sb)->dqio_sem);
623627
ocfs2_commit_trans(osb, handle);
624628
out_ilock:
625629
ocfs2_unlock_global_qf(oinfo, 1);
@@ -666,9 +670,9 @@ static int ocfs2_write_dquot(struct dquot *dquot)
666670
mlog_errno(status);
667671
goto out;
668672
}
669-
mutex_lock(&sb_dqopt(dquot->dq_sb)->dqio_mutex);
673+
down_write(&sb_dqopt(dquot->dq_sb)->dqio_sem);
670674
status = ocfs2_local_write_dquot(dquot);
671-
mutex_unlock(&sb_dqopt(dquot->dq_sb)->dqio_mutex);
675+
up_write(&sb_dqopt(dquot->dq_sb)->dqio_sem);
672676
ocfs2_commit_trans(osb, handle);
673677
out:
674678
return status;
@@ -920,10 +924,10 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
920924

921925
/* In case user set some limits, sync dquot immediately to global
922926
* quota file so that information propagates quicker */
923-
spin_lock(&dq_data_lock);
927+
spin_lock(&dquot->dq_dqb_lock);
924928
if (dquot->dq_flags & mask)
925929
sync = 1;
926-
spin_unlock(&dq_data_lock);
930+
spin_unlock(&dquot->dq_dqb_lock);
927931
/* This is a slight hack but we can't afford getting global quota
928932
* lock if we already have a transaction started. */
929933
if (!sync || journal_current_handle()) {
@@ -939,7 +943,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
939943
mlog_errno(status);
940944
goto out_ilock;
941945
}
942-
mutex_lock(&sb_dqopt(sb)->dqio_mutex);
946+
down_write(&sb_dqopt(sb)->dqio_sem);
943947
status = ocfs2_sync_dquot(dquot);
944948
if (status < 0) {
945949
mlog_errno(status);
@@ -948,7 +952,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
948952
/* Now write updated local dquot structure */
949953
status = ocfs2_local_write_dquot(dquot);
950954
out_dlock:
951-
mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
955+
up_write(&sb_dqopt(sb)->dqio_sem);
952956
ocfs2_commit_trans(osb, handle);
953957
out_ilock:
954958
ocfs2_unlock_global_qf(oinfo, 1);

fs/ocfs2/quota_local.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -520,16 +520,16 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
520520
mlog_errno(status);
521521
goto out_drop_lock;
522522
}
523-
mutex_lock(&sb_dqopt(sb)->dqio_mutex);
524-
spin_lock(&dq_data_lock);
523+
down_write(&sb_dqopt(sb)->dqio_sem);
524+
spin_lock(&dquot->dq_dqb_lock);
525525
/* Add usage from quota entry into quota changes
526526
* of our node. Auxiliary variables are important
527527
* due to signedness */
528528
spacechange = le64_to_cpu(dqblk->dqb_spacemod);
529529
inodechange = le64_to_cpu(dqblk->dqb_inodemod);
530530
dquot->dq_dqb.dqb_curspace += spacechange;
531531
dquot->dq_dqb.dqb_curinodes += inodechange;
532-
spin_unlock(&dq_data_lock);
532+
spin_unlock(&dquot->dq_dqb_lock);
533533
/* We want to drop reference held by the crashed
534534
* node. Since we have our own reference we know
535535
* global structure actually won't be freed. */
@@ -553,7 +553,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
553553
unlock_buffer(qbh);
554554
ocfs2_journal_dirty(handle, qbh);
555555
out_commit:
556-
mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
556+
up_write(&sb_dqopt(sb)->dqio_sem);
557557
ocfs2_commit_trans(OCFS2_SB(sb), handle);
558558
out_drop_lock:
559559
ocfs2_unlock_global_qf(oinfo, 1);
@@ -691,9 +691,6 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
691691
struct ocfs2_quota_recovery *rec;
692692
int locked = 0;
693693

694-
/* We don't need the lock and we have to acquire quota file locks
695-
* which will later depend on this lock */
696-
mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
697694
info->dqi_max_spc_limit = 0x7fffffffffffffffLL;
698695
info->dqi_max_ino_limit = 0x7fffffffffffffffLL;
699696
oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS);
@@ -772,7 +769,6 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
772769
goto out_err;
773770
}
774771

775-
mutex_lock(&sb_dqopt(sb)->dqio_mutex);
776772
return 0;
777773
out_err:
778774
if (oinfo) {
@@ -786,7 +782,6 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
786782
kfree(oinfo);
787783
}
788784
brelse(bh);
789-
mutex_lock(&sb_dqopt(sb)->dqio_mutex);
790785
return -1;
791786
}
792787

@@ -882,12 +877,12 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
882877

883878
dqblk->dqb_id = cpu_to_le64(from_kqid(&init_user_ns,
884879
od->dq_dquot.dq_id));
885-
spin_lock(&dq_data_lock);
880+
spin_lock(&od->dq_dquot.dq_dqb_lock);
886881
dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
887882
od->dq_origspace);
888883
dqblk->dqb_inodemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curinodes -
889884
od->dq_originodes);
890-
spin_unlock(&dq_data_lock);
885+
spin_unlock(&od->dq_dquot.dq_dqb_lock);
891886
trace_olq_set_dquot(
892887
(unsigned long long)le64_to_cpu(dqblk->dqb_spacemod),
893888
(unsigned long long)le64_to_cpu(dqblk->dqb_inodemod),

0 commit comments

Comments
 (0)