Commit dbf00d8d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull udf fix from Jan Kara:
 "Fix for a race in UDF that can lead to memory corruption"

* tag 'fs_for_v7.0-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  udf: Fix race between file type conversion and writeback
  mpage: Provide variant of mpage_writepages() with own optional folio handler
parents d0c3bcd5 102e57d5
Loading
Loading
Loading
Loading
+24 −6
Original line number Diff line number Diff line
@@ -646,17 +646,24 @@ static int mpage_write_folio(struct writeback_control *wbc, struct folio *folio,
}

/**
 * mpage_writepages - walk the list of dirty pages of the given address space & writepage() all of them
 * __mpage_writepages - walk the list of dirty pages of the given address space
 * 			& writepage() all of them
 * @mapping: address space structure to write
 * @wbc: subtract the number of written pages from *@wbc->nr_to_write
 * @get_block: the filesystem's block mapper function.
 * @write_folio: handler to call for each folio before calling
 *		 mpage_write_folio()
 *
 * This is a library function, which implements the writepages()
 * address_space_operation.
 * address_space_operation. It calls @write_folio handler for each folio. If
 * the handler returns value > 0, it calls mpage_write_folio() to do the
 * folio writeback.
 */
int
mpage_writepages(struct address_space *mapping,
		struct writeback_control *wbc, get_block_t get_block)
__mpage_writepages(struct address_space *mapping,
		   struct writeback_control *wbc, get_block_t get_block,
		   int (*write_folio)(struct folio *folio,
				      struct writeback_control *wbc))
{
	struct mpage_data mpd = {
		.get_block	= get_block,
@@ -666,11 +673,22 @@ mpage_writepages(struct address_space *mapping,
	int error;

	blk_start_plug(&plug);
	while ((folio = writeback_iter(mapping, wbc, folio, &error)))
	while ((folio = writeback_iter(mapping, wbc, folio, &error))) {
		if (write_folio) {
			error = write_folio(folio, wbc);
			/*
			 * == 0 means folio is handled, < 0 means error. In
			 * both cases hand back control to writeback_iter()
			 */
			if (error <= 0)
				continue;
			/* Let mpage_write_folio() handle the folio. */
		}
		error = mpage_write_folio(wbc, folio, &mpd);
	}
	if (mpd.bio)
		mpage_bio_submit_write(mpd.bio);
	blk_finish_plug(&plug);
	return error;
}
EXPORT_SYMBOL(mpage_writepages);
EXPORT_SYMBOL(__mpage_writepages);
+15 −18
Original line number Diff line number Diff line
@@ -181,22 +181,23 @@ static void udf_write_failed(struct address_space *mapping, loff_t to)
	}
}

static int udf_adinicb_writepages(struct address_space *mapping,
static int udf_handle_page_wb(struct folio *folio,
			      struct writeback_control *wbc)
{
	struct inode *inode = mapping->host;
	struct inode *inode = folio->mapping->host;
	struct udf_inode_info *iinfo = UDF_I(inode);
	struct folio *folio = NULL;
	int error = 0;

	while ((folio = writeback_iter(mapping, wbc, folio, &error))) {
		BUG_ON(!folio_test_locked(folio));
		BUG_ON(folio->index != 0);
	/*
	 * Inodes in the normal format are handled by the generic code. This
	 * check is race-free as the folio lock protects us from inode type
	 * conversion.
	 */
	if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB)
		return 1;

	memcpy_from_file_folio(iinfo->i_data + iinfo->i_lenEAttr, folio,
				0, i_size_read(inode));
	folio_unlock(folio);
	}

	mark_inode_dirty(inode);
	return 0;
}
@@ -204,12 +205,8 @@ static int udf_adinicb_writepages(struct address_space *mapping,
static int udf_writepages(struct address_space *mapping,
			  struct writeback_control *wbc)
{
	struct inode *inode = mapping->host;
	struct udf_inode_info *iinfo = UDF_I(inode);

	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
		return udf_adinicb_writepages(mapping, wbc);
	return mpage_writepages(mapping, wbc, udf_get_block_wb);
	return __mpage_writepages(mapping, wbc, udf_get_block_wb,
				  udf_handle_page_wb);
}

static void udf_adinicb_read_folio(struct folio *folio)
+9 −2
Original line number Diff line number Diff line
@@ -17,7 +17,14 @@ struct readahead_control;

void mpage_readahead(struct readahead_control *, get_block_t get_block);
int mpage_read_folio(struct folio *folio, get_block_t get_block);
int mpage_writepages(struct address_space *mapping,
		struct writeback_control *wbc, get_block_t get_block);
int __mpage_writepages(struct address_space *mapping,
		struct writeback_control *wbc, get_block_t get_block,
		int (*write_folio)(struct folio *folio,
				   struct writeback_control *wbc));
static inline int mpage_writepages(struct address_space *mapping,
		struct writeback_control *wbc, get_block_t get_block)
{
	return __mpage_writepages(mapping, wbc, get_block, NULL);
}

#endif