Skip to content

Commit 60eb3b9

Browse files
Zhihao Chengrichardweinberger
authored andcommitted
ubifs: Fix 'ui->dirty' race between do_tmpfile() and writeback work
'ui->dirty' is not protected by 'ui_mutex' in function do_tmpfile() which may race with ubifs_write_inode[wb_workfn] to access/update 'ui->dirty', finally dirty space is released twice. open(O_TMPFILE) wb_workfn do_tmpfile ubifs_budget_space(ino_req = { .dirtied_ino = 1}) d_tmpfile // mark inode(tmpfile) dirty ubifs_jnl_update // without holding tmpfile's ui_mutex mark_inode_clean(ui) if (ui->dirty) ubifs_release_dirty_inode_budget(ui) // release first time ubifs_write_inode mutex_lock(&ui->ui_mutex) ubifs_release_dirty_inode_budget(ui) // release second time mutex_unlock(&ui->ui_mutex) ui->dirty = 0 Run generic/476 can reproduce following message easily (See reproducer in [Link]): UBIFS error (ubi0:0 pid 2578): ubifs_assert_failed [ubifs]: UBIFS assert failed: c->bi.dd_growth >= 0, in fs/ubifs/budget.c:554 UBIFS warning (ubi0:0 pid 2578): ubifs_ro_mode [ubifs]: switched to read-only mode, error -22 Workqueue: writeback wb_workfn (flush-ubifs_0_0) Call Trace: ubifs_ro_mode+0x54/0x60 [ubifs] ubifs_assert_failed+0x4b/0x80 [ubifs] ubifs_release_budget+0x468/0x5a0 [ubifs] ubifs_release_dirty_inode_budget+0x53/0x80 [ubifs] ubifs_write_inode+0x121/0x1f0 [ubifs] ... wb_workfn+0x283/0x7b0 Fix it by holding tmpfile ubifs inode lock during ubifs_jnl_update(). Similar problem exists in whiteout renaming, but previous fix("ubifs: Rename whiteout atomically") has solved the problem. Fixes: 474b937 ("ubifs: Implement O_TMPFILE") Link: https://bugzilla.kernel.org/show_bug.cgi?id=214765 Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> Signed-off-by: Richard Weinberger <richard@nod.at>
1 parent 278d9a2 commit 60eb3b9

1 file changed

Lines changed: 30 additions & 30 deletions

File tree

fs/ubifs/dir.c

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -397,14 +397,40 @@ static struct inode *create_whiteout(struct inode *dir, struct dentry *dentry)
397397
return ERR_PTR(err);
398398
}
399399

400+
/**
401+
* lock_2_inodes - a wrapper for locking two UBIFS inodes.
402+
* @inode1: first inode
403+
* @inode2: second inode
404+
*
405+
* We do not implement any tricks to guarantee strict lock ordering, because
406+
* VFS has already done it for us on the @i_mutex. So this is just a simple
407+
* wrapper function.
408+
*/
409+
static void lock_2_inodes(struct inode *inode1, struct inode *inode2)
410+
{
411+
mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1);
412+
mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2);
413+
}
414+
415+
/**
416+
* unlock_2_inodes - a wrapper for unlocking two UBIFS inodes.
417+
* @inode1: first inode
418+
* @inode2: second inode
419+
*/
420+
static void unlock_2_inodes(struct inode *inode1, struct inode *inode2)
421+
{
422+
mutex_unlock(&ubifs_inode(inode2)->ui_mutex);
423+
mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
424+
}
425+
400426
static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
401427
struct dentry *dentry, umode_t mode)
402428
{
403429
struct inode *inode;
404430
struct ubifs_info *c = dir->i_sb->s_fs_info;
405431
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1};
406432
struct ubifs_budget_req ino_req = { .dirtied_ino = 1 };
407-
struct ubifs_inode *ui, *dir_ui = ubifs_inode(dir);
433+
struct ubifs_inode *ui;
408434
int err, instantiated = 0;
409435
struct fscrypt_name nm;
410436

@@ -452,18 +478,18 @@ static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
452478
instantiated = 1;
453479
mutex_unlock(&ui->ui_mutex);
454480

455-
mutex_lock(&dir_ui->ui_mutex);
481+
lock_2_inodes(dir, inode);
456482
err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
457483
if (err)
458484
goto out_cancel;
459-
mutex_unlock(&dir_ui->ui_mutex);
485+
unlock_2_inodes(dir, inode);
460486

461487
ubifs_release_budget(c, &req);
462488

463489
return 0;
464490

465491
out_cancel:
466-
mutex_unlock(&dir_ui->ui_mutex);
492+
unlock_2_inodes(dir, inode);
467493
out_inode:
468494
make_bad_inode(inode);
469495
if (!instantiated)
@@ -690,32 +716,6 @@ static int ubifs_dir_release(struct inode *dir, struct file *file)
690716
return 0;
691717
}
692718

693-
/**
694-
* lock_2_inodes - a wrapper for locking two UBIFS inodes.
695-
* @inode1: first inode
696-
* @inode2: second inode
697-
*
698-
* We do not implement any tricks to guarantee strict lock ordering, because
699-
* VFS has already done it for us on the @i_mutex. So this is just a simple
700-
* wrapper function.
701-
*/
702-
static void lock_2_inodes(struct inode *inode1, struct inode *inode2)
703-
{
704-
mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1);
705-
mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2);
706-
}
707-
708-
/**
709-
* unlock_2_inodes - a wrapper for unlocking two UBIFS inodes.
710-
* @inode1: first inode
711-
* @inode2: second inode
712-
*/
713-
static void unlock_2_inodes(struct inode *inode1, struct inode *inode2)
714-
{
715-
mutex_unlock(&ubifs_inode(inode2)->ui_mutex);
716-
mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
717-
}
718-
719719
static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
720720
struct dentry *dentry)
721721
{

0 commit comments

Comments
 (0)