From: Jan Kara Attached patch should fix reported deadlock in journalled quota code. quotactl() call was violating the locking rules and didn't start transaction when it should. From: Found a couple of symbols not exported that were needed by the ext3.ko module. --- 25-akpm/fs/dquot.c | 8 ++++++-- 25-akpm/fs/ext3/super.c | 36 ++++++++++++++++++++++++++++++++++++ 25-akpm/include/linux/quota.h | 2 ++ 3 files changed, 44 insertions(+), 2 deletions(-) diff -puN fs/dquot.c~fix-deadlock-in-journalled-quota fs/dquot.c --- 25/fs/dquot.c~fix-deadlock-in-journalled-quota 2004-05-09 21:37:23.960044368 -0700 +++ 25-akpm/fs/dquot.c 2004-05-09 21:37:27.452513432 -0700 @@ -529,7 +529,7 @@ we_slept: clear_dquot_dirty(dquot); if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { spin_unlock(&dq_list_lock); - dquot_release(dquot); + dquot->dq_sb->dq_op->release_dquot(dquot); goto we_slept; } atomic_dec(&dquot->dq_count); @@ -605,7 +605,7 @@ we_slept: * finished or it will be canceled due to dq_count > 1 test */ wait_on_dquot(dquot); /* Read the dquot and instantiate it (everything done only if needed) */ - if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && dquot_acquire(dquot) < 0) { + if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && sb->dq_op->acquire_dquot(dquot) < 0) { dqput(dquot); return NODQUOT; } @@ -1259,6 +1259,8 @@ struct dquot_operations dquot_operations .free_inode = dquot_free_inode, .transfer = dquot_transfer, .write_dquot = dquot_commit, + .acquire_dquot = dquot_acquire, + .release_dquot = dquot_release, .mark_dirty = dquot_mark_dquot_dirty, .write_info = dquot_commit_info }; @@ -1759,6 +1761,8 @@ EXPORT_SYMBOL(vfs_get_dqblk); EXPORT_SYMBOL(vfs_set_dqblk); EXPORT_SYMBOL(dquot_commit); EXPORT_SYMBOL(dquot_commit_info); +EXPORT_SYMBOL(dquot_acquire); +EXPORT_SYMBOL(dquot_release); EXPORT_SYMBOL(dquot_mark_dquot_dirty); EXPORT_SYMBOL(dquot_initialize); EXPORT_SYMBOL(dquot_drop); diff -puN fs/ext3/super.c~fix-deadlock-in-journalled-quota fs/ext3/super.c --- 25/fs/ext3/super.c~fix-deadlock-in-journalled-quota 2004-05-09 21:37:23.962044064 -0700 +++ 25-akpm/fs/ext3/super.c 2004-05-09 21:37:23.970042848 -0700 @@ -521,6 +521,8 @@ static void ext3_clear_inode(struct inod static int ext3_dquot_initialize(struct inode *inode, int type); static int ext3_dquot_drop(struct inode *inode); static int ext3_write_dquot(struct dquot *dquot); +static int ext3_acquire_dquot(struct dquot *dquot); +static int ext3_release_dquot(struct dquot *dquot); static int ext3_mark_dquot_dirty(struct dquot *dquot); static int ext3_write_info(struct super_block *sb, int type); static int ext3_quota_on(struct super_block *sb, int type, int format_id, char *path); @@ -536,6 +538,8 @@ static struct dquot_operations ext3_quot .free_inode = dquot_free_inode, .transfer = dquot_transfer, .write_dquot = ext3_write_dquot, + .acquire_dquot = ext3_acquire_dquot, + .release_dquot = ext3_release_dquot, .mark_dirty = ext3_mark_dquot_dirty, .write_info = ext3_write_info }; @@ -2181,6 +2185,38 @@ static int ext3_write_dquot(struct dquot return ret; } +static int ext3_acquire_dquot(struct dquot *dquot) +{ + int ret, err; + handle_t *handle; + + handle = ext3_journal_start(dquot_to_inode(dquot), + EXT3_QUOTA_INIT_BLOCKS); + if (IS_ERR(handle)) + return PTR_ERR(handle); + ret = dquot_acquire(dquot); + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; +} + +static int ext3_release_dquot(struct dquot *dquot) +{ + int ret, err; + handle_t *handle; + + handle = ext3_journal_start(dquot_to_inode(dquot), + EXT3_QUOTA_INIT_BLOCKS); + if (IS_ERR(handle)) + return PTR_ERR(handle); + ret = dquot_release(dquot); + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; +} + static int ext3_mark_dquot_dirty(struct dquot *dquot) { /* Are we journalling quotas? */ diff -puN include/linux/quota.h~fix-deadlock-in-journalled-quota include/linux/quota.h --- 25/include/linux/quota.h~fix-deadlock-in-journalled-quota 2004-05-09 21:37:23.963043912 -0700 +++ 25-akpm/include/linux/quota.h 2004-05-09 21:37:23.971042696 -0700 @@ -250,6 +250,8 @@ struct dquot_operations { int (*free_inode) (const struct inode *, unsigned long); int (*transfer) (struct inode *, struct iattr *); int (*write_dquot) (struct dquot *); /* Ordinary dquot write */ + int (*acquire_dquot) (struct dquot *); /* Quota is going to be created on disk */ + int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */ int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */ int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */ }; _