|
@@ -3229,13 +3229,17 @@ static int ext4_releasepage(struct page *page, gfp_t wait)
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_FS_DAX
|
|
#ifdef CONFIG_FS_DAX
|
|
-int ext4_dax_mmap_get_block(struct inode *inode, sector_t iblock,
|
|
|
|
- struct buffer_head *bh_result, int create)
|
|
|
|
|
|
+/*
|
|
|
|
+ * Get block function for DAX IO and mmap faults. It takes care of converting
|
|
|
|
+ * unwritten extents to written ones and initializes new / converted blocks
|
|
|
|
+ * to zeros.
|
|
|
|
+ */
|
|
|
|
+int ext4_dax_get_block(struct inode *inode, sector_t iblock,
|
|
|
|
+ struct buffer_head *bh_result, int create)
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- ext4_debug("ext4_dax_mmap_get_block: inode %lu, create flag %d\n",
|
|
|
|
- inode->i_ino, create);
|
|
|
|
|
|
+ ext4_debug("inode %lu, create flag %d\n", inode->i_ino, create);
|
|
if (!create)
|
|
if (!create)
|
|
return _ext4_get_block(inode, iblock, bh_result, 0);
|
|
return _ext4_get_block(inode, iblock, bh_result, 0);
|
|
|
|
|
|
@@ -3247,9 +3251,9 @@ int ext4_dax_mmap_get_block(struct inode *inode, sector_t iblock,
|
|
|
|
|
|
if (buffer_unwritten(bh_result)) {
|
|
if (buffer_unwritten(bh_result)) {
|
|
/*
|
|
/*
|
|
- * We are protected by i_mmap_sem so we know block cannot go
|
|
|
|
- * away from under us even though we dropped i_data_sem.
|
|
|
|
- * Convert extent to written and write zeros there.
|
|
|
|
|
|
+ * We are protected by i_mmap_sem or i_mutex so we know block
|
|
|
|
+ * cannot go away from under us even though we dropped
|
|
|
|
+ * i_data_sem. Convert extent to written and write zeros there.
|
|
*/
|
|
*/
|
|
ret = ext4_get_block_trans(inode, iblock, bh_result,
|
|
ret = ext4_get_block_trans(inode, iblock, bh_result,
|
|
EXT4_GET_BLOCKS_CONVERT |
|
|
EXT4_GET_BLOCKS_CONVERT |
|
|
@@ -3264,6 +3268,14 @@ int ext4_dax_mmap_get_block(struct inode *inode, sector_t iblock,
|
|
clear_buffer_new(bh_result);
|
|
clear_buffer_new(bh_result);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
+#else
|
|
|
|
+/* Just define empty function, it will never get called. */
|
|
|
|
+int ext4_dax_get_block(struct inode *inode, sector_t iblock,
|
|
|
|
+ struct buffer_head *bh_result, int create)
|
|
|
|
+{
|
|
|
|
+ BUG();
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
static int ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
|
|
static int ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
|
|
@@ -3385,8 +3397,20 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter,
|
|
iocb->private = NULL;
|
|
iocb->private = NULL;
|
|
if (overwrite)
|
|
if (overwrite)
|
|
get_block_func = ext4_dio_get_block_overwrite;
|
|
get_block_func = ext4_dio_get_block_overwrite;
|
|
- else if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) ||
|
|
|
|
- round_down(offset, 1 << inode->i_blkbits) >= inode->i_size) {
|
|
|
|
|
|
+ else if (IS_DAX(inode)) {
|
|
|
|
+ /*
|
|
|
|
+ * We can avoid zeroing for aligned DAX writes beyond EOF. Other
|
|
|
|
+ * writes need zeroing either because they can race with page
|
|
|
|
+ * faults or because they use partial blocks.
|
|
|
|
+ */
|
|
|
|
+ if (round_down(offset, 1<<inode->i_blkbits) >= inode->i_size &&
|
|
|
|
+ ext4_aligned_io(inode, offset, count))
|
|
|
|
+ get_block_func = ext4_dio_get_block;
|
|
|
|
+ else
|
|
|
|
+ get_block_func = ext4_dax_get_block;
|
|
|
|
+ dio_flags = DIO_LOCKING;
|
|
|
|
+ } else if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) ||
|
|
|
|
+ round_down(offset, 1 << inode->i_blkbits) >= inode->i_size) {
|
|
get_block_func = ext4_dio_get_block;
|
|
get_block_func = ext4_dio_get_block;
|
|
dio_flags = DIO_LOCKING | DIO_SKIP_HOLES;
|
|
dio_flags = DIO_LOCKING | DIO_SKIP_HOLES;
|
|
} else if (is_sync_kiocb(iocb)) {
|
|
} else if (is_sync_kiocb(iocb)) {
|
|
@@ -3400,7 +3424,6 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter,
|
|
BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode));
|
|
BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode));
|
|
#endif
|
|
#endif
|
|
if (IS_DAX(inode)) {
|
|
if (IS_DAX(inode)) {
|
|
- dio_flags &= ~DIO_SKIP_HOLES;
|
|
|
|
ret = dax_do_io(iocb, inode, iter, offset, get_block_func,
|
|
ret = dax_do_io(iocb, inode, iter, offset, get_block_func,
|
|
ext4_end_io_dio, dio_flags);
|
|
ext4_end_io_dio, dio_flags);
|
|
} else
|
|
} else
|