summaryrefslogtreecommitdiff
path: root/fs/udf/inode.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2023-01-18 17:09:49 +0300
committerJan Kara <jack@suse.cz>2023-01-26 18:46:35 +0300
commit36580ed08776224f25f9a34ede6eed7a4e11aed8 (patch)
tree6edbc609857b7641b362537d6c8266a464c74bd6 /fs/udf/inode.c
parent7010839ccfd4f875c23c1758f6321ee6312cc548 (diff)
downloadlinux-36580ed08776224f25f9a34ede6eed7a4e11aed8.tar.xz
udf: Do not allocate blocks on page writeback
Now when we allocate blocks on write page fault there should be no block allocation happening on page writeback. So just ignore the 'create' flag passed to udf_get_block(). Note that we can spot dirty buffers without underlying blocks allocated in writeback when we race with expanding truncate. However in that case these buffers do not contain valid data so we can safely ignore them and we would just create ourselves problem when to trim the tail extent. Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf/inode.c')
-rw-r--r--fs/udf/inode.c46
1 files changed, 34 insertions, 12 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index bac4f905bbd1..356e15daef18 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -68,6 +68,8 @@ static void udf_prealloc_extents(struct inode *, int, int,
static void udf_merge_extents(struct inode *, struct kernel_long_ad *, int *);
static int udf_update_extents(struct inode *, struct kernel_long_ad *, int,
int, struct extent_position *);
+static int udf_get_block_wb(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result, int create);
static void __udf_clear_extent_cache(struct inode *inode)
{
@@ -186,7 +188,7 @@ static void udf_write_failed(struct address_space *mapping, loff_t to)
static int udf_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
- return mpage_writepages(mapping, wbc, udf_get_block);
+ return mpage_writepages(mapping, wbc, udf_get_block_wb);
}
static int udf_read_folio(struct file *file, struct folio *folio)
@@ -367,23 +369,15 @@ static int udf_map_block(struct inode *inode, struct udf_map_rq *map)
return err;
}
-static int udf_get_block(struct inode *inode, sector_t block,
- struct buffer_head *bh_result, int create)
+static int __udf_get_block(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result, int flags)
{
int err;
struct udf_map_rq map = {
.lblk = block,
- .iflags = create ? UDF_MAP_CREATE : 0,
+ .iflags = flags,
};
- /*
- * We preallocate blocks only for regular files. It also makes sense
- * for directories but there's a problem when to drop the
- * preallocation. We might use some delayed work for that but I feel
- * it's overengineering for a filesystem like UDF.
- */
- if (!S_ISREG(inode->i_mode))
- map.iflags |= UDF_MAP_NOPREALLOC;
err = udf_map_block(inode, &map);
if (err < 0)
return err;
@@ -395,6 +389,34 @@ static int udf_get_block(struct inode *inode, sector_t block,
return 0;
}
+int udf_get_block(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result, int create)
+{
+ int flags = create ? UDF_MAP_CREATE : 0;
+
+ /*
+ * We preallocate blocks only for regular files. It also makes sense
+ * for directories but there's a problem when to drop the
+ * preallocation. We might use some delayed work for that but I feel
+ * it's overengineering for a filesystem like UDF.
+ */
+ if (!S_ISREG(inode->i_mode))
+ flags |= UDF_MAP_NOPREALLOC;
+ return __udf_get_block(inode, block, bh_result, flags);
+}
+
+/*
+ * We shouldn't be allocating blocks on page writeback since we allocate them
+ * on page fault. We can spot dirty buffers without allocated blocks though
+ * when truncate expands file. These however don't have valid data so we can
+ * safely ignore them. So never allocate blocks from page writeback.
+ */
+static int udf_get_block_wb(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result, int create)
+{
+ return __udf_get_block(inode, block, bh_result, 0);
+}
+
/* Extend the file with new blocks totaling 'new_block_bytes',
* return the number of extents added
*/