Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f727395 authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

f2fs: fix deadlock during inline_data conversion



A deadlock can be occurred:
Thread 1]                             Thread 2]
 - f2fs_write_data_pages              - f2fs_write_begin
   - lock_page(page #0)
                                        - grab_cache_page(page #X)
                                        - get_node_page(inode_page)
                                        - grab_cache_page(page #0)
                                          : to convert inline_data
   - f2fs_write_data_page
     - f2fs_write_inline_data
       - get_node_page(inode_page)

In this case, trying to lock inode_page and page #0 causes deadlock.
In order to avoid this, this patch adds a rule for this locking policy,
which is that page #0 should be locked followed by inode_page lock.

Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent ce3e6d25
Loading
Loading
Loading
Loading
+14 −14
Original line number Diff line number Diff line
@@ -936,6 +936,17 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	trace_f2fs_write_begin(inode, pos, len, flags);

	f2fs_balance_fs(sbi);

	/*
	 * We should check this at this moment to avoid deadlock on inode page
	 * and #0 page. The locking rule for inline_data conversion should be:
	 * lock_page(page #0) -> lock_page(inode_page)
	 */
	if (index != 0) {
		err = f2fs_convert_inline_inode(inode);
		if (err)
			goto fail;
	}
repeat:
	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page) {
@@ -960,22 +971,11 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
			set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
			sync_inode_page(&dn);
			goto put_next;
		} else if (page->index == 0) {
			err = f2fs_convert_inline_page(&dn, page);
			if (err)
				goto put_fail;
		} else {
			struct page *p = grab_cache_page(inode->i_mapping, 0);
			if (!p) {
				err = -ENOMEM;
				goto put_fail;
		}
			err = f2fs_convert_inline_page(&dn, p);
			f2fs_put_page(p, 1);
		err = f2fs_convert_inline_page(&dn, page);
		if (err)
			goto put_fail;
	}
	}
	err = f2fs_reserve_block(&dn, index);
	if (err)
		goto put_fail;