diff options
author | Chao Yu <yuchao0@huawei.com> | 2018-09-25 03:36:02 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2018-10-22 20:54:48 -0400 |
commit | 78130819695f17f5c042d8ba097802639478faf5 (patch) | |
tree | 468624c7bdc9ab656be4982a635cca65526444c2 | |
parent | af033b2aa8a874fd5737fafe90d159136527b5b4 (diff) |
f2fs: fix to keep project quota consistent
This patch does below changes to keep consistence of project quota data
in sudden power-cut case:
- update inode.i_projid and project quota atomically under lock_op() in
f2fs_ioc_setproject()
- recover inode.i_projid and project quota in recover_inode()
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r-- | fs/f2fs/f2fs.h | 1 | ||||
-rw-r--r-- | fs/f2fs/file.c | 37 | ||||
-rw-r--r-- | fs/f2fs/recovery.c | 12 |
3 files changed, 39 insertions, 11 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index f447cbc2295f..56204a8f8a12 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -2811,6 +2811,7 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count); | |||
2811 | int f2fs_precache_extents(struct inode *inode); | 2811 | int f2fs_precache_extents(struct inode *inode); |
2812 | long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); | 2812 | long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); |
2813 | long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | 2813 | long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
2814 | int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid); | ||
2814 | int f2fs_pin_file_control(struct inode *inode, bool inc); | 2815 | int f2fs_pin_file_control(struct inode *inode, bool inc); |
2815 | 2816 | ||
2816 | /* | 2817 | /* |
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 971463e0589e..88b124677189 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c | |||
@@ -2613,13 +2613,29 @@ static int f2fs_ioc_get_features(struct file *filp, unsigned long arg) | |||
2613 | } | 2613 | } |
2614 | 2614 | ||
2615 | #ifdef CONFIG_QUOTA | 2615 | #ifdef CONFIG_QUOTA |
2616 | int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid) | ||
2617 | { | ||
2618 | struct dquot *transfer_to[MAXQUOTAS] = {}; | ||
2619 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | ||
2620 | struct super_block *sb = sbi->sb; | ||
2621 | int err = 0; | ||
2622 | |||
2623 | transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid)); | ||
2624 | if (!IS_ERR(transfer_to[PRJQUOTA])) { | ||
2625 | err = __dquot_transfer(inode, transfer_to); | ||
2626 | if (err) | ||
2627 | set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); | ||
2628 | dqput(transfer_to[PRJQUOTA]); | ||
2629 | } | ||
2630 | return err; | ||
2631 | } | ||
2632 | |||
2616 | static int f2fs_ioc_setproject(struct file *filp, __u32 projid) | 2633 | static int f2fs_ioc_setproject(struct file *filp, __u32 projid) |
2617 | { | 2634 | { |
2618 | struct inode *inode = file_inode(filp); | 2635 | struct inode *inode = file_inode(filp); |
2619 | struct f2fs_inode_info *fi = F2FS_I(inode); | 2636 | struct f2fs_inode_info *fi = F2FS_I(inode); |
2620 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 2637 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
2621 | struct super_block *sb = sbi->sb; | 2638 | struct super_block *sb = sbi->sb; |
2622 | struct dquot *transfer_to[MAXQUOTAS] = {}; | ||
2623 | struct page *ipage; | 2639 | struct page *ipage; |
2624 | kprojid_t kprojid; | 2640 | kprojid_t kprojid; |
2625 | int err; | 2641 | int err; |
@@ -2660,21 +2676,24 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid) | |||
2660 | if (err) | 2676 | if (err) |
2661 | return err; | 2677 | return err; |
2662 | 2678 | ||
2663 | transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid)); | 2679 | f2fs_lock_op(sbi); |
2664 | if (!IS_ERR(transfer_to[PRJQUOTA])) { | 2680 | err = f2fs_transfer_project_quota(inode, kprojid); |
2665 | err = __dquot_transfer(inode, transfer_to); | 2681 | if (err) |
2666 | dqput(transfer_to[PRJQUOTA]); | 2682 | goto out_unlock; |
2667 | if (err) | ||
2668 | goto out_dirty; | ||
2669 | } | ||
2670 | 2683 | ||
2671 | F2FS_I(inode)->i_projid = kprojid; | 2684 | F2FS_I(inode)->i_projid = kprojid; |
2672 | inode->i_ctime = current_time(inode); | 2685 | inode->i_ctime = current_time(inode); |
2673 | out_dirty: | ||
2674 | f2fs_mark_inode_dirty_sync(inode, true); | 2686 | f2fs_mark_inode_dirty_sync(inode, true); |
2687 | out_unlock: | ||
2688 | f2fs_unlock_op(sbi); | ||
2675 | return err; | 2689 | return err; |
2676 | } | 2690 | } |
2677 | #else | 2691 | #else |
2692 | int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid) | ||
2693 | { | ||
2694 | return 0; | ||
2695 | } | ||
2696 | |||
2678 | static int f2fs_ioc_setproject(struct file *filp, __u32 projid) | 2697 | static int f2fs_ioc_setproject(struct file *filp, __u32 projid) |
2679 | { | 2698 | { |
2680 | if (projid != F2FS_DEF_PROJID) | 2699 | if (projid != F2FS_DEF_PROJID) |
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index df2123759ac7..1dfb17f9f9ff 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c | |||
@@ -254,10 +254,18 @@ static int recover_inode(struct inode *inode, struct page *page) | |||
254 | F2FS_FITS_IN_INODE(raw, le16_to_cpu(raw->i_extra_isize), | 254 | F2FS_FITS_IN_INODE(raw, le16_to_cpu(raw->i_extra_isize), |
255 | i_projid)) { | 255 | i_projid)) { |
256 | projid_t i_projid; | 256 | projid_t i_projid; |
257 | kprojid_t kprojid; | ||
257 | 258 | ||
258 | i_projid = (projid_t)le32_to_cpu(raw->i_projid); | 259 | i_projid = (projid_t)le32_to_cpu(raw->i_projid); |
259 | F2FS_I(inode)->i_projid = | 260 | kprojid = make_kprojid(&init_user_ns, i_projid); |
260 | make_kprojid(&init_user_ns, i_projid); | 261 | |
262 | if (!projid_eq(kprojid, F2FS_I(inode)->i_projid)) { | ||
263 | err = f2fs_transfer_project_quota(inode, | ||
264 | kprojid); | ||
265 | if (err) | ||
266 | return err; | ||
267 | F2FS_I(inode)->i_projid = kprojid; | ||
268 | } | ||
261 | } | 269 | } |
262 | } | 270 | } |
263 | 271 | ||