ext4: add project quota support
This patch adds mount options for enabling/disabling project quota accounting and enforcement. A new specific inode is also used for project quota accounting. [ Includes fix from Dan Carpenter to crrect error checking from dqget(). ] Signed-off-by: Li Xi <lixi@ddn.com> Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Reviewed-by: Andreas Dilger <adilger@dilger.ca> Reviewed-by: Jan Kara <jack@suse.cz>
This commit is contained in:
		
							parent
							
								
									040cb3786d
								
							
						
					
					
						commit
						689c958cbe
					
				| @ -1261,7 +1261,7 @@ struct ext4_super_block { | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /* Number of quota types we support */ | /* Number of quota types we support */ | ||||||
| #define EXT4_MAXQUOTAS 2 | #define EXT4_MAXQUOTAS 3 | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * fourth extended-fs super-block data in memory |  * fourth extended-fs super-block data in memory | ||||||
|  | |||||||
| @ -1097,8 +1097,8 @@ static int bdev_try_to_free_page(struct super_block *sb, struct page *page, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_QUOTA | #ifdef CONFIG_QUOTA | ||||||
| #define QTYPE2NAME(t) ((t) == USRQUOTA ? "user" : "group") | static char *quotatypes[] = INITQFNAMES; | ||||||
| #define QTYPE2MOPT(on, t) ((t) == USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA)) | #define QTYPE2NAME(t) (quotatypes[t]) | ||||||
| 
 | 
 | ||||||
| static int ext4_write_dquot(struct dquot *dquot); | static int ext4_write_dquot(struct dquot *dquot); | ||||||
| static int ext4_acquire_dquot(struct dquot *dquot); | static int ext4_acquire_dquot(struct dquot *dquot); | ||||||
| @ -2558,6 +2558,12 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly) | |||||||
| 			 "without CONFIG_QUOTA"); | 			 "without CONFIG_QUOTA"); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
|  | 	if (ext4_has_feature_project(sb) && !readonly) { | ||||||
|  | 		ext4_msg(sb, KERN_ERR, | ||||||
|  | 			 "Filesystem with project quota feature cannot be mounted RDWR " | ||||||
|  | 			 "without CONFIG_QUOTA"); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
| #endif  /* CONFIG_QUOTA */ | #endif  /* CONFIG_QUOTA */ | ||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
| @ -3686,7 +3692,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||||||
| 		sb->s_qcop = &dquot_quotactl_sysfile_ops; | 		sb->s_qcop = &dquot_quotactl_sysfile_ops; | ||||||
| 	else | 	else | ||||||
| 		sb->s_qcop = &ext4_qctl_operations; | 		sb->s_qcop = &ext4_qctl_operations; | ||||||
| 	sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP; | 	sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ; | ||||||
| #endif | #endif | ||||||
| 	memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid)); | 	memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid)); | ||||||
| 
 | 
 | ||||||
| @ -4822,6 +4828,48 @@ restore_opts: | |||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_QUOTA | ||||||
|  | static int ext4_statfs_project(struct super_block *sb, | ||||||
|  | 			       kprojid_t projid, struct kstatfs *buf) | ||||||
|  | { | ||||||
|  | 	struct kqid qid; | ||||||
|  | 	struct dquot *dquot; | ||||||
|  | 	u64 limit; | ||||||
|  | 	u64 curblock; | ||||||
|  | 
 | ||||||
|  | 	qid = make_kqid_projid(projid); | ||||||
|  | 	dquot = dqget(sb, qid); | ||||||
|  | 	if (IS_ERR(dquot)) | ||||||
|  | 		return PTR_ERR(dquot); | ||||||
|  | 	spin_lock(&dq_data_lock); | ||||||
|  | 
 | ||||||
|  | 	limit = (dquot->dq_dqb.dqb_bsoftlimit ? | ||||||
|  | 		 dquot->dq_dqb.dqb_bsoftlimit : | ||||||
|  | 		 dquot->dq_dqb.dqb_bhardlimit) >> sb->s_blocksize_bits; | ||||||
|  | 	if (limit && buf->f_blocks > limit) { | ||||||
|  | 		curblock = dquot->dq_dqb.dqb_curspace >> sb->s_blocksize_bits; | ||||||
|  | 		buf->f_blocks = limit; | ||||||
|  | 		buf->f_bfree = buf->f_bavail = | ||||||
|  | 			(buf->f_blocks > curblock) ? | ||||||
|  | 			 (buf->f_blocks - curblock) : 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	limit = dquot->dq_dqb.dqb_isoftlimit ? | ||||||
|  | 		dquot->dq_dqb.dqb_isoftlimit : | ||||||
|  | 		dquot->dq_dqb.dqb_ihardlimit; | ||||||
|  | 	if (limit && buf->f_files > limit) { | ||||||
|  | 		buf->f_files = limit; | ||||||
|  | 		buf->f_ffree = | ||||||
|  | 			(buf->f_files > dquot->dq_dqb.dqb_curinodes) ? | ||||||
|  | 			 (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	spin_unlock(&dq_data_lock); | ||||||
|  | 	dqput(dquot); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) | static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) | ||||||
| { | { | ||||||
| 	struct super_block *sb = dentry->d_sb; | 	struct super_block *sb = dentry->d_sb; | ||||||
| @ -4854,6 +4902,11 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) | |||||||
| 	buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; | 	buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; | ||||||
| 	buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; | 	buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_QUOTA | ||||||
|  | 	if (ext4_test_inode_flag(dentry->d_inode, EXT4_INODE_PROJINHERIT) && | ||||||
|  | 	    sb_has_quota_limits_enabled(sb, PRJQUOTA)) | ||||||
|  | 		ext4_statfs_project(sb, EXT4_I(dentry->d_inode)->i_projid, buf); | ||||||
|  | #endif | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -5018,7 +5071,8 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id, | |||||||
| 	struct inode *qf_inode; | 	struct inode *qf_inode; | ||||||
| 	unsigned long qf_inums[EXT4_MAXQUOTAS] = { | 	unsigned long qf_inums[EXT4_MAXQUOTAS] = { | ||||||
| 		le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), | 		le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), | ||||||
| 		le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum) | 		le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum), | ||||||
|  | 		le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum) | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	BUG_ON(!ext4_has_feature_quota(sb)); | 	BUG_ON(!ext4_has_feature_quota(sb)); | ||||||
| @ -5046,7 +5100,8 @@ static int ext4_enable_quotas(struct super_block *sb) | |||||||
| 	int type, err = 0; | 	int type, err = 0; | ||||||
| 	unsigned long qf_inums[EXT4_MAXQUOTAS] = { | 	unsigned long qf_inums[EXT4_MAXQUOTAS] = { | ||||||
| 		le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), | 		le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), | ||||||
| 		le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum) | 		le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum), | ||||||
|  | 		le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum) | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; | 	sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user