diff options
Diffstat (limited to 'fs/quota/dquot.c')
| -rw-r--r-- | fs/quota/dquot.c | 20 | 
1 files changed, 15 insertions, 5 deletions
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 831d49a4111..7f30bdc57d1 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -528,7 +528,7 @@ restart:  		if (atomic_read(&dquot->dq_count)) {  			DEFINE_WAIT(wait); -			atomic_inc(&dquot->dq_count); +			dqgrab(dquot);  			prepare_to_wait(&dquot->dq_wait_unused, &wait,  					TASK_UNINTERRUPTIBLE);  			spin_unlock(&dq_list_lock); @@ -581,9 +581,17 @@ int dquot_scan_active(struct super_block *sb,  		dqstats_inc(DQST_LOOKUPS);  		dqput(old_dquot);  		old_dquot = dquot; -		ret = fn(dquot, priv); -		if (ret < 0) -			goto out; +		/* +		 * ->release_dquot() can be racing with us. Our reference +		 * protects us from new calls to it so just wait for any +		 * outstanding call and recheck the DQ_ACTIVE_B after that. +		 */ +		wait_on_dquot(dquot); +		if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { +			ret = fn(dquot, priv); +			if (ret < 0) +				goto out; +		}  		spin_lock(&dq_list_lock);  		/* We are safe to continue now because our dquot could not  		 * be moved out of the inuse list while we hold the reference */ @@ -624,7 +632,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type)  			/* Now we have active dquot from which someone is   			 * holding reference so we can safely just increase  			 * use count */ -			atomic_inc(&dquot->dq_count); +			dqgrab(dquot);  			spin_unlock(&dq_list_lock);  			dqstats_inc(DQST_LOOKUPS);  			err = sb->dq_op->write_dquot(dquot); @@ -694,6 +702,7 @@ dqcache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)  	struct dquot *dquot;  	unsigned long freed = 0; +	spin_lock(&dq_list_lock);  	head = free_dquots.prev;  	while (head != &free_dquots && sc->nr_to_scan) {  		dquot = list_entry(head, struct dquot, dq_free); @@ -705,6 +714,7 @@ dqcache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)  		freed++;  		head = free_dquots.prev;  	} +	spin_unlock(&dq_list_lock);  	return freed;  }  | 
