diff options
| author | Chao Yu <yuchao0@huawei.com> | 2017-07-26 00:01:41 +0800 |
|---|---|---|
| committer | Mister Oyster <oysterized@gmail.com> | 2017-10-04 15:23:29 +0200 |
| commit | b404bc44dbc1df424a3853b13eee44036fe5a85c (patch) | |
| tree | 06ace60fb67a8c03208a2a639c7712b29cc98915 | |
| parent | 54010e63d33e00627c1062e2fe2946850e9dead3 (diff) | |
f2fs: support project quota
This patch adds to support plain project quota.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
| -rw-r--r-- | Documentation/filesystems/f2fs.txt | 1 | ||||
| -rw-r--r-- | fs/f2fs/f2fs.h | 33 | ||||
| -rw-r--r-- | fs/f2fs/file.c | 13 | ||||
| -rw-r--r-- | fs/f2fs/inode.c | 24 | ||||
| -rw-r--r-- | fs/f2fs/namei.c | 30 | ||||
| -rw-r--r-- | fs/f2fs/node.c | 7 | ||||
| -rw-r--r-- | fs/f2fs/super.c | 26 | ||||
| -rw-r--r-- | include/linux/f2fs_fs.h | 3 | ||||
| -rw-r--r-- | include/uapi/linux/fs.h | 1 |
9 files changed, 123 insertions, 15 deletions
diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index 66956006a..eac67c969 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -162,6 +162,7 @@ io_bits=%u Set the bit size of write IO requests. It should be set with "mode=lfs". usrquota Enable plain user disk quota accounting. grpquota Enable plain group disk quota accounting. +prjquota Enable plain project quota accounting. ================================================================================ DEBUGFS ENTRIES diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index f01b156ca..1cf12c64d 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -93,6 +93,7 @@ extern char *fault_name[FAULT_MAX]; #define F2FS_MOUNT_LFS 0x00040000 #define F2FS_MOUNT_USRQUOTA 0x00080000 #define F2FS_MOUNT_GRPQUOTA 0x00100000 +#define F2FS_MOUNT_PRJQUOTA 0x00200000 #define clear_opt(sbi, option) ((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option) #define set_opt(sbi, option) ((sbi)->mount_opt.opt |= F2FS_MOUNT_##option) @@ -116,6 +117,7 @@ struct f2fs_mount_info { #define F2FS_FEATURE_BLKZONED 0x0002 #define F2FS_FEATURE_ATOMIC_WRITE 0x0004 #define F2FS_FEATURE_EXTRA_ATTR 0x0008 +#define F2FS_FEATURE_PRJQUOTA 0x0010 #define F2FS_HAS_FEATURE(sb, mask) \ ((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0) @@ -674,6 +676,7 @@ struct f2fs_inode_info { struct rw_semaphore i_mmap_sem; 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, @@ -1032,6 +1035,10 @@ enum { MAX_TIME, }; +#ifdef CONFIG_QUOTA +#define F2FS_MAXQUOTAS 2 +#endif + struct f2fs_sb_info { struct super_block *sb; /* pointer to VFS super block */ struct proc_dir_entry *s_proc; /* proc entry */ @@ -1993,6 +2000,20 @@ static inline void f2fs_change_bit(unsigned int nr, char *addr) *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 */ enum { FI_NEW_INODE, /* indicate newly allocated inode */ @@ -2021,6 +2042,7 @@ enum { FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */ FI_HOT_DATA, /* indicate file is hot */ 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, @@ -2372,6 +2394,12 @@ static inline int get_extra_isize(struct inode *inode) (offsetof(struct f2fs_inode, i_extra_end) - \ 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 */ @@ -2970,6 +2998,11 @@ static inline int f2fs_sb_has_extra_attr(struct super_block *sb) 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 static inline int get_blkz_type(struct f2fs_sb_info *sbi, struct block_device *bdev, block_t blkaddr) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index feb34bd88..38f394f8e 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1527,19 +1527,6 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id) 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) { struct inode *inode = file_inode(filp); diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 4c3f2370a..755325688 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -114,6 +114,7 @@ static int do_read_inode(struct inode *inode) struct f2fs_inode_info *fi = F2FS_I(inode); struct page *node_page; struct f2fs_inode *ri; + projid_t i_projid; /* Check if ino is within scope */ if (check_nid_range(sbi, inode->i_ino)) { @@ -173,6 +174,16 @@ static int do_read_inode(struct inode *inode) if (!need_inode_block_update(sbi, inode->i_ino)) 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); stat_inc_inline_xattr(inode); @@ -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_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); + 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_cold_node(inode, node_page); diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index e97b15a5b..3c404cd32 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -59,6 +59,12 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) 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); dquot_initialize(inode); err = dquot_alloc_inode(inode); @@ -89,6 +95,12 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) stat_inc_inline_inode(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); return inode; @@ -206,6 +218,11 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, !fscrypt_has_permitted_context(dir, inode)) 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; + dquot_initialize(dir); f2fs_balance_fs(sbi, true); @@ -727,6 +744,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, 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; + dquot_initialize(old_dir); dquot_initialize(new_dir); @@ -891,6 +913,14 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, !fscrypt_has_permitted_context(old_dir, new_inode))) 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; + dquot_initialize(old_dir); dquot_initialize(new_dir); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index cfc04ad8b..ee3c5f216 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -2285,8 +2285,13 @@ retry: dst->i_links = cpu_to_le32(1); dst->i_xattr_nid = 0; 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; + 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.ino = ino; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index af66a3f3a..c87008321 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -108,6 +108,7 @@ enum { Opt_nolazytime, Opt_usrquota, Opt_grpquota, + Opt_prjquota, Opt_err, }; @@ -145,6 +146,7 @@ static match_table_t f2fs_tokens = { {Opt_nolazytime, "nolazytime"}, {Opt_usrquota, "usrquota"}, {Opt_grpquota, "grpquota"}, + {Opt_prjquota, "prjquota"}, {Opt_err, NULL}, }; @@ -391,9 +393,18 @@ static int parse_options(struct super_block *sb, char *options) case Opt_grpquota: set_opt(sbi, GRPQUOTA); break; + case Opt_prjquota: + if (F2FS_MAXQUOTAS <= 2) { + f2fs_msg(sb, KERN_INFO, + "prjquota operations not supported"); + return -EINVAL; + } + set_opt(sbi, PRJQUOTA); + break; #else case Opt_usrquota: case Opt_grpquota: + case Opt_prjquota: f2fs_msg(sb, KERN_INFO, "quota operations not supported"); break; @@ -813,6 +824,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",usrquota"); if (test_opt(sbi, GRPQUOTA)) seq_puts(seq, ",grpquota"); + if (test_opt(sbi, PRJQUOTA)) + seq_puts(seq, ",prjquota"); #endif return 0; @@ -1168,6 +1181,12 @@ static void f2fs_quota_off_umount(struct super_block *sb) 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 = { .get_reserved_space = f2fs_get_reserved_space, .write_dquot = dquot_commit, @@ -1177,6 +1196,10 @@ static const struct dquot_operations f2fs_quota_operations = { .write_info = dquot_commit_info, .alloc_dquot = dquot_alloc, .destroy_dquot = dquot_destroy, +#if 0 /* not support */ + .get_projid = f2fs_get_projid, + .get_next_id = dquot_get_next_id, +#endif }; static const struct quotactl_ops f2fs_quotactl_ops = { @@ -1960,6 +1983,9 @@ try_onemore: #ifdef CONFIG_QUOTA sb->dq_op = &f2fs_quota_operations; sb->s_qcop = &f2fs_quotactl_ops; +#if 0 /* not support */ + sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ; +#endif #endif sb->s_op = &f2fs_sops; diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index b7331bfd4..bc0e6fc41 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -239,6 +239,7 @@ struct f2fs_inode { struct { __le16 i_extra_isize; /* extra inode attribute size */ __le16 i_padding; /* padding */ + __le32 i_projid; /* project id */ __le32 i_extra_end[0]; /* for attribute size calculation */ }; __le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */ @@ -522,4 +523,6 @@ enum { #define S_SHIFT 12 +#define F2FS_DEF_PROJID 0 /* default project ID */ + #endif /* _LINUX_F2FS_FS_H */ diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index 87a962d06..94e3374ba 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -243,6 +243,7 @@ struct fscrypt_key { #define FS_EXTENT_FL 0x00080000 /* Extents */ #define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */ #define FS_NOCOW_FL 0x00800000 /* Do not cow file */ +#define FS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ #define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ |
