Commit 5c57132e authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim

f2fs: support project quota

This patch adds to support plain project quota.
Signed-off-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent a6d3a479
...@@ -164,6 +164,7 @@ io_bits=%u Set the bit size of write IO requests. It should be set ...@@ -164,6 +164,7 @@ io_bits=%u Set the bit size of write IO requests. It should be set
with "mode=lfs". with "mode=lfs".
usrquota Enable plain user disk quota accounting. usrquota Enable plain user disk quota accounting.
grpquota Enable plain group disk quota accounting. grpquota Enable plain group disk quota accounting.
prjquota Enable plain project quota accounting.
================================================================================ ================================================================================
DEBUGFS ENTRIES DEBUGFS ENTRIES
......
...@@ -91,6 +91,7 @@ extern char *fault_name[FAULT_MAX]; ...@@ -91,6 +91,7 @@ extern char *fault_name[FAULT_MAX];
#define F2FS_MOUNT_LFS 0x00040000 #define F2FS_MOUNT_LFS 0x00040000
#define F2FS_MOUNT_USRQUOTA 0x00080000 #define F2FS_MOUNT_USRQUOTA 0x00080000
#define F2FS_MOUNT_GRPQUOTA 0x00100000 #define F2FS_MOUNT_GRPQUOTA 0x00100000
#define F2FS_MOUNT_PRJQUOTA 0x00200000
#define clear_opt(sbi, option) ((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option) #define clear_opt(sbi, option) ((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
#define set_opt(sbi, option) ((sbi)->mount_opt.opt |= F2FS_MOUNT_##option) #define set_opt(sbi, option) ((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
...@@ -114,6 +115,7 @@ struct f2fs_mount_info { ...@@ -114,6 +115,7 @@ struct f2fs_mount_info {
#define F2FS_FEATURE_BLKZONED 0x0002 #define F2FS_FEATURE_BLKZONED 0x0002
#define F2FS_FEATURE_ATOMIC_WRITE 0x0004 #define F2FS_FEATURE_ATOMIC_WRITE 0x0004
#define F2FS_FEATURE_EXTRA_ATTR 0x0008 #define F2FS_FEATURE_EXTRA_ATTR 0x0008
#define F2FS_FEATURE_PRJQUOTA 0x0010
#define F2FS_HAS_FEATURE(sb, mask) \ #define F2FS_HAS_FEATURE(sb, mask) \
((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0) ((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0)
...@@ -570,6 +572,7 @@ struct f2fs_inode_info { ...@@ -570,6 +572,7 @@ struct f2fs_inode_info {
struct rw_semaphore i_mmap_sem; struct rw_semaphore i_mmap_sem;
int i_extra_isize; /* size of extra space located in i_addr */ int i_extra_isize; /* size of extra space located in i_addr */
kprojid_t i_projid; /* id for project quota */
}; };
static inline void get_extent_info(struct extent_info *ext, static inline void get_extent_info(struct extent_info *ext,
...@@ -1887,6 +1890,20 @@ static inline void f2fs_change_bit(unsigned int nr, char *addr) ...@@ -1887,6 +1890,20 @@ static inline void f2fs_change_bit(unsigned int nr, char *addr)
*addr ^= mask; *addr ^= mask;
} }
#define F2FS_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
#define F2FS_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL)
#define F2FS_FL_INHERITED (FS_PROJINHERIT_FL)
static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags)
{
if (S_ISDIR(mode))
return flags;
else if (S_ISREG(mode))
return flags & F2FS_REG_FLMASK;
else
return flags & F2FS_OTHER_FLMASK;
}
/* used for f2fs_inode_info->flags */ /* used for f2fs_inode_info->flags */
enum { enum {
FI_NEW_INODE, /* indicate newly allocated inode */ FI_NEW_INODE, /* indicate newly allocated inode */
...@@ -1916,6 +1933,7 @@ enum { ...@@ -1916,6 +1933,7 @@ enum {
FI_NO_PREALLOC, /* indicate skipped preallocated blocks */ FI_NO_PREALLOC, /* indicate skipped preallocated blocks */
FI_HOT_DATA, /* indicate file is hot */ FI_HOT_DATA, /* indicate file is hot */
FI_EXTRA_ATTR, /* indicate file has extra attribute */ FI_EXTRA_ATTR, /* indicate file has extra attribute */
FI_PROJ_INHERIT, /* indicate file inherits projectid */
}; };
static inline void __mark_inode_dirty_flag(struct inode *inode, static inline void __mark_inode_dirty_flag(struct inode *inode,
...@@ -2239,6 +2257,12 @@ static inline int get_extra_isize(struct inode *inode) ...@@ -2239,6 +2257,12 @@ static inline int get_extra_isize(struct inode *inode)
(offsetof(struct f2fs_inode, i_extra_end) - \ (offsetof(struct f2fs_inode, i_extra_end) - \
offsetof(struct f2fs_inode, i_extra_isize)) \ offsetof(struct f2fs_inode, i_extra_isize)) \
#define F2FS_OLD_ATTRIBUTE_SIZE (offsetof(struct f2fs_inode, i_addr))
#define F2FS_FITS_IN_INODE(f2fs_inode, extra_isize, field) \
((offsetof(typeof(*f2fs_inode), field) + \
sizeof((f2fs_inode)->field)) \
<= (F2FS_OLD_ATTRIBUTE_SIZE + extra_isize)) \
/* /*
* file.c * file.c
*/ */
...@@ -2836,6 +2860,11 @@ static inline int f2fs_sb_has_extra_attr(struct super_block *sb) ...@@ -2836,6 +2860,11 @@ static inline int f2fs_sb_has_extra_attr(struct super_block *sb)
return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_EXTRA_ATTR); return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_EXTRA_ATTR);
} }
static inline int f2fs_sb_has_project_quota(struct super_block *sb)
{
return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_PRJQUOTA);
}
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
static inline int get_blkz_type(struct f2fs_sb_info *sbi, static inline int get_blkz_type(struct f2fs_sb_info *sbi,
struct block_device *bdev, block_t blkaddr) struct block_device *bdev, block_t blkaddr)
......
...@@ -1518,19 +1518,6 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id) ...@@ -1518,19 +1518,6 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id)
return 0; return 0;
} }
#define F2FS_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
#define F2FS_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL)
static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags)
{
if (S_ISDIR(mode))
return flags;
else if (S_ISREG(mode))
return flags & F2FS_REG_FLMASK;
else
return flags & F2FS_OTHER_FLMASK;
}
static int f2fs_ioc_getflags(struct file *filp, unsigned long arg) static int f2fs_ioc_getflags(struct file *filp, unsigned long arg)
{ {
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
......
...@@ -114,6 +114,7 @@ static int do_read_inode(struct inode *inode) ...@@ -114,6 +114,7 @@ static int do_read_inode(struct inode *inode)
struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_inode_info *fi = F2FS_I(inode);
struct page *node_page; struct page *node_page;
struct f2fs_inode *ri; struct f2fs_inode *ri;
projid_t i_projid;
/* Check if ino is within scope */ /* Check if ino is within scope */
if (check_nid_range(sbi, inode->i_ino)) { if (check_nid_range(sbi, inode->i_ino)) {
...@@ -173,6 +174,16 @@ static int do_read_inode(struct inode *inode) ...@@ -173,6 +174,16 @@ static int do_read_inode(struct inode *inode)
if (!need_inode_block_update(sbi, inode->i_ino)) if (!need_inode_block_update(sbi, inode->i_ino))
fi->last_disk_size = inode->i_size; fi->last_disk_size = inode->i_size;
if (fi->i_flags & FS_PROJINHERIT_FL)
set_inode_flag(inode, FI_PROJ_INHERIT);
if (f2fs_has_extra_attr(inode) && f2fs_sb_has_project_quota(sbi->sb) &&
F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid))
i_projid = (projid_t)le32_to_cpu(ri->i_projid);
else
i_projid = F2FS_DEF_PROJID;
fi->i_projid = make_kprojid(&init_user_ns, i_projid);
f2fs_put_page(node_page, 1); f2fs_put_page(node_page, 1);
stat_inc_inline_xattr(inode); stat_inc_inline_xattr(inode);
...@@ -299,9 +310,20 @@ int update_inode(struct inode *inode, struct page *node_page) ...@@ -299,9 +310,20 @@ int update_inode(struct inode *inode, struct page *node_page)
ri->i_generation = cpu_to_le32(inode->i_generation); ri->i_generation = cpu_to_le32(inode->i_generation);
ri->i_dir_level = F2FS_I(inode)->i_dir_level; ri->i_dir_level = F2FS_I(inode)->i_dir_level;
if (f2fs_has_extra_attr(inode)) if (f2fs_has_extra_attr(inode)) {
ri->i_extra_isize = cpu_to_le16(F2FS_I(inode)->i_extra_isize); ri->i_extra_isize = cpu_to_le16(F2FS_I(inode)->i_extra_isize);
if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)->sb) &&
F2FS_FITS_IN_INODE(ri, F2FS_I(inode)->i_extra_isize,
i_projid)) {
projid_t i_projid;
i_projid = from_kprojid(&init_user_ns,
F2FS_I(inode)->i_projid);
ri->i_projid = cpu_to_le32(i_projid);
}
}
__set_inode_rdev(inode, ri); __set_inode_rdev(inode, ri);
set_cold_node(inode, node_page); set_cold_node(inode, node_page);
......
...@@ -58,6 +58,13 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) ...@@ -58,6 +58,13 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
goto fail; goto fail;
} }
if (f2fs_sb_has_project_quota(sbi->sb) &&
(F2FS_I(dir)->i_flags & FS_PROJINHERIT_FL))
F2FS_I(inode)->i_projid = F2FS_I(dir)->i_projid;
else
F2FS_I(inode)->i_projid = make_kprojid(&init_user_ns,
F2FS_DEF_PROJID);
err = dquot_initialize(inode); err = dquot_initialize(inode);
if (err) if (err)
goto fail_drop; goto fail_drop;
...@@ -90,6 +97,12 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) ...@@ -90,6 +97,12 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
stat_inc_inline_inode(inode); stat_inc_inline_inode(inode);
stat_inc_inline_dir(inode); stat_inc_inline_dir(inode);
F2FS_I(inode)->i_flags =
f2fs_mask_flags(mode, F2FS_I(dir)->i_flags & F2FS_FL_INHERITED);
if (F2FS_I(inode)->i_flags & FS_PROJINHERIT_FL)
set_inode_flag(inode, FI_PROJ_INHERIT);
trace_f2fs_new_inode(inode, 0); trace_f2fs_new_inode(inode, 0);
return inode; return inode;
...@@ -209,6 +222,11 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -209,6 +222,11 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
!fscrypt_has_permitted_context(dir, inode)) !fscrypt_has_permitted_context(dir, inode))
return -EPERM; return -EPERM;
if (is_inode_flag_set(dir, FI_PROJ_INHERIT) &&
(!projid_eq(F2FS_I(dir)->i_projid,
F2FS_I(old_dentry->d_inode)->i_projid)))
return -EXDEV;
err = dquot_initialize(dir); err = dquot_initialize(dir);
if (err) if (err)
return err; return err;
...@@ -733,6 +751,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -733,6 +751,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out; goto out;
} }
if (is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
(!projid_eq(F2FS_I(new_dir)->i_projid,
F2FS_I(old_dentry->d_inode)->i_projid)))
return -EXDEV;
err = dquot_initialize(old_dir); err = dquot_initialize(old_dir);
if (err) if (err)
goto out; goto out;
...@@ -921,6 +944,14 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -921,6 +944,14 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
!fscrypt_has_permitted_context(old_dir, new_inode))) !fscrypt_has_permitted_context(old_dir, new_inode)))
return -EPERM; return -EPERM;
if ((is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
!projid_eq(F2FS_I(new_dir)->i_projid,
F2FS_I(old_dentry->d_inode)->i_projid)) ||
(is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
!projid_eq(F2FS_I(old_dir)->i_projid,
F2FS_I(new_dentry->d_inode)->i_projid)))
return -EXDEV;
err = dquot_initialize(old_dir); err = dquot_initialize(old_dir);
if (err) if (err)
goto out; goto out;
......
...@@ -2265,8 +2265,13 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) ...@@ -2265,8 +2265,13 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
dst->i_links = cpu_to_le32(1); dst->i_links = cpu_to_le32(1);
dst->i_xattr_nid = 0; dst->i_xattr_nid = 0;
dst->i_inline = src->i_inline & (F2FS_INLINE_XATTR | F2FS_EXTRA_ATTR); dst->i_inline = src->i_inline & (F2FS_INLINE_XATTR | F2FS_EXTRA_ATTR);
if (dst->i_inline & F2FS_EXTRA_ATTR) if (dst->i_inline & F2FS_EXTRA_ATTR) {
dst->i_extra_isize = src->i_extra_isize; dst->i_extra_isize = src->i_extra_isize;
if (f2fs_sb_has_project_quota(sbi->sb) &&
F2FS_FITS_IN_INODE(src, le16_to_cpu(src->i_extra_isize),
i_projid))
dst->i_projid = src->i_projid;
}
new_ni = old_ni; new_ni = old_ni;
new_ni.ino = ino; new_ni.ino = ino;
......
...@@ -109,6 +109,7 @@ enum { ...@@ -109,6 +109,7 @@ enum {
Opt_nolazytime, Opt_nolazytime,
Opt_usrquota, Opt_usrquota,
Opt_grpquota, Opt_grpquota,
Opt_prjquota,
Opt_err, Opt_err,
}; };
...@@ -146,6 +147,7 @@ static match_table_t f2fs_tokens = { ...@@ -146,6 +147,7 @@ static match_table_t f2fs_tokens = {
{Opt_nolazytime, "nolazytime"}, {Opt_nolazytime, "nolazytime"},
{Opt_usrquota, "usrquota"}, {Opt_usrquota, "usrquota"},
{Opt_grpquota, "grpquota"}, {Opt_grpquota, "grpquota"},
{Opt_prjquota, "prjquota"},
{Opt_err, NULL}, {Opt_err, NULL},
}; };
...@@ -392,9 +394,13 @@ static int parse_options(struct super_block *sb, char *options) ...@@ -392,9 +394,13 @@ static int parse_options(struct super_block *sb, char *options)
case Opt_grpquota: case Opt_grpquota:
set_opt(sbi, GRPQUOTA); set_opt(sbi, GRPQUOTA);
break; break;
case Opt_prjquota:
set_opt(sbi, PRJQUOTA);
break;
#else #else
case Opt_usrquota: case Opt_usrquota:
case Opt_grpquota: case Opt_grpquota:
case Opt_prjquota:
f2fs_msg(sb, KERN_INFO, f2fs_msg(sb, KERN_INFO,
"quota operations not supported"); "quota operations not supported");
break; break;
...@@ -814,6 +820,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) ...@@ -814,6 +820,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",usrquota"); seq_puts(seq, ",usrquota");
if (test_opt(sbi, GRPQUOTA)) if (test_opt(sbi, GRPQUOTA))
seq_puts(seq, ",grpquota"); seq_puts(seq, ",grpquota");
if (test_opt(sbi, PRJQUOTA))
seq_puts(seq, ",prjquota");
#endif #endif
return 0; return 0;
...@@ -1172,6 +1180,12 @@ static void f2fs_quota_off_umount(struct super_block *sb) ...@@ -1172,6 +1180,12 @@ static void f2fs_quota_off_umount(struct super_block *sb)
f2fs_quota_off(sb, type); f2fs_quota_off(sb, type);
} }
int f2fs_get_projid(struct inode *inode, kprojid_t *projid)
{
*projid = F2FS_I(inode)->i_projid;
return 0;
}
static const struct dquot_operations f2fs_quota_operations = { static const struct dquot_operations f2fs_quota_operations = {
.get_reserved_space = f2fs_get_reserved_space, .get_reserved_space = f2fs_get_reserved_space,
.write_dquot = dquot_commit, .write_dquot = dquot_commit,
...@@ -1181,6 +1195,7 @@ static const struct dquot_operations f2fs_quota_operations = { ...@@ -1181,6 +1195,7 @@ static const struct dquot_operations f2fs_quota_operations = {
.write_info = dquot_commit_info, .write_info = dquot_commit_info,
.alloc_dquot = dquot_alloc, .alloc_dquot = dquot_alloc,
.destroy_dquot = dquot_destroy, .destroy_dquot = dquot_destroy,
.get_projid = f2fs_get_projid,
.get_next_id = dquot_get_next_id, .get_next_id = dquot_get_next_id,
}; };
...@@ -1964,7 +1979,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1964,7 +1979,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
sb->dq_op = &f2fs_quota_operations; sb->dq_op = &f2fs_quota_operations;
sb->s_qcop = &f2fs_quotactl_ops; sb->s_qcop = &f2fs_quotactl_ops;
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
sb->s_op = &f2fs_sops; sb->s_op = &f2fs_sops;
......
...@@ -239,6 +239,7 @@ struct f2fs_inode { ...@@ -239,6 +239,7 @@ struct f2fs_inode {
struct { struct {
__le16 i_extra_isize; /* extra inode attribute size */ __le16 i_extra_isize; /* extra inode attribute size */
__le16 i_padding; /* padding */ __le16 i_padding; /* padding */
__le32 i_projid; /* project id */
__le32 i_extra_end[0]; /* for attribute size calculation */ __le32 i_extra_end[0]; /* for attribute size calculation */
}; };
__le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */ __le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */
...@@ -522,4 +523,6 @@ enum { ...@@ -522,4 +523,6 @@ enum {
#define S_SHIFT 12 #define S_SHIFT 12
#define F2FS_DEF_PROJID 0 /* default project ID */
#endif /* _LINUX_F2FS_FS_H */ #endif /* _LINUX_F2FS_FS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment