Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 319108
b: refs/heads/master
c: 7c319d3
h: refs/heads/master
v: v3
  • Loading branch information
Aditya Kali authored and Theodore Ts'o committed Jul 23, 2012
1 parent d30b86f commit 656060d
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 11 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4bd809dbbf177ad0c450d702466b1da63e1b4b7e
refs/heads/master: 7c319d328505b7781b65238ae9f53293b5ee0ca8
5 changes: 4 additions & 1 deletion trunk/fs/ext4/ext4.h
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,8 @@ static inline struct timespec ext4_current_time(struct inode *inode)
static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
{
return ino == EXT4_ROOT_INO ||
ino == EXT4_USR_QUOTA_INO ||
ino == EXT4_GRP_QUOTA_INO ||
ino == EXT4_JOURNAL_INO ||
ino == EXT4_RESIZE_INO ||
(ino >= EXT4_FIRST_INO(sb) &&
Expand Down Expand Up @@ -1497,7 +1499,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\
EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\
EXT4_FEATURE_RO_COMPAT_BIGALLOC |\
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\
EXT4_FEATURE_RO_COMPAT_QUOTA)

/*
* Default values for user and/or group using reserved blocks
Expand Down
18 changes: 12 additions & 6 deletions trunk/fs/ext4/ext4_jbd2.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,20 @@
#ifdef CONFIG_QUOTA
/* Amount of blocks needed for quota update - we know that the structure was
* allocated so we need to update only data block */
#define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 1 : 0)
#define EXT4_QUOTA_TRANS_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\
EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\
1 : 0)
/* Amount of blocks needed for quota insert/delete - we do some block writes
* but inode, sb and group updates are done only once */
#define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\
(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_INIT_REWRITE) : 0)

#define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\
(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_DEL_REWRITE) : 0)
#define EXT4_QUOTA_INIT_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\
EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\
(DQUOT_INIT_ALLOC*(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)\
+3+DQUOT_INIT_REWRITE) : 0)

#define EXT4_QUOTA_DEL_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\
EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\
(DQUOT_DEL_ALLOC*(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)\
+3+DQUOT_DEL_REWRITE) : 0)
#else
#define EXT4_QUOTA_TRANS_BLOCKS(sb) 0
#define EXT4_QUOTA_INIT_BLOCKS(sb) 0
Expand Down
137 changes: 134 additions & 3 deletions trunk/fs/ext4/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -1137,12 +1137,18 @@ static int ext4_mark_dquot_dirty(struct dquot *dquot);
static int ext4_write_info(struct super_block *sb, int type);
static int ext4_quota_on(struct super_block *sb, int type, int format_id,
struct path *path);
static int ext4_quota_on_sysfile(struct super_block *sb, int type,
int format_id);
static int ext4_quota_off(struct super_block *sb, int type);
static int ext4_quota_off_sysfile(struct super_block *sb, int type);
static int ext4_quota_on_mount(struct super_block *sb, int type);
static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
size_t len, loff_t off);
static ssize_t ext4_quota_write(struct super_block *sb, int type,
const char *data, size_t len, loff_t off);
static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
unsigned int flags);
static int ext4_enable_quotas(struct super_block *sb);

static const struct dquot_operations ext4_quota_operations = {
.get_reserved_space = ext4_get_reserved_space,
Expand All @@ -1164,6 +1170,16 @@ static const struct quotactl_ops ext4_qctl_operations = {
.get_dqblk = dquot_get_dqblk,
.set_dqblk = dquot_set_dqblk
};

static const struct quotactl_ops ext4_qctl_sysfile_operations = {
.quota_on_meta = ext4_quota_on_sysfile,
.quota_off = ext4_quota_off_sysfile,
.quota_sync = dquot_quota_sync,
.get_info = dquot_get_dqinfo,
.set_info = dquot_set_dqinfo,
.get_dqblk = dquot_get_dqblk,
.set_dqblk = dquot_set_dqblk
};
#endif

static const struct super_operations ext4_sops = {
Expand Down Expand Up @@ -2661,6 +2677,16 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
"extents feature\n");
return 0;
}

#ifndef CONFIG_QUOTA
if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
!readonly) {
ext4_msg(sb, KERN_ERR,
"Filesystem with quota feature cannot be mounted RDWR "
"without CONFIG_QUOTA");
return 0;
}
#endif /* CONFIG_QUOTA */
return 1;
}

Expand Down Expand Up @@ -3748,6 +3774,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
#ifdef CONFIG_QUOTA
sb->s_qcop = &ext4_qctl_operations;
sb->dq_op = &ext4_quota_operations;

if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) {
/* Use qctl operations for hidden quota files. */
sb->s_qcop = &ext4_qctl_sysfile_operations;
}
#endif
memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));

Expand Down Expand Up @@ -3960,6 +3991,16 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
} else
descr = "out journal";

#ifdef CONFIG_QUOTA
/* Enable quota usage during mount. */
if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
!(sb->s_flags & MS_RDONLY)) {
ret = ext4_enable_quotas(sb);
if (ret)
goto failed_mount7;
}
#endif /* CONFIG_QUOTA */

ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
"Opts: %s%s%s", descr, sbi->s_es->s_mount_opts,
*sbi->s_es->s_mount_opts ? "; " : "", orig_data);
Expand Down Expand Up @@ -4682,16 +4723,26 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
if (sbi->s_journal == NULL)
ext4_commit_super(sb, 1);

unlock_super(sb);
#ifdef CONFIG_QUOTA
/* Release old quota file names */
for (i = 0; i < MAXQUOTAS; i++)
if (old_opts.s_qf_names[i] &&
old_opts.s_qf_names[i] != sbi->s_qf_names[i])
kfree(old_opts.s_qf_names[i]);
if (enable_quota) {
if (sb_any_quota_suspended(sb))
dquot_resume(sb, -1);
else if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_QUOTA)) {
err = ext4_enable_quotas(sb);
if (err) {
lock_super(sb);
goto restore_opts;
}
}
}
#endif
unlock_super(sb);
if (enable_quota)
dquot_resume(sb, -1);

ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data);
kfree(orig_data);
Expand Down Expand Up @@ -4904,6 +4955,74 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
return dquot_quota_on(sb, type, format_id, path);
}

static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
unsigned int flags)
{
int err;
struct inode *qf_inode;
unsigned long qf_inums[MAXQUOTAS] = {
le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
};

BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA));

if (!qf_inums[type])
return -EPERM;

qf_inode = ext4_iget(sb, qf_inums[type]);
if (IS_ERR(qf_inode)) {
ext4_error(sb, "Bad quota inode # %lu", qf_inums[type]);
return PTR_ERR(qf_inode);
}

err = dquot_enable(qf_inode, type, format_id, flags);
iput(qf_inode);

return err;
}

/* Enable usage tracking for all quota types. */
static int ext4_enable_quotas(struct super_block *sb)
{
int type, err = 0;
unsigned long qf_inums[MAXQUOTAS] = {
le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
};

sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
for (type = 0; type < MAXQUOTAS; type++) {
if (qf_inums[type]) {
err = ext4_quota_enable(sb, type, QFMT_VFS_V1,
DQUOT_USAGE_ENABLED);
if (err) {
ext4_warning(sb,
"Failed to enable quota (type=%d) "
"tracking. Please run e2fsck to fix.",
type);
return err;
}
}
}
return 0;
}

/*
* quota_on function that is used when QUOTA feature is set.
*/
static int ext4_quota_on_sysfile(struct super_block *sb, int type,
int format_id)
{
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA))
return -EINVAL;

/*
* USAGE was enabled at mount time. Only need to enable LIMITS now.
*/
return ext4_quota_enable(sb, type, format_id, DQUOT_LIMITS_ENABLED);
}

static int ext4_quota_off(struct super_block *sb, int type)
{
struct inode *inode = sb_dqopt(sb)->files[type];
Expand All @@ -4930,6 +5049,18 @@ static int ext4_quota_off(struct super_block *sb, int type)
return dquot_quota_off(sb, type);
}

/*
* quota_off function that is used when QUOTA feature is set.
*/
static int ext4_quota_off_sysfile(struct super_block *sb, int type)
{
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA))
return -EINVAL;

/* Disable only the limits. */
return dquot_disable(sb, type, DQUOT_LIMITS_ENABLED);
}

/* Read data from quotafile - avoid pagecache and such because we cannot afford
* acquiring the locks... As quota files are never truncated and quota code
* itself serializes the operations (and no one else should touch the files)
Expand Down

0 comments on commit 656060d

Please sign in to comment.