Blame view
fs/xfs/xfs_aops.c
18.3 KB
0b61f8a40 xfs: convert to S... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
1da177e4c Linux-2.6.12-rc2 |
2 |
/* |
7b7187698 [XFS] Update lice... |
3 |
* Copyright (c) 2000-2005 Silicon Graphics, Inc. |
98c1a7c0e xfs: update my co... |
4 |
* Copyright (c) 2016-2018 Christoph Hellwig. |
7b7187698 [XFS] Update lice... |
5 |
* All Rights Reserved. |
1da177e4c Linux-2.6.12-rc2 |
6 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
7 |
#include "xfs.h" |
70a9883c5 xfs: create a sha... |
8 |
#include "xfs_shared.h" |
239880ef6 xfs: decouple log... |
9 10 11 |
#include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" |
1da177e4c Linux-2.6.12-rc2 |
12 |
#include "xfs_mount.h" |
1da177e4c Linux-2.6.12-rc2 |
13 |
#include "xfs_inode.h" |
239880ef6 xfs: decouple log... |
14 |
#include "xfs_trans.h" |
1da177e4c Linux-2.6.12-rc2 |
15 |
#include "xfs_iomap.h" |
0b1b213fc xfs: event tracin... |
16 |
#include "xfs_trace.h" |
3ed3a4343 xfs: truncate del... |
17 |
#include "xfs_bmap.h" |
689881145 xfs: create xfs_b... |
18 |
#include "xfs_bmap_util.h" |
ef4736678 xfs: allocate del... |
19 |
#include "xfs_reflink.h" |
1da177e4c Linux-2.6.12-rc2 |
20 |
|
fbcc02561 xfs: Introduce wr... |
21 |
struct xfs_writepage_ctx { |
598ecfbaa iomap: lift the x... |
22 |
struct iomap_writepage_ctx ctx; |
d9252d526 xfs: validate wri... |
23 |
unsigned int data_seq; |
e666aa37f xfs: avoid COW fo... |
24 |
unsigned int cow_seq; |
fbcc02561 xfs: Introduce wr... |
25 |
}; |
598ecfbaa iomap: lift the x... |
26 27 28 29 30 |
static inline struct xfs_writepage_ctx * XFS_WPC(struct iomap_writepage_ctx *ctx) { return container_of(ctx, struct xfs_writepage_ctx, ctx); } |
0829c3602 [XFS] Add infrast... |
31 |
/* |
fc0063c44 xfs: reduce ioend... |
32 33 |
* Fast and loose check if this write could update the on-disk inode size. */ |
598ecfbaa iomap: lift the x... |
34 |
static inline bool xfs_ioend_is_append(struct iomap_ioend *ioend) |
fc0063c44 xfs: reduce ioend... |
35 36 37 38 |
{ return ioend->io_offset + ioend->io_size > XFS_I(ioend->io_inode)->i_d.di_size; } |
281627df3 xfs: log file siz... |
39 40 |
STATIC int xfs_setfilesize_trans_alloc( |
598ecfbaa iomap: lift the x... |
41 |
struct iomap_ioend *ioend) |
281627df3 xfs: log file siz... |
42 43 44 45 |
{ struct xfs_mount *mp = XFS_I(ioend->io_inode)->i_mount; struct xfs_trans *tp; int error; |
73d30d487 xfs: remove XFS_T... |
46 |
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp); |
253f4911f xfs: better xfs_t... |
47 |
if (error) |
281627df3 xfs: log file siz... |
48 |
return error; |
281627df3 xfs: log file siz... |
49 |
|
5653017bc xfs: turn io_appe... |
50 |
ioend->io_private = tp; |
281627df3 xfs: log file siz... |
51 52 |
/* |
437a255aa xfs: fix direct I... |
53 |
* We may pass freeze protection with a transaction. So tell lockdep |
d9457dc05 xfs: Convert to n... |
54 55 |
* we released it. */ |
bee9182d9 introduce __sb_wr... |
56 |
__sb_writers_release(ioend->io_inode->i_sb, SB_FREEZE_FS); |
d9457dc05 xfs: Convert to n... |
57 |
/* |
281627df3 xfs: log file siz... |
58 59 60 |
* We hand off the transaction to the completion thread now, so * clear the flag here. */ |
9070733b4 xfs: abstract PF_... |
61 |
current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); |
281627df3 xfs: log file siz... |
62 63 |
return 0; } |
fc0063c44 xfs: reduce ioend... |
64 |
/* |
2813d682e xfs: remove the i... |
65 |
* Update on-disk file size now that data has been written to disk. |
ba87ea699 [XFS] Fix to prev... |
66 |
*/ |
281627df3 xfs: log file siz... |
67 |
STATIC int |
e372843a4 xfs: refactor xfs... |
68 |
__xfs_setfilesize( |
2ba662370 xfs: don't alloca... |
69 70 71 72 |
struct xfs_inode *ip, struct xfs_trans *tp, xfs_off_t offset, size_t size) |
ba87ea699 [XFS] Fix to prev... |
73 |
{ |
ba87ea699 [XFS] Fix to prev... |
74 |
xfs_fsize_t isize; |
ba87ea699 [XFS] Fix to prev... |
75 |
|
aa6bf01d3 xfs: use per-file... |
76 |
xfs_ilock(ip, XFS_ILOCK_EXCL); |
2ba662370 xfs: don't alloca... |
77 |
isize = xfs_new_eof(ip, offset + size); |
281627df3 xfs: log file siz... |
78 79 |
if (!isize) { xfs_iunlock(ip, XFS_ILOCK_EXCL); |
4906e2154 xfs: remove the f... |
80 |
xfs_trans_cancel(tp); |
281627df3 xfs: log file siz... |
81 |
return 0; |
ba87ea699 [XFS] Fix to prev... |
82 |
} |
2ba662370 xfs: don't alloca... |
83 |
trace_xfs_setfilesize(ip, offset, size); |
281627df3 xfs: log file siz... |
84 85 86 87 |
ip->i_d.di_size = isize; xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
70393313d xfs: saner xfs_tr... |
88 |
return xfs_trans_commit(tp); |
77d7a0c2e xfs: Non-blocking... |
89 |
} |
e372843a4 xfs: refactor xfs... |
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
int xfs_setfilesize( struct xfs_inode *ip, xfs_off_t offset, size_t size) { struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; int error; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp); if (error) return error; return __xfs_setfilesize(ip, tp, offset, size); } |
2ba662370 xfs: don't alloca... |
106 107 |
STATIC int xfs_setfilesize_ioend( |
598ecfbaa iomap: lift the x... |
108 |
struct iomap_ioend *ioend, |
0e51a8e19 xfs: optimize bio... |
109 |
int error) |
2ba662370 xfs: don't alloca... |
110 111 |
{ struct xfs_inode *ip = XFS_I(ioend->io_inode); |
5653017bc xfs: turn io_appe... |
112 |
struct xfs_trans *tp = ioend->io_private; |
2ba662370 xfs: don't alloca... |
113 114 115 116 117 118 |
/* * The transaction may have been allocated in the I/O submission thread, * thus we need to mark ourselves as being in a transaction manually. * Similarly for freeze protection. */ |
9070733b4 xfs: abstract PF_... |
119 |
current_set_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); |
bee9182d9 introduce __sb_wr... |
120 |
__sb_writers_acquired(VFS_I(ip)->i_sb, SB_FREEZE_FS); |
2ba662370 xfs: don't alloca... |
121 |
|
5cb13dcd0 cancel the setfil... |
122 |
/* we abort the update if there was an IO error */ |
0e51a8e19 xfs: optimize bio... |
123 |
if (error) { |
5cb13dcd0 cancel the setfil... |
124 |
xfs_trans_cancel(tp); |
0e51a8e19 xfs: optimize bio... |
125 |
return error; |
5cb13dcd0 cancel the setfil... |
126 |
} |
e372843a4 xfs: refactor xfs... |
127 |
return __xfs_setfilesize(ip, tp, ioend->io_offset, ioend->io_size); |
2ba662370 xfs: don't alloca... |
128 |
} |
77d7a0c2e xfs: Non-blocking... |
129 |
/* |
5ec4fabb0 xfs: cleanup data... |
130 |
* IO write completion. |
f6d6d4fcd [XFS] Initial pas... |
131 132 |
*/ STATIC void |
cb357bf3d xfs: implement pe... |
133 |
xfs_end_ioend( |
598ecfbaa iomap: lift the x... |
134 |
struct iomap_ioend *ioend) |
0829c3602 [XFS] Add infrast... |
135 |
{ |
0e51a8e19 xfs: optimize bio... |
136 |
struct xfs_inode *ip = XFS_I(ioend->io_inode); |
787eb4855 xfs: fix and stre... |
137 138 |
xfs_off_t offset = ioend->io_offset; size_t size = ioend->io_size; |
73d30d487 xfs: remove XFS_T... |
139 |
unsigned int nofs_flag; |
4e4cbee93 block: switch bio... |
140 |
int error; |
ba87ea699 [XFS] Fix to prev... |
141 |
|
af055e37a xfs: fix xfs_log_... |
142 |
/* |
73d30d487 xfs: remove XFS_T... |
143 144 145 146 147 148 149 |
* We can allocate memory here while doing writeback on behalf of * memory reclaim. To avoid memory allocation deadlocks set the * task-wide nofs context for the following operations. */ nofs_flag = memalloc_nofs_save(); /* |
787eb4855 xfs: fix and stre... |
150 |
* Just clean up the in-memory strutures if the fs has been shut down. |
af055e37a xfs: fix xfs_log_... |
151 |
*/ |
787eb4855 xfs: fix and stre... |
152 |
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { |
0e51a8e19 xfs: optimize bio... |
153 |
error = -EIO; |
787eb4855 xfs: fix and stre... |
154 155 |
goto done; } |
04f658ee2 xfs: improve ioen... |
156 |
|
5ec4fabb0 xfs: cleanup data... |
157 |
/* |
787eb4855 xfs: fix and stre... |
158 |
* Clean up any COW blocks on an I/O error. |
43caeb187 xfs: move mapping... |
159 |
*/ |
4e4cbee93 block: switch bio... |
160 |
error = blk_status_to_errno(ioend->io_bio->bi_status); |
787eb4855 xfs: fix and stre... |
161 |
if (unlikely(error)) { |
760fea8bf xfs: remove the f... |
162 |
if (ioend->io_flags & IOMAP_F_SHARED) |
787eb4855 xfs: fix and stre... |
163 |
xfs_reflink_cancel_cow_range(ip, offset, size, true); |
787eb4855 xfs: fix and stre... |
164 |
goto done; |
43caeb187 xfs: move mapping... |
165 166 167 |
} /* |
be225fec7 xfs: remove the i... |
168 |
* Success: commit the COW or unwritten blocks if needed. |
5ec4fabb0 xfs: cleanup data... |
169 |
*/ |
760fea8bf xfs: remove the f... |
170 |
if (ioend->io_flags & IOMAP_F_SHARED) |
787eb4855 xfs: fix and stre... |
171 |
error = xfs_reflink_end_cow(ip, offset, size); |
4e087a3b3 xfs: use a struct... |
172 |
else if (ioend->io_type == IOMAP_UNWRITTEN) |
ee70daaba xfs: update i_siz... |
173 |
error = xfs_iomap_write_unwritten(ip, offset, size, false); |
be225fec7 xfs: remove the i... |
174 |
else |
5653017bc xfs: turn io_appe... |
175 |
ASSERT(!xfs_ioend_is_append(ioend) || ioend->io_private); |
ba87ea699 [XFS] Fix to prev... |
176 |
|
04f658ee2 xfs: improve ioen... |
177 |
done: |
5653017bc xfs: turn io_appe... |
178 |
if (ioend->io_private) |
787eb4855 xfs: fix and stre... |
179 |
error = xfs_setfilesize_ioend(ioend, error); |
598ecfbaa iomap: lift the x... |
180 |
iomap_finish_ioends(ioend, error); |
73d30d487 xfs: remove XFS_T... |
181 |
memalloc_nofs_restore(nofs_flag); |
3994fc489 xfs: merge adjace... |
182 183 184 |
} /* |
7dbae9fbd xfs: allow mergin... |
185 186 187 188 189 190 |
* If the to be merged ioend has a preallocated transaction for file * size updates we need to ensure the ioend it is merged into also * has one. If it already has one we can simply cancel the transaction * as it is guaranteed to be clean. */ static void |
5653017bc xfs: turn io_appe... |
191 |
xfs_ioend_merge_private( |
598ecfbaa iomap: lift the x... |
192 193 |
struct iomap_ioend *ioend, struct iomap_ioend *next) |
7dbae9fbd xfs: allow mergin... |
194 |
{ |
5653017bc xfs: turn io_appe... |
195 196 197 |
if (!ioend->io_private) { ioend->io_private = next->io_private; next->io_private = NULL; |
7dbae9fbd xfs: allow mergin... |
198 199 200 201 |
} else { xfs_setfilesize_ioend(next, -ECANCELED); } } |
cb357bf3d xfs: implement pe... |
202 203 204 205 206 |
/* Finish all pending io completions. */ void xfs_end_io( struct work_struct *work) { |
433dad94e xfs: refactor the... |
207 208 |
struct xfs_inode *ip = container_of(work, struct xfs_inode, i_ioend_work); |
598ecfbaa iomap: lift the x... |
209 |
struct iomap_ioend *ioend; |
433dad94e xfs: refactor the... |
210 |
struct list_head tmp; |
cb357bf3d xfs: implement pe... |
211 |
unsigned long flags; |
cb357bf3d xfs: implement pe... |
212 |
spin_lock_irqsave(&ip->i_ioend_lock, flags); |
433dad94e xfs: refactor the... |
213 |
list_replace_init(&ip->i_ioend_list, &tmp); |
cb357bf3d xfs: implement pe... |
214 |
spin_unlock_irqrestore(&ip->i_ioend_lock, flags); |
598ecfbaa iomap: lift the x... |
215 216 |
iomap_sort_ioends(&tmp); while ((ioend = list_first_entry_or_null(&tmp, struct iomap_ioend, |
433dad94e xfs: refactor the... |
217 |
io_list))) { |
cb357bf3d xfs: implement pe... |
218 |
list_del_init(&ioend->io_list); |
598ecfbaa iomap: lift the x... |
219 |
iomap_ioend_try_merge(ioend, &tmp, xfs_ioend_merge_private); |
cb357bf3d xfs: implement pe... |
220 221 222 |
xfs_end_ioend(ioend); } } |
598ecfbaa iomap: lift the x... |
223 |
static inline bool xfs_ioend_needs_workqueue(struct iomap_ioend *ioend) |
760fea8bf xfs: remove the f... |
224 225 226 227 228 |
{ return ioend->io_private || ioend->io_type == IOMAP_UNWRITTEN || (ioend->io_flags & IOMAP_F_SHARED); } |
0e51a8e19 xfs: optimize bio... |
229 230 231 |
STATIC void xfs_end_bio( struct bio *bio) |
0829c3602 [XFS] Add infrast... |
232 |
{ |
598ecfbaa iomap: lift the x... |
233 |
struct iomap_ioend *ioend = bio->bi_private; |
cb357bf3d xfs: implement pe... |
234 |
struct xfs_inode *ip = XFS_I(ioend->io_inode); |
cb357bf3d xfs: implement pe... |
235 |
unsigned long flags; |
0829c3602 [XFS] Add infrast... |
236 |
|
598ecfbaa iomap: lift the x... |
237 238 239 240 241 242 243 244 |
ASSERT(xfs_ioend_needs_workqueue(ioend)); spin_lock_irqsave(&ip->i_ioend_lock, flags); if (list_empty(&ip->i_ioend_list)) WARN_ON_ONCE(!queue_work(ip->i_mount->m_unwritten_workqueue, &ip->i_ioend_work)); list_add_tail(&ioend->io_list, &ip->i_ioend_list); spin_unlock_irqrestore(&ip->i_ioend_lock, flags); |
0829c3602 [XFS] Add infrast... |
245 |
} |
d9252d526 xfs: validate wri... |
246 247 248 249 250 251 |
/* * Fast revalidation of the cached writeback mapping. Return true if the current * mapping is valid, false otherwise. */ static bool xfs_imap_valid( |
598ecfbaa iomap: lift the x... |
252 |
struct iomap_writepage_ctx *wpc, |
d9252d526 xfs: validate wri... |
253 |
struct xfs_inode *ip, |
4e087a3b3 xfs: use a struct... |
254 |
loff_t offset) |
d9252d526 xfs: validate wri... |
255 |
{ |
4e087a3b3 xfs: use a struct... |
256 257 |
if (offset < wpc->iomap.offset || offset >= wpc->iomap.offset + wpc->iomap.length) |
d9252d526 xfs: validate wri... |
258 259 260 261 262 263 |
return false; /* * If this is a COW mapping, it is sufficient to check that the mapping * covers the offset. Be careful to check this first because the caller * can revalidate a COW mapping without updating the data seqno. */ |
760fea8bf xfs: remove the f... |
264 |
if (wpc->iomap.flags & IOMAP_F_SHARED) |
d9252d526 xfs: validate wri... |
265 266 267 268 269 270 271 272 273 |
return true; /* * This is not a COW mapping. Check the sequence number of the data fork * because concurrent changes could have invalidated the extent. Check * the COW fork because concurrent changes since the last time we * checked (and found nothing at this offset) could have added * overlapping blocks. */ |
598ecfbaa iomap: lift the x... |
274 |
if (XFS_WPC(wpc)->data_seq != READ_ONCE(ip->i_df.if_seq)) |
d9252d526 xfs: validate wri... |
275 276 |
return false; if (xfs_inode_has_cow_data(ip) && |
598ecfbaa iomap: lift the x... |
277 |
XFS_WPC(wpc)->cow_seq != READ_ONCE(ip->i_cowfp->if_seq)) |
d9252d526 xfs: validate wri... |
278 279 280 |
return false; return true; } |
4ad765edb xfs: move xfs_iom... |
281 282 |
/* * Pass in a dellalloc extent and convert it to real extents, return the real |
4e087a3b3 xfs: use a struct... |
283 |
* extent that maps offset_fsb in wpc->iomap. |
4ad765edb xfs: move xfs_iom... |
284 285 |
* * The current page is held locked so nothing could have removed the block |
7588cbeec xfs: retry COW fo... |
286 287 |
* backing offset_fsb, although it could have moved from the COW to the data * fork by another thread. |
4ad765edb xfs: move xfs_iom... |
288 289 290 |
*/ static int xfs_convert_blocks( |
598ecfbaa iomap: lift the x... |
291 |
struct iomap_writepage_ctx *wpc, |
4ad765edb xfs: move xfs_iom... |
292 |
struct xfs_inode *ip, |
760fea8bf xfs: remove the f... |
293 |
int whichfork, |
4e087a3b3 xfs: use a struct... |
294 |
loff_t offset) |
4ad765edb xfs: move xfs_iom... |
295 296 |
{ int error; |
598ecfbaa iomap: lift the x... |
297 298 299 300 301 302 |
unsigned *seq; if (whichfork == XFS_COW_FORK) seq = &XFS_WPC(wpc)->cow_seq; else seq = &XFS_WPC(wpc)->data_seq; |
4ad765edb xfs: move xfs_iom... |
303 304 |
/* |
4e087a3b3 xfs: use a struct... |
305 306 307 308 |
* Attempt to allocate whatever delalloc extent currently backs offset * and put the result into wpc->iomap. Allocate in a loop because it * may take several attempts to allocate real blocks for a contiguous * delalloc extent if free space is sufficiently fragmented. |
4ad765edb xfs: move xfs_iom... |
309 310 |
*/ do { |
760fea8bf xfs: remove the f... |
311 |
error = xfs_bmapi_convert_delalloc(ip, whichfork, offset, |
598ecfbaa iomap: lift the x... |
312 |
&wpc->iomap, seq); |
4ad765edb xfs: move xfs_iom... |
313 314 |
if (error) return error; |
4e087a3b3 xfs: use a struct... |
315 |
} while (wpc->iomap.offset + wpc->iomap.length <= offset); |
4ad765edb xfs: move xfs_iom... |
316 317 318 |
return 0; } |
598ecfbaa iomap: lift the x... |
319 |
static int |
1da177e4c Linux-2.6.12-rc2 |
320 |
xfs_map_blocks( |
598ecfbaa iomap: lift the x... |
321 |
struct iomap_writepage_ctx *wpc, |
1da177e4c Linux-2.6.12-rc2 |
322 |
struct inode *inode, |
5c665e5b5 xfs: remove xfs_m... |
323 |
loff_t offset) |
1da177e4c Linux-2.6.12-rc2 |
324 |
{ |
a206c817c xfs: kill xfs_iomap |
325 326 |
struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; |
93407472a fs: add i_blocksi... |
327 |
ssize_t count = i_blocksize(inode); |
b4e29032f xfs: remove the s... |
328 329 |
xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, offset + count); |
c2f09217a xfs: fix missing ... |
330 331 |
xfs_fileoff_t cow_fsb; int whichfork; |
5c665e5b5 xfs: remove xfs_m... |
332 |
struct xfs_bmbt_irec imap; |
060d4eaa0 xfs: remove xfs_r... |
333 |
struct xfs_iext_cursor icur; |
7588cbeec xfs: retry COW fo... |
334 |
int retries = 0; |
a206c817c xfs: kill xfs_iomap |
335 |
int error = 0; |
a206c817c xfs: kill xfs_iomap |
336 |
|
d9252d526 xfs: validate wri... |
337 338 |
if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; |
889c65b3f xfs: remove the i... |
339 |
/* |
889c65b3f xfs: remove the i... |
340 341 342 |
* COW fork blocks can overlap data fork blocks even if the blocks * aren't shared. COW I/O always takes precedent, so we must always * check for overlap on reflink inodes unless the mapping is already a |
e666aa37f xfs: avoid COW fo... |
343 344 345 346 347 348 349 350 351 352 |
* COW one, or the COW fork hasn't changed from the last time we looked * at it. * * It's safe to check the COW fork if_seq here without the ILOCK because * we've indirectly protected against concurrent updates: writeback has * the page locked, which prevents concurrent invalidations by reflink * and directio and prevents concurrent buffered writes to the same * page. Changes to if_seq always happen under i_lock, which protects * against concurrent updates and provides a memory barrier on the way * out that ensures that we always see the current value. |
889c65b3f xfs: remove the i... |
353 |
*/ |
4e087a3b3 xfs: use a struct... |
354 |
if (xfs_imap_valid(wpc, ip, offset)) |
889c65b3f xfs: remove the i... |
355 |
return 0; |
889c65b3f xfs: remove the i... |
356 357 358 359 360 361 |
/* * If we don't have a valid map, now it's time to get a new one for this * offset. This will convert delayed allocations (including COW ones) * into real extents. If we return without a valid map, it means we * landed in a hole and we skip the block. */ |
7588cbeec xfs: retry COW fo... |
362 |
retry: |
c2f09217a xfs: fix missing ... |
363 364 |
cow_fsb = NULLFILEOFF; whichfork = XFS_DATA_FORK; |
988ef9279 xfs: remove nonbl... |
365 |
xfs_ilock(ip, XFS_ILOCK_SHARED); |
f7e67b20e xfs: move the for... |
366 |
ASSERT(ip->i_df.if_format != XFS_DINODE_FMT_BTREE || |
8ff2957d5 xfs: simplify xfs... |
367 |
(ip->i_df.if_flags & XFS_IFEXTENTS)); |
060d4eaa0 xfs: remove xfs_r... |
368 369 370 371 372 |
/* * Check if this is offset is covered by a COW extents, and if yes use * it directly instead of looking up anything in the data fork. */ |
51d626903 xfs: introduce a ... |
373 |
if (xfs_inode_has_cow_data(ip) && |
e666aa37f xfs: avoid COW fo... |
374 375 376 |
xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &imap)) cow_fsb = imap.br_startoff; if (cow_fsb != NULLFILEOFF && cow_fsb <= offset_fsb) { |
598ecfbaa iomap: lift the x... |
377 |
XFS_WPC(wpc)->cow_seq = READ_ONCE(ip->i_cowfp->if_seq); |
5c665e5b5 xfs: remove xfs_m... |
378 |
xfs_iunlock(ip, XFS_ILOCK_SHARED); |
be225fec7 xfs: remove the i... |
379 |
|
760fea8bf xfs: remove the f... |
380 |
whichfork = XFS_COW_FORK; |
5c665e5b5 xfs: remove xfs_m... |
381 382 383 384 |
goto allocate_blocks; } /* |
d9252d526 xfs: validate wri... |
385 386 |
* No COW extent overlap. Revalidate now that we may have updated * ->cow_seq. If the data mapping is still valid, we're done. |
5c665e5b5 xfs: remove xfs_m... |
387 |
*/ |
4e087a3b3 xfs: use a struct... |
388 |
if (xfs_imap_valid(wpc, ip, offset)) { |
5c665e5b5 xfs: remove xfs_m... |
389 390 391 392 393 394 395 396 397 |
xfs_iunlock(ip, XFS_ILOCK_SHARED); return 0; } /* * If we don't have a valid map, now it's time to get a new one for this * offset. This will convert delayed allocations (including COW ones) * into real extents. */ |
3345746ef xfs: simplify xfs... |
398 399 |
if (!xfs_iext_lookup_extent(ip, &ip->i_df, offset_fsb, &icur, &imap)) imap.br_startoff = end_fsb; /* fake a hole past EOF */ |
598ecfbaa iomap: lift the x... |
400 |
XFS_WPC(wpc)->data_seq = READ_ONCE(ip->i_df.if_seq); |
8ff2957d5 xfs: simplify xfs... |
401 |
xfs_iunlock(ip, XFS_ILOCK_SHARED); |
a206c817c xfs: kill xfs_iomap |
402 |
|
12df89f28 xfs: also truncat... |
403 |
/* landed in a hole or beyond EOF? */ |
3345746ef xfs: simplify xfs... |
404 |
if (imap.br_startoff > offset_fsb) { |
3345746ef xfs: simplify xfs... |
405 |
imap.br_blockcount = imap.br_startoff - offset_fsb; |
5c665e5b5 xfs: remove xfs_m... |
406 |
imap.br_startoff = offset_fsb; |
5c665e5b5 xfs: remove xfs_m... |
407 |
imap.br_startblock = HOLESTARTBLOCK; |
be225fec7 xfs: remove the i... |
408 |
imap.br_state = XFS_EXT_NORM; |
8ff2957d5 xfs: simplify xfs... |
409 |
} |
e2f6ad462 xfs: make xfs_wri... |
410 |
|
12df89f28 xfs: also truncat... |
411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
/* * Truncate to the next COW extent if there is one. This is the only * opportunity to do this because we can skip COW fork lookups for the * subsequent blocks in the mapping; however, the requirement to treat * the COW range separately remains. */ if (cow_fsb != NULLFILEOFF && cow_fsb < imap.br_startoff + imap.br_blockcount) imap.br_blockcount = cow_fsb - imap.br_startoff; /* got a delalloc extent? */ if (imap.br_startblock != HOLESTARTBLOCK && isnullstartblock(imap.br_startblock)) goto allocate_blocks; |
4e087a3b3 xfs: use a struct... |
425 |
xfs_bmbt_to_iomap(ip, &wpc->iomap, &imap, 0); |
760fea8bf xfs: remove the f... |
426 |
trace_xfs_map_blocks_found(ip, offset, count, whichfork, &imap); |
5c665e5b5 xfs: remove xfs_m... |
427 428 |
return 0; allocate_blocks: |
760fea8bf xfs: remove the f... |
429 |
error = xfs_convert_blocks(wpc, ip, whichfork, offset); |
7588cbeec xfs: retry COW fo... |
430 431 432 433 434 435 436 437 |
if (error) { /* * If we failed to find the extent in the COW fork we might have * raced with a COW to data fork conversion or truncate. * Restart the lookup to catch the extent in the data fork for * the former case, but prevent additional retries to avoid * looping forever for the latter case. */ |
760fea8bf xfs: remove the f... |
438 |
if (error == -EAGAIN && whichfork == XFS_COW_FORK && !retries++) |
7588cbeec xfs: retry COW fo... |
439 440 |
goto retry; ASSERT(error != -EAGAIN); |
5c665e5b5 xfs: remove xfs_m... |
441 |
return error; |
7588cbeec xfs: retry COW fo... |
442 |
} |
4ad765edb xfs: move xfs_iom... |
443 444 445 446 447 448 |
/* * Due to merging the return real extent might be larger than the * original delalloc one. Trim the return extent to the next COW * boundary again to force a re-lookup. */ |
760fea8bf xfs: remove the f... |
449 |
if (whichfork != XFS_COW_FORK && cow_fsb != NULLFILEOFF) { |
4e087a3b3 xfs: use a struct... |
450 451 452 453 454 |
loff_t cow_offset = XFS_FSB_TO_B(mp, cow_fsb); if (cow_offset < wpc->iomap.offset + wpc->iomap.length) wpc->iomap.length = cow_offset - wpc->iomap.offset; } |
4ad765edb xfs: move xfs_iom... |
455 |
|
4e087a3b3 xfs: use a struct... |
456 457 |
ASSERT(wpc->iomap.offset <= offset); ASSERT(wpc->iomap.offset + wpc->iomap.length > offset); |
760fea8bf xfs: remove the f... |
458 |
trace_xfs_map_blocks_alloc(ip, offset, count, whichfork, &imap); |
8ff2957d5 xfs: simplify xfs... |
459 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
460 |
} |
598ecfbaa iomap: lift the x... |
461 462 463 |
static int xfs_prepare_ioend( struct iomap_ioend *ioend, |
e10de3723 xfs: don't chain ... |
464 |
int status) |
f6d6d4fcd [XFS] Initial pas... |
465 |
{ |
73d30d487 xfs: remove XFS_T... |
466 467 468 469 470 471 472 473 |
unsigned int nofs_flag; /* * We can allocate memory here while doing writeback on behalf of * memory reclaim. To avoid memory allocation deadlocks set the * task-wide nofs context for the following operations. */ nofs_flag = memalloc_nofs_save(); |
5eda43000 xfs: mark specula... |
474 |
/* Convert CoW extents to regular */ |
760fea8bf xfs: remove the f... |
475 |
if (!status && (ioend->io_flags & IOMAP_F_SHARED)) { |
5eda43000 xfs: mark specula... |
476 477 478 |
status = xfs_reflink_convert_cow(XFS_I(ioend->io_inode), ioend->io_offset, ioend->io_size); } |
e10de3723 xfs: don't chain ... |
479 480 |
/* Reserve log space if we might write beyond the on-disk inode size. */ if (!status && |
760fea8bf xfs: remove the f... |
481 |
((ioend->io_flags & IOMAP_F_SHARED) || |
4e087a3b3 xfs: use a struct... |
482 |
ioend->io_type != IOMAP_UNWRITTEN) && |
bb18782aa xfs: build bios d... |
483 |
xfs_ioend_is_append(ioend) && |
5653017bc xfs: turn io_appe... |
484 |
!ioend->io_private) |
e10de3723 xfs: don't chain ... |
485 |
status = xfs_setfilesize_trans_alloc(ioend); |
bb18782aa xfs: build bios d... |
486 |
|
73d30d487 xfs: remove XFS_T... |
487 |
memalloc_nofs_restore(nofs_flag); |
598ecfbaa iomap: lift the x... |
488 489 490 |
if (xfs_ioend_needs_workqueue(ioend)) ioend->io_bio->bi_end_io = xfs_end_bio; return status; |
f6d6d4fcd [XFS] Initial pas... |
491 |
} |
3ed3a4343 xfs: truncate del... |
492 |
/* |
82cb14175 xfs: add support ... |
493 494 495 |
* If the page has delalloc blocks on it, we need to punch them out before we * invalidate the page. If we don't, we leave a stale delalloc mapping on the * inode that can trip up a later direct I/O read operation on the same region. |
3ed3a4343 xfs: truncate del... |
496 |
* |
82cb14175 xfs: add support ... |
497 498 499 500 501 |
* We prevent this by truncating away the delalloc regions on the page. Because * they are delalloc, we can do this without needing a transaction. Indeed - if * we get ENOSPC errors, we have to be able to do this truncation without a * transaction as there is no space left for block reservation (typically why we * see a ENOSPC in writeback). |
3ed3a4343 xfs: truncate del... |
502 |
*/ |
598ecfbaa iomap: lift the x... |
503 504 |
static void xfs_discard_page( |
763e4cdc0 iomap: support pa... |
505 506 |
struct page *page, loff_t fileoff) |
3ed3a4343 xfs: truncate del... |
507 508 509 |
{ struct inode *inode = page->mapping->host; struct xfs_inode *ip = XFS_I(inode); |
036257213 xfs: simplify xfs... |
510 |
struct xfs_mount *mp = ip->i_mount; |
763e4cdc0 iomap: support pa... |
511 512 513 |
unsigned int pageoff = offset_in_page(fileoff); xfs_fileoff_t start_fsb = XFS_B_TO_FSBT(mp, fileoff); xfs_fileoff_t pageoff_fsb = XFS_B_TO_FSBT(mp, pageoff); |
036257213 xfs: simplify xfs... |
514 |
int error; |
3ed3a4343 xfs: truncate del... |
515 |
|
036257213 xfs: simplify xfs... |
516 |
if (XFS_FORCED_SHUTDOWN(mp)) |
e8c3753ce xfs: don't warn a... |
517 |
goto out_invalidate; |
4ab45e259 xfs: ratelimit xf... |
518 |
xfs_alert_ratelimited(mp, |
c96900435 xfs: use %px for ... |
519 |
"page discard on page "PTR_FMT", inode 0x%llx, offset %llu.", |
763e4cdc0 iomap: support pa... |
520 |
page, ip->i_ino, fileoff); |
3ed3a4343 xfs: truncate del... |
521 |
|
036257213 xfs: simplify xfs... |
522 |
error = xfs_bmap_punch_delalloc_range(ip, start_fsb, |
763e4cdc0 iomap: support pa... |
523 |
i_blocks_per_page(inode, page) - pageoff_fsb); |
036257213 xfs: simplify xfs... |
524 525 |
if (error && !XFS_FORCED_SHUTDOWN(mp)) xfs_alert(mp, "page discard unable to remove delalloc mapping."); |
3ed3a4343 xfs: truncate del... |
526 |
out_invalidate: |
763e4cdc0 iomap: support pa... |
527 |
iomap_invalidatepage(page, pageoff, PAGE_SIZE - pageoff); |
3ed3a4343 xfs: truncate del... |
528 |
} |
598ecfbaa iomap: lift the x... |
529 530 531 532 533 |
static const struct iomap_writeback_ops xfs_writeback_ops = { .map_blocks = xfs_map_blocks, .prepare_ioend = xfs_prepare_ioend, .discard_page = xfs_discard_page, }; |
f51623b21 [XFS] Move some c... |
534 |
|
7d4fb40ad [XFS] Start write... |
535 |
STATIC int |
fbcc02561 xfs: Introduce wr... |
536 537 538 539 |
xfs_vm_writepage( struct page *page, struct writeback_control *wbc) { |
be225fec7 xfs: remove the i... |
540 |
struct xfs_writepage_ctx wpc = { }; |
fbcc02561 xfs: Introduce wr... |
541 |
|
598ecfbaa iomap: lift the x... |
542 |
return iomap_writepage(page, wbc, &wpc.ctx, &xfs_writeback_ops); |
fbcc02561 xfs: Introduce wr... |
543 544 545 |
} STATIC int |
7d4fb40ad [XFS] Start write... |
546 547 548 549 |
xfs_vm_writepages( struct address_space *mapping, struct writeback_control *wbc) { |
be225fec7 xfs: remove the i... |
550 |
struct xfs_writepage_ctx wpc = { }; |
fbcc02561 xfs: Introduce wr... |
551 |
|
b3aea4edc [XFS] kill the v_... |
552 |
xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED); |
598ecfbaa iomap: lift the x... |
553 |
return iomap_writepages(mapping, wbc, &wpc.ctx, &xfs_writeback_ops); |
7d4fb40ad [XFS] Start write... |
554 |
} |
6e2608dfd xfs, dax: introdu... |
555 556 557 558 559 |
STATIC int xfs_dax_writepages( struct address_space *mapping, struct writeback_control *wbc) { |
30fa529e3 xfs: add a xfs_in... |
560 561 562 |
struct xfs_inode *ip = XFS_I(mapping->host); xfs_iflags_clear(ip, XFS_ITRUNCATED); |
6e2608dfd xfs, dax: introdu... |
563 |
return dax_writeback_mapping_range(mapping, |
3f666c56c dax: Pass dax_dev... |
564 |
xfs_inode_buftarg(ip)->bt_daxdev, wbc); |
6e2608dfd xfs, dax: introdu... |
565 |
} |
1da177e4c Linux-2.6.12-rc2 |
566 |
STATIC sector_t |
e4c573bb6 [XFS] Switch over... |
567 |
xfs_vm_bmap( |
1da177e4c Linux-2.6.12-rc2 |
568 569 570 |
struct address_space *mapping, sector_t block) { |
b84e77229 xfs: use iomap_bmap |
571 |
struct xfs_inode *ip = XFS_I(mapping->host); |
1da177e4c Linux-2.6.12-rc2 |
572 |
|
b84e77229 xfs: use iomap_bmap |
573 |
trace_xfs_vm_bmap(ip); |
db1327b16 xfs: report share... |
574 575 576 |
/* * The swap code (ab-)uses ->bmap to get a block mapping and then |
793057e1c vfs: Replace stra... |
577 |
* bypasses the file system for actual I/O. We really can't allow |
db1327b16 xfs: report share... |
578 |
* that on reflinks inodes, so we have to skip out here. And yes, |
eb5e248d5 xfs: don't allow ... |
579 580 581 582 |
* 0 is the magic code for a bmap error. * * Since we don't pass back blockdev info, we can't return bmap * information for rt files either. |
db1327b16 xfs: report share... |
583 |
*/ |
66ae56a53 xfs: introduce an... |
584 |
if (xfs_is_cow_inode(ip) || XFS_IS_REALTIME_INODE(ip)) |
db1327b16 xfs: report share... |
585 |
return 0; |
690c2a388 xfs: split out a ... |
586 |
return iomap_bmap(mapping, block, &xfs_read_iomap_ops); |
1da177e4c Linux-2.6.12-rc2 |
587 588 589 |
} STATIC int |
e4c573bb6 [XFS] Switch over... |
590 |
xfs_vm_readpage( |
1da177e4c Linux-2.6.12-rc2 |
591 592 593 |
struct file *unused, struct page *page) { |
690c2a388 xfs: split out a ... |
594 |
return iomap_readpage(page, &xfs_read_iomap_ops); |
1da177e4c Linux-2.6.12-rc2 |
595 |
} |
9d24a13a9 iomap: convert fr... |
596 597 598 |
STATIC void xfs_vm_readahead( struct readahead_control *rac) |
1da177e4c Linux-2.6.12-rc2 |
599 |
{ |
9d24a13a9 iomap: convert fr... |
600 |
iomap_readahead(rac, &xfs_read_iomap_ops); |
22e757a49 xfs: don't dirty ... |
601 |
} |
67482129c iomap: add a swap... |
602 603 604 605 606 607 |
static int xfs_iomap_swapfile_activate( struct swap_info_struct *sis, struct file *swap_file, sector_t *span) { |
30fa529e3 xfs: add a xfs_in... |
608 |
sis->bdev = xfs_inode_buftarg(XFS_I(file_inode(swap_file)))->bt_bdev; |
690c2a388 xfs: split out a ... |
609 610 |
return iomap_swapfile_activate(sis, swap_file, span, &xfs_read_iomap_ops); |
67482129c iomap: add a swap... |
611 |
} |
f5e54d6e5 [PATCH] mark addr... |
612 |
const struct address_space_operations xfs_address_space_operations = { |
e4c573bb6 [XFS] Switch over... |
613 |
.readpage = xfs_vm_readpage, |
9d24a13a9 iomap: convert fr... |
614 |
.readahead = xfs_vm_readahead, |
e4c573bb6 [XFS] Switch over... |
615 |
.writepage = xfs_vm_writepage, |
7d4fb40ad [XFS] Start write... |
616 |
.writepages = xfs_vm_writepages, |
82cb14175 xfs: add support ... |
617 |
.set_page_dirty = iomap_set_page_dirty, |
9e91c5728 iomap: lift commo... |
618 619 |
.releasepage = iomap_releasepage, .invalidatepage = iomap_invalidatepage, |
e4c573bb6 [XFS] Switch over... |
620 |
.bmap = xfs_vm_bmap, |
6e2608dfd xfs, dax: introdu... |
621 |
.direct_IO = noop_direct_IO, |
82cb14175 xfs: add support ... |
622 623 |
.migratepage = iomap_migrate_page, .is_partially_uptodate = iomap_is_partially_uptodate, |
aa261f549 HWPOISON: Enable ... |
624 |
.error_remove_page = generic_error_remove_page, |
67482129c iomap: add a swap... |
625 |
.swap_activate = xfs_iomap_swapfile_activate, |
1da177e4c Linux-2.6.12-rc2 |
626 |
}; |
6e2608dfd xfs, dax: introdu... |
627 628 629 630 631 632 |
const struct address_space_operations xfs_dax_aops = { .writepages = xfs_dax_writepages, .direct_IO = noop_direct_IO, .set_page_dirty = noop_set_page_dirty, .invalidatepage = noop_invalidatepage, |
67482129c iomap: add a swap... |
633 |
.swap_activate = xfs_iomap_swapfile_activate, |
6e2608dfd xfs, dax: introdu... |
634 |
}; |