@@ -3806,6 +3806,7 @@ vm_fault_t btrfs_dax_fault(struct vm_fault *vmf);
int btrfs_dax_file_range_compare(struct inode *src, loff_t srcoff,
struct inode *dest, loff_t destoff, loff_t len,
bool *is_same);
+int btrfs_dax_zero_block(struct inode *inode, loff_t from, loff_t len, bool front);
#else
static inline ssize_t btrfs_file_dax_write(struct kiocb *iocb, struct iov_iter *from)
{
@@ -132,7 +132,8 @@ static int btrfs_iomap_begin(struct inode *inode, loff_t pos,
* This will be true for reads only since we have already
* allocated em
*/
- if (em->block_start == EXTENT_MAP_HOLE) {
+ if (em->block_start == EXTENT_MAP_HOLE ||
+ em->flags == EXTENT_FLAG_FILLING) {
iomap->type = IOMAP_HOLE;
return 0;
}
@@ -234,4 +235,28 @@ int btrfs_dax_file_range_compare(struct inode *src, loff_t srcoff,
{
return dax_file_range_compare(src, srcoff, dest, destoff, len, is_same, &btrfs_iomap_ops);
}
+
+/*
+ * zero a part of the page only. This should CoW (via iomap_begin) if required
+ */
+int btrfs_dax_zero_block(struct inode *inode, loff_t from, loff_t len, bool front)
+{
+ loff_t start = round_down(from, PAGE_SIZE);
+ loff_t end = round_up(from, PAGE_SIZE);
+ loff_t offset = from;
+ int ret = 0;
+
+ if (front) {
+ len = from - start;
+ offset = start;
+ } else {
+ if (!len)
+ len = end - from;
+ }
+
+ if (len)
+ ret = iomap_zero_range(inode, offset, len, NULL, &btrfs_iomap_ops);
+
+ return (ret < 0) ? ret : 0;
+}
#endif /* CONFIG_FS_DAX */
@@ -4833,6 +4833,10 @@ int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len,
(!len || IS_ALIGNED(len, blocksize)))
goto out;
+#ifdef CONFIG_FS_DAX
+ if (IS_DAX(inode))
+ return btrfs_dax_zero_block(inode, from, len, front);
+#endif
block_start = round_down(from, blocksize);
block_end = block_start + blocksize - 1;