xref: /linux/fs/exfat/iomap.c (revision fab183d632628381b466a41479489541ac0e29a0)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * iomap callack functions
4  *
5  * Copyright (C) 2026 Namjae Jeon <linkinjeon@kernel.org>
6  */
7 
8 #include <linux/iomap.h>
9 #include <linux/pagemap.h>
10 
11 #include "exfat_raw.h"
12 #include "exfat_fs.h"
13 #include "iomap.h"
14 
15 /*
16  * exfat_file_write_dio_end_io - Direct I/O write completion handler
17  *
18  * Updates i_size if the write extended the file. Called from the dio layer
19  * after I/O completion.
20  */
exfat_file_write_dio_end_io(struct kiocb * iocb,ssize_t size,int error,unsigned int flags)21 static int exfat_file_write_dio_end_io(struct kiocb *iocb, ssize_t size,
22 		int error, unsigned int flags)
23 {
24 	struct inode *inode = file_inode(iocb->ki_filp);
25 
26 	if (error)
27 		return error;
28 
29 	if (size && i_size_read(inode) < iocb->ki_pos + size) {
30 		i_size_write(inode, iocb->ki_pos + size);
31 		mark_inode_dirty(inode);
32 	}
33 
34 	return 0;
35 }
36 
37 const struct iomap_dio_ops exfat_write_dio_ops = {
38 	.end_io		= exfat_file_write_dio_end_io,
39 };
40 
__exfat_iomap_begin(struct inode * inode,loff_t offset,loff_t length,unsigned int flags,struct iomap * iomap,bool may_alloc)41 static int __exfat_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
42 		unsigned int flags, struct iomap *iomap, bool may_alloc)
43 {
44 	struct super_block *sb = inode->i_sb;
45 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
46 	struct exfat_inode_info *ei = EXFAT_I(inode);
47 	unsigned int cluster, num_clusters;
48 	loff_t cluster_offset, cluster_length;
49 	int err;
50 	bool balloc = false;
51 
52 	if (!may_alloc) {
53 		/* Completely beyond EOF. Treat as hole */
54 		if (i_size_read(inode) <= offset) {
55 			iomap->type = IOMAP_HOLE;
56 			iomap->addr = IOMAP_NULL_ADDR;
57 			iomap->offset = offset;
58 			iomap->length = length;
59 			return 0;
60 		}
61 
62 		/* Clamp length if the requested range goes beyond i_size */
63 		if (offset + length > i_size_read(inode))
64 			length = round_up(i_size_read(inode),
65 					  i_blocksize(inode)) - offset;
66 	}
67 
68 	num_clusters = exfat_bytes_to_cluster_round_up(sbi,
69 			offset + length) - exfat_bytes_to_cluster(sbi, offset);
70 
71 	mutex_lock(&sbi->s_lock);
72 	iomap->bdev = inode->i_sb->s_bdev;
73 	iomap->offset = offset;
74 
75 	err = exfat_map_cluster(inode, exfat_bytes_to_cluster(sbi, offset),
76 			&cluster, &num_clusters, may_alloc, &balloc);
77 	if (err)
78 		goto out;
79 
80 	cluster_offset = exfat_cluster_offset(sbi, offset);
81 	cluster_length = exfat_cluster_to_bytes(sbi, num_clusters);
82 
83 	iomap->length = min_t(loff_t, length, cluster_length - cluster_offset);
84 	iomap->addr = exfat_cluster_to_phys_bytes(sbi, cluster) + cluster_offset;
85 	iomap->type = IOMAP_MAPPED;
86 	iomap->flags = IOMAP_F_MERGED;
87 
88 	if (may_alloc || flags & IOMAP_ZERO) {
89 		if (balloc)
90 			iomap->flags |= IOMAP_F_NEW;
91 		else if (iomap->offset + iomap->length >= ei->valid_size) {
92 			/*
93 			 * This is a write that starts at or extends beyond
94 			 * the current valid_size. The region between the old
95 			 * valid_size and the end of this write needs to be
96 			 * zeroed in the page cache to prevent stale data
97 			 * exposure (see IOMAP_F_ZERO_TAIL handling in
98 			 * __iomap_write_begin()).
99 			 */
100 			iomap->flags |= IOMAP_F_ZERO_TAIL;
101 		}
102 	} else {
103 		/*
104 		 * valid_size is tracked in byte granularity and
105 		 * marks the exact boundary between valid data and
106 		 * holes (or unwritten space).
107 		 *
108 		 * When IOMAP_REPORT is set (used by lseek(SEEK_HOLE)
109 		 * and SEEK_DATA), we return IOMAP_HOLE. This allows
110 		 * iomap_seek_hole_iter() to directly return the
111 		 * precise byte position.
112 		 *
113 		 * For normal I/O paths (without IOMAP_REPORT) we
114 		 * return IOMAP_UNWRITTEN so the write path can
115 		 * distinguish it from a real hole.
116 		 */
117 		if (offset >= ei->valid_size) {
118 			iomap->type = flags & IOMAP_REPORT ?
119 				IOMAP_HOLE : IOMAP_UNWRITTEN;
120 		} else if (offset + iomap->length > ei->valid_size) {
121 			if (flags & IOMAP_REPORT) {
122 				/*
123 				 * For SEEK_HOLE/SEEK_DATA, clip the length
124 				 * to the exact byte boundary (valid_size).
125 				 * This ensures the caller gets the precise
126 				 * hole position in byte units.
127 				 */
128 				iomap->length = ei->valid_size - iomap->offset;
129 			} else
130 				iomap->length = round_up(ei->valid_size,
131 							 i_blocksize(inode)) -
132 								iomap->offset;
133 		}
134 	}
135 
136 	iomap->flags |= IOMAP_F_MERGED;
137 out:
138 	mutex_unlock(&sbi->s_lock);
139 	return err;
140 }
141 
exfat_iomap_begin(struct inode * inode,loff_t offset,loff_t length,unsigned int flags,struct iomap * iomap,struct iomap * srcmap)142 static int exfat_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
143 		unsigned int flags, struct iomap *iomap, struct iomap *srcmap)
144 {
145 	return __exfat_iomap_begin(inode, offset, length, flags, iomap, false);
146 }
147 
exfat_write_iomap_begin(struct inode * inode,loff_t offset,loff_t length,unsigned int flags,struct iomap * iomap,struct iomap * srcmap)148 static int exfat_write_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
149 		unsigned int flags, struct iomap *iomap, struct iomap *srcmap)
150 {
151 	return __exfat_iomap_begin(inode, offset, length, flags, iomap, true);
152 }
153 
154 static DEFINE_IOMAP_ITER_NEXT(exfat_iomap_next, exfat_iomap_begin);
155 
156 const struct iomap_ops exfat_iomap_ops = {
157 	.iomap_next = exfat_iomap_next,
158 };
159 
160 /*
161  * exfat_write_iomap_end - Update the state after write
162  *
163  * Extends ->valid_size to cover the newly written range.
164  * Marks the inode dirty if metadata was changed.
165  */
exfat_write_iomap_end(struct inode * inode,loff_t pos,loff_t length,ssize_t written,unsigned int flags,struct iomap * iomap)166 static int exfat_write_iomap_end(struct inode *inode, loff_t pos, loff_t length,
167 		ssize_t written, unsigned int flags, struct iomap *iomap)
168 {
169 	struct exfat_inode_info *ei = EXFAT_I(inode);
170 	bool dirtied = false;
171 	loff_t end;
172 
173 	if (!written)
174 		return 0;
175 
176 	end = pos + written;
177 
178 	if (ei->valid_size < end) {
179 		ei->valid_size = end;
180 		if (ei->zeroed_size < end)
181 			ei->zeroed_size = end;
182 		dirtied = true;
183 	}
184 
185 	if (dirtied || iomap->flags & IOMAP_F_SIZE_CHANGED)
186 		mark_inode_dirty(inode);
187 
188 	return written;
189 }
190 
191 static DEFINE_IOMAP_ITER_NEXT_END(exfat_write_iomap_next,
192 		exfat_write_iomap_begin, exfat_write_iomap_end);
193 
194 const struct iomap_ops exfat_write_iomap_ops = {
195 	.iomap_next	= exfat_write_iomap_next,
196 };
197 
198 /*
199  * exfat_writeback_range - Map folio during writeback
200  *
201  * Called for each folio during writeback. If the folio falls outside the
202  * current iomap, remaps by calling read_iomap_begin.
203  */
exfat_writeback_range(struct iomap_writepage_ctx * wpc,struct folio * folio,u64 offset,unsigned int len,u64 end_pos)204 static ssize_t exfat_writeback_range(struct iomap_writepage_ctx *wpc,
205 		struct folio *folio, u64 offset, unsigned int len, u64 end_pos)
206 {
207 	if (offset < wpc->iomap.offset ||
208 	    offset >= wpc->iomap.offset + wpc->iomap.length) {
209 		int error;
210 
211 		error = __exfat_iomap_begin(wpc->inode, offset, len,
212 				0, &wpc->iomap, false);
213 		if (error)
214 			return error;
215 	}
216 
217 	return iomap_add_to_ioend(wpc, folio, offset, end_pos, len);
218 }
219 
220 const struct iomap_writeback_ops exfat_writeback_ops = {
221 	.writeback_range	= exfat_writeback_range,
222 	.writeback_submit	= iomap_ioend_writeback_submit,
223 };
224 
225 /**
226  * exfat_iomap_read_end_io - iomap read bio completion handler for exFAT
227  * @bio: bio that has completed reading
228  *
229  * exfat_iomap_begin() rounds up MAPPED extents to the block boundary of
230  * valid_size. This ensures that any subsequent blocks are treated as
231  * IOMAP_UNWRITTEN, but it also causes the "straddle block" containing
232  * valid_size to be read from disk. The disk data beyond valid_size in
233  * this block is stale and must be zeroed to prevent data leakage.
234  */
exfat_iomap_read_end_io(struct bio * bio)235 static void exfat_iomap_read_end_io(struct bio *bio)
236 {
237 	int error = blk_status_to_errno(bio->bi_status);
238 	struct folio_iter iter;
239 
240 	bio_for_each_folio_all(iter, bio) {
241 		struct folio *folio = iter.folio;
242 		struct exfat_inode_info *ei = EXFAT_I(folio->mapping->host);
243 		s64 valid_size;
244 		loff_t pos = folio_pos(folio);
245 
246 		valid_size = ei->valid_size;
247 		if (pos + iter.offset < valid_size &&
248 		    pos + iter.offset + iter.length > valid_size)
249 			folio_zero_segment(folio, offset_in_folio(folio, valid_size),
250 					   iter.offset + iter.length);
251 
252 		iomap_finish_folio_read(folio, iter.offset, iter.length, error);
253 	}
254 	bio_put(bio);
255 }
256 
exfat_iomap_bio_submit_read(const struct iomap_iter * iter,struct iomap_read_folio_ctx * ctx)257 static void exfat_iomap_bio_submit_read(const struct iomap_iter *iter,
258 		struct iomap_read_folio_ctx *ctx)
259 {
260 	iomap_bio_submit_read_endio(iter, ctx, exfat_iomap_read_end_io);
261 }
262 
263 const struct iomap_read_ops exfat_iomap_bio_read_ops = {
264 	.read_folio_range	= iomap_bio_read_folio_range,
265 	.submit_read		= exfat_iomap_bio_submit_read,
266 };
267 
exfat_iomap_swap_activate(struct swap_info_struct * sis,struct file * file,sector_t * span)268 int exfat_iomap_swap_activate(struct swap_info_struct *sis,
269 			       struct file *file, sector_t *span)
270 {
271 	return iomap_swapfile_activate(sis, file, span, &exfat_iomap_ops);
272 }
273