summaryrefslogtreecommitdiff
path: root/fs/quota/dquot.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/quota/dquot.c')
-rw-r--r--fs/quota/dquot.c53
1 files changed, 29 insertions, 24 deletions
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index b40410cd39af..1d5d08787cce 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -1020,14 +1020,19 @@ static int dqinit_needed(struct inode *inode, int type)
/* This routine is guarded by s_umount semaphore */
static int add_dquot_ref(struct super_block *sb, int type)
{
- struct inode *inode, *old_inode = NULL;
+ void **i;
+ struct genradix_iter iter;
#ifdef CONFIG_QUOTA_DEBUG
int reserved = 0;
#endif
int err = 0;
- spin_lock(&sb->s_inode_list_lock);
- list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
+ rcu_read_lock();
+ genradix_for_each(&sb->s_inodes.items, iter, i) {
+ struct inode *inode = *((struct inode **) i);
+ if (!inode)
+ continue;
+
spin_lock(&inode->i_lock);
if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
!atomic_read(&inode->i_writecount) ||
@@ -1037,33 +1042,21 @@ static int add_dquot_ref(struct super_block *sb, int type)
}
__iget(inode);
spin_unlock(&inode->i_lock);
- spin_unlock(&sb->s_inode_list_lock);
+ rcu_read_unlock();
#ifdef CONFIG_QUOTA_DEBUG
if (unlikely(inode_get_rsv_space(inode) > 0))
reserved = 1;
#endif
- iput(old_inode);
err = __dquot_initialize(inode, type);
- if (err) {
- iput(inode);
+ iput(inode);
+ if (err)
goto out;
- }
- /*
- * We hold a reference to 'inode' so it couldn't have been
- * removed from s_inodes list while we dropped the
- * s_inode_list_lock. We cannot iput the inode now as we can be
- * holding the last reference and we cannot iput it under
- * s_inode_list_lock. So we keep the reference and iput it
- * later.
- */
- old_inode = inode;
cond_resched();
- spin_lock(&sb->s_inode_list_lock);
+ rcu_read_lock();
}
- spin_unlock(&sb->s_inode_list_lock);
- iput(old_inode);
+ rcu_read_unlock();
out:
#ifdef CONFIG_QUOTA_DEBUG
if (reserved) {
@@ -1077,13 +1070,25 @@ out:
static void remove_dquot_ref(struct super_block *sb, int type)
{
- struct inode *inode;
+ struct genradix_iter iter;
+ void **i;
#ifdef CONFIG_QUOTA_DEBUG
int reserved = 0;
#endif
- spin_lock(&sb->s_inode_list_lock);
- list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
+ rcu_read_lock();
+ genradix_for_each(&sb->s_inodes.items, iter, i) {
+ struct inode *inode = *((struct inode **) i);
+ if (!inode)
+ continue;
+
+ spin_lock(&inode->i_lock);
+ bool on_list = inode->i_sb_list_idx != 0;
+ spin_unlock(&inode->i_lock);
+
+ if (!on_list)
+ continue;
+
/*
* We have to scan also I_NEW inodes because they can already
* have quota pointer initialized. Luckily, we need to touch
@@ -1107,7 +1112,7 @@ static void remove_dquot_ref(struct super_block *sb, int type)
}
spin_unlock(&dq_data_lock);
}
- spin_unlock(&sb->s_inode_list_lock);
+ rcu_read_unlock();
#ifdef CONFIG_QUOTA_DEBUG
if (reserved) {
printk(KERN_WARNING "VFS (%s): Writes happened after quota"