1 ext4: implement allocation of pre-zeroed blocks
3 From: Jan Kara <jack@suse.com>
5 DAX page fault path needs to get blocks that are pre-zeroed to avoid
6 races when two concurrent page faults happen in the same block of a
7 file. Implement support for this in ext4_map_blocks().
9 Signed-off-by: Jan Kara <jack@suse.com>
10 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
12 fs/ext4/ext4.h | 4 ++++
13 fs/ext4/extents.c | 8 ++++++++
14 fs/ext4/inode.c | 20 +++++++++++++++++---
15 include/trace/events/ext4.h | 3 ++-
16 4 files changed, 31 insertions(+), 4 deletions(-)
18 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
19 index 785737a342e6..0a11a34d54c9 100644
22 @@ -553,6 +553,10 @@ enum {
23 #define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080
24 /* Convert written extents to unwritten */
25 #define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0100
26 + /* Write zeros to newly created written extents */
27 +#define EXT4_GET_BLOCKS_ZERO 0x0200
28 +#define EXT4_GET_BLOCKS_CREATE_ZERO (EXT4_GET_BLOCKS_CREATE |\
29 + EXT4_GET_BLOCKS_ZERO)
32 * The bit position of these flags must not overlap with any of the
33 diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
34 index 273bf40cca23..8e0d853a8044 100644
35 --- a/fs/ext4/extents.c
36 +++ b/fs/ext4/extents.c
37 @@ -4040,6 +4040,14 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode,
39 /* IO end_io complete, convert the filled extent to written */
40 if (flags & EXT4_GET_BLOCKS_CONVERT) {
41 + if (flags & EXT4_GET_BLOCKS_ZERO) {
42 + if (allocated > map->m_len)
43 + allocated = map->m_len;
44 + err = ext4_issue_zeroout(inode, map->m_lblk, newblock,
49 ret = ext4_convert_unwritten_extents_endio(handle, inode, map,
52 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
53 index 5e5795bde6b4..73c6214084d4 100644
56 @@ -643,7 +643,7 @@ found:
57 if ((flags & EXT4_GET_BLOCKS_PRE_IO) &&
58 ext4_es_lookup_extent(inode, map->m_lblk, &es)) {
59 if (ext4_es_is_written(&es))
63 status = map->m_flags & EXT4_MAP_UNWRITTEN ?
64 EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
65 @@ -654,11 +654,24 @@ found:
66 status |= EXTENT_STATUS_DELAYED;
67 ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len,
75 + if (flags & EXT4_GET_BLOCKS_ZERO &&
76 + map->m_flags & EXT4_MAP_MAPPED &&
77 + map->m_flags & EXT4_MAP_NEW) {
78 + ret = ext4_issue_zeroout(inode, map->m_lblk,
79 + map->m_pblk, map->m_len);
89 up_write((&EXT4_I(inode)->i_data_sem));
90 if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
91 ret = check_block_validity(inode, map);
92 @@ -3041,6 +3054,7 @@ int ext4_get_block_dax(struct inode *inode, sector_t iblock,
93 struct buffer_head *bh_result, int create)
95 int flags = EXT4_GET_BLOCKS_PRE_IO | EXT4_GET_BLOCKS_UNWRIT_EXT;
98 flags |= EXT4_GET_BLOCKS_CREATE;
99 ext4_debug("ext4_get_block_dax: inode %lu, create flag %d\n",
100 diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
101 index 5f2ace56efc5..4e4b2fa78609 100644
102 --- a/include/trace/events/ext4.h
103 +++ b/include/trace/events/ext4.h
104 @@ -42,7 +42,8 @@ struct extent_status;
105 { EXT4_GET_BLOCKS_CONVERT, "CONVERT" }, \
106 { EXT4_GET_BLOCKS_METADATA_NOFAIL, "METADATA_NOFAIL" }, \
107 { EXT4_GET_BLOCKS_NO_NORMALIZE, "NO_NORMALIZE" }, \
108 - { EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" })
109 + { EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" }, \
110 + { EXT4_GET_BLOCKS_ZERO, "ZERO" })
112 #define show_mflags(flags) __print_flags(flags, "", \
113 { EXT4_MAP_NEW, "N" }, \
118 To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
119 the body of a message to majordomo@vger.kernel.org
120 More majordomo info at http://vger.kernel.org/majordomo-info.html