Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

quota: Convert dqio_mutex to rwsem

Convert dqio_mutex to rwsem and call it dqio_sem. No functional changes
yet.

Signed-off-by: Jan Kara <jack@suse.cz>

Jan Kara bc8230ee aae4e7a8

+36 -41
+4 -9
fs/ext4/super.c
··· 5263 5263 return 0; 5264 5264 } 5265 5265 5266 - /* Helper function for writing quotas on sync - we need to start transaction 5267 - * before quota file is locked for write. Otherwise the are possible deadlocks: 5268 - * Process 1 Process 2 5269 - * ext4_create() quota_sync() 5270 - * jbd2_journal_start() write_dquot() 5271 - * dquot_initialize() down(dqio_mutex) 5272 - * down(dqio_mutex) jbd2_journal_start() 5273 - * 5274 - */ 5275 5266 5276 5267 #ifdef CONFIG_QUOTA 5277 5268 5269 + /* 5270 + * Helper functions so that transaction is started before we acquire dqio_sem 5271 + * to keep correct lock ordering of transaction > dqio_sem 5272 + */ 5278 5273 static inline struct inode *dquot_to_inode(struct dquot *dquot) 5279 5274 { 5280 5275 return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type];
+10 -10
fs/ocfs2/quota_global.c
··· 33 33 * Locking of quotas with OCFS2 is rather complex. Here are rules that 34 34 * should be obeyed by all the functions: 35 35 * - 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. 37 37 * - any modification of global quota file holds inode cluster lock, i_mutex, 38 38 * and ip_alloc_sem of the global quota file (achieved by 39 39 * ocfs2_lock_global_qf). It also has to hold qinfo_lock. ··· 42 42 * 43 43 * A rough sketch of locking dependencies (lf = local file, gf = global file): 44 44 * Normal filesystem operation: 45 - * start_trans -> dqio_mutex -> write to lf 45 + * start_trans -> dqio_sem -> write to lf 46 46 * 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 -> 48 48 * write to gf 49 49 * -> write to lf 50 50 * Acquire dquot for the first time: ··· 60 60 * Recovery: 61 61 * inode cluster lock of recovered lf 62 62 * -> 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 -> 64 64 * write to gf 65 65 */ 66 66 ··· 611 611 mlog_errno(status); 612 612 goto out_ilock; 613 613 } 614 - mutex_lock(&sb_dqopt(sb)->dqio_mutex); 614 + down_write(&sb_dqopt(sb)->dqio_sem); 615 615 status = ocfs2_sync_dquot(dquot); 616 616 if (status < 0) 617 617 mlog_errno(status); ··· 619 619 status = ocfs2_local_write_dquot(dquot); 620 620 if (status < 0) 621 621 mlog_errno(status); 622 - mutex_unlock(&sb_dqopt(sb)->dqio_mutex); 622 + up_write(&sb_dqopt(sb)->dqio_sem); 623 623 ocfs2_commit_trans(osb, handle); 624 624 out_ilock: 625 625 ocfs2_unlock_global_qf(oinfo, 1); ··· 666 666 mlog_errno(status); 667 667 goto out; 668 668 } 669 - mutex_lock(&sb_dqopt(dquot->dq_sb)->dqio_mutex); 669 + down_write(&sb_dqopt(dquot->dq_sb)->dqio_sem); 670 670 status = ocfs2_local_write_dquot(dquot); 671 - mutex_unlock(&sb_dqopt(dquot->dq_sb)->dqio_mutex); 671 + up_write(&sb_dqopt(dquot->dq_sb)->dqio_sem); 672 672 ocfs2_commit_trans(osb, handle); 673 673 out: 674 674 return status; ··· 939 939 mlog_errno(status); 940 940 goto out_ilock; 941 941 } 942 - mutex_lock(&sb_dqopt(sb)->dqio_mutex); 942 + down_write(&sb_dqopt(sb)->dqio_sem); 943 943 status = ocfs2_sync_dquot(dquot); 944 944 if (status < 0) { 945 945 mlog_errno(status); ··· 948 948 /* Now write updated local dquot structure */ 949 949 status = ocfs2_local_write_dquot(dquot); 950 950 out_dlock: 951 - mutex_unlock(&sb_dqopt(sb)->dqio_mutex); 951 + up_write(&sb_dqopt(sb)->dqio_sem); 952 952 ocfs2_commit_trans(osb, handle); 953 953 out_ilock: 954 954 ocfs2_unlock_global_qf(oinfo, 1);
+5 -5
fs/ocfs2/quota_local.c
··· 520 520 mlog_errno(status); 521 521 goto out_drop_lock; 522 522 } 523 - mutex_lock(&sb_dqopt(sb)->dqio_mutex); 523 + down_write(&sb_dqopt(sb)->dqio_sem); 524 524 spin_lock(&dq_data_lock); 525 525 /* Add usage from quota entry into quota changes 526 526 * of our node. Auxiliary variables are important ··· 553 553 unlock_buffer(qbh); 554 554 ocfs2_journal_dirty(handle, qbh); 555 555 out_commit: 556 - mutex_unlock(&sb_dqopt(sb)->dqio_mutex); 556 + up_write(&sb_dqopt(sb)->dqio_sem); 557 557 ocfs2_commit_trans(OCFS2_SB(sb), handle); 558 558 out_drop_lock: 559 559 ocfs2_unlock_global_qf(oinfo, 1); ··· 693 693 694 694 /* We don't need the lock and we have to acquire quota file locks 695 695 * which will later depend on this lock */ 696 - mutex_unlock(&sb_dqopt(sb)->dqio_mutex); 696 + up_write(&sb_dqopt(sb)->dqio_sem); 697 697 info->dqi_max_spc_limit = 0x7fffffffffffffffLL; 698 698 info->dqi_max_ino_limit = 0x7fffffffffffffffLL; 699 699 oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS); ··· 772 772 goto out_err; 773 773 } 774 774 775 - mutex_lock(&sb_dqopt(sb)->dqio_mutex); 775 + down_write(&sb_dqopt(sb)->dqio_sem); 776 776 return 0; 777 777 out_err: 778 778 if (oinfo) { ··· 786 786 kfree(oinfo); 787 787 } 788 788 brelse(bh); 789 - mutex_lock(&sb_dqopt(sb)->dqio_mutex); 789 + down_write(&sb_dqopt(sb)->dqio_sem); 790 790 return -1; 791 791 } 792 792
+14 -14
fs/quota/dquot.c
··· 120 120 * spinlock to internal buffers before writing. 121 121 * 122 122 * Lock ordering (including related VFS locks) is the following: 123 - * s_umount > i_mutex > journal_lock > dquot->dq_lock > dqio_mutex 123 + * s_umount > i_mutex > journal_lock > dquot->dq_lock > dqio_sem 124 124 */ 125 125 126 126 static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_list_lock); ··· 406 406 struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); 407 407 408 408 mutex_lock(&dquot->dq_lock); 409 - mutex_lock(&dqopt->dqio_mutex); 409 + down_write(&dqopt->dqio_sem); 410 410 if (!test_bit(DQ_READ_B, &dquot->dq_flags)) 411 411 ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot); 412 412 if (ret < 0) ··· 436 436 smp_mb__before_atomic(); 437 437 set_bit(DQ_ACTIVE_B, &dquot->dq_flags); 438 438 out_iolock: 439 - mutex_unlock(&dqopt->dqio_mutex); 439 + up_write(&dqopt->dqio_sem); 440 440 mutex_unlock(&dquot->dq_lock); 441 441 return ret; 442 442 } ··· 450 450 int ret = 0; 451 451 struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); 452 452 453 - mutex_lock(&dqopt->dqio_mutex); 453 + down_write(&dqopt->dqio_sem); 454 454 spin_lock(&dq_list_lock); 455 455 if (!clear_dquot_dirty(dquot)) { 456 456 spin_unlock(&dq_list_lock); ··· 464 464 else 465 465 ret = -EIO; 466 466 out_sem: 467 - mutex_unlock(&dqopt->dqio_mutex); 467 + up_write(&dqopt->dqio_sem); 468 468 return ret; 469 469 } 470 470 EXPORT_SYMBOL(dquot_commit); ··· 481 481 /* Check whether we are not racing with some other dqget() */ 482 482 if (atomic_read(&dquot->dq_count) > 1) 483 483 goto out_dqlock; 484 - mutex_lock(&dqopt->dqio_mutex); 484 + down_write(&dqopt->dqio_sem); 485 485 if (dqopt->ops[dquot->dq_id.type]->release_dqblk) { 486 486 ret = dqopt->ops[dquot->dq_id.type]->release_dqblk(dquot); 487 487 /* Write the info */ ··· 493 493 ret = ret2; 494 494 } 495 495 clear_bit(DQ_ACTIVE_B, &dquot->dq_flags); 496 - mutex_unlock(&dqopt->dqio_mutex); 496 + up_write(&dqopt->dqio_sem); 497 497 out_dqlock: 498 498 mutex_unlock(&dquot->dq_lock); 499 499 return ret; ··· 2060 2060 int ret; 2061 2061 struct quota_info *dqopt = sb_dqopt(sb); 2062 2062 2063 - mutex_lock(&dqopt->dqio_mutex); 2063 + down_write(&dqopt->dqio_sem); 2064 2064 ret = dqopt->ops[type]->write_file_info(sb, type); 2065 - mutex_unlock(&dqopt->dqio_mutex); 2065 + up_write(&dqopt->dqio_sem); 2066 2066 return ret; 2067 2067 } 2068 2068 EXPORT_SYMBOL(dquot_commit_info); ··· 2076 2076 return -ESRCH; 2077 2077 if (!dqopt->ops[qid->type]->get_next_id) 2078 2078 return -ENOSYS; 2079 - mutex_lock(&dqopt->dqio_mutex); 2079 + down_write(&dqopt->dqio_sem); 2080 2080 err = dqopt->ops[qid->type]->get_next_id(sb, qid); 2081 - mutex_unlock(&dqopt->dqio_mutex); 2081 + up_write(&dqopt->dqio_sem); 2082 2082 return err; 2083 2083 } 2084 2084 EXPORT_SYMBOL(dquot_get_next_id); ··· 2328 2328 dqopt->info[type].dqi_format = fmt; 2329 2329 dqopt->info[type].dqi_fmt_id = format_id; 2330 2330 INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list); 2331 - mutex_lock(&dqopt->dqio_mutex); 2331 + down_write(&dqopt->dqio_sem); 2332 2332 error = dqopt->ops[type]->read_file_info(sb, type); 2333 2333 if (error < 0) { 2334 - mutex_unlock(&dqopt->dqio_mutex); 2334 + up_write(&dqopt->dqio_sem); 2335 2335 goto out_file_init; 2336 2336 } 2337 2337 if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) 2338 2338 dqopt->info[type].dqi_flags |= DQF_SYS_FILE; 2339 - mutex_unlock(&dqopt->dqio_mutex); 2339 + up_write(&dqopt->dqio_sem); 2340 2340 spin_lock(&dq_state_lock); 2341 2341 dqopt->flags |= dquot_state_flag(flags, type); 2342 2342 spin_unlock(&dq_state_lock);
+1 -1
fs/quota/quota_tree.c
··· 379 379 if (!ddquot) 380 380 return -ENOMEM; 381 381 382 - /* dq_off is guarded by dqio_mutex */ 382 + /* dq_off is guarded by dqio_sem */ 383 383 if (!dquot->dq_off) { 384 384 ret = dq_insert_tree(info, dquot); 385 385 if (ret < 0) {
+1 -1
fs/super.c
··· 242 242 atomic_set(&s->s_active, 1); 243 243 mutex_init(&s->s_vfs_rename_mutex); 244 244 lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key); 245 - mutex_init(&s->s_dquot.dqio_mutex); 245 + init_rwsem(&s->s_dquot.dqio_sem); 246 246 s->s_maxbytes = MAX_NON_LFS; 247 247 s->s_op = &default_op; 248 248 s->s_time_gran = 1000000000;
+1 -1
include/linux/quota.h
··· 521 521 522 522 struct quota_info { 523 523 unsigned int flags; /* Flags for diskquotas on this device */ 524 - struct mutex dqio_mutex; /* lock device while I/O in progress */ 524 + struct rw_semaphore dqio_sem; /* Lock quota file while I/O in progress */ 525 525 struct inode *files[MAXQUOTAS]; /* inodes of quotafiles */ 526 526 struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ 527 527 const struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */