f2fs: fix to keep project quota consistent
authorChao Yu <yuchao0@huawei.com>
Tue, 25 Sep 2018 07:36:02 +0000 (15:36 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 23 Oct 2018 00:54:48 +0000 (17:54 -0700)
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>
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/recovery.c

index f447cbc..56204a8 100644 (file)
@@ -2811,6 +2811,7 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count);
 int f2fs_precache_extents(struct inode *inode);
 long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
 long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid);
 int f2fs_pin_file_control(struct inode *inode, bool inc);
 
 /*
index 971463e..88b1246 100644 (file)
@@ -2613,13 +2613,29 @@ static int f2fs_ioc_get_features(struct file *filp, unsigned long arg)
 }
 
 #ifdef CONFIG_QUOTA
+int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid)
+{
+       struct dquot *transfer_to[MAXQUOTAS] = {};
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       struct super_block *sb = sbi->sb;
+       int err = 0;
+
+       transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
+       if (!IS_ERR(transfer_to[PRJQUOTA])) {
+               err = __dquot_transfer(inode, transfer_to);
+               if (err)
+                       set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
+               dqput(transfer_to[PRJQUOTA]);
+       }
+       return err;
+}
+
 static int f2fs_ioc_setproject(struct file *filp, __u32 projid)
 {
        struct inode *inode = file_inode(filp);
        struct f2fs_inode_info *fi = F2FS_I(inode);
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct super_block *sb = sbi->sb;
-       struct dquot *transfer_to[MAXQUOTAS] = {};
        struct page *ipage;
        kprojid_t kprojid;
        int err;
@@ -2660,21 +2676,24 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid)
        if (err)
                return err;
 
-       transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
-       if (!IS_ERR(transfer_to[PRJQUOTA])) {
-               err = __dquot_transfer(inode, transfer_to);
-               dqput(transfer_to[PRJQUOTA]);
-               if (err)
-                       goto out_dirty;
-       }
+       f2fs_lock_op(sbi);
+       err = f2fs_transfer_project_quota(inode, kprojid);
+       if (err)
+               goto out_unlock;
 
        F2FS_I(inode)->i_projid = kprojid;
        inode->i_ctime = current_time(inode);
-out_dirty:
        f2fs_mark_inode_dirty_sync(inode, true);
+out_unlock:
+       f2fs_unlock_op(sbi);
        return err;
 }
 #else
+int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid)
+{
+       return 0;
+}
+
 static int f2fs_ioc_setproject(struct file *filp, __u32 projid)
 {
        if (projid != F2FS_DEF_PROJID)
index df21237..1dfb17f 100644 (file)
@@ -254,10 +254,18 @@ static int recover_inode(struct inode *inode, struct page *page)
                        F2FS_FITS_IN_INODE(raw, le16_to_cpu(raw->i_extra_isize),
                                                                i_projid)) {
                        projid_t i_projid;
+                       kprojid_t kprojid;
 
                        i_projid = (projid_t)le32_to_cpu(raw->i_projid);
-                       F2FS_I(inode)->i_projid =
-                               make_kprojid(&init_user_ns, i_projid);
+                       kprojid = make_kprojid(&init_user_ns, i_projid);
+
+                       if (!projid_eq(kprojid, F2FS_I(inode)->i_projid)) {
+                               err = f2fs_transfer_project_quota(inode,
+                                                               kprojid);
+                               if (err)
+                                       return err;
+                               F2FS_I(inode)->i_projid = kprojid;
+                       }
                }
        }