#include <linux/proc_fs.h>
#include <linux/security.h>
#include <linux/kmod.h>
+#include <linux/pagemap.h>
#include <asm/uaccess.h>
int dquot_acquire(struct dquot *dquot)
{
- int ret = 0;
+ int ret = 0, ret2 = 0;
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
down(&dquot->dq_lock);
/* Instantiate dquot if needed */
if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) {
ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+ /* Write the info if needed */
+ if (info_dirty(&dqopt->info[dquot->dq_type]))
+ ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type);
if (ret < 0)
goto out_iolock;
+ if (ret2 < 0) {
+ ret = ret2;
+ goto out_iolock;
+ }
}
set_bit(DQ_ACTIVE_B, &dquot->dq_flags);
out_iolock:
*/
int dquot_commit(struct dquot *dquot)
{
- int ret = 0;
+ int ret = 0, ret2 = 0;
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
down(&dqopt->dqio_sem);
spin_unlock(&dq_list_lock);
/* Inactive dquot can be only if there was error during read/init
* => we have better not writing it */
- if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
+ if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+ if (info_dirty(&dqopt->info[dquot->dq_type]))
+ ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type);
+ if (ret >= 0)
+ ret = ret2;
+ }
out_sem:
up(&dqopt->dqio_sem);
- if (info_dirty(&dqopt->info[dquot->dq_type]))
- dquot->dq_sb->dq_op->write_info(dquot->dq_sb, dquot->dq_type);
return ret;
}
*/
int dquot_release(struct dquot *dquot)
{
- int ret = 0;
+ int ret = 0, ret2 = 0;
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
down(&dquot->dq_lock);
if (atomic_read(&dquot->dq_count) > 1)
goto out_dqlock;
down(&dqopt->dqio_sem);
- ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
+ if (dqopt->ops[dquot->dq_type]->release_dqblk) {
+ ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot);
+ /* Write the info */
+ if (info_dirty(&dqopt->info[dquot->dq_type]))
+ ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type);
+ if (ret >= 0)
+ ret = ret2;
+ }
clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
up(&dqopt->dqio_sem);
out_dqlock:
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);
{
struct dquot *dquot;
- dquot = kmem_cache_alloc(dquot_cachep, SLAB_KERNEL);
+ dquot = kmem_cache_alloc(dquot_cachep, SLAB_NOFS);
if(!dquot)
return NODQUOT;
* 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;
}
if (transfer_to[cnt] == NODQUOT)
continue;
- dquot_decr_inodes(transfer_from[cnt], 1);
- dquot_decr_space(transfer_from[cnt], space);
+ /* Due to IO error we might not have transfer_from[] structure */
+ if (transfer_from[cnt]) {
+ dquot_decr_inodes(transfer_from[cnt], 1);
+ dquot_decr_space(transfer_from[cnt], space);
+ }
dquot_incr_inodes(transfer_to[cnt], 1);
dquot_incr_space(transfer_to[cnt], space);
.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
};
error = -EINVAL;
if (!fmt->qf_ops->check_quota_file(sb, type))
goto out_file_init;
- /* We don't want quota and atime on quota files (deadlocks possible) */
+ /* We don't want quota and atime on quota files (deadlocks possible)
+ * We also need to set GFP mask differently because we cannot recurse
+ * into filesystem when allocating page for quota inode */
down_write(&dqopt->dqptr_sem);
inode->i_flags |= S_NOQUOTA | S_NOATIME;
+
+ /*
+ * We write to quota files deep within filesystem code. We don't want
+ * the VFS to reenter filesystem code when it tries to allocate a
+ * pagecache page for the quota file write. So clear __GFP_FS in
+ * the quota file's allocation flags.
+ */
+ mapping_set_gfp_mask(inode->i_mapping,
+ mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
+
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
to_drop[cnt] = inode->i_dquot[cnt];
inode->i_dquot[cnt] = NODQUOT;
dquot_cachep = kmem_cache_create("dquot",
sizeof(struct dquot), sizeof(unsigned long) * 4,
- SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, NULL, NULL);
- if (!dquot_cachep)
- panic("Cannot create dquot SLAB cache");
+ SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_PANIC,
+ NULL, NULL);
order = 0;
dquot_hash = (struct hlist_head *)__get_free_pages(GFP_ATOMIC, order);
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);