diff options
Diffstat (limited to 'fs/quota')
| -rw-r--r-- | fs/quota/Kconfig | 7 | ||||
| -rw-r--r-- | fs/quota/Makefile | 2 | ||||
| -rw-r--r-- | fs/quota/dquot.c | 555 | ||||
| -rw-r--r-- | fs/quota/kqid.c | 132 | ||||
| -rw-r--r-- | fs/quota/netlink.c | 26 | ||||
| -rw-r--r-- | fs/quota/quota.c | 162 | ||||
| -rw-r--r-- | fs/quota/quota_tree.c | 31 | ||||
| -rw-r--r-- | fs/quota/quota_v1.c | 12 | ||||
| -rw-r--r-- | fs/quota/quota_v2.c | 28 | 
9 files changed, 654 insertions, 301 deletions
diff --git a/fs/quota/Kconfig b/fs/quota/Kconfig index 880fd988436..c51df1dd237 100644 --- a/fs/quota/Kconfig +++ b/fs/quota/Kconfig @@ -8,9 +8,10 @@ config QUOTA  	help  	  If you say Y here, you will be able to set per user limits for disk  	  usage (also called disk quotas). Currently, it works for the -	  ext2, ext3, and reiserfs file system. ext3 also supports journalled -	  quotas for which you don't need to run quotacheck(8) after an unclean -	  shutdown. +	  ext2, ext3, ext4, jfs, ocfs2 and reiserfs file systems. +	  Note that gfs2 and xfs use their own quota system. +	  Ext3, ext4 and reiserfs also support journaled quotas for which +	  you don't need to run quotacheck(8) after an unclean shutdown.  	  For further details, read the Quota mini-HOWTO, available from  	  <http://www.tldp.org/docs.html#howto>, or the documentation provided  	  with the quota tools. Probably the quota support is only useful for diff --git a/fs/quota/Makefile b/fs/quota/Makefile index 5f9e9e276af..c66c37cdaa3 100644 --- a/fs/quota/Makefile +++ b/fs/quota/Makefile @@ -2,6 +2,6 @@ obj-$(CONFIG_QUOTA)		+= dquot.o  obj-$(CONFIG_QFMT_V1)		+= quota_v1.o  obj-$(CONFIG_QFMT_V2)		+= quota_v2.o  obj-$(CONFIG_QUOTA_TREE)	+= quota_tree.o -obj-$(CONFIG_QUOTACTL)		+= quota.o +obj-$(CONFIG_QUOTACTL)		+= quota.o kqid.o  obj-$(CONFIG_QUOTACTL_COMPAT)	+= compat.o  obj-$(CONFIG_QUOTA_NETLINK_INTERFACE)	+= netlink.o diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 0fed41e6efc..7f30bdc57d1 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -71,14 +71,14 @@  #include <linux/module.h>  #include <linux/proc_fs.h>  #include <linux/security.h> +#include <linux/sched.h>  #include <linux/kmod.h>  #include <linux/namei.h> -#include <linux/buffer_head.h>  #include <linux/capability.h>  #include <linux/quotaops.h> -#include <linux/writeback.h> /* for inode_lock, oddly enough.. */ +#include "../internal.h" /* ugh */ -#include <asm/uaccess.h> +#include <linux/uaccess.h>  /*   * There are three quota SMP locks. dq_list_lock protects all lists with quotas @@ -116,15 +116,15 @@   * spinlock to internal buffers before writing.   *   * Lock ordering (including related VFS locks) is the following: - *   i_mutex > dqonoff_sem > journal_lock > dqptr_sem > dquot->dq_lock > + *   dqonoff_mutex > i_mutex > journal_lock > dqptr_sem > dquot->dq_lock >   *   dqio_mutex + * dqonoff_mutex > i_mutex comes from dquot_quota_sync, dquot_enable, etc.   * The lock ordering of dqptr_sem imposed by quota code is only dqonoff_sem >   * dqptr_sem. But filesystem has to count with the fact that functions such as   * dquot_alloc_space() acquire dqptr_sem and they usually have to be called   * from inside a transaction to keep filesystem consistency after a crash. Also   * filesystems usually want to do some IO on dquot from ->mark_dirty which is   * called with dqptr_sem held. - * i_mutex on quota files is special (it's below dqio_mutex)   */  static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_list_lock); @@ -133,16 +133,20 @@ __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_data_lock);  EXPORT_SYMBOL(dq_data_lock);  void __quota_error(struct super_block *sb, const char *func, -		  const char *fmt, ...) +		   const char *fmt, ...)  { -	va_list args; -  	if (printk_ratelimit()) { +		va_list args; +		struct va_format vaf; +  		va_start(args, fmt); -		printk(KERN_ERR "Quota error (device %s): %s: ", -		       sb->s_id, func); -		vprintk(fmt, args); -		printk("\n"); + +		vaf.fmt = fmt; +		vaf.va = &args; + +		printk(KERN_ERR "Quota error (device %s): %s: %pV\n", +		       sb->s_id, func, &vaf); +  		va_end(args);  	}  } @@ -249,8 +253,10 @@ static qsize_t inode_get_rsv_space(struct inode *inode);  static void __dquot_initialize(struct inode *inode, int type);  static inline unsigned int -hashfn(const struct super_block *sb, unsigned int id, int type) +hashfn(const struct super_block *sb, struct kqid qid)  { +	unsigned int id = from_kqid(&init_user_ns, qid); +	int type = qid.type;  	unsigned long tmp;  	tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type); @@ -263,7 +269,7 @@ hashfn(const struct super_block *sb, unsigned int id, int type)  static inline void insert_dquot_hash(struct dquot *dquot)  {  	struct hlist_head *head; -	head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type); +	head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id);  	hlist_add_head(&dquot->dq_hash, head);  } @@ -273,15 +279,14 @@ static inline void remove_dquot_hash(struct dquot *dquot)  }  static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, -				unsigned int id, int type) +				struct kqid qid)  {  	struct hlist_node *node;  	struct dquot *dquot;  	hlist_for_each (node, dquot_hash+hashent) {  		dquot = hlist_entry(node, struct dquot, dq_hash); -		if (dquot->dq_sb == sb && dquot->dq_id == id && -		    dquot->dq_type == type) +		if (dquot->dq_sb == sb && qid_eq(dquot->dq_id, qid))  			return dquot;  	}  	return NULL; @@ -347,7 +352,7 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)  	spin_lock(&dq_list_lock);  	if (!test_and_set_bit(DQ_MOD_B, &dquot->dq_flags)) {  		list_add(&dquot->dq_dirty, &sb_dqopt(dquot->dq_sb)-> -				info[dquot->dq_type].dqi_dirty_list); +				info[dquot->dq_id.type].dqi_dirty_list);  		ret = 0;  	}  	spin_unlock(&dq_list_lock); @@ -406,17 +411,17 @@ int dquot_acquire(struct dquot *dquot)  	mutex_lock(&dquot->dq_lock);  	mutex_lock(&dqopt->dqio_mutex);  	if (!test_bit(DQ_READ_B, &dquot->dq_flags)) -		ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot); +		ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot);  	if (ret < 0)  		goto out_iolock;  	set_bit(DQ_READ_B, &dquot->dq_flags);  	/* 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); +		ret = dqopt->ops[dquot->dq_id.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 (info_dirty(&dqopt->info[dquot->dq_id.type])) { +			ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info( +					dquot->dq_sb, dquot->dq_id.type);  		}  		if (ret < 0)  			goto out_iolock; @@ -438,7 +443,7 @@ EXPORT_SYMBOL(dquot_acquire);   */  int dquot_commit(struct dquot *dquot)  { -	int ret = 0, ret2 = 0; +	int ret = 0;  	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);  	mutex_lock(&dqopt->dqio_mutex); @@ -450,15 +455,10 @@ int dquot_commit(struct dquot *dquot)  	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)) { -		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; -	} +	if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) +		ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot); +	else +		ret = -EIO;  out_sem:  	mutex_unlock(&dqopt->dqio_mutex);  	return ret; @@ -478,12 +478,12 @@ int dquot_release(struct dquot *dquot)  	if (atomic_read(&dquot->dq_count) > 1)  		goto out_dqlock;  	mutex_lock(&dqopt->dqio_mutex); -	if (dqopt->ops[dquot->dq_type]->release_dqblk) { -		ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot); +	if (dqopt->ops[dquot->dq_id.type]->release_dqblk) { +		ret = dqopt->ops[dquot->dq_id.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 (info_dirty(&dqopt->info[dquot->dq_id.type])) { +			ret2 = dqopt->ops[dquot->dq_id.type]->write_file_info( +						dquot->dq_sb, dquot->dq_id.type);  		}  		if (ret >= 0)  			ret = ret2; @@ -522,13 +522,13 @@ restart:  	list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {  		if (dquot->dq_sb != sb)  			continue; -		if (dquot->dq_type != type) +		if (dquot->dq_id.type != type)  			continue;  		/* Wait for dquot users */  		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 */ @@ -596,12 +604,14 @@ out:  }  EXPORT_SYMBOL(dquot_scan_active); -int dquot_quota_sync(struct super_block *sb, int type, int wait) +/* Write all dquot structures to quota files */ +int dquot_writeback_dquots(struct super_block *sb, int type)  {  	struct list_head *dirty;  	struct dquot *dquot;  	struct quota_info *dqopt = sb_dqopt(sb);  	int cnt; +	int err, ret = 0;  	mutex_lock(&dqopt->dqonoff_mutex);  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) { @@ -622,10 +632,12 @@ int dquot_quota_sync(struct super_block *sb, int type, int wait)  			/* 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); -			sb->dq_op->write_dquot(dquot); +			err = sb->dq_op->write_dquot(dquot); +			if (!ret && err) +				err = ret;  			dqput(dquot);  			spin_lock(&dq_list_lock);  		} @@ -639,7 +651,21 @@ int dquot_quota_sync(struct super_block *sb, int type, int wait)  	dqstats_inc(DQST_SYNCS);  	mutex_unlock(&dqopt->dqonoff_mutex); -	if (!wait || (sb_dqopt(sb)->flags & DQUOT_QUOTA_SYS_FILE)) +	return ret; +} +EXPORT_SYMBOL(dquot_writeback_dquots); + +/* Write all dquot structures to disk and make them visible from userspace */ +int dquot_quota_sync(struct super_block *sb, int type) +{ +	struct quota_info *dqopt = sb_dqopt(sb); +	int cnt; +	int ret; + +	ret = dquot_writeback_dquots(sb, type); +	if (ret) +		return ret; +	if (dqopt->flags & DQUOT_QUOTA_SYS_FILE)  		return 0;  	/* This is not very clever (and fast) but currently I don't know about @@ -653,59 +679,55 @@ int dquot_quota_sync(struct super_block *sb, int type, int wait)  	 * Now when everything is written we can discard the pagecache so  	 * that userspace sees the changes.  	 */ -	mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); +	mutex_lock(&dqopt->dqonoff_mutex);  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {  		if (type != -1 && cnt != type)  			continue;  		if (!sb_has_quota_active(sb, cnt))  			continue; -		mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex, -				  I_MUTEX_QUOTA); -		truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0); -		mutex_unlock(&sb_dqopt(sb)->files[cnt]->i_mutex); +		mutex_lock(&dqopt->files[cnt]->i_mutex); +		truncate_inode_pages(&dqopt->files[cnt]->i_data, 0); +		mutex_unlock(&dqopt->files[cnt]->i_mutex);  	} -	mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); +	mutex_unlock(&dqopt->dqonoff_mutex);  	return 0;  }  EXPORT_SYMBOL(dquot_quota_sync); -/* Free unused dquots from cache */ -static void prune_dqcache(int count) +static unsigned long +dqcache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)  {  	struct list_head *head;  	struct dquot *dquot; +	unsigned long freed = 0; +	spin_lock(&dq_list_lock);  	head = free_dquots.prev; -	while (head != &free_dquots && count) { +	while (head != &free_dquots && sc->nr_to_scan) {  		dquot = list_entry(head, struct dquot, dq_free);  		remove_dquot_hash(dquot);  		remove_free_dquot(dquot);  		remove_inuse(dquot);  		do_destroy_dquot(dquot); -		count--; +		sc->nr_to_scan--; +		freed++;  		head = free_dquots.prev;  	} +	spin_unlock(&dq_list_lock); +	return freed;  } -/* - * This is called from kswapd when we think we need some - * more memory - */ -static int shrink_dqcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask) +static unsigned long +dqcache_shrink_count(struct shrinker *shrink, struct shrink_control *sc)  { -	if (nr) { -		spin_lock(&dq_list_lock); -		prune_dqcache(nr); -		spin_unlock(&dq_list_lock); -	} -	return ((unsigned) -		percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS]) -		/100) * sysctl_vfs_cache_pressure; +	return vfs_pressure_ratio( +	percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS]));  }  static struct shrinker dqcache_shrinker = { -	.shrink = shrink_dqcache_memory, +	.count_objects = dqcache_shrink_count, +	.scan_objects = dqcache_shrink_scan,  	.seeks = DEFAULT_SEEKS,  }; @@ -722,7 +744,8 @@ void dqput(struct dquot *dquot)  #ifdef CONFIG_QUOTA_DEBUG  	if (!atomic_read(&dquot->dq_count)) {  		quota_error(dquot->dq_sb, "trying to free free dquot of %s %d", -			    quotatypes[dquot->dq_type], dquot->dq_id); +			    quotatypes[dquot->dq_id.type], +			    from_kqid(&init_user_ns, dquot->dq_id));  		BUG();  	}  #endif @@ -733,7 +756,7 @@ we_slept:  		/* We have more than one user... nothing to do */  		atomic_dec(&dquot->dq_count);  		/* Releasing dquot during quotaoff phase? */ -		if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_type) && +		if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_id.type) &&  		    atomic_read(&dquot->dq_count) == 1)  			wake_up(&dquot->dq_wait_unused);  		spin_unlock(&dq_list_lock); @@ -796,7 +819,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)  	INIT_LIST_HEAD(&dquot->dq_dirty);  	init_waitqueue_head(&dquot->dq_wait_unused);  	dquot->dq_sb = sb; -	dquot->dq_type = type; +	dquot->dq_id = make_kqid_invalid(type);  	atomic_set(&dquot->dq_count, 1);  	return dquot; @@ -810,35 +833,35 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)   *   a) checking for quota flags under dq_list_lock and   *   b) getting a reference to dquot before we release dq_list_lock   */ -struct dquot *dqget(struct super_block *sb, unsigned int id, int type) +struct dquot *dqget(struct super_block *sb, struct kqid qid)  { -	unsigned int hashent = hashfn(sb, id, type); +	unsigned int hashent = hashfn(sb, qid);  	struct dquot *dquot = NULL, *empty = NULL; -        if (!sb_has_quota_active(sb, type)) +        if (!sb_has_quota_active(sb, qid.type))  		return NULL;  we_slept:  	spin_lock(&dq_list_lock);  	spin_lock(&dq_state_lock); -	if (!sb_has_quota_active(sb, type)) { +	if (!sb_has_quota_active(sb, qid.type)) {  		spin_unlock(&dq_state_lock);  		spin_unlock(&dq_list_lock);  		goto out;  	}  	spin_unlock(&dq_state_lock); -	dquot = find_dquot(hashent, sb, id, type); +	dquot = find_dquot(hashent, sb, qid);  	if (!dquot) {  		if (!empty) {  			spin_unlock(&dq_list_lock); -			empty = get_empty_dquot(sb, type); +			empty = get_empty_dquot(sb, qid.type);  			if (!empty)  				schedule();	/* Try to wait for a moment... */  			goto we_slept;  		}  		dquot = empty;  		empty = NULL; -		dquot->dq_id = id; +		dquot->dq_id = qid;  		/* all dquots go on the inuse_list */  		put_inuse(dquot);  		/* hash it first so it can be found */ @@ -896,33 +919,38 @@ static void add_dquot_ref(struct super_block *sb, int type)  	int reserved = 0;  #endif -	spin_lock(&inode_lock); +	spin_lock(&inode_sb_list_lock);  	list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { -		if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) +		spin_lock(&inode->i_lock); +		if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || +		    !atomic_read(&inode->i_writecount) || +		    !dqinit_needed(inode, type)) { +			spin_unlock(&inode->i_lock);  			continue; +		} +		__iget(inode); +		spin_unlock(&inode->i_lock); +		spin_unlock(&inode_sb_list_lock); +  #ifdef CONFIG_QUOTA_DEBUG  		if (unlikely(inode_get_rsv_space(inode) > 0))  			reserved = 1;  #endif -		if (!atomic_read(&inode->i_writecount)) -			continue; -		if (!dqinit_needed(inode, type)) -			continue; - -		__iget(inode); -		spin_unlock(&inode_lock); -  		iput(old_inode);  		__dquot_initialize(inode, type); -		/* We hold a reference to 'inode' so it couldn't have been -		 * removed from s_inodes list while we dropped the inode_lock. -		 * We cannot iput the inode now as we can be holding the last -		 * reference and we cannot iput it under inode_lock. So we -		 * keep the reference and iput it later. */ + +		/* +		 * We hold a reference to 'inode' so it couldn't have been +		 * removed from s_inodes list while we dropped the +		 * inode_sb_list_lock We cannot iput the inode now as we can be +		 * holding the last reference and we cannot iput it under +		 * inode_sb_list_lock. So we keep the reference and iput it +		 * later. +		 */  		old_inode = inode; -		spin_lock(&inode_lock); +		spin_lock(&inode_sb_list_lock);  	} -	spin_unlock(&inode_lock); +	spin_unlock(&inode_sb_list_lock);  	iput(old_inode);  #ifdef CONFIG_QUOTA_DEBUG @@ -947,7 +975,7 @@ static inline int dqput_blocks(struct dquot *dquot)  /*   * Remove references to dquots from inode and add dquot to list for freeing - * if we have the last referece to dquot + * if we have the last reference to dquot   * We can't race with anybody because we hold dqptr_sem for writing...   */  static int remove_inode_dquot_ref(struct inode *inode, int type, @@ -1003,7 +1031,7 @@ static void remove_dquot_ref(struct super_block *sb, int type,  	struct inode *inode;  	int reserved = 0; -	spin_lock(&inode_lock); +	spin_lock(&inode_sb_list_lock);  	list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {  		/*  		 *  We have to scan also I_NEW inodes because they can already @@ -1017,7 +1045,7 @@ static void remove_dquot_ref(struct super_block *sb, int type,  			remove_inode_dquot_ref(inode, type, tofree_head);  		}  	} -	spin_unlock(&inode_lock); +	spin_unlock(&inode_sb_list_lock);  #ifdef CONFIG_QUOTA_DEBUG  	if (reserved) {  		printk(KERN_WARNING "VFS (%s): Writes happened after quota" @@ -1068,6 +1096,14 @@ static void dquot_claim_reserved_space(struct dquot *dquot, qsize_t number)  	dquot->dq_dqb.dqb_rsvspace -= number;  } +static void dquot_reclaim_reserved_space(struct dquot *dquot, qsize_t number) +{ +	if (WARN_ON_ONCE(dquot->dq_dqb.dqb_curspace < number)) +		number = dquot->dq_dqb.dqb_curspace; +	dquot->dq_dqb.dqb_rsvspace += number; +	dquot->dq_dqb.dqb_curspace -= number; +} +  static inline  void dquot_free_reserved_space(struct dquot *dquot, qsize_t number)  { @@ -1103,6 +1139,12 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)  	clear_bit(DQ_BLKS_B, &dquot->dq_flags);  } +struct dquot_warn { +	struct super_block *w_sb; +	struct kqid w_dq_id; +	short w_type; +}; +  static int warning_issued(struct dquot *dquot, const int warntype)  {  	int flag = (warntype == QUOTA_NL_BHARDWARN || @@ -1118,41 +1160,44 @@ static int warning_issued(struct dquot *dquot, const int warntype)  #ifdef CONFIG_PRINT_QUOTA_WARNING  static int flag_print_warnings = 1; -static int need_print_warning(struct dquot *dquot) +static int need_print_warning(struct dquot_warn *warn)  {  	if (!flag_print_warnings)  		return 0; -	switch (dquot->dq_type) { +	switch (warn->w_dq_id.type) {  		case USRQUOTA: -			return current_fsuid() == dquot->dq_id; +			return uid_eq(current_fsuid(), warn->w_dq_id.uid);  		case GRPQUOTA: -			return in_group_p(dquot->dq_id); +			return in_group_p(warn->w_dq_id.gid); +		case PRJQUOTA:	/* Never taken... Just make gcc happy */ +			return 0;  	}  	return 0;  }  /* Print warning to user which exceeded quota */ -static void print_warning(struct dquot *dquot, const int warntype) +static void print_warning(struct dquot_warn *warn)  {  	char *msg = NULL;  	struct tty_struct *tty; +	int warntype = warn->w_type;  	if (warntype == QUOTA_NL_IHARDBELOW ||  	    warntype == QUOTA_NL_ISOFTBELOW ||  	    warntype == QUOTA_NL_BHARDBELOW || -	    warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot)) +	    warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(warn))  		return;  	tty = get_current_tty();  	if (!tty)  		return; -	tty_write_message(tty, dquot->dq_sb->s_id); +	tty_write_message(tty, warn->w_sb->s_id);  	if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN)  		tty_write_message(tty, ": warning, ");  	else  		tty_write_message(tty, ": write failed, "); -	tty_write_message(tty, quotatypes[dquot->dq_type]); +	tty_write_message(tty, quotatypes[warn->w_dq_id.type]);  	switch (warntype) {  		case QUOTA_NL_IHARDWARN:  			msg = " file limit reached.\r\n"; @@ -1178,32 +1223,39 @@ static void print_warning(struct dquot *dquot, const int warntype)  }  #endif +static void prepare_warning(struct dquot_warn *warn, struct dquot *dquot, +			    int warntype) +{ +	if (warning_issued(dquot, warntype)) +		return; +	warn->w_type = warntype; +	warn->w_sb = dquot->dq_sb; +	warn->w_dq_id = dquot->dq_id; +} +  /*   * Write warnings to the console and send warning messages over netlink.   * - * Note that this function can sleep. + * Note that this function can call into tty and networking code.   */ -static void flush_warnings(struct dquot *const *dquots, char *warntype) +static void flush_warnings(struct dquot_warn *warn)  { -	struct dquot *dq;  	int i;  	for (i = 0; i < MAXQUOTAS; i++) { -		dq = dquots[i]; -		if (dq && warntype[i] != QUOTA_NL_NOWARN && -		    !warning_issued(dq, warntype[i])) { +		if (warn[i].w_type == QUOTA_NL_NOWARN) +			continue;  #ifdef CONFIG_PRINT_QUOTA_WARNING -			print_warning(dq, warntype[i]); +		print_warning(&warn[i]);  #endif -			quota_send_warning(dq->dq_type, dq->dq_id, -					   dq->dq_sb->s_dev, warntype[i]); -		} +		quota_send_warning(warn[i].w_dq_id, +				   warn[i].w_sb->s_dev, warn[i].w_type);  	}  }  static int ignore_hardlimit(struct dquot *dquot)  { -	struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type]; +	struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];  	return capable(CAP_SYS_RESOURCE) &&  	       (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || @@ -1211,19 +1263,19 @@ static int ignore_hardlimit(struct dquot *dquot)  }  /* needs dq_data_lock */ -static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype) +static int check_idq(struct dquot *dquot, qsize_t inodes, +		     struct dquot_warn *warn)  {  	qsize_t newinodes = dquot->dq_dqb.dqb_curinodes + inodes; -	*warntype = QUOTA_NL_NOWARN; -	if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) || +	if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_id.type) ||  	    test_bit(DQ_FAKE_B, &dquot->dq_flags))  		return 0;  	if (dquot->dq_dqb.dqb_ihardlimit &&  	    newinodes > dquot->dq_dqb.dqb_ihardlimit &&              !ignore_hardlimit(dquot)) { -		*warntype = QUOTA_NL_IHARDWARN; +		prepare_warning(warn, dquot, QUOTA_NL_IHARDWARN);  		return -EDQUOT;  	} @@ -1232,29 +1284,29 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)  	    dquot->dq_dqb.dqb_itime &&  	    get_seconds() >= dquot->dq_dqb.dqb_itime &&              !ignore_hardlimit(dquot)) { -		*warntype = QUOTA_NL_ISOFTLONGWARN; +		prepare_warning(warn, dquot, QUOTA_NL_ISOFTLONGWARN);  		return -EDQUOT;  	}  	if (dquot->dq_dqb.dqb_isoftlimit &&  	    newinodes > dquot->dq_dqb.dqb_isoftlimit &&  	    dquot->dq_dqb.dqb_itime == 0) { -		*warntype = QUOTA_NL_ISOFTWARN; +		prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN);  		dquot->dq_dqb.dqb_itime = get_seconds() + -		    sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; +		    sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type].dqi_igrace;  	}  	return 0;  }  /* needs dq_data_lock */ -static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) +static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, +		     struct dquot_warn *warn)  {  	qsize_t tspace;  	struct super_block *sb = dquot->dq_sb; -	*warntype = QUOTA_NL_NOWARN; -	if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) || +	if (!sb_has_quota_limits_enabled(sb, dquot->dq_id.type) ||  	    test_bit(DQ_FAKE_B, &dquot->dq_flags))  		return 0; @@ -1265,7 +1317,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war  	    tspace > dquot->dq_dqb.dqb_bhardlimit &&              !ignore_hardlimit(dquot)) {  		if (!prealloc) -			*warntype = QUOTA_NL_BHARDWARN; +			prepare_warning(warn, dquot, QUOTA_NL_BHARDWARN);  		return -EDQUOT;  	} @@ -1275,7 +1327,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war  	    get_seconds() >= dquot->dq_dqb.dqb_btime &&              !ignore_hardlimit(dquot)) {  		if (!prealloc) -			*warntype = QUOTA_NL_BSOFTLONGWARN; +			prepare_warning(warn, dquot, QUOTA_NL_BSOFTLONGWARN);  		return -EDQUOT;  	} @@ -1283,9 +1335,9 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war  	    tspace > dquot->dq_dqb.dqb_bsoftlimit &&  	    dquot->dq_dqb.dqb_btime == 0) {  		if (!prealloc) { -			*warntype = QUOTA_NL_BSOFTWARN; +			prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN);  			dquot->dq_dqb.dqb_btime = get_seconds() + -			    sb_dqopt(sb)->info[dquot->dq_type].dqi_bgrace; +			    sb_dqopt(sb)->info[dquot->dq_id.type].dqi_bgrace;  		}  		else  			/* @@ -1304,7 +1356,7 @@ static int info_idq_free(struct dquot *dquot, qsize_t inodes)  	if (test_bit(DQ_FAKE_B, &dquot->dq_flags) ||  	    dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit || -	    !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type)) +	    !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_id.type))  		return QUOTA_NL_NOWARN;  	newinodes = dquot->dq_dqb.dqb_curinodes - inodes; @@ -1350,7 +1402,6 @@ static int dquot_active(const struct inode *inode)   */  static void __dquot_initialize(struct inode *inode, int type)  { -	unsigned int id = 0;  	int cnt;  	struct dquot *got[MAXQUOTAS];  	struct super_block *sb = inode->i_sb; @@ -1363,18 +1414,19 @@ static void __dquot_initialize(struct inode *inode, int type)  	/* First get references to structures we might need. */  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) { +		struct kqid qid;  		got[cnt] = NULL;  		if (type != -1 && cnt != type)  			continue;  		switch (cnt) {  		case USRQUOTA: -			id = inode->i_uid; +			qid = make_kqid_uid(inode->i_uid);  			break;  		case GRPQUOTA: -			id = inode->i_gid; +			qid = make_kqid_gid(inode->i_gid);  			break;  		} -		got[cnt] = dqget(sb, id, cnt); +		got[cnt] = dqget(sb, qid);  	}  	down_write(&sb_dqopt(sb)->dqptr_sem); @@ -1397,8 +1449,11 @@ static void __dquot_initialize(struct inode *inode, int type)  			 * did a write before quota was turned on  			 */  			rsv = inode_get_rsv_space(inode); -			if (unlikely(rsv)) +			if (unlikely(rsv)) { +				spin_lock(&dq_data_lock);  				dquot_resv_space(inode->i_dquot[cnt], rsv); +				spin_unlock(&dq_data_lock); +			}  		}  	}  out_err: @@ -1483,6 +1538,15 @@ void inode_claim_rsv_space(struct inode *inode, qsize_t number)  }  EXPORT_SYMBOL(inode_claim_rsv_space); +void inode_reclaim_rsv_space(struct inode *inode, qsize_t number) +{ +	spin_lock(&inode->i_lock); +	*inode_reserved_space(inode) += number; +	__inode_sub_bytes(inode, number); +	spin_unlock(&inode->i_lock); +} +EXPORT_SYMBOL(inode_reclaim_rsv_space); +  void inode_sub_rsv_space(struct inode *inode, qsize_t number)  {  	spin_lock(&inode->i_lock); @@ -1536,10 +1600,9 @@ static void inode_decr_space(struct inode *inode, qsize_t number, int reserve)  int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)  {  	int cnt, ret = 0; -	char warntype[MAXQUOTAS]; -	int warn = flags & DQUOT_SPACE_WARN; +	struct dquot_warn warn[MAXQUOTAS]; +	struct dquot **dquots = inode->i_dquot;  	int reserve = flags & DQUOT_SPACE_RESERVE; -	int nofail = flags & DQUOT_SPACE_NOFAIL;  	/*  	 * First test before acquiring mutex - solves deadlocks when we @@ -1550,38 +1613,38 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)  		goto out;  	} -	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) -		warntype[cnt] = QUOTA_NL_NOWARN; +		warn[cnt].w_type = QUOTA_NL_NOWARN; +	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);  	spin_lock(&dq_data_lock);  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) { -		if (!inode->i_dquot[cnt]) +		if (!dquots[cnt])  			continue; -		ret = check_bdq(inode->i_dquot[cnt], number, !warn, -				warntype+cnt); -		if (ret && !nofail) { +		ret = check_bdq(dquots[cnt], number, +				!(flags & DQUOT_SPACE_WARN), &warn[cnt]); +		if (ret && !(flags & DQUOT_SPACE_NOFAIL)) {  			spin_unlock(&dq_data_lock);  			goto out_flush_warn;  		}  	}  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) { -		if (!inode->i_dquot[cnt]) +		if (!dquots[cnt])  			continue;  		if (reserve) -			dquot_resv_space(inode->i_dquot[cnt], number); +			dquot_resv_space(dquots[cnt], number);  		else -			dquot_incr_space(inode->i_dquot[cnt], number); +			dquot_incr_space(dquots[cnt], number);  	}  	inode_incr_space(inode, number, reserve);  	spin_unlock(&dq_data_lock);  	if (reserve)  		goto out_flush_warn; -	mark_all_dquot_dirty(inode->i_dquot); +	mark_all_dquot_dirty(dquots);  out_flush_warn: -	flush_warnings(inode->i_dquot, warntype);  	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); +	flush_warnings(warn);  out:  	return ret;  } @@ -1593,36 +1656,37 @@ EXPORT_SYMBOL(__dquot_alloc_space);  int dquot_alloc_inode(const struct inode *inode)  {  	int cnt, ret = 0; -	char warntype[MAXQUOTAS]; +	struct dquot_warn warn[MAXQUOTAS]; +	struct dquot * const *dquots = inode->i_dquot;  	/* First test before acquiring mutex - solves deadlocks when we           * re-enter the quota code and are already holding the mutex */  	if (!dquot_active(inode))  		return 0;  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) -		warntype[cnt] = QUOTA_NL_NOWARN; +		warn[cnt].w_type = QUOTA_NL_NOWARN;  	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);  	spin_lock(&dq_data_lock);  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) { -		if (!inode->i_dquot[cnt]) +		if (!dquots[cnt])  			continue; -		ret = check_idq(inode->i_dquot[cnt], 1, warntype + cnt); +		ret = check_idq(dquots[cnt], 1, &warn[cnt]);  		if (ret)  			goto warn_put_all;  	}  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) { -		if (!inode->i_dquot[cnt]) +		if (!dquots[cnt])  			continue; -		dquot_incr_inodes(inode->i_dquot[cnt], 1); +		dquot_incr_inodes(dquots[cnt], 1);  	}  warn_put_all:  	spin_unlock(&dq_data_lock);  	if (ret == 0) -		mark_all_dquot_dirty(inode->i_dquot); -	flush_warnings(inode->i_dquot, warntype); +		mark_all_dquot_dirty(dquots);  	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); +	flush_warnings(warn);  	return ret;  }  EXPORT_SYMBOL(dquot_alloc_inode); @@ -1657,12 +1721,42 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)  EXPORT_SYMBOL(dquot_claim_space_nodirty);  /* + * Convert allocated space back to in-memory reserved quotas + */ +void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) +{ +	int cnt; + +	if (!dquot_active(inode)) { +		inode_reclaim_rsv_space(inode, number); +		return; +	} + +	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); +	spin_lock(&dq_data_lock); +	/* Claim reserved quotas to allocated quotas */ +	for (cnt = 0; cnt < MAXQUOTAS; cnt++) { +		if (inode->i_dquot[cnt]) +			dquot_reclaim_reserved_space(inode->i_dquot[cnt], +						     number); +	} +	/* Update inode bytes */ +	inode_reclaim_rsv_space(inode, number); +	spin_unlock(&dq_data_lock); +	mark_all_dquot_dirty(inode->i_dquot); +	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); +	return; +} +EXPORT_SYMBOL(dquot_reclaim_space_nodirty); + +/*   * This operation can block, but only after everything is updated   */  void __dquot_free_space(struct inode *inode, qsize_t number, int flags)  {  	unsigned int cnt; -	char warntype[MAXQUOTAS]; +	struct dquot_warn warn[MAXQUOTAS]; +	struct dquot **dquots = inode->i_dquot;  	int reserve = flags & DQUOT_SPACE_RESERVE;  	/* First test before acquiring mutex - solves deadlocks when we @@ -1675,23 +1769,28 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)  	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);  	spin_lock(&dq_data_lock);  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) { -		if (!inode->i_dquot[cnt]) +		int wtype; + +		warn[cnt].w_type = QUOTA_NL_NOWARN; +		if (!dquots[cnt])  			continue; -		warntype[cnt] = info_bdq_free(inode->i_dquot[cnt], number); +		wtype = info_bdq_free(dquots[cnt], number); +		if (wtype != QUOTA_NL_NOWARN) +			prepare_warning(&warn[cnt], dquots[cnt], wtype);  		if (reserve) -			dquot_free_reserved_space(inode->i_dquot[cnt], number); +			dquot_free_reserved_space(dquots[cnt], number);  		else -			dquot_decr_space(inode->i_dquot[cnt], number); +			dquot_decr_space(dquots[cnt], number);  	}  	inode_decr_space(inode, number, reserve);  	spin_unlock(&dq_data_lock);  	if (reserve)  		goto out_unlock; -	mark_all_dquot_dirty(inode->i_dquot); +	mark_all_dquot_dirty(dquots);  out_unlock: -	flush_warnings(inode->i_dquot, warntype);  	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); +	flush_warnings(warn);  }  EXPORT_SYMBOL(__dquot_free_space); @@ -1701,7 +1800,8 @@ EXPORT_SYMBOL(__dquot_free_space);  void dquot_free_inode(const struct inode *inode)  {  	unsigned int cnt; -	char warntype[MAXQUOTAS]; +	struct dquot_warn warn[MAXQUOTAS]; +	struct dquot * const *dquots = inode->i_dquot;  	/* First test before acquiring mutex - solves deadlocks when we           * re-enter the quota code and are already holding the mutex */ @@ -1711,15 +1811,20 @@ void dquot_free_inode(const struct inode *inode)  	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);  	spin_lock(&dq_data_lock);  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) { -		if (!inode->i_dquot[cnt]) +		int wtype; + +		warn[cnt].w_type = QUOTA_NL_NOWARN; +		if (!dquots[cnt])  			continue; -		warntype[cnt] = info_idq_free(inode->i_dquot[cnt], 1); -		dquot_decr_inodes(inode->i_dquot[cnt], 1); +		wtype = info_idq_free(dquots[cnt], 1); +		if (wtype != QUOTA_NL_NOWARN) +			prepare_warning(&warn[cnt], dquots[cnt], wtype); +		dquot_decr_inodes(dquots[cnt], 1);  	}  	spin_unlock(&dq_data_lock); -	mark_all_dquot_dirty(inode->i_dquot); -	flush_warnings(inode->i_dquot, warntype); +	mark_all_dquot_dirty(dquots);  	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); +	flush_warnings(warn);  }  EXPORT_SYMBOL(dquot_free_inode); @@ -1740,16 +1845,20 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)  	struct dquot *transfer_from[MAXQUOTAS] = {};  	int cnt, ret = 0;  	char is_valid[MAXQUOTAS] = {}; -	char warntype_to[MAXQUOTAS]; -	char warntype_from_inodes[MAXQUOTAS], warntype_from_space[MAXQUOTAS]; +	struct dquot_warn warn_to[MAXQUOTAS]; +	struct dquot_warn warn_from_inodes[MAXQUOTAS]; +	struct dquot_warn warn_from_space[MAXQUOTAS];  	/* First test before acquiring mutex - solves deadlocks when we           * re-enter the quota code and are already holding the mutex */  	if (IS_NOQUOTA(inode))  		return 0;  	/* Initialize the arrays */ -	for (cnt = 0; cnt < MAXQUOTAS; cnt++) -		warntype_to[cnt] = QUOTA_NL_NOWARN; +	for (cnt = 0; cnt < MAXQUOTAS; cnt++) { +		warn_to[cnt].w_type = QUOTA_NL_NOWARN; +		warn_from_inodes[cnt].w_type = QUOTA_NL_NOWARN; +		warn_from_space[cnt].w_type = QUOTA_NL_NOWARN; +	}  	down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);  	if (IS_NOQUOTA(inode)) {	/* File without quota accounting? */  		up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); @@ -1771,10 +1880,10 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)  			continue;  		is_valid[cnt] = 1;  		transfer_from[cnt] = inode->i_dquot[cnt]; -		ret = check_idq(transfer_to[cnt], 1, warntype_to + cnt); +		ret = check_idq(transfer_to[cnt], 1, &warn_to[cnt]);  		if (ret)  			goto over_quota; -		ret = check_bdq(transfer_to[cnt], space, 0, warntype_to + cnt); +		ret = check_bdq(transfer_to[cnt], space, 0, &warn_to[cnt]);  		if (ret)  			goto over_quota;  	} @@ -1787,10 +1896,15 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)  			continue;  		/* Due to IO error we might not have transfer_from[] structure */  		if (transfer_from[cnt]) { -			warntype_from_inodes[cnt] = -				info_idq_free(transfer_from[cnt], 1); -			warntype_from_space[cnt] = -				info_bdq_free(transfer_from[cnt], space); +			int wtype; +			wtype = info_idq_free(transfer_from[cnt], 1); +			if (wtype != QUOTA_NL_NOWARN) +				prepare_warning(&warn_from_inodes[cnt], +						transfer_from[cnt], wtype); +			wtype = info_bdq_free(transfer_from[cnt], space); +			if (wtype != QUOTA_NL_NOWARN) +				prepare_warning(&warn_from_space[cnt], +						transfer_from[cnt], wtype);  			dquot_decr_inodes(transfer_from[cnt], 1);  			dquot_decr_space(transfer_from[cnt], cur_space);  			dquot_free_reserved_space(transfer_from[cnt], @@ -1808,9 +1922,9 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)  	mark_all_dquot_dirty(transfer_from);  	mark_all_dquot_dirty(transfer_to); -	flush_warnings(transfer_to, warntype_to); -	flush_warnings(transfer_from, warntype_from_inodes); -	flush_warnings(transfer_from, warntype_from_space); +	flush_warnings(warn_to); +	flush_warnings(warn_from_inodes); +	flush_warnings(warn_from_space);  	/* Pass back references to put */  	for (cnt = 0; cnt < MAXQUOTAS; cnt++)  		if (is_valid[cnt]) @@ -1819,7 +1933,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)  over_quota:  	spin_unlock(&dq_data_lock);  	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); -	flush_warnings(transfer_to, warntype_to); +	flush_warnings(warn_to);  	return ret;  }  EXPORT_SYMBOL(__dquot_transfer); @@ -1836,10 +1950,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)  	if (!dquot_active(inode))  		return 0; -	if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) -		transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA); -	if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) -		transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA); +	if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) +		transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(iattr->ia_uid)); +	if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid)) +		transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(iattr->ia_gid));  	ret = __dquot_transfer(inode, transfer_to);  	dqput_all(transfer_to); @@ -1993,8 +2107,7 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags)  			/* If quota was reenabled in the meantime, we have  			 * nothing to do */  			if (!sb_has_quota_loaded(sb, cnt)) { -				mutex_lock_nested(&toputinode[cnt]->i_mutex, -						  I_MUTEX_QUOTA); +				mutex_lock(&toputinode[cnt]->i_mutex);  				toputinode[cnt]->i_flags &= ~(S_IMMUTABLE |  				  S_NOATIME | S_NOQUOTA);  				truncate_inode_pages(&toputinode[cnt]->i_data, @@ -2089,7 +2202,7 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,  		/* We don't want quota and atime on quota files (deadlocks  		 * possible) Also nobody should write to the file - we use  		 * special IO operations which ignore the immutable bit. */ -		mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); +		mutex_lock(&inode->i_mutex);  		oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE |  					     S_NOQUOTA);  		inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE; @@ -2119,6 +2232,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,  		mutex_unlock(&dqopt->dqio_mutex);  		goto out_file_init;  	} +	if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) +		dqopt->info[type].dqi_flags |= DQF_SYS_FILE;  	mutex_unlock(&dqopt->dqio_mutex);  	spin_lock(&dq_state_lock);  	dqopt->flags |= dquot_state_flag(flags, type); @@ -2134,7 +2249,7 @@ out_file_init:  	iput(inode);  out_lock:  	if (oldflags != -1) { -		mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); +		mutex_lock(&inode->i_mutex);  		/* Set the flags back (in the case of accidental quotaon()  		 * on a wrong file we don't want to mess up the flags) */  		inode->i_flags &= ~(S_NOATIME | S_NOQUOTA | S_IMMUTABLE); @@ -2185,14 +2300,14 @@ int dquot_resume(struct super_block *sb, int type)  }  EXPORT_SYMBOL(dquot_resume); -int dquot_quota_on_path(struct super_block *sb, int type, int format_id, -		      struct path *path) +int dquot_quota_on(struct super_block *sb, int type, int format_id, +		   struct path *path)  {  	int error = security_quota_on(path->dentry);  	if (error)  		return error;  	/* Quota file not on the same filesystem? */ -	if (path->mnt->mnt_sb != sb) +	if (path->dentry->d_sb != sb)  		error = -EXDEV;  	else  		error = vfs_load_quota_inode(path->dentry->d_inode, type, @@ -2200,20 +2315,6 @@ int dquot_quota_on_path(struct super_block *sb, int type, int format_id,  					     DQUOT_LIMITS_ENABLED);  	return error;  } -EXPORT_SYMBOL(dquot_quota_on_path); - -int dquot_quota_on(struct super_block *sb, int type, int format_id, char *name) -{ -	struct path path; -	int error; - -	error = kern_path(name, LOOKUP_FOLLOW, &path); -	if (!error) { -		error = dquot_quota_on_path(sb, type, format_id, &path); -		path_put(&path); -	} -	return error; -}  EXPORT_SYMBOL(dquot_quota_on);  /* @@ -2312,9 +2413,9 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)  	memset(di, 0, sizeof(*di));  	di->d_version = FS_DQUOT_VERSION; -	di->d_flags = dquot->dq_type == USRQUOTA ? +	di->d_flags = dquot->dq_id.type == USRQUOTA ?  			FS_USER_QUOTA : FS_GROUP_QUOTA; -	di->d_id = dquot->dq_id; +	di->d_id = from_kqid_munged(current_user_ns(), dquot->dq_id);  	spin_lock(&dq_data_lock);  	di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit); @@ -2328,12 +2429,12 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)  	spin_unlock(&dq_data_lock);  } -int dquot_get_dqblk(struct super_block *sb, int type, qid_t id, +int dquot_get_dqblk(struct super_block *sb, struct kqid qid,  		    struct fs_disk_quota *di)  {  	struct dquot *dquot; -	dquot = dqget(sb, id, type); +	dquot = dqget(sb, qid);  	if (!dquot)  		return -ESRCH;  	do_get_dqblk(dquot, di); @@ -2353,7 +2454,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)  {  	struct mem_dqblk *dm = &dquot->dq_dqb;  	int check_blim = 0, check_ilim = 0; -	struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type]; +	struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];  	if (di->d_fieldmask & ~VFS_FS_DQ_MASK)  		return -EINVAL; @@ -2440,13 +2541,13 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)  	return 0;  } -int dquot_set_dqblk(struct super_block *sb, int type, qid_t id, +int dquot_set_dqblk(struct super_block *sb, struct kqid qid,  		  struct fs_disk_quota *di)  {  	struct dquot *dquot;  	int rc; -	dquot = dqget(sb, id, type); +	dquot = dqget(sb, qid);  	if (!dquot) {  		rc = -ESRCH;  		goto out; @@ -2472,7 +2573,7 @@ int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)  	spin_lock(&dq_data_lock);  	ii->dqi_bgrace = mi->dqi_bgrace;  	ii->dqi_igrace = mi->dqi_igrace; -	ii->dqi_flags = mi->dqi_flags & DQF_MASK; +	ii->dqi_flags = mi->dqi_flags & DQF_GETINFO_MASK;  	ii->dqi_valid = IIF_ALL;  	spin_unlock(&dq_data_lock);  	mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); @@ -2498,8 +2599,8 @@ int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)  	if (ii->dqi_valid & IIF_IGRACE)  		mi->dqi_igrace = ii->dqi_igrace;  	if (ii->dqi_valid & IIF_FLAGS) -		mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | -				(ii->dqi_flags & DQF_MASK); +		mi->dqi_flags = (mi->dqi_flags & ~DQF_SETINFO_MASK) | +				(ii->dqi_flags & DQF_SETINFO_MASK);  	spin_unlock(&dq_data_lock);  	mark_info_dirty(sb, type);  	/* Force write to disk */ @@ -2532,7 +2633,7 @@ static int do_proc_dqstats(struct ctl_table *table, int write,  	return proc_dointvec(table, write, buffer, lenp, ppos);  } -static ctl_table fs_dqstats_table[] = { +static struct ctl_table fs_dqstats_table[] = {  	{  		.procname	= "lookups",  		.data		= &dqstats.stat[DQST_LOOKUPS], @@ -2601,7 +2702,7 @@ static ctl_table fs_dqstats_table[] = {  	{ },  }; -static ctl_table fs_table[] = { +static struct ctl_table fs_table[] = {  	{  		.procname	= "quota",  		.mode		= 0555, @@ -2610,7 +2711,7 @@ static ctl_table fs_table[] = {  	{ },  }; -static ctl_table sys_table[] = { +static struct ctl_table sys_table[] = {  	{  		.procname	= "fs",  		.mode		= 0555, diff --git a/fs/quota/kqid.c b/fs/quota/kqid.c new file mode 100644 index 00000000000..2f97b0e2c50 --- /dev/null +++ b/fs/quota/kqid.c @@ -0,0 +1,132 @@ +#include <linux/fs.h> +#include <linux/quota.h> +#include <linux/export.h> + +/** + *	qid_eq - Test to see if to kquid values are the same + *	@left: A qid value + *	@right: Another quid value + * + *	Return true if the two qid values are equal and false otherwise. + */ +bool qid_eq(struct kqid left, struct kqid right) +{ +	if (left.type != right.type) +		return false; +	switch(left.type) { +	case USRQUOTA: +		return uid_eq(left.uid, right.uid); +	case GRPQUOTA: +		return gid_eq(left.gid, right.gid); +	case PRJQUOTA: +		return projid_eq(left.projid, right.projid); +	default: +		BUG(); +	} +} +EXPORT_SYMBOL(qid_eq); + +/** + *	qid_lt - Test to see if one qid value is less than another + *	@left: The possibly lesser qid value + *	@right: The possibly greater qid value + * + *	Return true if left is less than right and false otherwise. + */ +bool qid_lt(struct kqid left, struct kqid right) +{ +	if (left.type < right.type) +		return true; +	if (left.type > right.type) +		return false; +	switch (left.type) { +	case USRQUOTA: +		return uid_lt(left.uid, right.uid); +	case GRPQUOTA: +		return gid_lt(left.gid, right.gid); +	case PRJQUOTA: +		return projid_lt(left.projid, right.projid); +	default: +		BUG(); +	} +} +EXPORT_SYMBOL(qid_lt); + +/** + *	from_kqid - Create a qid from a kqid user-namespace pair. + *	@targ: The user namespace we want a qid in. + *	@kuid: The kernel internal quota identifier to start with. + * + *	Map @kqid into the user-namespace specified by @targ and + *	return the resulting qid. + * + *	There is always a mapping into the initial user_namespace. + * + *	If @kqid has no mapping in @targ (qid_t)-1 is returned. + */ +qid_t from_kqid(struct user_namespace *targ, struct kqid kqid) +{ +	switch (kqid.type) { +	case USRQUOTA: +		return from_kuid(targ, kqid.uid); +	case GRPQUOTA: +		return from_kgid(targ, kqid.gid); +	case PRJQUOTA: +		return from_kprojid(targ, kqid.projid); +	default: +		BUG(); +	} +} +EXPORT_SYMBOL(from_kqid); + +/** + *	from_kqid_munged - Create a qid from a kqid user-namespace pair. + *	@targ: The user namespace we want a qid in. + *	@kqid: The kernel internal quota identifier to start with. + * + *	Map @kqid into the user-namespace specified by @targ and + *	return the resulting qid. + * + *	There is always a mapping into the initial user_namespace. + * + *	Unlike from_kqid from_kqid_munged never fails and always + *	returns a valid projid.  This makes from_kqid_munged + *	appropriate for use in places where failing to provide + *	a qid_t is not a good option. + * + *	If @kqid has no mapping in @targ the kqid.type specific + *	overflow identifier is returned. + */ +qid_t from_kqid_munged(struct user_namespace *targ, struct kqid kqid) +{ +	switch (kqid.type) { +	case USRQUOTA: +		return from_kuid_munged(targ, kqid.uid); +	case GRPQUOTA: +		return from_kgid_munged(targ, kqid.gid); +	case PRJQUOTA: +		return from_kprojid_munged(targ, kqid.projid); +	default: +		BUG(); +	} +} +EXPORT_SYMBOL(from_kqid_munged); + +/** + *	qid_valid - Report if a valid value is stored in a kqid. + *	@qid: The kernel internal quota identifier to test. + */ +bool qid_valid(struct kqid qid) +{ +	switch (qid.type) { +	case USRQUOTA: +		return uid_valid(qid.uid); +	case GRPQUOTA: +		return gid_valid(qid.gid); +	case PRJQUOTA: +		return projid_valid(qid.projid); +	default: +		BUG(); +	} +} +EXPORT_SYMBOL(qid_valid); diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c index d67908b407d..72d29177998 100644 --- a/fs/quota/netlink.c +++ b/fs/quota/netlink.c @@ -9,13 +9,25 @@  #include <net/netlink.h>  #include <net/genetlink.h> +static const struct genl_multicast_group quota_mcgrps[] = { +	{ .name = "events", }, +}; +  /* Netlink family structure for quota */  static struct genl_family quota_genl_family = { -	.id = GENL_ID_GENERATE, +	/* +	 * Needed due to multicast group ID abuse - old code assumed +	 * the family ID was also a valid multicast group ID (which +	 * isn't true) and userspace might thus rely on it. Assign a +	 * static ID for this group to make dealing with that easier. +	 */ +	.id = GENL_ID_VFS_DQUOT,  	.hdrsize = 0,  	.name = "VFS_DQUOT",  	.version = 1,  	.maxattr = QUOTA_NL_A_MAX, +	.mcgrps = quota_mcgrps, +	.n_mcgrps = ARRAY_SIZE(quota_mcgrps),  };  /** @@ -30,7 +42,7 @@ static struct genl_family quota_genl_family = {   *   */ -void quota_send_warning(short type, unsigned int id, dev_t dev, +void quota_send_warning(struct kqid qid, dev_t dev,  			const char warntype)  {  	static atomic_t seq; @@ -56,10 +68,11 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,  		  "VFS: Cannot store netlink header in quota warning.\n");  		goto err_out;  	} -	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type); +	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, qid.type);  	if (ret)  		goto attr_err_out; -	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id); +	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, +			  from_kqid_munged(&init_user_ns, qid));  	if (ret)  		goto attr_err_out;  	ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); @@ -71,12 +84,13 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,  	ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));  	if (ret)  		goto attr_err_out; -	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid()); +	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, +			  from_kuid_munged(&init_user_ns, current_uid()));  	if (ret)  		goto attr_err_out;  	genlmsg_end(skb, msg_head); -	genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); +	genlmsg_multicast("a_genl_family, skb, 0, 0, GFP_NOFS);  	return;  attr_err_out:  	printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); diff --git a/fs/quota/quota.c b/fs/quota/quota.c index b299961e1ed..ff3f0b3cfdb 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -9,11 +9,10 @@  #include <linux/namei.h>  #include <linux/slab.h>  #include <asm/current.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h>  #include <linux/kernel.h>  #include <linux/security.h>  #include <linux/syscalls.h> -#include <linux/buffer_head.h>  #include <linux/capability.h>  #include <linux/quotaops.h>  #include <linux/types.h> @@ -28,13 +27,14 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,  	case Q_SYNC:  	case Q_GETINFO:  	case Q_XGETQSTAT: +	case Q_XGETQSTATV:  	case Q_XQUOTASYNC:  		break;  	/* allow to query information for dquots we "own" */  	case Q_GETQUOTA:  	case Q_XGETQUOTA: -		if ((type == USRQUOTA && current_euid() == id) || -		    (type == GRPQUOTA && in_egroup_p(id))) +		if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) || +		    (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))  			break;  		/*FALLTHROUGH*/  	default: @@ -48,7 +48,7 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,  static void quota_sync_one(struct super_block *sb, void *arg)  {  	if (sb->s_qcop && sb->s_qcop->quota_sync) -		sb->s_qcop->quota_sync(sb, *(int *)arg, 1); +		sb->s_qcop->quota_sync(sb, *(int *)arg);  }  static int quota_sync_all(int type) @@ -64,18 +64,15 @@ static int quota_sync_all(int type)  }  static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id, -		         void __user *addr) +		         struct path *path)  { -	char *pathname; -	int ret = -ENOSYS; - -	pathname = getname(addr); -	if (IS_ERR(pathname)) -		return PTR_ERR(pathname); -	if (sb->s_qcop->quota_on) -		ret = sb->s_qcop->quota_on(sb, type, id, pathname); -	putname(pathname); -	return ret; +	if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta) +		return -ENOSYS; +	if (sb->s_qcop->quota_on_meta) +		return sb->s_qcop->quota_on_meta(sb, type, id); +	if (IS_ERR(path)) +		return PTR_ERR(path); +	return sb->s_qcop->quota_on(sb, type, id, path);  }  static int quota_getfmt(struct super_block *sb, int type, void __user *addr) @@ -120,6 +117,7 @@ static int quota_setinfo(struct super_block *sb, int type, void __user *addr)  static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)  { +	memset(dst, 0, sizeof(*dst));  	dst->dqb_bhardlimit = src->d_blk_hardlimit;  	dst->dqb_bsoftlimit = src->d_blk_softlimit;  	dst->dqb_curspace = src->d_bcount; @@ -134,13 +132,17 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)  static int quota_getquota(struct super_block *sb, int type, qid_t id,  			  void __user *addr)  { +	struct kqid qid;  	struct fs_disk_quota fdq;  	struct if_dqblk idq;  	int ret;  	if (!sb->s_qcop->get_dqblk)  		return -ENOSYS; -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq); +	qid = make_kqid(current_user_ns(), type, id); +	if (!qid_valid(qid)) +		return -EINVAL; +	ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);  	if (ret)  		return ret;  	copy_to_if_dqblk(&idq, &fdq); @@ -180,13 +182,17 @@ static int quota_setquota(struct super_block *sb, int type, qid_t id,  {  	struct fs_disk_quota fdq;  	struct if_dqblk idq; +	struct kqid qid;  	if (copy_from_user(&idq, addr, sizeof(idq)))  		return -EFAULT;  	if (!sb->s_qcop->set_dqblk)  		return -ENOSYS; +	qid = make_kqid(current_user_ns(), type, id); +	if (!qid_valid(qid)) +		return -EINVAL;  	copy_from_if_dqblk(&fdq, &idq); -	return sb->s_qcop->set_dqblk(sb, type, id, &fdq); +	return sb->s_qcop->set_dqblk(sb, qid, &fdq);  }  static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr) @@ -213,35 +219,79 @@ static int quota_getxstate(struct super_block *sb, void __user *addr)  	return ret;  } +static int quota_getxstatev(struct super_block *sb, void __user *addr) +{ +	struct fs_quota_statv fqs; +	int ret; + +	if (!sb->s_qcop->get_xstatev) +		return -ENOSYS; + +	memset(&fqs, 0, sizeof(fqs)); +	if (copy_from_user(&fqs, addr, 1)) /* Just read qs_version */ +		return -EFAULT; + +	/* If this kernel doesn't support user specified version, fail */ +	switch (fqs.qs_version) { +	case FS_QSTATV_VERSION1: +		break; +	default: +		return -EINVAL; +	} +	ret = sb->s_qcop->get_xstatev(sb, &fqs); +	if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) +		return -EFAULT; +	return ret; +} +  static int quota_setxquota(struct super_block *sb, int type, qid_t id,  			   void __user *addr)  {  	struct fs_disk_quota fdq; +	struct kqid qid;  	if (copy_from_user(&fdq, addr, sizeof(fdq)))  		return -EFAULT;  	if (!sb->s_qcop->set_dqblk)  		return -ENOSYS; -	return sb->s_qcop->set_dqblk(sb, type, id, &fdq); +	qid = make_kqid(current_user_ns(), type, id); +	if (!qid_valid(qid)) +		return -EINVAL; +	return sb->s_qcop->set_dqblk(sb, qid, &fdq);  }  static int quota_getxquota(struct super_block *sb, int type, qid_t id,  			   void __user *addr)  {  	struct fs_disk_quota fdq; +	struct kqid qid;  	int ret;  	if (!sb->s_qcop->get_dqblk)  		return -ENOSYS; -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq); +	qid = make_kqid(current_user_ns(), type, id); +	if (!qid_valid(qid)) +		return -EINVAL; +	ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);  	if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))  		return -EFAULT;  	return ret;  } +static int quota_rmxquota(struct super_block *sb, void __user *addr) +{ +	__u32 flags; + +	if (copy_from_user(&flags, addr, sizeof(flags))) +		return -EFAULT; +	if (!sb->s_qcop->rm_xquota) +		return -ENOSYS; +	return sb->s_qcop->rm_xquota(sb, flags); +} +  /* Copy parameters and call proper function */  static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, -		       void __user *addr) +		       void __user *addr, struct path *path)  {  	int ret; @@ -256,7 +306,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,  	switch (cmd) {  	case Q_QUOTAON: -		return quota_quotaon(sb, type, cmd, id, addr); +		return quota_quotaon(sb, type, cmd, id, path);  	case Q_QUOTAOFF:  		if (!sb->s_qcop->quota_off)  			return -ENOSYS; @@ -274,46 +324,71 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,  	case Q_SYNC:  		if (!sb->s_qcop->quota_sync)  			return -ENOSYS; -		return sb->s_qcop->quota_sync(sb, type, 1); +		return sb->s_qcop->quota_sync(sb, type);  	case Q_XQUOTAON:  	case Q_XQUOTAOFF: -	case Q_XQUOTARM:  		return quota_setxstate(sb, cmd, addr); +	case Q_XQUOTARM: +		return quota_rmxquota(sb, addr);  	case Q_XGETQSTAT:  		return quota_getxstate(sb, addr); +	case Q_XGETQSTATV: +		return quota_getxstatev(sb, addr);  	case Q_XSETQLIM:  		return quota_setxquota(sb, type, id, addr);  	case Q_XGETQUOTA:  		return quota_getxquota(sb, type, id, addr);  	case Q_XQUOTASYNC: -		/* caller already holds s_umount */  		if (sb->s_flags & MS_RDONLY)  			return -EROFS; -		writeback_inodes_sb(sb); +		/* XFS quotas are fully coherent now, making this call a noop */  		return 0;  	default:  		return -EINVAL;  	}  } +#ifdef CONFIG_BLOCK + +/* Return 1 if 'cmd' will block on frozen filesystem */ +static int quotactl_cmd_write(int cmd) +{ +	switch (cmd) { +	case Q_GETFMT: +	case Q_GETINFO: +	case Q_SYNC: +	case Q_XGETQSTAT: +	case Q_XGETQSTATV: +	case Q_XGETQUOTA: +	case Q_XQUOTASYNC: +		return 0; +	} +	return 1; +} + +#endif /* CONFIG_BLOCK */ +  /*   * look up a superblock on which quota ops will be performed   * - use the name of a block device to find the superblock thereon   */ -static struct super_block *quotactl_block(const char __user *special) +static struct super_block *quotactl_block(const char __user *special, int cmd)  {  #ifdef CONFIG_BLOCK  	struct block_device *bdev;  	struct super_block *sb; -	char *tmp = getname(special); +	struct filename *tmp = getname(special);  	if (IS_ERR(tmp))  		return ERR_CAST(tmp); -	bdev = lookup_bdev(tmp); +	bdev = lookup_bdev(tmp->name);  	putname(tmp);  	if (IS_ERR(bdev))  		return ERR_CAST(bdev); -	sb = get_super(bdev); +	if (quotactl_cmd_write(cmd)) +		sb = get_super_thawed(bdev); +	else +		sb = get_super(bdev);  	bdput(bdev);  	if (!sb)  		return ERR_PTR(-ENODEV); @@ -335,6 +410,7 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,  {  	uint cmds, type;  	struct super_block *sb = NULL; +	struct path path, *pathp = NULL;  	int ret;  	cmds = cmd >> SUBCMDSHIFT; @@ -351,12 +427,30 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,  		return -ENODEV;  	} -	sb = quotactl_block(special); -	if (IS_ERR(sb)) -		return PTR_ERR(sb); +	/* +	 * Path for quotaon has to be resolved before grabbing superblock +	 * because that gets s_umount sem which is also possibly needed by path +	 * resolution (think about autofs) and thus deadlocks could arise. +	 */ +	if (cmds == Q_QUOTAON) { +		ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path); +		if (ret) +			pathp = ERR_PTR(ret); +		else +			pathp = &path; +	} + +	sb = quotactl_block(special, cmds); +	if (IS_ERR(sb)) { +		ret = PTR_ERR(sb); +		goto out; +	} -	ret = do_quotactl(sb, type, cmds, id, addr); +	ret = do_quotactl(sb, type, cmds, id, addr, pathp);  	drop_super(sb); +out: +	if (pathp && !IS_ERR(pathp)) +		path_put(pathp);  	return ret;  } diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c index 9e48874eabc..d65877fbe8f 100644 --- a/fs/quota/quota_tree.c +++ b/fs/quota/quota_tree.c @@ -22,9 +22,10 @@ MODULE_LICENSE("GPL");  #define __QUOTA_QT_PARANOIA -static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth) +static int get_index(struct qtree_mem_dqinfo *info, struct kqid qid, int depth)  {  	unsigned int epb = info->dqi_usable_bs >> 2; +	qid_t id = from_kqid(&init_user_ns, qid);  	depth = info->dqi_qtree_depth - depth - 1;  	while (depth--) @@ -244,7 +245,7 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info,  		/* This is enough as the block is already zeroed and the entry  		 * list is empty... */  		info->dqi_free_entry = blk; -		mark_info_dirty(dquot->dq_sb, dquot->dq_type); +		mark_info_dirty(dquot->dq_sb, dquot->dq_id.type);  	}  	/* Block will be full? */  	if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) { @@ -357,7 +358,7 @@ static inline int dq_insert_tree(struct qtree_mem_dqinfo *info,   */  int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)  { -	int type = dquot->dq_type; +	int type = dquot->dq_id.type;  	struct super_block *sb = dquot->dq_sb;  	ssize_t ret;  	char *ddquot = getdqbuf(info->dqi_entry_size); @@ -468,8 +469,8 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,  		return -ENOMEM;  	ret = read_blk(info, *blk, buf);  	if (ret < 0) { -		quota_error(dquot->dq_sb, "Can't read quota data " -			    "block %u", blk); +		quota_error(dquot->dq_sb, "Can't read quota data block %u", +			    *blk);  		goto out_buf;  	}  	newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); @@ -493,8 +494,9 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,  		} else {  			ret = write_blk(info, *blk, buf);  			if (ret < 0) -				quota_error(dquot->dq_sb, "Can't write quota " -					    "tree block %u", blk); +				quota_error(dquot->dq_sb, +					    "Can't write quota tree block %u", +					    *blk);  		}  	}  out_buf: @@ -537,8 +539,9 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,  		ddquot += info->dqi_entry_size;  	}  	if (i == qtree_dqstr_in_blk(info)) { -		quota_error(dquot->dq_sb, "Quota for id %u referenced " -			    "but not present", dquot->dq_id); +		quota_error(dquot->dq_sb, +			    "Quota for id %u referenced but not present", +			    from_kqid(&init_user_ns, dquot->dq_id));  		ret = -EIO;  		goto out_buf;  	} else { @@ -588,7 +591,7 @@ static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info,  int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)  { -	int type = dquot->dq_type; +	int type = dquot->dq_id.type;  	struct super_block *sb = dquot->dq_sb;  	loff_t offset;  	char *ddquot; @@ -606,8 +609,10 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)  		offset = find_dqentry(info, dquot);  		if (offset <= 0) {	/* Entry not present? */  			if (offset < 0) -				quota_error(sb, "Can't read quota structure " -					    "for id %u", dquot->dq_id); +				quota_error(sb,"Can't read quota structure " +					    "for id %u", +					    from_kqid(&init_user_ns, +						      dquot->dq_id));  			dquot->dq_off = 0;  			set_bit(DQ_FAKE_B, &dquot->dq_flags);  			memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); @@ -625,7 +630,7 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)  		if (ret >= 0)  			ret = -EIO;  		quota_error(sb, "Error while reading quota structure for id %u", -			    dquot->dq_id); +			    from_kqid(&init_user_ns, dquot->dq_id));  		set_bit(DQ_FAKE_B, &dquot->dq_flags);  		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));  		kfree(ddquot); diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c index 34b37a67bb1..469c6848b32 100644 --- a/fs/quota/quota_v1.c +++ b/fs/quota/quota_v1.c @@ -54,7 +54,7 @@ static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m)  static int v1_read_dqblk(struct dquot *dquot)  { -	int type = dquot->dq_type; +	int type = dquot->dq_id.type;  	struct v1_disk_dqblk dqblk;  	if (!sb_dqopt(dquot->dq_sb)->files[type]) @@ -63,7 +63,8 @@ static int v1_read_dqblk(struct dquot *dquot)  	/* Set structure to 0s in case read fails/is after end of file */  	memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));  	dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk, -			sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id)); +			sizeof(struct v1_disk_dqblk), +			v1_dqoff(from_kqid(&init_user_ns, dquot->dq_id)));  	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);  	if (dquot->dq_dqb.dqb_bhardlimit == 0 && @@ -78,12 +79,13 @@ static int v1_read_dqblk(struct dquot *dquot)  static int v1_commit_dqblk(struct dquot *dquot)  { -	short type = dquot->dq_type; +	short type = dquot->dq_id.type;  	ssize_t ret;  	struct v1_disk_dqblk dqblk;  	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb); -	if (dquot->dq_id == 0) { +	if (((type == USRQUOTA) && uid_eq(dquot->dq_id.uid, GLOBAL_ROOT_UID)) || +	    ((type == GRPQUOTA) && gid_eq(dquot->dq_id.gid, GLOBAL_ROOT_GID))) {  		dqblk.dqb_btime =  			sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;  		dqblk.dqb_itime = @@ -93,7 +95,7 @@ static int v1_commit_dqblk(struct dquot *dquot)  	if (sb_dqopt(dquot->dq_sb)->files[type])  		ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,  			(char *)&dqblk, sizeof(struct v1_disk_dqblk), -			v1_dqoff(dquot->dq_id)); +			v1_dqoff(from_kqid(&init_user_ns, dquot->dq_id)));  	if (ret != sizeof(struct v1_disk_dqblk)) {  		quota_error(dquot->dq_sb, "dquota write failed");  		if (ret >= 0) diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 65444d29406..02751ec695c 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -112,7 +112,7 @@ static int v2_read_file_info(struct super_block *sb, int type)  	if (!info->dqi_priv) {  		printk(KERN_WARNING  		       "Not enough memory for quota information structure.\n"); -		return -1; +		return -ENOMEM;  	}  	qinfo = info->dqi_priv;  	if (version == 0) { @@ -196,7 +196,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)  	struct v2r0_disk_dqblk *d = dp;  	struct mem_dqblk *m = &dquot->dq_dqb;  	struct qtree_mem_dqinfo *info = -			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; +			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;  	d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);  	d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit); @@ -206,7 +206,7 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)  	d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));  	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);  	d->dqb_btime = cpu_to_le64(m->dqb_btime); -	d->dqb_id = cpu_to_le32(dquot->dq_id); +	d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));  	if (qtree_entry_unused(info, dp))  		d->dqb_itime = cpu_to_le64(1);  } @@ -215,11 +215,13 @@ static int v2r0_is_id(void *dp, struct dquot *dquot)  {  	struct v2r0_disk_dqblk *d = dp;  	struct qtree_mem_dqinfo *info = -			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; +			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;  	if (qtree_entry_unused(info, dp))  		return 0; -	return le32_to_cpu(d->dqb_id) == dquot->dq_id; +	return qid_eq(make_kqid(&init_user_ns, dquot->dq_id.type, +				le32_to_cpu(d->dqb_id)), +		      dquot->dq_id);  }  static void v2r1_disk2memdqb(struct dquot *dquot, void *dp) @@ -247,7 +249,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)  	struct v2r1_disk_dqblk *d = dp;  	struct mem_dqblk *m = &dquot->dq_dqb;  	struct qtree_mem_dqinfo *info = -			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; +			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;  	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);  	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit); @@ -257,7 +259,7 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)  	d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));  	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);  	d->dqb_btime = cpu_to_le64(m->dqb_btime); -	d->dqb_id = cpu_to_le32(dquot->dq_id); +	d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));  	if (qtree_entry_unused(info, dp))  		d->dqb_itime = cpu_to_le64(1);  } @@ -266,26 +268,28 @@ static int v2r1_is_id(void *dp, struct dquot *dquot)  {  	struct v2r1_disk_dqblk *d = dp;  	struct qtree_mem_dqinfo *info = -			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; +			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;  	if (qtree_entry_unused(info, dp))  		return 0; -	return le32_to_cpu(d->dqb_id) == dquot->dq_id; +	return qid_eq(make_kqid(&init_user_ns, dquot->dq_id.type, +				le32_to_cpu(d->dqb_id)), +		      dquot->dq_id);  }  static int v2_read_dquot(struct dquot *dquot)  { -	return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot); +	return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);  }  static int v2_write_dquot(struct dquot *dquot)  { -	return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot); +	return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);  }  static int v2_release_dquot(struct dquot *dquot)  { -	return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot); +	return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);  }  static int v2_free_file_info(struct super_block *sb, int type)  | 
