f2fs: support plain user/group quota
Chao Yu
maintainerPATCH 1/1 f2fs: support plain user/group quota
From: Chao Yu <[email protected]>
This patch adds to support plain user/group quota.
- setattr() calls dquot_transfer which will transfer inode->i_blocks. We can't reclaim that during f2fs_evict_inode(). So, we need to count node blocks as well in order to match i_blocks with dquot's space.
- in f2fs_remount, we need to make RW in prior to dquot_resume.
--- fs/f2fs/data.c | 10 +- fs/f2fs/f2fs.h | 98 ++++++++++++++----- fs/f2fs/file.c | 34 +++++-- fs/f2fs/inode.c | 5 + fs/f2fs/namei.c | 66 ++++++++++++- fs/f2fs/node.c | 9 +- fs/f2fs/super.c | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 466 insertions(+), 40 deletions(-)
fs/f2fs/data.c +6 -4
@@ -491,14 +491,15 @@ void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr)int reserve_new_blocks (struct dnode_of_data *dn,blkcnt_t count) {struct f2fs_sb_info *sbi =F2FS_I_SB (dn->inode); +int err;if (!count)return 0 ;if (unlikely (is_inode_flag_set (dn->inode,FI_NO_ALLOC )))return -EPERM ; -if (unlikely (!inc_valid_block_count (sbi, dn->inode, &count))) -return -ENOSPC ; +if (unlikely ((err =inc_valid_block_count (sbi, dn->inode, &count)))) +return err;trace_f2fs_reserve_new_blocks (dn->inode, dn->nid, dn->ofs_in_node, count);
@@ -749,6 +750,7 @@ static int __allocate_data_block(struct dnode_of_data *dn)struct node_info ni;pgoff_t fofs;blkcnt_t count =1 ; +int err;if (unlikely (is_inode_flag_set (dn->inode,FI_NO_ALLOC )))return -EPERM ;
@@ -757,8 +759,8 @@ static int __allocate_data_block(struct dnode_of_data *dn)if (dn->data_blkaddr ==NEW_ADDR ) goto alloc; -if (unlikely (!inc_valid_block_count (sbi, dn->inode, &count))) -return -ENOSPC ; +if (unlikely ((err =inc_valid_block_count (sbi, dn->inode, &count)))) +return err; alloc:get_node_info (sbi, dn->nid, &ni);
fs/f2fs/f2fs.h +75 -23
205 lines not on this page · raw message
fs/f2fs/file.c +27 -7
@@ -448,11 +448,10 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)static int f2fs_file_open (struct inode *inode,struct file *filp) { -int ret =generic_file_open (inode, filp);struct dentry *dir; -if (!ret &&f2fs_encrypted_inode (inode)) { - ret =fscrypt_get_encryption_info (inode); +if (f2fs_encrypted_inode (inode)) { +int ret =fscrypt_get_encryption_info (inode);if (ret)return -EACCES ;if (!fscrypt_has_encryption_key (inode))
@@ -465,7 +464,7 @@ static int f2fs_file_open(struct inode *inode, struct file *filp)return -EPERM ; }dput (dir); -return ret; +return dquot_file_open (inode, filp); }int truncate_data_blocks_range (struct dnode_of_data *dn,int count)
@@ -716,6 +715,20 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)if (err)return err; +if (is_quota_modification (inode, attr)) { + err =dquot_initialize (inode); +if (err) +return err; + } +if ((attr->ia_valid &ATTR_UID && + !uid_eq (attr->ia_uid, inode->i_uid)) || + (attr->ia_valid &ATTR_GID && + !gid_eq (attr->ia_gid, inode->i_gid))) { + err =dquot_transfer (inode, attr); +if (err) +return err; + } +if (attr->ia_valid &ATTR_SIZE ) {if (f2fs_encrypted_inode (inode)) { err =fscrypt_get_encryption_info (inode);
@@ -1002,9 +1015,9 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,if (do_replace[i]) {f2fs_i_blocks_write (src_inode, -1 , false); +1 , false, false);f2fs_i_blocks_write (dst_inode, -1 , true); +1 , true, false);f2fs_replace_block (sbi, &dn, dn.data_blkaddr, blkaddr[i], ni.version, true, false);
@@ -1529,6 +1542,13 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)inode_lock (inode); +/* Is it quota file? Do not allow user to mess with it */ +if (IS_NOQUOTA (inode)) { +inode_unlock (inode); + ret = -EPERM ; + goto unlock_out; + } + flags =f2fs_mask_flags (inode->i_mode, flags); oldflags = fi->i_flags;
@@ -1548,7 +1568,7 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg) inode->i_ctime =current_time (inode);f2fs_set_inode_flags (inode);f2fs_mark_inode_dirty_sync (inode, false); - +unlock_out:inode_unlock (inode); out:mnt_drop_write_file (filp);
fs/f2fs/inode.c +5 -0
@@ -373,6 +373,8 @@ void f2fs_evict_inode(struct inode *inode)if (inode->i_nlink ||is_bad_inode (inode)) goto no_delete; +dquot_initialize (inode); +remove_ino_entry (sbi, inode->i_ino,APPEND_INO );remove_ino_entry (sbi, inode->i_ino,UPDATE_INO );
@@ -405,8 +407,11 @@ void f2fs_evict_inode(struct inode *inode)if (err)update_inode_page (inode); +dquot_free_inode (inode);sb_end_intwrite (inode->i_sb); no_delete: +dquot_drop (inode); +stat_dec_inline_xattr (inode);stat_dec_inline_dir (inode);stat_dec_inline_inode (inode);
fs/f2fs/namei.c +65 -1
147 lines not on this page · raw message
fs/f2fs/node.c +4 -5
@@ -1040,10 +1040,9 @@ struct page *new_node_page(struct dnode_of_data *dn,if (!page)return ERR_PTR (-ENOMEM ); -if (unlikely (!inc_valid_node_count (sbi, dn->inode, !ofs))) { - err = -ENOSPC ; +if (unlikely ((err =inc_valid_node_count (sbi, dn->inode, !ofs)))) goto fail; - } +#ifdef CONFIG_F2FS_CHECK_FS get_node_info (sbi, dn->nid, &new_ni);f2fs_bug_on (sbi, new_ni.blk_addr !=NULL_ADDR );
@@ -2210,7 +2209,7 @@ int recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr)/* 2: update xattr nid in inode */ remove_free_nid (sbi, new_xnid);f2fs_i_xnid_write (inode, new_xnid); -if (unlikely (!inc_valid_node_count (sbi, inode, false))) +if (unlikely (inc_valid_node_count (sbi, inode, false)))f2fs_bug_on (sbi,1 );update_inode_page (inode);
@@ -2268,7 +2267,7 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) new_ni = old_ni; new_ni.ino = ino; -if (unlikely (!inc_valid_node_count (sbi,NULL , true))) +if (unlikely (inc_valid_node_count (sbi,NULL , true)))WARN_ON (1 );set_node_addr (sbi, &new_ni,NEW_ADDR , false);inc_valid_inode_count (sbi);
fs/f2fs/super.c +284 -0
373 lines not on this page · raw message
Signature · 1 line
2.13.0.90.g1eb437020
Jaegeuk Kim
maintainerHi Chao,
I've updated your patch like this.
- modify description
- use filemap_write_and_wait() directly aligned to the below v2 patch.
f2fs: avoid deadlock caused by lock order of page and
Thanks,
Quoted 1 line
From
4aa1d70e8e7767712733dc79147030aa682ee9efMon Sep 17 00:00:00 2001
From: Chao Yu <[email protected]>
Date: Thu, 6 Jul 2017 21:52:45 +0800
Subject: [PATCH] f2fs: support plain user/group quota
This patch adds to support plain user/group quota.
Change Note by Jaegeuk Kim.
- Use f2fs page cache for quota files in order to consider garbage collection. so, quota files are not tolerable for sudden power-cuts, so user needs to do quotacheck.
- setattr() calls dquot_transfer which will transfer inode->i_blocks. We can't reclaim that during f2fs_evict_inode(). So, we need to count node blocks as well in order to match i_blocks with dquot's space.
Note that, Chao wrote a patch to count inode->i_blocks without inode block. (f2fs: don't count inode block in in-memory inode.i_blocks)
- in f2fs_remount, we need to make RW in prior to dquot_resume.
- handle fault_injection case during f2fs_quota_off_umount
- TODO: Project quota
--- fs/f2fs/data.c | 10 +- fs/f2fs/f2fs.h | 88 +++++++++++++----- fs/f2fs/file.c | 34 +++++-- fs/f2fs/inode.c | 5 + fs/f2fs/namei.c | 66 ++++++++++++- fs/f2fs/node.c | 9 +- fs/f2fs/super.c | 280 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 452 insertions(+), 40 deletions(-)
fs/f2fs/data.c +6 -4
@@ -491,14 +491,15 @@ void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr)int reserve_new_blocks (struct dnode_of_data *dn,blkcnt_t count) {struct f2fs_sb_info *sbi =F2FS_I_SB (dn->inode); +int err;if (!count)return 0 ;if (unlikely (is_inode_flag_set (dn->inode,FI_NO_ALLOC )))return -EPERM ; -if (unlikely (!inc_valid_block_count (sbi, dn->inode, &count))) -return -ENOSPC ; +if (unlikely ((err =inc_valid_block_count (sbi, dn->inode, &count)))) +return err;trace_f2fs_reserve_new_blocks (dn->inode, dn->nid, dn->ofs_in_node, count);
@@ -749,6 +750,7 @@ static int __allocate_data_block(struct dnode_of_data *dn)struct node_info ni;pgoff_t fofs;blkcnt_t count =1 ; +int err;if (unlikely (is_inode_flag_set (dn->inode,FI_NO_ALLOC )))return -EPERM ;
@@ -757,8 +759,8 @@ static int __allocate_data_block(struct dnode_of_data *dn)if (dn->data_blkaddr ==NEW_ADDR ) goto alloc; -if (unlikely (!inc_valid_block_count (sbi, dn->inode, &count))) -return -ENOSPC ; +if (unlikely ((err =inc_valid_block_count (sbi, dn->inode, &count)))) +return err; alloc:get_node_info (sbi, dn->nid, &ni);
fs/f2fs/f2fs.h +65 -23
189 lines not on this page · raw message
fs/f2fs/file.c +27 -7
@@ -442,11 +442,10 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)static int f2fs_file_open (struct inode *inode,struct file *filp) { -int ret =generic_file_open (inode, filp);struct dentry *dir; -if (!ret &&f2fs_encrypted_inode (inode)) { - ret =fscrypt_get_encryption_info (inode); +if (f2fs_encrypted_inode (inode)) { +int ret =fscrypt_get_encryption_info (inode);if (ret)return -EACCES ;if (!fscrypt_has_encryption_key (inode))
@@ -459,7 +458,7 @@ static int f2fs_file_open(struct inode *inode, struct file *filp)return -EPERM ; }dput (dir); -return ret; +return dquot_file_open (inode, filp); }int truncate_data_blocks_range (struct dnode_of_data *dn,int count)
@@ -710,6 +709,20 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)if (err)return err; +if (is_quota_modification (inode, attr)) { + err =dquot_initialize (inode); +if (err) +return err; + } +if ((attr->ia_valid &ATTR_UID && + !uid_eq (attr->ia_uid, inode->i_uid)) || + (attr->ia_valid &ATTR_GID && + !gid_eq (attr->ia_gid, inode->i_gid))) { + err =dquot_transfer (inode, attr); +if (err) +return err; + } +if (attr->ia_valid &ATTR_SIZE ) {if (f2fs_encrypted_inode (inode)) { err =fscrypt_get_encryption_info (inode);
@@ -996,9 +1009,9 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,if (do_replace[i]) {f2fs_i_blocks_write (src_inode, -1 , false); +1 , false, false);f2fs_i_blocks_write (dst_inode, -1 , true); +1 , true, false);f2fs_replace_block (sbi, &dn, dn.data_blkaddr, blkaddr[i], ni.version, true, false);
@@ -1523,6 +1536,13 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)inode_lock (inode); +/* Is it quota file? Do not allow user to mess with it */ +if (IS_NOQUOTA (inode)) { +inode_unlock (inode); + ret = -EPERM ; + goto unlock_out; + } + flags =f2fs_mask_flags (inode->i_mode, flags); oldflags = fi->i_flags;
@@ -1542,7 +1562,7 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg) inode->i_ctime =current_time (inode);f2fs_set_inode_flags (inode);f2fs_mark_inode_dirty_sync (inode, false); - +unlock_out:inode_unlock (inode); out:mnt_drop_write_file (filp);
fs/f2fs/inode.c +5 -0
@@ -373,6 +373,8 @@ void f2fs_evict_inode(struct inode *inode)if (inode->i_nlink ||is_bad_inode (inode)) goto no_delete; +dquot_initialize (inode); +remove_ino_entry (sbi, inode->i_ino,APPEND_INO );remove_ino_entry (sbi, inode->i_ino,UPDATE_INO );
@@ -405,8 +407,11 @@ void f2fs_evict_inode(struct inode *inode)if (err)update_inode_page (inode); +dquot_free_inode (inode);sb_end_intwrite (inode->i_sb); no_delete: +dquot_drop (inode); +stat_dec_inline_xattr (inode);stat_dec_inline_dir (inode);stat_dec_inline_inode (inode);
fs/f2fs/namei.c +65 -1
147 lines not on this page · raw message
fs/f2fs/node.c +4 -5
@@ -1040,10 +1040,9 @@ struct page *new_node_page(struct dnode_of_data *dn,if (!page)return ERR_PTR (-ENOMEM ); -if (unlikely (!inc_valid_node_count (sbi, dn->inode, !ofs))) { - err = -ENOSPC ; +if (unlikely ((err =inc_valid_node_count (sbi, dn->inode, !ofs)))) goto fail; - } +#ifdef CONFIG_F2FS_CHECK_FS get_node_info (sbi, dn->nid, &new_ni);f2fs_bug_on (sbi, new_ni.blk_addr !=NULL_ADDR );
@@ -2210,7 +2209,7 @@ int recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr)/* 2: update xattr nid in inode */ remove_free_nid (sbi, new_xnid);f2fs_i_xnid_write (inode, new_xnid); -if (unlikely (!inc_valid_node_count (sbi, inode, false))) +if (unlikely (inc_valid_node_count (sbi, inode, false)))f2fs_bug_on (sbi,1 );update_inode_page (inode);
@@ -2268,7 +2267,7 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) new_ni = old_ni; new_ni.ino = ino; -if (unlikely (!inc_valid_node_count (sbi,NULL , true))) +if (unlikely (inc_valid_node_count (sbi,NULL , true)))WARN_ON (1 );set_node_addr (sbi, &new_ni,NEW_ADDR , false);inc_valid_inode_count (sbi);
fs/f2fs/super.c +280 -0
369 lines not on this page · raw message
Signature · 1 line
2.13.0.rc1.294.g07d810a77f-goog
Chao Yu
maintainerHi Jaegeuk,
Quoted 8 lines · Jaegeuk Kim
Hi Chao,
I've updated your patch like this.
- modify description
- usefilemap_write_and_wait()directly aligned to the below v2 patch.f2fs: avoid deadlock caused by lock order of page and
Looks good to me.
I've updated doc in the patch rebased on this version as well.
Thanks,