* [PATCH 1/2] f2fs: add quota_ino feature infra
@ 2017-10-31 3:40 Jaegeuk Kim
2017-10-31 3:40 ` [PATCH 2/2] f2fs: support quota sys files Jaegeuk Kim
2017-11-02 14:25 ` [f2fs-dev] [PATCH 1/2] f2fs: add quota_ino feature infra Chao Yu
0 siblings, 2 replies; 7+ messages in thread
From: Jaegeuk Kim @ 2017-10-31 3:40 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, linux-f2fs-devel; +Cc: Jaegeuk Kim
This patch adds quota_ino feature infra to be used for quota files.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fs/f2fs/f2fs.h | 6 ++++++
fs/f2fs/sysfs.c | 7 +++++++
include/linux/f2fs_fs.h | 6 +++++-
3 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 4a75f07f1dc8..9a1c7ffa6845 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -122,6 +122,7 @@ struct f2fs_mount_info {
#define F2FS_FEATURE_PRJQUOTA 0x0010
#define F2FS_FEATURE_INODE_CHKSUM 0x0020
#define F2FS_FEATURE_FLEXIBLE_INLINE_XATTR 0x0040
+#define F2FS_FEATURE_QUOTA_INO 0x0080
#define F2FS_HAS_FEATURE(sb, mask) \
((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0)
@@ -3070,6 +3071,11 @@ static inline int f2fs_sb_has_flexible_inline_xattr(struct super_block *sb)
return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_FLEXIBLE_INLINE_XATTR);
}
+static inline int f2fs_sb_has_quota_ino(struct super_block *sb)
+{
+ return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_QUOTA_INO);
+}
+
#ifdef CONFIG_BLK_DEV_ZONED
static inline int get_blkz_type(struct f2fs_sb_info *sbi,
struct block_device *bdev, block_t blkaddr)
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index f0fdc89ce82f..9835348b6e5d 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -110,6 +110,9 @@ static ssize_t features_show(struct f2fs_attr *a,
if (f2fs_sb_has_flexible_inline_xattr(sb))
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
len ? ", " : "", "flexible_inline_xattr");
+ if (f2fs_sb_has_quota_ino(sb))
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
+ len ? ", " : "", "quota_ino");
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
return len;
}
@@ -227,6 +230,7 @@ enum feat_id {
FEAT_PROJECT_QUOTA,
FEAT_INODE_CHECKSUM,
FEAT_FLEXIBLE_INLINE_XATTR,
+ FEAT_QUOTA_INO,
};
static ssize_t f2fs_feature_show(struct f2fs_attr *a,
@@ -240,6 +244,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a,
case FEAT_PROJECT_QUOTA:
case FEAT_INODE_CHECKSUM:
case FEAT_FLEXIBLE_INLINE_XATTR:
+ case FEAT_QUOTA_INO:
return snprintf(buf, PAGE_SIZE, "supported\n");
}
return 0;
@@ -314,6 +319,7 @@ F2FS_FEATURE_RO_ATTR(extra_attr, FEAT_EXTRA_ATTR);
F2FS_FEATURE_RO_ATTR(project_quota, FEAT_PROJECT_QUOTA);
F2FS_FEATURE_RO_ATTR(inode_checksum, FEAT_INODE_CHECKSUM);
F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR);
+F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO);
#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
static struct attribute *f2fs_attrs[] = {
@@ -364,6 +370,7 @@ static struct attribute *f2fs_feat_attrs[] = {
ATTR_LIST(project_quota),
ATTR_LIST(inode_checksum),
ATTR_LIST(flexible_inline_xattr),
+ ATTR_LIST(quota_ino),
NULL,
};
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index 50a8ee501bf1..ce34007972c3 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -36,6 +36,9 @@
#define F2FS_NODE_INO(sbi) ((sbi)->node_ino_num)
#define F2FS_META_INO(sbi) ((sbi)->meta_ino_num)
+#define F2FS_QUOTA_INO 3
+#define F2FS_MAX_QUOTAS 3
+
#define F2FS_IO_SIZE(sbi) (1 << (sbi)->write_io_size_bits) /* Blocks */
#define F2FS_IO_SIZE_KB(sbi) (1 << ((sbi)->write_io_size_bits + 2)) /* KB */
#define F2FS_IO_SIZE_BYTES(sbi) (1 << ((sbi)->write_io_size_bits + 12)) /* B */
@@ -108,7 +111,8 @@ struct f2fs_super_block {
__u8 encryption_level; /* versioning level for encryption */
__u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */
struct f2fs_device devs[MAX_DEVICES]; /* device list */
- __u8 reserved[327]; /* valid reserved region */
+ __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
+ __u8 reserved[315]; /* valid reserved region */
} __packed;
/*
--
2.14.0.rc1.383.gd1ce394fe2-goog
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/2] f2fs: support quota sys files
2017-10-31 3:40 [PATCH 1/2] f2fs: add quota_ino feature infra Jaegeuk Kim
@ 2017-10-31 3:40 ` Jaegeuk Kim
2017-11-02 14:45 ` [f2fs-dev] " Chao Yu
2017-11-02 14:25 ` [f2fs-dev] [PATCH 1/2] f2fs: add quota_ino feature infra Chao Yu
1 sibling, 1 reply; 7+ messages in thread
From: Jaegeuk Kim @ 2017-10-31 3:40 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, linux-f2fs-devel; +Cc: Jaegeuk Kim
This patch supports hidden quota files in the system, which will be used for
Android. It requires up-to-date f2fs-tools later than v1.9.0.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fs/f2fs/checkpoint.c | 9 +++-
fs/f2fs/f2fs.h | 9 +++-
fs/f2fs/recovery.c | 8 ++-
fs/f2fs/super.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++-----
4 files changed, 153 insertions(+), 18 deletions(-)
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 6b52d4b66c7b..78e1b2998bbd 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -615,6 +615,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
block_t start_blk, orphan_blocks, i, j;
unsigned int s_flags = sbi->sb->s_flags;
int err = 0;
+#ifdef CONFIG_QUOTA
+ int quota_enabled;
+#endif
if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
return 0;
@@ -627,8 +630,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
#ifdef CONFIG_QUOTA
/* Needed for iput() to work correctly and not trash data */
sbi->sb->s_flags |= MS_ACTIVE;
+
/* Turn on quotas so that they are updated correctly */
- f2fs_enable_quota_files(sbi);
+ quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
#endif
start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
@@ -656,7 +660,8 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
out:
#ifdef CONFIG_QUOTA
/* Turn quotas off */
- f2fs_quota_off_umount(sbi->sb);
+ if (quota_enabled)
+ f2fs_quota_off_umount(sbi->sb);
#endif
sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 9a1c7ffa6845..e1d3a940d9f8 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1384,6 +1384,13 @@ static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp)
return le64_to_cpu(cp->checkpoint_ver);
}
+static inline unsigned long f2fs_qf_ino(struct super_block *sb, int type)
+{
+ if (type < F2FS_QUOTA_INO)
+ return le32_to_cpu(F2FS_SB(sb)->raw_super->qf_ino[type]);
+ return 0;
+}
+
static inline __u64 cur_cp_crc(struct f2fs_checkpoint *cp)
{
size_t crc_offset = le32_to_cpu(cp->checksum_offset);
@@ -2526,7 +2533,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
*/
int f2fs_inode_dirtied(struct inode *inode, bool sync);
void f2fs_inode_synced(struct inode *inode);
-void f2fs_enable_quota_files(struct f2fs_sb_info *sbi);
+int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly);
void f2fs_quota_off_umount(struct super_block *sb);
int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover);
int f2fs_sync_fs(struct super_block *sb, int sync);
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 9626758bc762..92c57ace1939 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -594,6 +594,9 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
int ret = 0;
unsigned long s_flags = sbi->sb->s_flags;
bool need_writecp = false;
+#ifdef CONFIG_QUOTA
+ int quota_enabled;
+#endif
if (s_flags & MS_RDONLY) {
f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs");
@@ -604,7 +607,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
/* Needed for iput() to work correctly and not trash data */
sbi->sb->s_flags |= MS_ACTIVE;
/* Turn on quotas so that they are updated correctly */
- f2fs_enable_quota_files(sbi);
+ quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
#endif
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
@@ -665,7 +668,8 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
out:
#ifdef CONFIG_QUOTA
/* Turn quotas off */
- f2fs_quota_off_umount(sbi->sb);
+ if (quota_enabled)
+ f2fs_quota_off_umount(sbi->sb);
#endif
sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 96e145c34ba2..0ca7b055e4e0 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -213,6 +213,12 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype,
"quota options when quota turned on");
return -EINVAL;
}
+ if (f2fs_sb_has_quota_ino(sb)) {
+ f2fs_msg(sb, KERN_INFO,
+ "QUOTA feature is enabled, so ignore qf_name");
+ return 0;
+ }
+
qname = match_strdup(args);
if (!qname) {
f2fs_msg(sb, KERN_ERR,
@@ -291,6 +297,18 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
return -1;
}
}
+
+ if (f2fs_sb_has_quota_ino(sbi->sb) && sbi->s_jquota_fmt) {
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "QUOTA feature is enabled, so ignore jquota_fmt");
+ sbi->s_jquota_fmt = 0;
+ }
+ if (f2fs_sb_has_quota_ino(sbi->sb) && sb_rdonly(sbi->sb)) {
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "Filesystem with quota feature cannot be mounted RDWR "
+ "without CONFIG_QUOTA");
+ return -1;
+ }
return 0;
}
#endif
@@ -1172,6 +1190,7 @@ static void default_options(struct f2fs_sb_info *sbi)
#endif
}
+static int f2fs_enable_quotas(struct super_block *sb);
static int f2fs_remount(struct super_block *sb, int *flags, char *data)
{
struct f2fs_sb_info *sbi = F2FS_SB(sb);
@@ -1238,6 +1257,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
if (f2fs_readonly(sb) && (*flags & MS_RDONLY))
goto skip;
+#ifdef CONFIG_QUOTA
if (!f2fs_readonly(sb) && (*flags & MS_RDONLY)) {
err = dquot_suspend(sb, -1);
if (err < 0)
@@ -1245,9 +1265,15 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
} else {
/* dquot_resume needs RW */
sb->s_flags &= ~MS_RDONLY;
- dquot_resume(sb, -1);
+ if (sb_any_quota_suspended(sb)) {
+ dquot_resume(sb, -1);
+ } else if (f2fs_sb_has_quota_ino(sb)) {
+ err = f2fs_enable_quotas(sb);
+ if (err)
+ goto restore_opts;
+ }
}
-
+#endif
/* disallow enable/disable extent_cache dynamically */
if (no_extent_cache == !!test_opt(sbi, EXTENT_CACHE)) {
err = -EINVAL;
@@ -1454,19 +1480,91 @@ static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type)
sbi->s_jquota_fmt, type);
}
-void f2fs_enable_quota_files(struct f2fs_sb_info *sbi)
+int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly)
{
- int i, ret;
+ int enabled = 0;
+ int i, err;
+
+ if (f2fs_sb_has_quota_ino(sbi->sb) && rdonly) {
+ err = f2fs_enable_quotas(sbi->sb);
+ if (err) {
+ f2fs_msg(sbi->sb, KERN_ERR,
+ "Cannot turn on quota_ino: %d", err);
+ return 0;
+ }
+ return 1;
+ }
for (i = 0; i < MAXQUOTAS; i++) {
if (sbi->s_qf_names[i]) {
- ret = f2fs_quota_on_mount(sbi, i);
- if (ret < 0)
- f2fs_msg(sbi->sb, KERN_ERR,
- "Cannot turn on journaled "
- "quota: error %d", ret);
+ err = f2fs_quota_on_mount(sbi, i);
+ if (!err) {
+ enabled = 1;
+ continue;
+ }
+ f2fs_msg(sbi->sb, KERN_ERR,
+ "Cannot turn on quotas: %d on %d", err, i);
+ }
+ }
+ return enabled;
+}
+
+static int f2fs_quota_enable(struct super_block *sb, int type, int format_id,
+ unsigned int flags)
+{
+ struct inode *qf_inode;
+ unsigned long qf_inum;
+ int err;
+
+ BUG_ON(!f2fs_sb_has_quota_ino(sb));
+
+ qf_inum = f2fs_qf_ino(sb, type);
+ if (!qf_inum)
+ return -EPERM;
+
+ qf_inode = f2fs_iget(sb, qf_inum);
+ if (IS_ERR(qf_inode)) {
+ f2fs_msg(sb, KERN_ERR,
+ "Bad quota inode %u:%lu", type, qf_inum);
+ return PTR_ERR(qf_inode);
+ }
+
+ /* Don't account quota for quota files to avoid recursion */
+ qf_inode->i_flags |= S_NOQUOTA;
+ err = dquot_enable(qf_inode, type, format_id, flags);
+ iput(qf_inode);
+ return err;
+}
+
+static int f2fs_enable_quotas(struct super_block *sb)
+{
+ int type, err = 0;
+ unsigned long qf_inum;
+ bool quota_mopt[MAXQUOTAS] = {
+ test_opt(F2FS_SB(sb), USRQUOTA),
+ test_opt(F2FS_SB(sb), GRPQUOTA),
+ test_opt(F2FS_SB(sb), PRJQUOTA),
+ };
+
+ sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NOLIST_DIRTY;
+ for (type = 0; type < MAXQUOTAS; type++) {
+ qf_inum = f2fs_qf_ino(sb, type);
+ if (qf_inum) {
+ err = f2fs_quota_enable(sb, type, QFMT_VFS_V1,
+ DQUOT_USAGE_ENABLED |
+ (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0));
+ if (err) {
+ f2fs_msg(sb, KERN_ERR,
+ "Failed to enable quota tracking "
+ "(type=%d, err=%d). Please run "
+ "fsck to fix.", type, err);
+ for (type--; type >= 0; type--)
+ dquot_quota_off(sb, type);
+ return err;
+ }
}
}
+ return 0;
}
static int f2fs_quota_sync(struct super_block *sb, int type)
@@ -1537,7 +1635,7 @@ static int f2fs_quota_off(struct super_block *sb, int type)
f2fs_quota_sync(sb, type);
err = dquot_quota_off(sb, type);
- if (err)
+ if (err || f2fs_sb_has_quota_ino(sb))
goto out_put;
inode_lock(inode);
@@ -2364,7 +2462,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
#ifdef CONFIG_QUOTA
sb->dq_op = &f2fs_quota_operations;
- sb->s_qcop = &f2fs_quotactl_ops;
+ if (f2fs_sb_has_quota_ino(sb))
+ sb->s_qcop = &dquot_quotactl_sysfile_ops;
+ else
+ sb->s_qcop = &f2fs_quotactl_ops;
sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
#endif
@@ -2535,10 +2636,24 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
if (err)
goto free_root_inode;
+#ifdef CONFIG_QUOTA
+ /*
+ * Turn on quotas which were not enabled for read-only mounts if
+ * filesystem has quota feature, so that they are updated correctly.
+ */
+ if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) {
+ err = f2fs_enable_quotas(sb);
+ if (err) {
+ f2fs_msg(sb, KERN_ERR,
+ "Cannot turn on quotas: error %d", err);
+ goto free_sysfs;
+ }
+ }
+#endif
/* if there are nt orphan nodes free them */
err = recover_orphan_inodes(sbi);
if (err)
- goto free_sysfs;
+ goto free_meta;
/* recover fsynced data */
if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
@@ -2572,7 +2687,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
err = -EINVAL;
f2fs_msg(sb, KERN_ERR,
"Need to recover fsync data");
- goto free_sysfs;
+ goto free_meta;
}
}
skip_recovery:
@@ -2606,6 +2721,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
return 0;
free_meta:
+#ifdef CONFIG_QUOTA
+ if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb))
+ f2fs_quota_off_umount(sbi->sb);
+#endif
f2fs_sync_inode_meta(sbi);
/*
* Some dirty meta pages can be produced by recover_orphan_inodes()
--
2.14.0.rc1.383.gd1ce394fe2-goog
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [f2fs-dev] [PATCH 1/2] f2fs: add quota_ino feature infra
2017-10-31 3:40 [PATCH 1/2] f2fs: add quota_ino feature infra Jaegeuk Kim
2017-10-31 3:40 ` [PATCH 2/2] f2fs: support quota sys files Jaegeuk Kim
@ 2017-11-02 14:25 ` Chao Yu
1 sibling, 0 replies; 7+ messages in thread
From: Chao Yu @ 2017-11-02 14:25 UTC (permalink / raw)
To: Jaegeuk Kim, linux-kernel, linux-fsdevel, linux-f2fs-devel
On 2017/10/31 11:40, Jaegeuk Kim wrote:
> This patch adds quota_ino feature infra to be used for quota files.
>
> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
> ---
> fs/f2fs/f2fs.h | 6 ++++++
> fs/f2fs/sysfs.c | 7 +++++++
> include/linux/f2fs_fs.h | 6 +++++-
> 3 files changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 4a75f07f1dc8..9a1c7ffa6845 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -122,6 +122,7 @@ struct f2fs_mount_info {
> #define F2FS_FEATURE_PRJQUOTA 0x0010
> #define F2FS_FEATURE_INODE_CHKSUM 0x0020
> #define F2FS_FEATURE_FLEXIBLE_INLINE_XATTR 0x0040
> +#define F2FS_FEATURE_QUOTA_INO 0x0080
>
> #define F2FS_HAS_FEATURE(sb, mask) \
> ((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0)
> @@ -3070,6 +3071,11 @@ static inline int f2fs_sb_has_flexible_inline_xattr(struct super_block *sb)
> return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_FLEXIBLE_INLINE_XATTR);
> }
>
> +static inline int f2fs_sb_has_quota_ino(struct super_block *sb)
> +{
> + return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_QUOTA_INO);
> +}
> +
> #ifdef CONFIG_BLK_DEV_ZONED
> static inline int get_blkz_type(struct f2fs_sb_info *sbi,
> struct block_device *bdev, block_t blkaddr)
> diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
> index f0fdc89ce82f..9835348b6e5d 100644
> --- a/fs/f2fs/sysfs.c
> +++ b/fs/f2fs/sysfs.c
> @@ -110,6 +110,9 @@ static ssize_t features_show(struct f2fs_attr *a,
> if (f2fs_sb_has_flexible_inline_xattr(sb))
> len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
> len ? ", " : "", "flexible_inline_xattr");
> + if (f2fs_sb_has_quota_ino(sb))
> + len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
> + len ? ", " : "", "quota_ino");
> len += snprintf(buf + len, PAGE_SIZE - len, "\n");
> return len;
> }
> @@ -227,6 +230,7 @@ enum feat_id {
> FEAT_PROJECT_QUOTA,
> FEAT_INODE_CHECKSUM,
> FEAT_FLEXIBLE_INLINE_XATTR,
> + FEAT_QUOTA_INO,
> };
>
> static ssize_t f2fs_feature_show(struct f2fs_attr *a,
> @@ -240,6 +244,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a,
> case FEAT_PROJECT_QUOTA:
> case FEAT_INODE_CHECKSUM:
> case FEAT_FLEXIBLE_INLINE_XATTR:
> + case FEAT_QUOTA_INO:
> return snprintf(buf, PAGE_SIZE, "supported\n");
> }
> return 0;
> @@ -314,6 +319,7 @@ F2FS_FEATURE_RO_ATTR(extra_attr, FEAT_EXTRA_ATTR);
> F2FS_FEATURE_RO_ATTR(project_quota, FEAT_PROJECT_QUOTA);
> F2FS_FEATURE_RO_ATTR(inode_checksum, FEAT_INODE_CHECKSUM);
> F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR);
> +F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO);
>
> #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
> static struct attribute *f2fs_attrs[] = {
> @@ -364,6 +370,7 @@ static struct attribute *f2fs_feat_attrs[] = {
> ATTR_LIST(project_quota),
> ATTR_LIST(inode_checksum),
> ATTR_LIST(flexible_inline_xattr),
> + ATTR_LIST(quota_ino),
> NULL,
> };
>
> diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
> index 50a8ee501bf1..ce34007972c3 100644
> --- a/include/linux/f2fs_fs.h
> +++ b/include/linux/f2fs_fs.h
> @@ -36,6 +36,9 @@
> #define F2FS_NODE_INO(sbi) ((sbi)->node_ino_num)
> #define F2FS_META_INO(sbi) ((sbi)->meta_ino_num)
>
> +#define F2FS_QUOTA_INO 3
> +#define F2FS_MAX_QUOTAS 3
> +
> #define F2FS_IO_SIZE(sbi) (1 << (sbi)->write_io_size_bits) /* Blocks */
> #define F2FS_IO_SIZE_KB(sbi) (1 << ((sbi)->write_io_size_bits + 2)) /* KB */
> #define F2FS_IO_SIZE_BYTES(sbi) (1 << ((sbi)->write_io_size_bits + 12)) /* B */
> @@ -108,7 +111,8 @@ struct f2fs_super_block {
> __u8 encryption_level; /* versioning level for encryption */
> __u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */
> struct f2fs_device devs[MAX_DEVICES]; /* device list */
> - __u8 reserved[327]; /* valid reserved region */
> + __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
> + __u8 reserved[315]; /* valid reserved region */
> } __packed;
>
> /*
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [f2fs-dev] [PATCH 2/2] f2fs: support quota sys files
2017-10-31 3:40 ` [PATCH 2/2] f2fs: support quota sys files Jaegeuk Kim
@ 2017-11-02 14:45 ` Chao Yu
2017-11-03 3:37 ` Jaegeuk Kim
0 siblings, 1 reply; 7+ messages in thread
From: Chao Yu @ 2017-11-02 14:45 UTC (permalink / raw)
To: Jaegeuk Kim, linux-kernel, linux-fsdevel, linux-f2fs-devel
On 2017/10/31 11:40, Jaegeuk Kim wrote:
> This patch supports hidden quota files in the system, which will be used for
> Android. It requires up-to-date f2fs-tools later than v1.9.0.
>
> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> ---
> fs/f2fs/checkpoint.c | 9 +++-
> fs/f2fs/f2fs.h | 9 +++-
> fs/f2fs/recovery.c | 8 ++-
> fs/f2fs/super.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++-----
> 4 files changed, 153 insertions(+), 18 deletions(-)
>
> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
> index 6b52d4b66c7b..78e1b2998bbd 100644
> --- a/fs/f2fs/checkpoint.c
> +++ b/fs/f2fs/checkpoint.c
> @@ -615,6 +615,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
> block_t start_blk, orphan_blocks, i, j;
> unsigned int s_flags = sbi->sb->s_flags;
> int err = 0;
> +#ifdef CONFIG_QUOTA
> + int quota_enabled;
> +#endif
>
> if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
> return 0;
> @@ -627,8 +630,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
> #ifdef CONFIG_QUOTA
> /* Needed for iput() to work correctly and not trash data */
> sbi->sb->s_flags |= MS_ACTIVE;
> +
> /* Turn on quotas so that they are updated correctly */
> - f2fs_enable_quota_files(sbi);
> + quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
> #endif
>
> start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
> @@ -656,7 +660,8 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
> out:
> #ifdef CONFIG_QUOTA
> /* Turn quotas off */
> - f2fs_quota_off_umount(sbi->sb);
> + if (quota_enabled)
> + f2fs_quota_off_umount(sbi->sb);
> #endif
> sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
>
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 9a1c7ffa6845..e1d3a940d9f8 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -1384,6 +1384,13 @@ static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp)
> return le64_to_cpu(cp->checkpoint_ver);
> }
>
> +static inline unsigned long f2fs_qf_ino(struct super_block *sb, int type)
> +{
> + if (type < F2FS_QUOTA_INO)
Why not just use F2FS_MAX_QUOTAS instead of F2FS_QUOTA_INO? since in patch 1/2
we have defined qf_ino array with upper-boundary F2FS_MAX_QUOTAS.
__le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
Other part looks good to me. ;)
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Thanks,
> + return le32_to_cpu(F2FS_SB(sb)->raw_super->qf_ino[type]);
> + return 0;
> +}
> +
> static inline __u64 cur_cp_crc(struct f2fs_checkpoint *cp)
> {
> size_t crc_offset = le32_to_cpu(cp->checksum_offset);
> @@ -2526,7 +2533,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
> */
> int f2fs_inode_dirtied(struct inode *inode, bool sync);
> void f2fs_inode_synced(struct inode *inode);
> -void f2fs_enable_quota_files(struct f2fs_sb_info *sbi);
> +int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly);
> void f2fs_quota_off_umount(struct super_block *sb);
> int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover);
> int f2fs_sync_fs(struct super_block *sb, int sync);
> diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
> index 9626758bc762..92c57ace1939 100644
> --- a/fs/f2fs/recovery.c
> +++ b/fs/f2fs/recovery.c
> @@ -594,6 +594,9 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
> int ret = 0;
> unsigned long s_flags = sbi->sb->s_flags;
> bool need_writecp = false;
> +#ifdef CONFIG_QUOTA
> + int quota_enabled;
> +#endif
>
> if (s_flags & MS_RDONLY) {
> f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs");
> @@ -604,7 +607,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
> /* Needed for iput() to work correctly and not trash data */
> sbi->sb->s_flags |= MS_ACTIVE;
> /* Turn on quotas so that they are updated correctly */
> - f2fs_enable_quota_files(sbi);
> + quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
> #endif
>
> fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
> @@ -665,7 +668,8 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
> out:
> #ifdef CONFIG_QUOTA
> /* Turn quotas off */
> - f2fs_quota_off_umount(sbi->sb);
> + if (quota_enabled)
> + f2fs_quota_off_umount(sbi->sb);
> #endif
> sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
>
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index 96e145c34ba2..0ca7b055e4e0 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -213,6 +213,12 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype,
> "quota options when quota turned on");
> return -EINVAL;
> }
> + if (f2fs_sb_has_quota_ino(sb)) {
> + f2fs_msg(sb, KERN_INFO,
> + "QUOTA feature is enabled, so ignore qf_name");
> + return 0;
> + }
> +
> qname = match_strdup(args);
> if (!qname) {
> f2fs_msg(sb, KERN_ERR,
> @@ -291,6 +297,18 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
> return -1;
> }
> }
> +
> + if (f2fs_sb_has_quota_ino(sbi->sb) && sbi->s_jquota_fmt) {
> + f2fs_msg(sbi->sb, KERN_INFO,
> + "QUOTA feature is enabled, so ignore jquota_fmt");
> + sbi->s_jquota_fmt = 0;
> + }
> + if (f2fs_sb_has_quota_ino(sbi->sb) && sb_rdonly(sbi->sb)) {
> + f2fs_msg(sbi->sb, KERN_INFO,
> + "Filesystem with quota feature cannot be mounted RDWR "
> + "without CONFIG_QUOTA");
> + return -1;
> + }
> return 0;
> }
> #endif
> @@ -1172,6 +1190,7 @@ static void default_options(struct f2fs_sb_info *sbi)
> #endif
> }
>
> +static int f2fs_enable_quotas(struct super_block *sb);
> static int f2fs_remount(struct super_block *sb, int *flags, char *data)
> {
> struct f2fs_sb_info *sbi = F2FS_SB(sb);
> @@ -1238,6 +1257,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
> if (f2fs_readonly(sb) && (*flags & MS_RDONLY))
> goto skip;
>
> +#ifdef CONFIG_QUOTA
> if (!f2fs_readonly(sb) && (*flags & MS_RDONLY)) {
> err = dquot_suspend(sb, -1);
> if (err < 0)
> @@ -1245,9 +1265,15 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
> } else {
> /* dquot_resume needs RW */
> sb->s_flags &= ~MS_RDONLY;
> - dquot_resume(sb, -1);
> + if (sb_any_quota_suspended(sb)) {
> + dquot_resume(sb, -1);
> + } else if (f2fs_sb_has_quota_ino(sb)) {
> + err = f2fs_enable_quotas(sb);
> + if (err)
> + goto restore_opts;
> + }
> }
> -
> +#endif
> /* disallow enable/disable extent_cache dynamically */
> if (no_extent_cache == !!test_opt(sbi, EXTENT_CACHE)) {
> err = -EINVAL;
> @@ -1454,19 +1480,91 @@ static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type)
> sbi->s_jquota_fmt, type);
> }
>
> -void f2fs_enable_quota_files(struct f2fs_sb_info *sbi)
> +int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly)
> {
> - int i, ret;
> + int enabled = 0;
> + int i, err;
> +
> + if (f2fs_sb_has_quota_ino(sbi->sb) && rdonly) {
> + err = f2fs_enable_quotas(sbi->sb);
> + if (err) {
> + f2fs_msg(sbi->sb, KERN_ERR,
> + "Cannot turn on quota_ino: %d", err);
> + return 0;
> + }
> + return 1;
> + }
>
> for (i = 0; i < MAXQUOTAS; i++) {
> if (sbi->s_qf_names[i]) {
> - ret = f2fs_quota_on_mount(sbi, i);
> - if (ret < 0)
> - f2fs_msg(sbi->sb, KERN_ERR,
> - "Cannot turn on journaled "
> - "quota: error %d", ret);
> + err = f2fs_quota_on_mount(sbi, i);
> + if (!err) {
> + enabled = 1;
> + continue;
> + }
> + f2fs_msg(sbi->sb, KERN_ERR,
> + "Cannot turn on quotas: %d on %d", err, i);
> + }
> + }
> + return enabled;
> +}
> +
> +static int f2fs_quota_enable(struct super_block *sb, int type, int format_id,
> + unsigned int flags)
> +{
> + struct inode *qf_inode;
> + unsigned long qf_inum;
> + int err;
> +
> + BUG_ON(!f2fs_sb_has_quota_ino(sb));
> +
> + qf_inum = f2fs_qf_ino(sb, type);
> + if (!qf_inum)
> + return -EPERM;
> +
> + qf_inode = f2fs_iget(sb, qf_inum);
> + if (IS_ERR(qf_inode)) {
> + f2fs_msg(sb, KERN_ERR,
> + "Bad quota inode %u:%lu", type, qf_inum);
> + return PTR_ERR(qf_inode);
> + }
> +
> + /* Don't account quota for quota files to avoid recursion */
> + qf_inode->i_flags |= S_NOQUOTA;
> + err = dquot_enable(qf_inode, type, format_id, flags);
> + iput(qf_inode);
> + return err;
> +}
> +
> +static int f2fs_enable_quotas(struct super_block *sb)
> +{
> + int type, err = 0;
> + unsigned long qf_inum;
> + bool quota_mopt[MAXQUOTAS] = {
> + test_opt(F2FS_SB(sb), USRQUOTA),
> + test_opt(F2FS_SB(sb), GRPQUOTA),
> + test_opt(F2FS_SB(sb), PRJQUOTA),
> + };
> +
> + sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NOLIST_DIRTY;
> + for (type = 0; type < MAXQUOTAS; type++) {
> + qf_inum = f2fs_qf_ino(sb, type);
> + if (qf_inum) {
> + err = f2fs_quota_enable(sb, type, QFMT_VFS_V1,
> + DQUOT_USAGE_ENABLED |
> + (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0));
> + if (err) {
> + f2fs_msg(sb, KERN_ERR,
> + "Failed to enable quota tracking "
> + "(type=%d, err=%d). Please run "
> + "fsck to fix.", type, err);
> + for (type--; type >= 0; type--)
> + dquot_quota_off(sb, type);
> + return err;
> + }
> }
> }
> + return 0;
> }
>
> static int f2fs_quota_sync(struct super_block *sb, int type)
> @@ -1537,7 +1635,7 @@ static int f2fs_quota_off(struct super_block *sb, int type)
> f2fs_quota_sync(sb, type);
>
> err = dquot_quota_off(sb, type);
> - if (err)
> + if (err || f2fs_sb_has_quota_ino(sb))
> goto out_put;
>
> inode_lock(inode);
> @@ -2364,7 +2462,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>
> #ifdef CONFIG_QUOTA
> sb->dq_op = &f2fs_quota_operations;
> - sb->s_qcop = &f2fs_quotactl_ops;
> + if (f2fs_sb_has_quota_ino(sb))
> + sb->s_qcop = &dquot_quotactl_sysfile_ops;
> + else
> + sb->s_qcop = &f2fs_quotactl_ops;
> sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
> #endif
>
> @@ -2535,10 +2636,24 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> if (err)
> goto free_root_inode;
>
> +#ifdef CONFIG_QUOTA
> + /*
> + * Turn on quotas which were not enabled for read-only mounts if
> + * filesystem has quota feature, so that they are updated correctly.
> + */
> + if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) {
> + err = f2fs_enable_quotas(sb);
> + if (err) {
> + f2fs_msg(sb, KERN_ERR,
> + "Cannot turn on quotas: error %d", err);
> + goto free_sysfs;
> + }
> + }
> +#endif
> /* if there are nt orphan nodes free them */
> err = recover_orphan_inodes(sbi);
> if (err)
> - goto free_sysfs;
> + goto free_meta;
>
> /* recover fsynced data */
> if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
> @@ -2572,7 +2687,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> err = -EINVAL;
> f2fs_msg(sb, KERN_ERR,
> "Need to recover fsync data");
> - goto free_sysfs;
> + goto free_meta;
> }
> }
> skip_recovery:
> @@ -2606,6 +2721,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> return 0;
>
> free_meta:
> +#ifdef CONFIG_QUOTA
> + if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb))
> + f2fs_quota_off_umount(sbi->sb);
> +#endif
> f2fs_sync_inode_meta(sbi);
> /*
> * Some dirty meta pages can be produced by recover_orphan_inodes()
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [f2fs-dev] [PATCH 2/2] f2fs: support quota sys files
2017-11-02 14:45 ` [f2fs-dev] " Chao Yu
@ 2017-11-03 3:37 ` Jaegeuk Kim
2017-11-03 5:48 ` Chao Yu
0 siblings, 1 reply; 7+ messages in thread
From: Jaegeuk Kim @ 2017-11-03 3:37 UTC (permalink / raw)
To: Chao Yu; +Cc: linux-kernel, linux-fsdevel, linux-f2fs-devel
On 11/02, Chao Yu wrote:
> On 2017/10/31 11:40, Jaegeuk Kim wrote:
> > This patch supports hidden quota files in the system, which will be used for
> > Android. It requires up-to-date f2fs-tools later than v1.9.0.
> >
> > Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> > ---
> > fs/f2fs/checkpoint.c | 9 +++-
> > fs/f2fs/f2fs.h | 9 +++-
> > fs/f2fs/recovery.c | 8 ++-
> > fs/f2fs/super.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++-----
> > 4 files changed, 153 insertions(+), 18 deletions(-)
> >
> > diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
> > index 6b52d4b66c7b..78e1b2998bbd 100644
> > --- a/fs/f2fs/checkpoint.c
> > +++ b/fs/f2fs/checkpoint.c
> > @@ -615,6 +615,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
> > block_t start_blk, orphan_blocks, i, j;
> > unsigned int s_flags = sbi->sb->s_flags;
> > int err = 0;
> > +#ifdef CONFIG_QUOTA
> > + int quota_enabled;
> > +#endif
> >
> > if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
> > return 0;
> > @@ -627,8 +630,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
> > #ifdef CONFIG_QUOTA
> > /* Needed for iput() to work correctly and not trash data */
> > sbi->sb->s_flags |= MS_ACTIVE;
> > +
> > /* Turn on quotas so that they are updated correctly */
> > - f2fs_enable_quota_files(sbi);
> > + quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
> > #endif
> >
> > start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
> > @@ -656,7 +660,8 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
> > out:
> > #ifdef CONFIG_QUOTA
> > /* Turn quotas off */
> > - f2fs_quota_off_umount(sbi->sb);
> > + if (quota_enabled)
> > + f2fs_quota_off_umount(sbi->sb);
> > #endif
> > sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
> >
> > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > index 9a1c7ffa6845..e1d3a940d9f8 100644
> > --- a/fs/f2fs/f2fs.h
> > +++ b/fs/f2fs/f2fs.h
> > @@ -1384,6 +1384,13 @@ static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp)
> > return le64_to_cpu(cp->checkpoint_ver);
> > }
> >
> > +static inline unsigned long f2fs_qf_ino(struct super_block *sb, int type)
> > +{
> > + if (type < F2FS_QUOTA_INO)
>
> Why not just use F2FS_MAX_QUOTAS instead of F2FS_QUOTA_INO? since in patch 1/2
> we have defined qf_ino array with upper-boundary F2FS_MAX_QUOTAS.
It was intended to indicate # of enabled quotas. ;)
>
> __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
>
> Other part looks good to me. ;)
>
> Reviewed-by: Chao Yu <yuchao0@huawei.com>
>
> Thanks,
>
> > + return le32_to_cpu(F2FS_SB(sb)->raw_super->qf_ino[type]);
> > + return 0;
> > +}
> > +
> > static inline __u64 cur_cp_crc(struct f2fs_checkpoint *cp)
> > {
> > size_t crc_offset = le32_to_cpu(cp->checksum_offset);
> > @@ -2526,7 +2533,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
> > */
> > int f2fs_inode_dirtied(struct inode *inode, bool sync);
> > void f2fs_inode_synced(struct inode *inode);
> > -void f2fs_enable_quota_files(struct f2fs_sb_info *sbi);
> > +int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly);
> > void f2fs_quota_off_umount(struct super_block *sb);
> > int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover);
> > int f2fs_sync_fs(struct super_block *sb, int sync);
> > diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
> > index 9626758bc762..92c57ace1939 100644
> > --- a/fs/f2fs/recovery.c
> > +++ b/fs/f2fs/recovery.c
> > @@ -594,6 +594,9 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
> > int ret = 0;
> > unsigned long s_flags = sbi->sb->s_flags;
> > bool need_writecp = false;
> > +#ifdef CONFIG_QUOTA
> > + int quota_enabled;
> > +#endif
> >
> > if (s_flags & MS_RDONLY) {
> > f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs");
> > @@ -604,7 +607,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
> > /* Needed for iput() to work correctly and not trash data */
> > sbi->sb->s_flags |= MS_ACTIVE;
> > /* Turn on quotas so that they are updated correctly */
> > - f2fs_enable_quota_files(sbi);
> > + quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
> > #endif
> >
> > fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
> > @@ -665,7 +668,8 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
> > out:
> > #ifdef CONFIG_QUOTA
> > /* Turn quotas off */
> > - f2fs_quota_off_umount(sbi->sb);
> > + if (quota_enabled)
> > + f2fs_quota_off_umount(sbi->sb);
> > #endif
> > sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
> >
> > diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> > index 96e145c34ba2..0ca7b055e4e0 100644
> > --- a/fs/f2fs/super.c
> > +++ b/fs/f2fs/super.c
> > @@ -213,6 +213,12 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype,
> > "quota options when quota turned on");
> > return -EINVAL;
> > }
> > + if (f2fs_sb_has_quota_ino(sb)) {
> > + f2fs_msg(sb, KERN_INFO,
> > + "QUOTA feature is enabled, so ignore qf_name");
> > + return 0;
> > + }
> > +
> > qname = match_strdup(args);
> > if (!qname) {
> > f2fs_msg(sb, KERN_ERR,
> > @@ -291,6 +297,18 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
> > return -1;
> > }
> > }
> > +
> > + if (f2fs_sb_has_quota_ino(sbi->sb) && sbi->s_jquota_fmt) {
> > + f2fs_msg(sbi->sb, KERN_INFO,
> > + "QUOTA feature is enabled, so ignore jquota_fmt");
> > + sbi->s_jquota_fmt = 0;
> > + }
> > + if (f2fs_sb_has_quota_ino(sbi->sb) && sb_rdonly(sbi->sb)) {
> > + f2fs_msg(sbi->sb, KERN_INFO,
> > + "Filesystem with quota feature cannot be mounted RDWR "
> > + "without CONFIG_QUOTA");
> > + return -1;
> > + }
> > return 0;
> > }
> > #endif
> > @@ -1172,6 +1190,7 @@ static void default_options(struct f2fs_sb_info *sbi)
> > #endif
> > }
> >
> > +static int f2fs_enable_quotas(struct super_block *sb);
> > static int f2fs_remount(struct super_block *sb, int *flags, char *data)
> > {
> > struct f2fs_sb_info *sbi = F2FS_SB(sb);
> > @@ -1238,6 +1257,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
> > if (f2fs_readonly(sb) && (*flags & MS_RDONLY))
> > goto skip;
> >
> > +#ifdef CONFIG_QUOTA
> > if (!f2fs_readonly(sb) && (*flags & MS_RDONLY)) {
> > err = dquot_suspend(sb, -1);
> > if (err < 0)
> > @@ -1245,9 +1265,15 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
> > } else {
> > /* dquot_resume needs RW */
> > sb->s_flags &= ~MS_RDONLY;
> > - dquot_resume(sb, -1);
> > + if (sb_any_quota_suspended(sb)) {
> > + dquot_resume(sb, -1);
> > + } else if (f2fs_sb_has_quota_ino(sb)) {
> > + err = f2fs_enable_quotas(sb);
> > + if (err)
> > + goto restore_opts;
> > + }
> > }
> > -
> > +#endif
> > /* disallow enable/disable extent_cache dynamically */
> > if (no_extent_cache == !!test_opt(sbi, EXTENT_CACHE)) {
> > err = -EINVAL;
> > @@ -1454,19 +1480,91 @@ static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type)
> > sbi->s_jquota_fmt, type);
> > }
> >
> > -void f2fs_enable_quota_files(struct f2fs_sb_info *sbi)
> > +int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly)
> > {
> > - int i, ret;
> > + int enabled = 0;
> > + int i, err;
> > +
> > + if (f2fs_sb_has_quota_ino(sbi->sb) && rdonly) {
> > + err = f2fs_enable_quotas(sbi->sb);
> > + if (err) {
> > + f2fs_msg(sbi->sb, KERN_ERR,
> > + "Cannot turn on quota_ino: %d", err);
> > + return 0;
> > + }
> > + return 1;
> > + }
> >
> > for (i = 0; i < MAXQUOTAS; i++) {
> > if (sbi->s_qf_names[i]) {
> > - ret = f2fs_quota_on_mount(sbi, i);
> > - if (ret < 0)
> > - f2fs_msg(sbi->sb, KERN_ERR,
> > - "Cannot turn on journaled "
> > - "quota: error %d", ret);
> > + err = f2fs_quota_on_mount(sbi, i);
> > + if (!err) {
> > + enabled = 1;
> > + continue;
> > + }
> > + f2fs_msg(sbi->sb, KERN_ERR,
> > + "Cannot turn on quotas: %d on %d", err, i);
> > + }
> > + }
> > + return enabled;
> > +}
> > +
> > +static int f2fs_quota_enable(struct super_block *sb, int type, int format_id,
> > + unsigned int flags)
> > +{
> > + struct inode *qf_inode;
> > + unsigned long qf_inum;
> > + int err;
> > +
> > + BUG_ON(!f2fs_sb_has_quota_ino(sb));
> > +
> > + qf_inum = f2fs_qf_ino(sb, type);
> > + if (!qf_inum)
> > + return -EPERM;
> > +
> > + qf_inode = f2fs_iget(sb, qf_inum);
> > + if (IS_ERR(qf_inode)) {
> > + f2fs_msg(sb, KERN_ERR,
> > + "Bad quota inode %u:%lu", type, qf_inum);
> > + return PTR_ERR(qf_inode);
> > + }
> > +
> > + /* Don't account quota for quota files to avoid recursion */
> > + qf_inode->i_flags |= S_NOQUOTA;
> > + err = dquot_enable(qf_inode, type, format_id, flags);
> > + iput(qf_inode);
> > + return err;
> > +}
> > +
> > +static int f2fs_enable_quotas(struct super_block *sb)
> > +{
> > + int type, err = 0;
> > + unsigned long qf_inum;
> > + bool quota_mopt[MAXQUOTAS] = {
> > + test_opt(F2FS_SB(sb), USRQUOTA),
> > + test_opt(F2FS_SB(sb), GRPQUOTA),
> > + test_opt(F2FS_SB(sb), PRJQUOTA),
> > + };
> > +
> > + sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NOLIST_DIRTY;
> > + for (type = 0; type < MAXQUOTAS; type++) {
> > + qf_inum = f2fs_qf_ino(sb, type);
> > + if (qf_inum) {
> > + err = f2fs_quota_enable(sb, type, QFMT_VFS_V1,
> > + DQUOT_USAGE_ENABLED |
> > + (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0));
> > + if (err) {
> > + f2fs_msg(sb, KERN_ERR,
> > + "Failed to enable quota tracking "
> > + "(type=%d, err=%d). Please run "
> > + "fsck to fix.", type, err);
> > + for (type--; type >= 0; type--)
> > + dquot_quota_off(sb, type);
> > + return err;
> > + }
> > }
> > }
> > + return 0;
> > }
> >
> > static int f2fs_quota_sync(struct super_block *sb, int type)
> > @@ -1537,7 +1635,7 @@ static int f2fs_quota_off(struct super_block *sb, int type)
> > f2fs_quota_sync(sb, type);
> >
> > err = dquot_quota_off(sb, type);
> > - if (err)
> > + if (err || f2fs_sb_has_quota_ino(sb))
> > goto out_put;
> >
> > inode_lock(inode);
> > @@ -2364,7 +2462,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >
> > #ifdef CONFIG_QUOTA
> > sb->dq_op = &f2fs_quota_operations;
> > - sb->s_qcop = &f2fs_quotactl_ops;
> > + if (f2fs_sb_has_quota_ino(sb))
> > + sb->s_qcop = &dquot_quotactl_sysfile_ops;
> > + else
> > + sb->s_qcop = &f2fs_quotactl_ops;
> > sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
> > #endif
> >
> > @@ -2535,10 +2636,24 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> > if (err)
> > goto free_root_inode;
> >
> > +#ifdef CONFIG_QUOTA
> > + /*
> > + * Turn on quotas which were not enabled for read-only mounts if
> > + * filesystem has quota feature, so that they are updated correctly.
> > + */
> > + if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) {
> > + err = f2fs_enable_quotas(sb);
> > + if (err) {
> > + f2fs_msg(sb, KERN_ERR,
> > + "Cannot turn on quotas: error %d", err);
> > + goto free_sysfs;
> > + }
> > + }
> > +#endif
> > /* if there are nt orphan nodes free them */
> > err = recover_orphan_inodes(sbi);
> > if (err)
> > - goto free_sysfs;
> > + goto free_meta;
> >
> > /* recover fsynced data */
> > if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
> > @@ -2572,7 +2687,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> > err = -EINVAL;
> > f2fs_msg(sb, KERN_ERR,
> > "Need to recover fsync data");
> > - goto free_sysfs;
> > + goto free_meta;
> > }
> > }
> > skip_recovery:
> > @@ -2606,6 +2721,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> > return 0;
> >
> > free_meta:
> > +#ifdef CONFIG_QUOTA
> > + if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb))
> > + f2fs_quota_off_umount(sbi->sb);
> > +#endif
> > f2fs_sync_inode_meta(sbi);
> > /*
> > * Some dirty meta pages can be produced by recover_orphan_inodes()
> >
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [f2fs-dev] [PATCH 2/2] f2fs: support quota sys files
2017-11-03 3:37 ` Jaegeuk Kim
@ 2017-11-03 5:48 ` Chao Yu
2017-11-03 18:27 ` Jaegeuk Kim
0 siblings, 1 reply; 7+ messages in thread
From: Chao Yu @ 2017-11-03 5:48 UTC (permalink / raw)
To: Jaegeuk Kim, Chao Yu; +Cc: linux-kernel, linux-fsdevel, linux-f2fs-devel
On 2017/11/3 11:37, Jaegeuk Kim wrote:
> On 11/02, Chao Yu wrote:
>> On 2017/10/31 11:40, Jaegeuk Kim wrote:
>>> This patch supports hidden quota files in the system, which will be used for
>>> Android. It requires up-to-date f2fs-tools later than v1.9.0.
>>>
>>> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
>>> ---
>>> fs/f2fs/checkpoint.c | 9 +++-
>>> fs/f2fs/f2fs.h | 9 +++-
>>> fs/f2fs/recovery.c | 8 ++-
>>> fs/f2fs/super.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++-----
>>> 4 files changed, 153 insertions(+), 18 deletions(-)
>>>
>>> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
>>> index 6b52d4b66c7b..78e1b2998bbd 100644
>>> --- a/fs/f2fs/checkpoint.c
>>> +++ b/fs/f2fs/checkpoint.c
>>> @@ -615,6 +615,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
>>> block_t start_blk, orphan_blocks, i, j;
>>> unsigned int s_flags = sbi->sb->s_flags;
>>> int err = 0;
>>> +#ifdef CONFIG_QUOTA
>>> + int quota_enabled;
>>> +#endif
>>>
>>> if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
>>> return 0;
>>> @@ -627,8 +630,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
>>> #ifdef CONFIG_QUOTA
>>> /* Needed for iput() to work correctly and not trash data */
>>> sbi->sb->s_flags |= MS_ACTIVE;
>>> +
>>> /* Turn on quotas so that they are updated correctly */
>>> - f2fs_enable_quota_files(sbi);
>>> + quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
>>> #endif
>>>
>>> start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
>>> @@ -656,7 +660,8 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
>>> out:
>>> #ifdef CONFIG_QUOTA
>>> /* Turn quotas off */
>>> - f2fs_quota_off_umount(sbi->sb);
>>> + if (quota_enabled)
>>> + f2fs_quota_off_umount(sbi->sb);
>>> #endif
>>> sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
>>>
>>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
>>> index 9a1c7ffa6845..e1d3a940d9f8 100644
>>> --- a/fs/f2fs/f2fs.h
>>> +++ b/fs/f2fs/f2fs.h
>>> @@ -1384,6 +1384,13 @@ static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp)
>>> return le64_to_cpu(cp->checkpoint_ver);
>>> }
>>>
>>> +static inline unsigned long f2fs_qf_ino(struct super_block *sb, int type)
>>> +{
>>> + if (type < F2FS_QUOTA_INO)
>>
>> Why not just use F2FS_MAX_QUOTAS instead of F2FS_QUOTA_INO? since in patch 1/2
>> we have defined qf_ino array with upper-boundary F2FS_MAX_QUOTAS.
>
> It was intended to indicate # of enabled quotas. ;)
Alright, so how about renaming it to F2FS_ENABLED_QUOTA_INO... :)
Thanks,
>
>>
>> __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
>>
>> Other part looks good to me. ;)
>>
>> Reviewed-by: Chao Yu <yuchao0@huawei.com>
>>
>> Thanks,
>>
>>> + return le32_to_cpu(F2FS_SB(sb)->raw_super->qf_ino[type]);
>>> + return 0;
>>> +}
>>> +
>>> static inline __u64 cur_cp_crc(struct f2fs_checkpoint *cp)
>>> {
>>> size_t crc_offset = le32_to_cpu(cp->checksum_offset);
>>> @@ -2526,7 +2533,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
>>> */
>>> int f2fs_inode_dirtied(struct inode *inode, bool sync);
>>> void f2fs_inode_synced(struct inode *inode);
>>> -void f2fs_enable_quota_files(struct f2fs_sb_info *sbi);
>>> +int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly);
>>> void f2fs_quota_off_umount(struct super_block *sb);
>>> int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover);
>>> int f2fs_sync_fs(struct super_block *sb, int sync);
>>> diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
>>> index 9626758bc762..92c57ace1939 100644
>>> --- a/fs/f2fs/recovery.c
>>> +++ b/fs/f2fs/recovery.c
>>> @@ -594,6 +594,9 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
>>> int ret = 0;
>>> unsigned long s_flags = sbi->sb->s_flags;
>>> bool need_writecp = false;
>>> +#ifdef CONFIG_QUOTA
>>> + int quota_enabled;
>>> +#endif
>>>
>>> if (s_flags & MS_RDONLY) {
>>> f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs");
>>> @@ -604,7 +607,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
>>> /* Needed for iput() to work correctly and not trash data */
>>> sbi->sb->s_flags |= MS_ACTIVE;
>>> /* Turn on quotas so that they are updated correctly */
>>> - f2fs_enable_quota_files(sbi);
>>> + quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
>>> #endif
>>>
>>> fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
>>> @@ -665,7 +668,8 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
>>> out:
>>> #ifdef CONFIG_QUOTA
>>> /* Turn quotas off */
>>> - f2fs_quota_off_umount(sbi->sb);
>>> + if (quota_enabled)
>>> + f2fs_quota_off_umount(sbi->sb);
>>> #endif
>>> sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
>>>
>>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
>>> index 96e145c34ba2..0ca7b055e4e0 100644
>>> --- a/fs/f2fs/super.c
>>> +++ b/fs/f2fs/super.c
>>> @@ -213,6 +213,12 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype,
>>> "quota options when quota turned on");
>>> return -EINVAL;
>>> }
>>> + if (f2fs_sb_has_quota_ino(sb)) {
>>> + f2fs_msg(sb, KERN_INFO,
>>> + "QUOTA feature is enabled, so ignore qf_name");
>>> + return 0;
>>> + }
>>> +
>>> qname = match_strdup(args);
>>> if (!qname) {
>>> f2fs_msg(sb, KERN_ERR,
>>> @@ -291,6 +297,18 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
>>> return -1;
>>> }
>>> }
>>> +
>>> + if (f2fs_sb_has_quota_ino(sbi->sb) && sbi->s_jquota_fmt) {
>>> + f2fs_msg(sbi->sb, KERN_INFO,
>>> + "QUOTA feature is enabled, so ignore jquota_fmt");
>>> + sbi->s_jquota_fmt = 0;
>>> + }
>>> + if (f2fs_sb_has_quota_ino(sbi->sb) && sb_rdonly(sbi->sb)) {
>>> + f2fs_msg(sbi->sb, KERN_INFO,
>>> + "Filesystem with quota feature cannot be mounted RDWR "
>>> + "without CONFIG_QUOTA");
>>> + return -1;
>>> + }
>>> return 0;
>>> }
>>> #endif
>>> @@ -1172,6 +1190,7 @@ static void default_options(struct f2fs_sb_info *sbi)
>>> #endif
>>> }
>>>
>>> +static int f2fs_enable_quotas(struct super_block *sb);
>>> static int f2fs_remount(struct super_block *sb, int *flags, char *data)
>>> {
>>> struct f2fs_sb_info *sbi = F2FS_SB(sb);
>>> @@ -1238,6 +1257,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
>>> if (f2fs_readonly(sb) && (*flags & MS_RDONLY))
>>> goto skip;
>>>
>>> +#ifdef CONFIG_QUOTA
>>> if (!f2fs_readonly(sb) && (*flags & MS_RDONLY)) {
>>> err = dquot_suspend(sb, -1);
>>> if (err < 0)
>>> @@ -1245,9 +1265,15 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
>>> } else {
>>> /* dquot_resume needs RW */
>>> sb->s_flags &= ~MS_RDONLY;
>>> - dquot_resume(sb, -1);
>>> + if (sb_any_quota_suspended(sb)) {
>>> + dquot_resume(sb, -1);
>>> + } else if (f2fs_sb_has_quota_ino(sb)) {
>>> + err = f2fs_enable_quotas(sb);
>>> + if (err)
>>> + goto restore_opts;
>>> + }
>>> }
>>> -
>>> +#endif
>>> /* disallow enable/disable extent_cache dynamically */
>>> if (no_extent_cache == !!test_opt(sbi, EXTENT_CACHE)) {
>>> err = -EINVAL;
>>> @@ -1454,19 +1480,91 @@ static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type)
>>> sbi->s_jquota_fmt, type);
>>> }
>>>
>>> -void f2fs_enable_quota_files(struct f2fs_sb_info *sbi)
>>> +int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly)
>>> {
>>> - int i, ret;
>>> + int enabled = 0;
>>> + int i, err;
>>> +
>>> + if (f2fs_sb_has_quota_ino(sbi->sb) && rdonly) {
>>> + err = f2fs_enable_quotas(sbi->sb);
>>> + if (err) {
>>> + f2fs_msg(sbi->sb, KERN_ERR,
>>> + "Cannot turn on quota_ino: %d", err);
>>> + return 0;
>>> + }
>>> + return 1;
>>> + }
>>>
>>> for (i = 0; i < MAXQUOTAS; i++) {
>>> if (sbi->s_qf_names[i]) {
>>> - ret = f2fs_quota_on_mount(sbi, i);
>>> - if (ret < 0)
>>> - f2fs_msg(sbi->sb, KERN_ERR,
>>> - "Cannot turn on journaled "
>>> - "quota: error %d", ret);
>>> + err = f2fs_quota_on_mount(sbi, i);
>>> + if (!err) {
>>> + enabled = 1;
>>> + continue;
>>> + }
>>> + f2fs_msg(sbi->sb, KERN_ERR,
>>> + "Cannot turn on quotas: %d on %d", err, i);
>>> + }
>>> + }
>>> + return enabled;
>>> +}
>>> +
>>> +static int f2fs_quota_enable(struct super_block *sb, int type, int format_id,
>>> + unsigned int flags)
>>> +{
>>> + struct inode *qf_inode;
>>> + unsigned long qf_inum;
>>> + int err;
>>> +
>>> + BUG_ON(!f2fs_sb_has_quota_ino(sb));
>>> +
>>> + qf_inum = f2fs_qf_ino(sb, type);
>>> + if (!qf_inum)
>>> + return -EPERM;
>>> +
>>> + qf_inode = f2fs_iget(sb, qf_inum);
>>> + if (IS_ERR(qf_inode)) {
>>> + f2fs_msg(sb, KERN_ERR,
>>> + "Bad quota inode %u:%lu", type, qf_inum);
>>> + return PTR_ERR(qf_inode);
>>> + }
>>> +
>>> + /* Don't account quota for quota files to avoid recursion */
>>> + qf_inode->i_flags |= S_NOQUOTA;
>>> + err = dquot_enable(qf_inode, type, format_id, flags);
>>> + iput(qf_inode);
>>> + return err;
>>> +}
>>> +
>>> +static int f2fs_enable_quotas(struct super_block *sb)
>>> +{
>>> + int type, err = 0;
>>> + unsigned long qf_inum;
>>> + bool quota_mopt[MAXQUOTAS] = {
>>> + test_opt(F2FS_SB(sb), USRQUOTA),
>>> + test_opt(F2FS_SB(sb), GRPQUOTA),
>>> + test_opt(F2FS_SB(sb), PRJQUOTA),
>>> + };
>>> +
>>> + sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NOLIST_DIRTY;
>>> + for (type = 0; type < MAXQUOTAS; type++) {
>>> + qf_inum = f2fs_qf_ino(sb, type);
>>> + if (qf_inum) {
>>> + err = f2fs_quota_enable(sb, type, QFMT_VFS_V1,
>>> + DQUOT_USAGE_ENABLED |
>>> + (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0));
>>> + if (err) {
>>> + f2fs_msg(sb, KERN_ERR,
>>> + "Failed to enable quota tracking "
>>> + "(type=%d, err=%d). Please run "
>>> + "fsck to fix.", type, err);
>>> + for (type--; type >= 0; type--)
>>> + dquot_quota_off(sb, type);
>>> + return err;
>>> + }
>>> }
>>> }
>>> + return 0;
>>> }
>>>
>>> static int f2fs_quota_sync(struct super_block *sb, int type)
>>> @@ -1537,7 +1635,7 @@ static int f2fs_quota_off(struct super_block *sb, int type)
>>> f2fs_quota_sync(sb, type);
>>>
>>> err = dquot_quota_off(sb, type);
>>> - if (err)
>>> + if (err || f2fs_sb_has_quota_ino(sb))
>>> goto out_put;
>>>
>>> inode_lock(inode);
>>> @@ -2364,7 +2462,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>>>
>>> #ifdef CONFIG_QUOTA
>>> sb->dq_op = &f2fs_quota_operations;
>>> - sb->s_qcop = &f2fs_quotactl_ops;
>>> + if (f2fs_sb_has_quota_ino(sb))
>>> + sb->s_qcop = &dquot_quotactl_sysfile_ops;
>>> + else
>>> + sb->s_qcop = &f2fs_quotactl_ops;
>>> sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
>>> #endif
>>>
>>> @@ -2535,10 +2636,24 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>>> if (err)
>>> goto free_root_inode;
>>>
>>> +#ifdef CONFIG_QUOTA
>>> + /*
>>> + * Turn on quotas which were not enabled for read-only mounts if
>>> + * filesystem has quota feature, so that they are updated correctly.
>>> + */
>>> + if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) {
>>> + err = f2fs_enable_quotas(sb);
>>> + if (err) {
>>> + f2fs_msg(sb, KERN_ERR,
>>> + "Cannot turn on quotas: error %d", err);
>>> + goto free_sysfs;
>>> + }
>>> + }
>>> +#endif
>>> /* if there are nt orphan nodes free them */
>>> err = recover_orphan_inodes(sbi);
>>> if (err)
>>> - goto free_sysfs;
>>> + goto free_meta;
>>>
>>> /* recover fsynced data */
>>> if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
>>> @@ -2572,7 +2687,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>>> err = -EINVAL;
>>> f2fs_msg(sb, KERN_ERR,
>>> "Need to recover fsync data");
>>> - goto free_sysfs;
>>> + goto free_meta;
>>> }
>>> }
>>> skip_recovery:
>>> @@ -2606,6 +2721,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>>> return 0;
>>>
>>> free_meta:
>>> +#ifdef CONFIG_QUOTA
>>> + if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb))
>>> + f2fs_quota_off_umount(sbi->sb);
>>> +#endif
>>> f2fs_sync_inode_meta(sbi);
>>> /*
>>> * Some dirty meta pages can be produced by recover_orphan_inodes()
>>>
>
> .
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [f2fs-dev] [PATCH 2/2] f2fs: support quota sys files
2017-11-03 5:48 ` Chao Yu
@ 2017-11-03 18:27 ` Jaegeuk Kim
0 siblings, 0 replies; 7+ messages in thread
From: Jaegeuk Kim @ 2017-11-03 18:27 UTC (permalink / raw)
To: Chao Yu; +Cc: Chao Yu, linux-kernel, linux-fsdevel, linux-f2fs-devel
On 11/03, Chao Yu wrote:
> On 2017/11/3 11:37, Jaegeuk Kim wrote:
> > On 11/02, Chao Yu wrote:
> >> On 2017/10/31 11:40, Jaegeuk Kim wrote:
> >>> This patch supports hidden quota files in the system, which will be used for
> >>> Android. It requires up-to-date f2fs-tools later than v1.9.0.
> >>>
> >>> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> >>> ---
> >>> fs/f2fs/checkpoint.c | 9 +++-
> >>> fs/f2fs/f2fs.h | 9 +++-
> >>> fs/f2fs/recovery.c | 8 ++-
> >>> fs/f2fs/super.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++-----
> >>> 4 files changed, 153 insertions(+), 18 deletions(-)
> >>>
> >>> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
> >>> index 6b52d4b66c7b..78e1b2998bbd 100644
> >>> --- a/fs/f2fs/checkpoint.c
> >>> +++ b/fs/f2fs/checkpoint.c
> >>> @@ -615,6 +615,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
> >>> block_t start_blk, orphan_blocks, i, j;
> >>> unsigned int s_flags = sbi->sb->s_flags;
> >>> int err = 0;
> >>> +#ifdef CONFIG_QUOTA
> >>> + int quota_enabled;
> >>> +#endif
> >>>
> >>> if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
> >>> return 0;
> >>> @@ -627,8 +630,9 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
> >>> #ifdef CONFIG_QUOTA
> >>> /* Needed for iput() to work correctly and not trash data */
> >>> sbi->sb->s_flags |= MS_ACTIVE;
> >>> +
> >>> /* Turn on quotas so that they are updated correctly */
> >>> - f2fs_enable_quota_files(sbi);
> >>> + quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
> >>> #endif
> >>>
> >>> start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
> >>> @@ -656,7 +660,8 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
> >>> out:
> >>> #ifdef CONFIG_QUOTA
> >>> /* Turn quotas off */
> >>> - f2fs_quota_off_umount(sbi->sb);
> >>> + if (quota_enabled)
> >>> + f2fs_quota_off_umount(sbi->sb);
> >>> #endif
> >>> sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
> >>>
> >>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> >>> index 9a1c7ffa6845..e1d3a940d9f8 100644
> >>> --- a/fs/f2fs/f2fs.h
> >>> +++ b/fs/f2fs/f2fs.h
> >>> @@ -1384,6 +1384,13 @@ static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp)
> >>> return le64_to_cpu(cp->checkpoint_ver);
> >>> }
> >>>
> >>> +static inline unsigned long f2fs_qf_ino(struct super_block *sb, int type)
> >>> +{
> >>> + if (type < F2FS_QUOTA_INO)
> >>
> >> Why not just use F2FS_MAX_QUOTAS instead of F2FS_QUOTA_INO? since in patch 1/2
> >> we have defined qf_ino array with upper-boundary F2FS_MAX_QUOTAS.
> >
> > It was intended to indicate # of enabled quotas. ;)
>
> Alright, so how about renaming it to F2FS_ENABLED_QUOTA_INO... :)
I just removed this. ;)
>
> Thanks,
>
> >
> >>
> >> __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
> >>
> >> Other part looks good to me. ;)
> >>
> >> Reviewed-by: Chao Yu <yuchao0@huawei.com>
> >>
> >> Thanks,
> >>
> >>> + return le32_to_cpu(F2FS_SB(sb)->raw_super->qf_ino[type]);
> >>> + return 0;
> >>> +}
> >>> +
> >>> static inline __u64 cur_cp_crc(struct f2fs_checkpoint *cp)
> >>> {
> >>> size_t crc_offset = le32_to_cpu(cp->checksum_offset);
> >>> @@ -2526,7 +2533,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
> >>> */
> >>> int f2fs_inode_dirtied(struct inode *inode, bool sync);
> >>> void f2fs_inode_synced(struct inode *inode);
> >>> -void f2fs_enable_quota_files(struct f2fs_sb_info *sbi);
> >>> +int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly);
> >>> void f2fs_quota_off_umount(struct super_block *sb);
> >>> int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover);
> >>> int f2fs_sync_fs(struct super_block *sb, int sync);
> >>> diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
> >>> index 9626758bc762..92c57ace1939 100644
> >>> --- a/fs/f2fs/recovery.c
> >>> +++ b/fs/f2fs/recovery.c
> >>> @@ -594,6 +594,9 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
> >>> int ret = 0;
> >>> unsigned long s_flags = sbi->sb->s_flags;
> >>> bool need_writecp = false;
> >>> +#ifdef CONFIG_QUOTA
> >>> + int quota_enabled;
> >>> +#endif
> >>>
> >>> if (s_flags & MS_RDONLY) {
> >>> f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs");
> >>> @@ -604,7 +607,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
> >>> /* Needed for iput() to work correctly and not trash data */
> >>> sbi->sb->s_flags |= MS_ACTIVE;
> >>> /* Turn on quotas so that they are updated correctly */
> >>> - f2fs_enable_quota_files(sbi);
> >>> + quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY);
> >>> #endif
> >>>
> >>> fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
> >>> @@ -665,7 +668,8 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
> >>> out:
> >>> #ifdef CONFIG_QUOTA
> >>> /* Turn quotas off */
> >>> - f2fs_quota_off_umount(sbi->sb);
> >>> + if (quota_enabled)
> >>> + f2fs_quota_off_umount(sbi->sb);
> >>> #endif
> >>> sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
> >>>
> >>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> >>> index 96e145c34ba2..0ca7b055e4e0 100644
> >>> --- a/fs/f2fs/super.c
> >>> +++ b/fs/f2fs/super.c
> >>> @@ -213,6 +213,12 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype,
> >>> "quota options when quota turned on");
> >>> return -EINVAL;
> >>> }
> >>> + if (f2fs_sb_has_quota_ino(sb)) {
> >>> + f2fs_msg(sb, KERN_INFO,
> >>> + "QUOTA feature is enabled, so ignore qf_name");
> >>> + return 0;
> >>> + }
> >>> +
> >>> qname = match_strdup(args);
> >>> if (!qname) {
> >>> f2fs_msg(sb, KERN_ERR,
> >>> @@ -291,6 +297,18 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
> >>> return -1;
> >>> }
> >>> }
> >>> +
> >>> + if (f2fs_sb_has_quota_ino(sbi->sb) && sbi->s_jquota_fmt) {
> >>> + f2fs_msg(sbi->sb, KERN_INFO,
> >>> + "QUOTA feature is enabled, so ignore jquota_fmt");
> >>> + sbi->s_jquota_fmt = 0;
> >>> + }
> >>> + if (f2fs_sb_has_quota_ino(sbi->sb) && sb_rdonly(sbi->sb)) {
> >>> + f2fs_msg(sbi->sb, KERN_INFO,
> >>> + "Filesystem with quota feature cannot be mounted RDWR "
> >>> + "without CONFIG_QUOTA");
> >>> + return -1;
> >>> + }
> >>> return 0;
> >>> }
> >>> #endif
> >>> @@ -1172,6 +1190,7 @@ static void default_options(struct f2fs_sb_info *sbi)
> >>> #endif
> >>> }
> >>>
> >>> +static int f2fs_enable_quotas(struct super_block *sb);
> >>> static int f2fs_remount(struct super_block *sb, int *flags, char *data)
> >>> {
> >>> struct f2fs_sb_info *sbi = F2FS_SB(sb);
> >>> @@ -1238,6 +1257,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
> >>> if (f2fs_readonly(sb) && (*flags & MS_RDONLY))
> >>> goto skip;
> >>>
> >>> +#ifdef CONFIG_QUOTA
> >>> if (!f2fs_readonly(sb) && (*flags & MS_RDONLY)) {
> >>> err = dquot_suspend(sb, -1);
> >>> if (err < 0)
> >>> @@ -1245,9 +1265,15 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
> >>> } else {
> >>> /* dquot_resume needs RW */
> >>> sb->s_flags &= ~MS_RDONLY;
> >>> - dquot_resume(sb, -1);
> >>> + if (sb_any_quota_suspended(sb)) {
> >>> + dquot_resume(sb, -1);
> >>> + } else if (f2fs_sb_has_quota_ino(sb)) {
> >>> + err = f2fs_enable_quotas(sb);
> >>> + if (err)
> >>> + goto restore_opts;
> >>> + }
> >>> }
> >>> -
> >>> +#endif
> >>> /* disallow enable/disable extent_cache dynamically */
> >>> if (no_extent_cache == !!test_opt(sbi, EXTENT_CACHE)) {
> >>> err = -EINVAL;
> >>> @@ -1454,19 +1480,91 @@ static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type)
> >>> sbi->s_jquota_fmt, type);
> >>> }
> >>>
> >>> -void f2fs_enable_quota_files(struct f2fs_sb_info *sbi)
> >>> +int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly)
> >>> {
> >>> - int i, ret;
> >>> + int enabled = 0;
> >>> + int i, err;
> >>> +
> >>> + if (f2fs_sb_has_quota_ino(sbi->sb) && rdonly) {
> >>> + err = f2fs_enable_quotas(sbi->sb);
> >>> + if (err) {
> >>> + f2fs_msg(sbi->sb, KERN_ERR,
> >>> + "Cannot turn on quota_ino: %d", err);
> >>> + return 0;
> >>> + }
> >>> + return 1;
> >>> + }
> >>>
> >>> for (i = 0; i < MAXQUOTAS; i++) {
> >>> if (sbi->s_qf_names[i]) {
> >>> - ret = f2fs_quota_on_mount(sbi, i);
> >>> - if (ret < 0)
> >>> - f2fs_msg(sbi->sb, KERN_ERR,
> >>> - "Cannot turn on journaled "
> >>> - "quota: error %d", ret);
> >>> + err = f2fs_quota_on_mount(sbi, i);
> >>> + if (!err) {
> >>> + enabled = 1;
> >>> + continue;
> >>> + }
> >>> + f2fs_msg(sbi->sb, KERN_ERR,
> >>> + "Cannot turn on quotas: %d on %d", err, i);
> >>> + }
> >>> + }
> >>> + return enabled;
> >>> +}
> >>> +
> >>> +static int f2fs_quota_enable(struct super_block *sb, int type, int format_id,
> >>> + unsigned int flags)
> >>> +{
> >>> + struct inode *qf_inode;
> >>> + unsigned long qf_inum;
> >>> + int err;
> >>> +
> >>> + BUG_ON(!f2fs_sb_has_quota_ino(sb));
> >>> +
> >>> + qf_inum = f2fs_qf_ino(sb, type);
> >>> + if (!qf_inum)
> >>> + return -EPERM;
> >>> +
> >>> + qf_inode = f2fs_iget(sb, qf_inum);
> >>> + if (IS_ERR(qf_inode)) {
> >>> + f2fs_msg(sb, KERN_ERR,
> >>> + "Bad quota inode %u:%lu", type, qf_inum);
> >>> + return PTR_ERR(qf_inode);
> >>> + }
> >>> +
> >>> + /* Don't account quota for quota files to avoid recursion */
> >>> + qf_inode->i_flags |= S_NOQUOTA;
> >>> + err = dquot_enable(qf_inode, type, format_id, flags);
> >>> + iput(qf_inode);
> >>> + return err;
> >>> +}
> >>> +
> >>> +static int f2fs_enable_quotas(struct super_block *sb)
> >>> +{
> >>> + int type, err = 0;
> >>> + unsigned long qf_inum;
> >>> + bool quota_mopt[MAXQUOTAS] = {
> >>> + test_opt(F2FS_SB(sb), USRQUOTA),
> >>> + test_opt(F2FS_SB(sb), GRPQUOTA),
> >>> + test_opt(F2FS_SB(sb), PRJQUOTA),
> >>> + };
> >>> +
> >>> + sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NOLIST_DIRTY;
> >>> + for (type = 0; type < MAXQUOTAS; type++) {
> >>> + qf_inum = f2fs_qf_ino(sb, type);
> >>> + if (qf_inum) {
> >>> + err = f2fs_quota_enable(sb, type, QFMT_VFS_V1,
> >>> + DQUOT_USAGE_ENABLED |
> >>> + (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0));
> >>> + if (err) {
> >>> + f2fs_msg(sb, KERN_ERR,
> >>> + "Failed to enable quota tracking "
> >>> + "(type=%d, err=%d). Please run "
> >>> + "fsck to fix.", type, err);
> >>> + for (type--; type >= 0; type--)
> >>> + dquot_quota_off(sb, type);
> >>> + return err;
> >>> + }
> >>> }
> >>> }
> >>> + return 0;
> >>> }
> >>>
> >>> static int f2fs_quota_sync(struct super_block *sb, int type)
> >>> @@ -1537,7 +1635,7 @@ static int f2fs_quota_off(struct super_block *sb, int type)
> >>> f2fs_quota_sync(sb, type);
> >>>
> >>> err = dquot_quota_off(sb, type);
> >>> - if (err)
> >>> + if (err || f2fs_sb_has_quota_ino(sb))
> >>> goto out_put;
> >>>
> >>> inode_lock(inode);
> >>> @@ -2364,7 +2462,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >>>
> >>> #ifdef CONFIG_QUOTA
> >>> sb->dq_op = &f2fs_quota_operations;
> >>> - sb->s_qcop = &f2fs_quotactl_ops;
> >>> + if (f2fs_sb_has_quota_ino(sb))
> >>> + sb->s_qcop = &dquot_quotactl_sysfile_ops;
> >>> + else
> >>> + sb->s_qcop = &f2fs_quotactl_ops;
> >>> sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
> >>> #endif
> >>>
> >>> @@ -2535,10 +2636,24 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >>> if (err)
> >>> goto free_root_inode;
> >>>
> >>> +#ifdef CONFIG_QUOTA
> >>> + /*
> >>> + * Turn on quotas which were not enabled for read-only mounts if
> >>> + * filesystem has quota feature, so that they are updated correctly.
> >>> + */
> >>> + if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) {
> >>> + err = f2fs_enable_quotas(sb);
> >>> + if (err) {
> >>> + f2fs_msg(sb, KERN_ERR,
> >>> + "Cannot turn on quotas: error %d", err);
> >>> + goto free_sysfs;
> >>> + }
> >>> + }
> >>> +#endif
> >>> /* if there are nt orphan nodes free them */
> >>> err = recover_orphan_inodes(sbi);
> >>> if (err)
> >>> - goto free_sysfs;
> >>> + goto free_meta;
> >>>
> >>> /* recover fsynced data */
> >>> if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
> >>> @@ -2572,7 +2687,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >>> err = -EINVAL;
> >>> f2fs_msg(sb, KERN_ERR,
> >>> "Need to recover fsync data");
> >>> - goto free_sysfs;
> >>> + goto free_meta;
> >>> }
> >>> }
> >>> skip_recovery:
> >>> @@ -2606,6 +2721,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >>> return 0;
> >>>
> >>> free_meta:
> >>> +#ifdef CONFIG_QUOTA
> >>> + if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb))
> >>> + f2fs_quota_off_umount(sbi->sb);
> >>> +#endif
> >>> f2fs_sync_inode_meta(sbi);
> >>> /*
> >>> * Some dirty meta pages can be produced by recover_orphan_inodes()
> >>>
> >
> > .
> >
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-11-03 18:27 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-31 3:40 [PATCH 1/2] f2fs: add quota_ino feature infra Jaegeuk Kim
2017-10-31 3:40 ` [PATCH 2/2] f2fs: support quota sys files Jaegeuk Kim
2017-11-02 14:45 ` [f2fs-dev] " Chao Yu
2017-11-03 3:37 ` Jaegeuk Kim
2017-11-03 5:48 ` Chao Yu
2017-11-03 18:27 ` Jaegeuk Kim
2017-11-02 14:25 ` [f2fs-dev] [PATCH 1/2] f2fs: add quota_ino feature infra Chao Yu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).