mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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
					
				
					 2 changed files with 61 additions and 6 deletions
				
			
		| 
						 | 
					@ -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 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 | 
				
			||||||
	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 a new issue