Blame view
fs/xfs/xfs_iomap.c
33.1 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
3e57ecf64 [XFS] Add paramet... |
2 |
* Copyright (c) 2000-2006 Silicon Graphics, Inc. |
51446f5ba xfs: rewrite and ... |
3 |
* Copyright (c) 2016 Christoph Hellwig. |
7b7187698 [XFS] Update lice... |
4 |
* All Rights Reserved. |
1da177e4c Linux-2.6.12-rc2 |
5 |
* |
7b7187698 [XFS] Update lice... |
6 7 |
* This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as |
1da177e4c Linux-2.6.12-rc2 |
8 9 |
* published by the Free Software Foundation. * |
7b7187698 [XFS] Update lice... |
10 11 12 13 |
* This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. |
1da177e4c Linux-2.6.12-rc2 |
14 |
* |
7b7187698 [XFS] Update lice... |
15 16 17 |
* You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
1da177e4c Linux-2.6.12-rc2 |
18 |
*/ |
3b3dce052 xfs: make xfs_bmb... |
19 |
#include <linux/iomap.h> |
1da177e4c Linux-2.6.12-rc2 |
20 |
#include "xfs.h" |
1da177e4c Linux-2.6.12-rc2 |
21 |
#include "xfs_fs.h" |
70a9883c5 xfs: create a sha... |
22 |
#include "xfs_shared.h" |
239880ef6 xfs: decouple log... |
23 24 25 |
#include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" |
1da177e4c Linux-2.6.12-rc2 |
26 |
#include "xfs_mount.h" |
3ab78df2a xfs: rework xfs_b... |
27 |
#include "xfs_defer.h" |
1da177e4c Linux-2.6.12-rc2 |
28 |
#include "xfs_inode.h" |
a844f4510 [XFS] Remove xfs_... |
29 |
#include "xfs_btree.h" |
a4fbe6ab1 xfs: decouple ino... |
30 |
#include "xfs_bmap_btree.h" |
1da177e4c Linux-2.6.12-rc2 |
31 |
#include "xfs_bmap.h" |
689881145 xfs: create xfs_b... |
32 |
#include "xfs_bmap_util.h" |
1da177e4c Linux-2.6.12-rc2 |
33 |
#include "xfs_error.h" |
a4fbe6ab1 xfs: decouple ino... |
34 |
#include "xfs_trans.h" |
1da177e4c Linux-2.6.12-rc2 |
35 |
#include "xfs_trans_space.h" |
1da177e4c Linux-2.6.12-rc2 |
36 |
#include "xfs_iomap.h" |
0b1b213fc xfs: event tracin... |
37 |
#include "xfs_trace.h" |
27b528679 xfs: add EOFBLOCK... |
38 |
#include "xfs_icache.h" |
a4fbe6ab1 xfs: decouple ino... |
39 |
#include "xfs_quota.h" |
76a4202a3 xfs: add quota-dr... |
40 41 |
#include "xfs_dquot_item.h" #include "xfs_dquot.h" |
2a06705cd xfs: create delal... |
42 |
#include "xfs_reflink.h" |
1da177e4c Linux-2.6.12-rc2 |
43 |
|
1da177e4c Linux-2.6.12-rc2 |
44 45 46 |
#define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ << mp->m_writeio_log) |
1da177e4c Linux-2.6.12-rc2 |
47 |
|
e9c497363 xfs: move xfs_bmb... |
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
void xfs_bmbt_to_iomap( struct xfs_inode *ip, struct iomap *iomap, struct xfs_bmbt_irec *imap) { struct xfs_mount *mp = ip->i_mount; if (imap->br_startblock == HOLESTARTBLOCK) { iomap->blkno = IOMAP_NULL_BLOCK; iomap->type = IOMAP_HOLE; } else if (imap->br_startblock == DELAYSTARTBLOCK) { iomap->blkno = IOMAP_NULL_BLOCK; iomap->type = IOMAP_DELALLOC; } else { iomap->blkno = xfs_fsb_to_db(ip, imap->br_startblock); if (imap->br_state == XFS_EXT_UNWRITTEN) iomap->type = IOMAP_UNWRITTEN; else iomap->type = IOMAP_MAPPED; } iomap->offset = XFS_FSB_TO_B(mp, imap->br_startoff); iomap->length = XFS_FSB_TO_B(mp, imap->br_blockcount); iomap->bdev = xfs_find_bdev_for_inode(VFS_I(ip)); |
486aff5e0 xfs: perform dax_... |
72 |
iomap->dax_dev = xfs_find_daxdev_for_inode(VFS_I(ip)); |
e9c497363 xfs: move xfs_bmb... |
73 |
} |
f7ca35227 xfs: create a sep... |
74 |
xfs_extlen_t |
f8e3a8257 xfs: factor our a... |
75 76 77 |
xfs_eof_alignment( struct xfs_inode *ip, xfs_extlen_t extsize) |
dd9f438e3 [XFS] Implement t... |
78 |
{ |
f8e3a8257 xfs: factor our a... |
79 80 |
struct xfs_mount *mp = ip->i_mount; xfs_extlen_t align = 0; |
dd9f438e3 [XFS] Implement t... |
81 |
|
bf322d983 xfs: cleanup xfs_... |
82 83 84 85 86 87 88 89 90 91 92 93 94 |
if (!XFS_IS_REALTIME_INODE(ip)) { /* * Round up the allocation request to a stripe unit * (m_dalign) boundary if the file size is >= stripe unit * size, and we are allocating past the allocation eof. * * If mounted with the "-o swalloc" option the alignment is * increased from the strip unit size to the stripe width. */ if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC)) align = mp->m_swidth; else if (mp->m_dalign) align = mp->m_dalign; |
76b573025 xfs: overflow in ... |
95 96 |
if (align && XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, align)) align = 0; |
bf322d983 xfs: cleanup xfs_... |
97 |
} |
dd9f438e3 [XFS] Implement t... |
98 99 100 101 102 103 |
/* * Always round up the allocation request to an extent boundary * (when file on a real-time subvolume or has di_extsize hint). */ if (extsize) { |
76b573025 xfs: overflow in ... |
104 105 |
if (align) align = roundup_64(align, extsize); |
dd9f438e3 [XFS] Implement t... |
106 107 |
else align = extsize; |
dd9f438e3 [XFS] Implement t... |
108 |
} |
f8e3a8257 xfs: factor our a... |
109 110 111 112 113 114 115 116 117 118 |
return align; } STATIC int xfs_iomap_eof_align_last_fsb( struct xfs_inode *ip, xfs_extlen_t extsize, xfs_fileoff_t *last_fsb) { xfs_extlen_t align = xfs_eof_alignment(ip, extsize); |
76b573025 xfs: overflow in ... |
119 120 |
if (align) { xfs_fileoff_t new_last_fsb = roundup_64(*last_fsb, align); |
f8e3a8257 xfs: factor our a... |
121 |
int eof, error; |
541d7d3c4 [XFS] kill unness... |
122 |
error = xfs_bmap_eof(ip, new_last_fsb, XFS_DATA_FORK, &eof); |
dd9f438e3 [XFS] Implement t... |
123 124 125 126 127 128 129 130 131 |
if (error) return error; if (eof) *last_fsb = new_last_fsb; } return 0; } STATIC int |
6d4a8ecb3 xfs: rename xfs_c... |
132 |
xfs_alert_fsblock_zero( |
572d95f49 [XFS] Improve err... |
133 134 135 |
xfs_inode_t *ip, xfs_bmbt_irec_t *imap) { |
6a19d9393 xfs: convert xfs_... |
136 |
xfs_alert_tag(ip->i_mount, XFS_PTAG_FSBLOCK_ZERO, |
572d95f49 [XFS] Improve err... |
137 138 |
"Access to block zero in inode %llu " "start_block: %llx start_off: %llx " |
08e96e1a3 xfs: remove newli... |
139 |
"blkcnt: %llx extent-state: %x", |
572d95f49 [XFS] Improve err... |
140 141 142 143 144 |
(unsigned long long)ip->i_ino, (unsigned long long)imap->br_startblock, (unsigned long long)imap->br_startoff, (unsigned long long)imap->br_blockcount, imap->br_state); |
2451337dd xfs: global error... |
145 |
return -EFSCORRUPTED; |
572d95f49 [XFS] Improve err... |
146 |
} |
a206c817c xfs: kill xfs_iomap |
147 |
int |
1da177e4c Linux-2.6.12-rc2 |
148 149 |
xfs_iomap_write_direct( xfs_inode_t *ip, |
f403b7f45 [XFS] Cleanup use... |
150 |
xfs_off_t offset, |
1da177e4c Linux-2.6.12-rc2 |
151 |
size_t count, |
3070451ee xfs: reduce stack... |
152 |
xfs_bmbt_irec_t *imap, |
405f80429 xfs: cleanup the ... |
153 |
int nmaps) |
1da177e4c Linux-2.6.12-rc2 |
154 155 |
{ xfs_mount_t *mp = ip->i_mount; |
1da177e4c Linux-2.6.12-rc2 |
156 157 |
xfs_fileoff_t offset_fsb; xfs_fileoff_t last_fsb; |
dd9f438e3 [XFS] Implement t... |
158 |
xfs_filblks_t count_fsb, resaligned; |
1da177e4c Linux-2.6.12-rc2 |
159 |
xfs_fsblock_t firstfsb; |
f13eb2055 xfs: introduce xf... |
160 |
xfs_extlen_t extsz; |
0116d9356 [XFS] Remove dead... |
161 |
int nimaps; |
06d10dd9c [XFS] Merge fixes... |
162 |
int quota_flag; |
1da177e4c Linux-2.6.12-rc2 |
163 164 |
int rt; xfs_trans_t *tp; |
2c3234d1e xfs: rename flist... |
165 |
struct xfs_defer_ops dfops; |
dd9f438e3 [XFS] Implement t... |
166 |
uint qblocks, resblks, resrtextents; |
dd9f438e3 [XFS] Implement t... |
167 |
int error; |
009c6e871 xfs: add missing ... |
168 |
int lockmode; |
1ca191576 xfs: Don't use un... |
169 |
int bmapi_flags = XFS_BMAPI_PREALLOC; |
253f4911f xfs: better xfs_t... |
170 |
uint tflags = 0; |
1da177e4c Linux-2.6.12-rc2 |
171 |
|
dd9f438e3 [XFS] Implement t... |
172 |
rt = XFS_IS_REALTIME_INODE(ip); |
957d0ebed [XFS] Cleanup ino... |
173 |
extsz = xfs_get_extsz_hint(ip); |
009c6e871 xfs: add missing ... |
174 175 176 |
lockmode = XFS_ILOCK_SHARED; /* locked by caller */ ASSERT(xfs_isilocked(ip, lockmode)); |
1da177e4c Linux-2.6.12-rc2 |
177 |
|
957d0ebed [XFS] Cleanup ino... |
178 179 |
offset_fsb = XFS_B_TO_FSBT(mp, offset); last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); |
ce7ae151d xfs: remove the i... |
180 |
if ((offset + count) > XFS_ISIZE(ip)) { |
009c6e871 xfs: add missing ... |
181 182 183 184 185 186 187 188 189 |
/* * Assert that the in-core extent list is present since this can * call xfs_iread_extents() and we only have the ilock shared. * This should be safe because the lock was held around a bmapi * call in the caller and we only need it to access the in-core * list. */ ASSERT(XFS_IFORK_PTR(ip, XFS_DATA_FORK)->if_flags & XFS_IFEXTENTS); |
f8e3a8257 xfs: factor our a... |
190 |
error = xfs_iomap_eof_align_last_fsb(ip, extsz, &last_fsb); |
dd9f438e3 [XFS] Implement t... |
191 |
if (error) |
009c6e871 xfs: add missing ... |
192 |
goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
193 |
} else { |
405f80429 xfs: cleanup the ... |
194 |
if (nmaps && (imap->br_startblock == HOLESTARTBLOCK)) |
dd9f438e3 [XFS] Implement t... |
195 |
last_fsb = MIN(last_fsb, (xfs_fileoff_t) |
3070451ee xfs: reduce stack... |
196 197 |
imap->br_blockcount + imap->br_startoff); |
1da177e4c Linux-2.6.12-rc2 |
198 |
} |
dd9f438e3 [XFS] Implement t... |
199 200 |
count_fsb = last_fsb - offset_fsb; ASSERT(count_fsb > 0); |
f13eb2055 xfs: introduce xf... |
201 |
resaligned = xfs_aligned_fsb_count(offset_fsb, count_fsb, extsz); |
dd9f438e3 [XFS] Implement t... |
202 203 204 205 |
if (unlikely(rt)) { resrtextents = qblocks = resaligned; resrtextents /= mp->m_sb.sb_rextsize; |
84e1e99f1 [XFS] Prevent ENO... |
206 207 208 209 |
resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); quota_flag = XFS_QMOPT_RES_RTBLKS; } else { resrtextents = 0; |
dd9f438e3 [XFS] Implement t... |
210 |
resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned); |
84e1e99f1 [XFS] Prevent ENO... |
211 212 |
quota_flag = XFS_QMOPT_RES_REGBLKS; } |
1da177e4c Linux-2.6.12-rc2 |
213 214 |
/* |
009c6e871 xfs: add missing ... |
215 216 217 218 219 220 221 222 223 |
* Drop the shared lock acquired by the caller, attach the dquot if * necessary and move on to transaction setup. */ xfs_iunlock(ip, lockmode); error = xfs_qm_dqattach(ip, 0); if (error) return error; /* |
1ca191576 xfs: Don't use un... |
224 225 226 227 228 |
* For DAX, we do not allocate unwritten extents, but instead we zero * the block before we commit the transaction. Ideally we'd like to do * this outside the transaction context, but if we commit and then crash * we may not have zeroed the blocks and this will be exposed on * recovery of the allocation. Hence we must zero before commit. |
3b0fe4780 xfs: Don't use re... |
229 |
* |
1ca191576 xfs: Don't use un... |
230 231 232 |
* Further, if we are mapping unwritten extents here, we need to zero * and convert them to written so that we don't need an unwritten extent * callback for DAX. This also means that we need to be able to dip into |
3b0fe4780 xfs: Don't use re... |
233 234 |
* the reserve block pool for bmbt block allocation if there is no space * left but we need to do unwritten extent conversion. |
1ca191576 xfs: Don't use un... |
235 236 237 |
*/ if (IS_DAX(VFS_I(ip))) { bmapi_flags = XFS_BMAPI_CONVERT | XFS_BMAPI_ZERO; |
63fbb4c18 xfs: remove the I... |
238 |
if (imap->br_state == XFS_EXT_UNWRITTEN) { |
253f4911f xfs: better xfs_t... |
239 |
tflags |= XFS_TRANS_RESERVE; |
3b0fe4780 xfs: Don't use re... |
240 241 |
resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1; } |
1ca191576 xfs: Don't use un... |
242 |
} |
253f4911f xfs: better xfs_t... |
243 244 245 |
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, resrtextents, tflags, &tp); if (error) |
b474c7ae4 xfs: Nuke XFS_ERR... |
246 |
return error; |
507630b29 xfs: use shared i... |
247 |
|
009c6e871 xfs: add missing ... |
248 249 |
lockmode = XFS_ILOCK_EXCL; xfs_ilock(ip, lockmode); |
1da177e4c Linux-2.6.12-rc2 |
250 |
|
7d095257e xfs: kill xfs_qmops |
251 |
error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, 0, quota_flag); |
dd9f438e3 [XFS] Implement t... |
252 |
if (error) |
507630b29 xfs: use shared i... |
253 |
goto out_trans_cancel; |
1da177e4c Linux-2.6.12-rc2 |
254 |
|
ddc3415ab xfs: simplify xfs... |
255 |
xfs_trans_ijoin(tp, ip, 0); |
1da177e4c Linux-2.6.12-rc2 |
256 |
|
1da177e4c Linux-2.6.12-rc2 |
257 |
/* |
3070451ee xfs: reduce stack... |
258 259 |
* From this point onwards we overwrite the imap pointer that the * caller gave to us. |
1da177e4c Linux-2.6.12-rc2 |
260 |
*/ |
2c3234d1e xfs: rename flist... |
261 |
xfs_defer_init(&dfops, &firstfsb); |
06d10dd9c [XFS] Merge fixes... |
262 |
nimaps = 1; |
d531d91d6 xfs: always use u... |
263 |
error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, |
264e89ad3 Merge branch 'xfs... |
264 |
bmapi_flags, &firstfsb, resblks, imap, |
2c3234d1e xfs: rename flist... |
265 |
&nimaps, &dfops); |
06d10dd9c [XFS] Merge fixes... |
266 |
if (error) |
507630b29 xfs: use shared i... |
267 |
goto out_bmap_cancel; |
1da177e4c Linux-2.6.12-rc2 |
268 269 |
/* |
06d10dd9c [XFS] Merge fixes... |
270 |
* Complete the transaction |
1da177e4c Linux-2.6.12-rc2 |
271 |
*/ |
8ad7c629b xfs: remove the i... |
272 |
error = xfs_defer_finish(&tp, &dfops); |
06d10dd9c [XFS] Merge fixes... |
273 |
if (error) |
507630b29 xfs: use shared i... |
274 |
goto out_bmap_cancel; |
1ca191576 xfs: Don't use un... |
275 |
|
70393313d xfs: saner xfs_tr... |
276 |
error = xfs_trans_commit(tp); |
06d10dd9c [XFS] Merge fixes... |
277 |
if (error) |
507630b29 xfs: use shared i... |
278 |
goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
279 |
|
06d10dd9c [XFS] Merge fixes... |
280 281 282 |
/* * Copy any maps to caller's array and return any error. */ |
1da177e4c Linux-2.6.12-rc2 |
283 |
if (nimaps == 0) { |
2451337dd xfs: global error... |
284 |
error = -ENOSPC; |
507630b29 xfs: use shared i... |
285 |
goto out_unlock; |
572d95f49 [XFS] Improve err... |
286 |
} |
507630b29 xfs: use shared i... |
287 |
if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip))) |
6d4a8ecb3 xfs: rename xfs_c... |
288 |
error = xfs_alert_fsblock_zero(ip, imap); |
1da177e4c Linux-2.6.12-rc2 |
289 |
|
507630b29 xfs: use shared i... |
290 |
out_unlock: |
009c6e871 xfs: add missing ... |
291 |
xfs_iunlock(ip, lockmode); |
507630b29 xfs: use shared i... |
292 |
return error; |
1da177e4c Linux-2.6.12-rc2 |
293 |
|
507630b29 xfs: use shared i... |
294 |
out_bmap_cancel: |
2c3234d1e xfs: rename flist... |
295 |
xfs_defer_cancel(&dfops); |
ea562ed6e xfs: fix delalloc... |
296 |
xfs_trans_unreserve_quota_nblks(tp, ip, (long)qblocks, 0, quota_flag); |
507630b29 xfs: use shared i... |
297 |
out_trans_cancel: |
4906e2154 xfs: remove the f... |
298 |
xfs_trans_cancel(tp); |
507630b29 xfs: use shared i... |
299 |
goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
300 |
} |
76a4202a3 xfs: add quota-dr... |
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
STATIC bool xfs_quota_need_throttle( struct xfs_inode *ip, int type, xfs_fsblock_t alloc_blocks) { struct xfs_dquot *dq = xfs_inode_dquot(ip, type); if (!dq || !xfs_this_quota_on(ip->i_mount, type)) return false; /* no hi watermark, no throttle */ if (!dq->q_prealloc_hi_wmark) return false; /* under the lo watermark, no throttle */ if (dq->q_res_bcount + alloc_blocks < dq->q_prealloc_lo_wmark) return false; return true; } STATIC void xfs_quota_calc_throttle( struct xfs_inode *ip, int type, xfs_fsblock_t *qblocks, |
f074051ff xfs: squash preal... |
328 329 |
int *qshift, int64_t *qfreesp) |
76a4202a3 xfs: add quota-dr... |
330 331 332 333 |
{ int64_t freesp; int shift = 0; struct xfs_dquot *dq = xfs_inode_dquot(ip, type); |
5cca3f611 xfs: check for nu... |
334 335 |
/* no dq, or over hi wmark, squash the prealloc completely */ if (!dq || dq->q_res_bcount >= dq->q_prealloc_hi_wmark) { |
76a4202a3 xfs: add quota-dr... |
336 |
*qblocks = 0; |
f074051ff xfs: squash preal... |
337 |
*qfreesp = 0; |
76a4202a3 xfs: add quota-dr... |
338 339 340 341 342 343 344 345 346 347 348 |
return; } freesp = dq->q_prealloc_hi_wmark - dq->q_res_bcount; if (freesp < dq->q_low_space[XFS_QLOWSP_5_PCNT]) { shift = 2; if (freesp < dq->q_low_space[XFS_QLOWSP_3_PCNT]) shift += 2; if (freesp < dq->q_low_space[XFS_QLOWSP_1_PCNT]) shift += 2; } |
f074051ff xfs: squash preal... |
349 350 |
if (freesp < *qfreesp) *qfreesp = freesp; |
76a4202a3 xfs: add quota-dr... |
351 352 353 354 355 356 |
/* only overwrite the throttle values if we are more aggressive */ if ((freesp >> shift) < (*qblocks >> *qshift)) { *qblocks = freesp; *qshift = shift; } } |
a1e16c266 xfs: limit specul... |
357 |
/* |
51446f5ba xfs: rewrite and ... |
358 359 360 361 |
* If we are doing a write at the end of the file and there are no allocations * past this one, then extend the allocation out to the file system's write * iosize. * |
055388a31 xfs: dynamic spec... |
362 |
* If we don't have a user specified preallocation size, dynamically increase |
51446f5ba xfs: rewrite and ... |
363 |
* the preallocation size as the size of the file grows. Cap the maximum size |
055388a31 xfs: dynamic spec... |
364 365 |
* at a single extent or less if the filesystem is near full. The closer the * filesystem is to full, the smaller the maximum prealocation. |
51446f5ba xfs: rewrite and ... |
366 367 368 369 370 371 372 373 |
* * As an exception we don't do any preallocation at all if the file is smaller * than the minimum preallocation and we are using the default dynamic * preallocation scheme, as it is likely this is the only write to the file that * is going to be done. * * We clean up any extra space left over when the file is closed in * xfs_inactive(). |
055388a31 xfs: dynamic spec... |
374 375 376 |
*/ STATIC xfs_fsblock_t xfs_iomap_prealloc_size( |
a1e16c266 xfs: limit specul... |
377 |
struct xfs_inode *ip, |
51446f5ba xfs: rewrite and ... |
378 379 |
loff_t offset, loff_t count, |
656152e55 xfs: use new exte... |
380 |
xfs_extnum_t idx) |
055388a31 xfs: dynamic spec... |
381 |
{ |
51446f5ba xfs: rewrite and ... |
382 |
struct xfs_mount *mp = ip->i_mount; |
656152e55 xfs: use new exte... |
383 |
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); |
51446f5ba xfs: rewrite and ... |
384 |
xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); |
656152e55 xfs: use new exte... |
385 |
struct xfs_bmbt_irec prev; |
3c58b5f80 xfs: reorganize x... |
386 387 |
int shift = 0; int64_t freesp; |
76a4202a3 xfs: add quota-dr... |
388 389 |
xfs_fsblock_t qblocks; int qshift = 0; |
51446f5ba xfs: rewrite and ... |
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
xfs_fsblock_t alloc_blocks = 0; if (offset + count <= XFS_ISIZE(ip)) return 0; if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) && (XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_writeio_blocks))) return 0; /* * If an explicit allocsize is set, the file is small, or we * are writing behind a hole, then use the minimum prealloc: */ if ((mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) || XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) || |
656152e55 xfs: use new exte... |
405 406 |
!xfs_iext_get_extent(ifp, idx - 1, &prev) || prev.br_startoff + prev.br_blockcount < offset_fsb) |
51446f5ba xfs: rewrite and ... |
407 |
return mp->m_writeio_blocks; |
055388a31 xfs: dynamic spec... |
408 |
|
51446f5ba xfs: rewrite and ... |
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
/* * Determine the initial size of the preallocation. We are beyond the * current EOF here, but we need to take into account whether this is * a sparse write or an extending write when determining the * preallocation size. Hence we need to look up the extent that ends * at the current write offset and use the result to determine the * preallocation size. * * If the extent is a hole, then preallocation is essentially disabled. * Otherwise we take the size of the preceding data extent as the basis * for the preallocation size. If the size of the extent is greater than * half the maximum extent length, then use the current offset as the * basis. This ensures that for large files the preallocation size * always extends to MAXEXTLEN rather than falling short due to things * like stripe unit/width alignment of real extents. */ |
656152e55 xfs: use new exte... |
425 426 |
if (prev.br_blockcount <= (MAXEXTLEN >> 1)) alloc_blocks = prev.br_blockcount << 1; |
51446f5ba xfs: rewrite and ... |
427 428 |
else alloc_blocks = XFS_B_TO_FSB(mp, offset); |
3c58b5f80 xfs: reorganize x... |
429 430 |
if (!alloc_blocks) goto check_writeio; |
76a4202a3 xfs: add quota-dr... |
431 |
qblocks = alloc_blocks; |
3c58b5f80 xfs: reorganize x... |
432 |
|
c9bdbdc07 xfs: push rounddo... |
433 434 435 436 437 438 439 440 441 |
/* * MAXEXTLEN is not a power of two value but we round the prealloc down * to the nearest power of two value after throttling. To prevent the * round down from unconditionally reducing the maximum supported prealloc * size, we round up first, apply appropriate throttling, round down and * cap the value to MAXEXTLEN. */ alloc_blocks = XFS_FILEOFF_MIN(roundup_pow_of_two(MAXEXTLEN), alloc_blocks); |
3c58b5f80 xfs: reorganize x... |
442 |
|
0d485ada4 xfs: use generic ... |
443 |
freesp = percpu_counter_read_positive(&mp->m_fdblocks); |
3c58b5f80 xfs: reorganize x... |
444 445 446 447 448 449 450 451 452 453 |
if (freesp < mp->m_low_space[XFS_LOWSP_5_PCNT]) { shift = 2; if (freesp < mp->m_low_space[XFS_LOWSP_4_PCNT]) shift++; if (freesp < mp->m_low_space[XFS_LOWSP_3_PCNT]) shift++; if (freesp < mp->m_low_space[XFS_LOWSP_2_PCNT]) shift++; if (freesp < mp->m_low_space[XFS_LOWSP_1_PCNT]) shift++; |
055388a31 xfs: dynamic spec... |
454 |
} |
76a4202a3 xfs: add quota-dr... |
455 456 |
/* |
f074051ff xfs: squash preal... |
457 458 |
* Check each quota to cap the prealloc size, provide a shift value to * throttle with and adjust amount of available space. |
76a4202a3 xfs: add quota-dr... |
459 460 |
*/ if (xfs_quota_need_throttle(ip, XFS_DQ_USER, alloc_blocks)) |
f074051ff xfs: squash preal... |
461 462 |
xfs_quota_calc_throttle(ip, XFS_DQ_USER, &qblocks, &qshift, &freesp); |
76a4202a3 xfs: add quota-dr... |
463 |
if (xfs_quota_need_throttle(ip, XFS_DQ_GROUP, alloc_blocks)) |
f074051ff xfs: squash preal... |
464 465 |
xfs_quota_calc_throttle(ip, XFS_DQ_GROUP, &qblocks, &qshift, &freesp); |
76a4202a3 xfs: add quota-dr... |
466 |
if (xfs_quota_need_throttle(ip, XFS_DQ_PROJ, alloc_blocks)) |
f074051ff xfs: squash preal... |
467 468 |
xfs_quota_calc_throttle(ip, XFS_DQ_PROJ, &qblocks, &qshift, &freesp); |
76a4202a3 xfs: add quota-dr... |
469 470 471 472 473 474 475 476 477 478 |
/* * The final prealloc size is set to the minimum of free space available * in each of the quotas and the overall filesystem. * * The shift throttle value is set to the maximum value as determined by * the global low free space values and per-quota low free space values. */ alloc_blocks = MIN(alloc_blocks, qblocks); shift = MAX(shift, qshift); |
3c58b5f80 xfs: reorganize x... |
479 480 |
if (shift) alloc_blocks >>= shift; |
c9bdbdc07 xfs: push rounddo... |
481 482 483 484 485 486 487 488 |
/* * rounddown_pow_of_two() returns an undefined result if we pass in * alloc_blocks = 0. */ if (alloc_blocks) alloc_blocks = rounddown_pow_of_two(alloc_blocks); if (alloc_blocks > MAXEXTLEN) alloc_blocks = MAXEXTLEN; |
3c58b5f80 xfs: reorganize x... |
489 490 491 492 493 494 495 496 497 |
/* * If we are still trying to allocate more space than is * available, squash the prealloc hard. This can happen if we * have a large file on a small filesystem and the above * lowspace thresholds are smaller than MAXEXTLEN. */ while (alloc_blocks && alloc_blocks >= freesp) alloc_blocks >>= 4; |
3c58b5f80 xfs: reorganize x... |
498 |
check_writeio: |
055388a31 xfs: dynamic spec... |
499 500 |
if (alloc_blocks < mp->m_writeio_blocks) alloc_blocks = mp->m_writeio_blocks; |
19cb7e385 xfs: xfs_iomap_pr... |
501 502 |
trace_xfs_iomap_prealloc_size(ip, alloc_blocks, shift, mp->m_writeio_blocks); |
055388a31 xfs: dynamic spec... |
503 504 |
return alloc_blocks; } |
51446f5ba xfs: rewrite and ... |
505 506 507 508 509 |
static int xfs_file_iomap_begin_delay( struct inode *inode, loff_t offset, loff_t count, |
51446f5ba xfs: rewrite and ... |
510 |
struct iomap *iomap) |
1da177e4c Linux-2.6.12-rc2 |
511 |
{ |
51446f5ba xfs: rewrite and ... |
512 513 514 515 516 517 |
struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); xfs_fileoff_t maxbytes_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes); |
f782088c9 xfs: pass post-eo... |
518 |
xfs_fileoff_t end_fsb; |
51446f5ba xfs: rewrite and ... |
519 520 |
int error = 0, eof = 0; struct xfs_bmbt_irec got; |
51446f5ba xfs: rewrite and ... |
521 |
xfs_extnum_t idx; |
f782088c9 xfs: pass post-eo... |
522 |
xfs_fsblock_t prealloc_blocks = 0; |
51446f5ba xfs: rewrite and ... |
523 524 525 |
ASSERT(!XFS_IS_REALTIME_INODE(ip)); ASSERT(!xfs_get_extsz_hint(ip)); |
dd9f438e3 [XFS] Implement t... |
526 |
|
51446f5ba xfs: rewrite and ... |
527 |
xfs_ilock(ip, XFS_ILOCK_EXCL); |
1da177e4c Linux-2.6.12-rc2 |
528 |
|
51446f5ba xfs: rewrite and ... |
529 530 531 |
if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE), |
9e24cfd04 xfs: remove unnee... |
532 |
mp, XFS_ERRTAG_BMAPIFORMAT))) { |
51446f5ba xfs: rewrite and ... |
533 534 535 536 |
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto out_unlock; } |
a1e16c266 xfs: limit specul... |
537 |
|
51446f5ba xfs: rewrite and ... |
538 |
XFS_STATS_INC(mp, xs_blk_mapw); |
055388a31 xfs: dynamic spec... |
539 |
|
51446f5ba xfs: rewrite and ... |
540 541 542 543 |
if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK); if (error) goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
544 |
} |
1da177e4c Linux-2.6.12-rc2 |
545 |
|
656152e55 xfs: use new exte... |
546 |
eof = !xfs_iext_lookup_extent(ip, ifp, offset_fsb, &idx, &got); |
51446f5ba xfs: rewrite and ... |
547 |
if (!eof && got.br_startoff <= offset_fsb) { |
3ba020bef xfs: optimize wri... |
548 549 550 551 552 553 554 555 556 557 |
if (xfs_is_reflink_inode(ip)) { bool shared; end_fsb = min(XFS_B_TO_FSB(mp, offset + count), maxbytes_fsb); xfs_trim_extent(&got, offset_fsb, end_fsb - offset_fsb); error = xfs_reflink_reserve_cow(ip, &got, &shared); if (error) goto out_unlock; } |
51446f5ba xfs: rewrite and ... |
558 559 |
trace_xfs_iomap_found(ip, offset, count, 0, &got); goto done; |
1da177e4c Linux-2.6.12-rc2 |
560 |
} |
dd9f438e3 [XFS] Implement t... |
561 |
|
51446f5ba xfs: rewrite and ... |
562 563 564 |
error = xfs_qm_dqattach_locked(ip, 0); if (error) goto out_unlock; |
3ed9116e8 xfs: limit specua... |
565 |
/* |
51446f5ba xfs: rewrite and ... |
566 567 568 569 570 571 572 |
* We cap the maximum length we map here to MAX_WRITEBACK_PAGES pages * to keep the chunks of work done where somewhat symmetric with the * work writeback does. This is a completely arbitrary number pulled * out of thin air as a best guess for initial testing. * * Note that the values needs to be less than 32-bits wide until * the lower level functions are updated. |
3ed9116e8 xfs: limit specua... |
573 |
*/ |
51446f5ba xfs: rewrite and ... |
574 |
count = min_t(loff_t, count, 1024 * PAGE_SIZE); |
f782088c9 xfs: pass post-eo... |
575 |
end_fsb = min(XFS_B_TO_FSB(mp, offset + count), maxbytes_fsb); |
51446f5ba xfs: rewrite and ... |
576 577 |
if (eof) { |
656152e55 xfs: use new exte... |
578 |
prealloc_blocks = xfs_iomap_prealloc_size(ip, offset, count, idx); |
51446f5ba xfs: rewrite and ... |
579 580 581 |
if (prealloc_blocks) { xfs_extlen_t align; xfs_off_t end_offset; |
f782088c9 xfs: pass post-eo... |
582 |
xfs_fileoff_t p_end_fsb; |
3ed9116e8 xfs: limit specua... |
583 |
|
51446f5ba xfs: rewrite and ... |
584 |
end_offset = XFS_WRITEIO_ALIGN(mp, offset + count - 1); |
f782088c9 xfs: pass post-eo... |
585 586 |
p_end_fsb = XFS_B_TO_FSBT(mp, end_offset) + prealloc_blocks; |
51446f5ba xfs: rewrite and ... |
587 588 589 |
align = xfs_eof_alignment(ip, 0); if (align) |
f782088c9 xfs: pass post-eo... |
590 |
p_end_fsb = roundup_64(p_end_fsb, align); |
51446f5ba xfs: rewrite and ... |
591 |
|
f782088c9 xfs: pass post-eo... |
592 593 594 |
p_end_fsb = min(p_end_fsb, maxbytes_fsb); ASSERT(p_end_fsb > offset_fsb); prealloc_blocks = p_end_fsb - end_fsb; |
51446f5ba xfs: rewrite and ... |
595 596 597 598 |
} } retry: |
be51f8119 xfs: support bmap... |
599 |
error = xfs_bmapi_reserve_delalloc(ip, XFS_DATA_FORK, offset_fsb, |
f782088c9 xfs: pass post-eo... |
600 |
end_fsb - offset_fsb, prealloc_blocks, &got, &idx, eof); |
055388a31 xfs: dynamic spec... |
601 602 |
switch (error) { case 0: |
51446f5ba xfs: rewrite and ... |
603 |
break; |
2451337dd xfs: global error... |
604 605 |
case -ENOSPC: case -EDQUOT: |
51446f5ba xfs: rewrite and ... |
606 |
/* retry without any preallocation */ |
0b1b213fc xfs: event tracin... |
607 |
trace_xfs_delalloc_enospc(ip, offset, count); |
f782088c9 xfs: pass post-eo... |
608 609 |
if (prealloc_blocks) { prealloc_blocks = 0; |
9aa05000f xfs: xfs_sync_dat... |
610 |
goto retry; |
055388a31 xfs: dynamic spec... |
611 |
} |
51446f5ba xfs: rewrite and ... |
612 613 614 |
/*FALLTHRU*/ default: goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
615 |
} |
f65e6fad2 xfs: use iomap ne... |
616 617 618 619 620 |
/* * Flag newly allocated delalloc blocks with IOMAP_F_NEW so we punch * them out if the write happens to fail. */ iomap->flags = IOMAP_F_NEW; |
51446f5ba xfs: rewrite and ... |
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 |
trace_xfs_iomap_alloc(ip, offset, count, 0, &got); done: if (isnullstartblock(got.br_startblock)) got.br_startblock = DELAYSTARTBLOCK; if (!got.br_startblock) { error = xfs_alert_fsblock_zero(ip, &got); if (error) goto out_unlock; } xfs_bmbt_to_iomap(ip, iomap, &got); out_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; |
1da177e4c Linux-2.6.12-rc2 |
637 638 639 640 641 642 643 644 |
} /* * Pass in a delayed allocate extent, convert it to real extents; * return to the caller the extent we create which maps on top of * the originating callers request. * * Called without a lock on the inode. |
e4143a1cf [XFS] Fix transac... |
645 646 647 |
* * We no longer bother to look at the incoming map - all we have to * guarantee is that whatever we allocate fills the required range. |
1da177e4c Linux-2.6.12-rc2 |
648 |
*/ |
a206c817c xfs: kill xfs_iomap |
649 |
int |
1da177e4c Linux-2.6.12-rc2 |
650 651 |
xfs_iomap_write_allocate( xfs_inode_t *ip, |
60b4984fc xfs: support allo... |
652 |
int whichfork, |
f403b7f45 [XFS] Cleanup use... |
653 |
xfs_off_t offset, |
405f80429 xfs: cleanup the ... |
654 |
xfs_bmbt_irec_t *imap) |
1da177e4c Linux-2.6.12-rc2 |
655 656 |
{ xfs_mount_t *mp = ip->i_mount; |
1da177e4c Linux-2.6.12-rc2 |
657 658 659 |
xfs_fileoff_t offset_fsb, last_block; xfs_fileoff_t end_fsb, map_start_fsb; xfs_fsblock_t first_block; |
2c3234d1e xfs: rename flist... |
660 |
struct xfs_defer_ops dfops; |
1da177e4c Linux-2.6.12-rc2 |
661 |
xfs_filblks_t count_fsb; |
1da177e4c Linux-2.6.12-rc2 |
662 |
xfs_trans_t *tp; |
f6106efae xfs: eliminate co... |
663 |
int nimaps; |
1da177e4c Linux-2.6.12-rc2 |
664 |
int error = 0; |
d2b3964a0 xfs: fix COW writ... |
665 |
int flags = XFS_BMAPI_DELALLOC; |
1da177e4c Linux-2.6.12-rc2 |
666 |
int nres; |
60b4984fc xfs: support allo... |
667 |
if (whichfork == XFS_COW_FORK) |
5eda43000 xfs: mark specula... |
668 |
flags |= XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC; |
60b4984fc xfs: support allo... |
669 |
|
1da177e4c Linux-2.6.12-rc2 |
670 671 672 |
/* * Make sure that the dquots are there. */ |
7d095257e xfs: kill xfs_qmops |
673 674 |
error = xfs_qm_dqattach(ip, 0); if (error) |
b474c7ae4 xfs: Nuke XFS_ERR... |
675 |
return error; |
1da177e4c Linux-2.6.12-rc2 |
676 |
|
24e17b5fb [XFS] Use the rig... |
677 |
offset_fsb = XFS_B_TO_FSBT(mp, offset); |
3070451ee xfs: reduce stack... |
678 679 |
count_fsb = imap->br_blockcount; map_start_fsb = imap->br_startoff; |
1da177e4c Linux-2.6.12-rc2 |
680 |
|
ff6d6af23 xfs: per-filesyst... |
681 |
XFS_STATS_ADD(mp, xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb)); |
1da177e4c Linux-2.6.12-rc2 |
682 683 684 685 686 687 688 689 690 691 |
while (count_fsb != 0) { /* * Set up a transaction with which to allocate the * backing store for the file. Do allocations in a * loop until we get some space in the range we are * interested in. The other space that might be allocated * is in the delayed allocation extent on which we sit * but before our buffer starts. */ |
1da177e4c Linux-2.6.12-rc2 |
692 693 |
nimaps = 0; while (nimaps == 0) { |
1da177e4c Linux-2.6.12-rc2 |
694 |
nres = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK); |
0af32fb46 xfs: fix bogus sp... |
695 696 697 698 699 700 701 |
/* * We have already reserved space for the extent and any * indirect blocks when creating the delalloc extent, * there is no need to reserve space in this transaction * again. */ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, |
253f4911f xfs: better xfs_t... |
702 703 |
0, XFS_TRANS_RESERVE, &tp); if (error) |
b474c7ae4 xfs: Nuke XFS_ERR... |
704 |
return error; |
253f4911f xfs: better xfs_t... |
705 |
|
1da177e4c Linux-2.6.12-rc2 |
706 |
xfs_ilock(ip, XFS_ILOCK_EXCL); |
ddc3415ab xfs: simplify xfs... |
707 |
xfs_trans_ijoin(tp, ip, 0); |
1da177e4c Linux-2.6.12-rc2 |
708 |
|
2c3234d1e xfs: rename flist... |
709 |
xfs_defer_init(&dfops, &first_block); |
1da177e4c Linux-2.6.12-rc2 |
710 |
|
1da177e4c Linux-2.6.12-rc2 |
711 |
/* |
e4143a1cf [XFS] Fix transac... |
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 |
* it is possible that the extents have changed since * we did the read call as we dropped the ilock for a * while. We have to be careful about truncates or hole * punchs here - we are not allowed to allocate * non-delalloc blocks here. * * The only protection against truncation is the pages * for the range we are being asked to convert are * locked and hence a truncate will block on them * first. * * As a result, if we go beyond the range we really * need and hit an delalloc extent boundary followed by * a hole while we have excess blocks in the map, we * will fill the hole incorrectly and overrun the * transaction reservation. * * Using a single map prevents this as we are forced to * check each map we look for overlap with the desired * range and abort as soon as we find it. Also, given * that we only return a single map, having one beyond * what we can return is probably a bit silly. * * We also need to check that we don't go beyond EOF; * this is a truncate optimisation as a truncate sets * the new file size before block on the pages we * currently have locked under writeback. Because they * are about to be tossed, we don't need to write them * back.... |
1da177e4c Linux-2.6.12-rc2 |
741 |
*/ |
e4143a1cf [XFS] Fix transac... |
742 |
nimaps = 1; |
ce7ae151d xfs: remove the i... |
743 |
end_fsb = XFS_B_TO_FSB(mp, XFS_ISIZE(ip)); |
7fb2cd4d3 xfs: remove unuse... |
744 |
error = xfs_bmap_last_offset(ip, &last_block, |
7c9ef85c5 [XFS] Catch error... |
745 746 747 |
XFS_DATA_FORK); if (error) goto trans_cancel; |
1da177e4c Linux-2.6.12-rc2 |
748 749 750 751 |
last_block = XFS_FILEOFF_MAX(last_block, end_fsb); if ((map_start_fsb + count_fsb) > last_block) { count_fsb = last_block - map_start_fsb; if (count_fsb == 0) { |
2451337dd xfs: global error... |
752 |
error = -EAGAIN; |
1da177e4c Linux-2.6.12-rc2 |
753 754 755 |
goto trans_cancel; } } |
3070451ee xfs: reduce stack... |
756 |
/* |
3070451ee xfs: reduce stack... |
757 758 759 |
* From this point onwards we overwrite the imap * pointer that the caller gave to us. */ |
c0dc7828a xfs: rename xfs_b... |
760 |
error = xfs_bmapi_write(tp, ip, map_start_fsb, |
60b4984fc xfs: support allo... |
761 |
count_fsb, flags, &first_block, |
dbd5c8c9a xfs: pass total b... |
762 |
nres, imap, &nimaps, |
2c3234d1e xfs: rename flist... |
763 |
&dfops); |
1da177e4c Linux-2.6.12-rc2 |
764 765 |
if (error) goto trans_cancel; |
8ad7c629b xfs: remove the i... |
766 |
error = xfs_defer_finish(&tp, &dfops); |
1da177e4c Linux-2.6.12-rc2 |
767 768 |
if (error) goto trans_cancel; |
70393313d xfs: saner xfs_tr... |
769 |
error = xfs_trans_commit(tp); |
1da177e4c Linux-2.6.12-rc2 |
770 771 772 773 774 775 776 777 778 779 |
if (error) goto error0; xfs_iunlock(ip, XFS_ILOCK_EXCL); } /* * See if we were able to allocate an extent that * covers at least part of the callers request */ |
3070451ee xfs: reduce stack... |
780 |
if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip))) |
6d4a8ecb3 xfs: rename xfs_c... |
781 |
return xfs_alert_fsblock_zero(ip, imap); |
86c4d6230 [XFS] Fix check f... |
782 |
|
3070451ee xfs: reduce stack... |
783 784 785 |
if ((offset_fsb >= imap->br_startoff) && (offset_fsb < (imap->br_startoff + imap->br_blockcount))) { |
ff6d6af23 xfs: per-filesyst... |
786 |
XFS_STATS_INC(mp, xs_xstrat_quick); |
e4143a1cf [XFS] Fix transac... |
787 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
788 |
} |
e4143a1cf [XFS] Fix transac... |
789 790 |
/* * So far we have not mapped the requested part of the |
1da177e4c Linux-2.6.12-rc2 |
791 792 |
* file, just surrounding data, try again. */ |
3070451ee xfs: reduce stack... |
793 794 |
count_fsb -= imap->br_blockcount; map_start_fsb = imap->br_startoff + imap->br_blockcount; |
1da177e4c Linux-2.6.12-rc2 |
795 796 797 |
} trans_cancel: |
2c3234d1e xfs: rename flist... |
798 |
xfs_defer_cancel(&dfops); |
4906e2154 xfs: remove the f... |
799 |
xfs_trans_cancel(tp); |
1da177e4c Linux-2.6.12-rc2 |
800 801 |
error0: xfs_iunlock(ip, XFS_ILOCK_EXCL); |
b474c7ae4 xfs: Nuke XFS_ERR... |
802 |
return error; |
1da177e4c Linux-2.6.12-rc2 |
803 804 805 806 807 |
} int xfs_iomap_write_unwritten( xfs_inode_t *ip, |
f403b7f45 [XFS] Cleanup use... |
808 |
xfs_off_t offset, |
ee70daaba xfs: update i_siz... |
809 810 |
xfs_off_t count, bool update_isize) |
1da177e4c Linux-2.6.12-rc2 |
811 812 |
{ xfs_mount_t *mp = ip->i_mount; |
1da177e4c Linux-2.6.12-rc2 |
813 814 815 |
xfs_fileoff_t offset_fsb; xfs_filblks_t count_fsb; xfs_filblks_t numblks_fsb; |
dd9f438e3 [XFS] Implement t... |
816 817 818 819 |
xfs_fsblock_t firstfsb; int nimaps; xfs_trans_t *tp; xfs_bmbt_irec_t imap; |
2c3234d1e xfs: rename flist... |
820 |
struct xfs_defer_ops dfops; |
ee70daaba xfs: update i_siz... |
821 |
struct inode *inode = VFS_I(ip); |
84803fb78 xfs: log file siz... |
822 |
xfs_fsize_t i_size; |
dd9f438e3 [XFS] Implement t... |
823 |
uint resblks; |
1da177e4c Linux-2.6.12-rc2 |
824 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
825 |
|
0b1b213fc xfs: event tracin... |
826 |
trace_xfs_unwritten_convert(ip, offset, count); |
1da177e4c Linux-2.6.12-rc2 |
827 828 829 830 |
offset_fsb = XFS_B_TO_FSBT(mp, offset); count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); count_fsb = (xfs_filblks_t)(count_fsb - offset_fsb); |
4ddd8bb1d [XFS] use minleft... |
831 832 833 834 835 836 837 838 839 840 |
/* * Reserve enough blocks in this transaction for two complete extent * btree splits. We may be converting the middle part of an unwritten * extent and in this case we will insert two new extents in the btree * each of which could cause a full split. * * This reservation amount will be used in the first call to * xfs_bmbt_split() to select an AG with enough space to satisfy the * rest of the operation. */ |
dd9f438e3 [XFS] Implement t... |
841 |
resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1; |
1da177e4c Linux-2.6.12-rc2 |
842 |
|
dd9f438e3 [XFS] Implement t... |
843 |
do { |
1da177e4c Linux-2.6.12-rc2 |
844 |
/* |
253f4911f xfs: better xfs_t... |
845 |
* Set up a transaction to convert the range of extents |
1da177e4c Linux-2.6.12-rc2 |
846 847 |
* from unwritten to real. Do allocations in a loop until * we have covered the range passed in. |
80641dc66 xfs: I/O completi... |
848 |
* |
253f4911f xfs: better xfs_t... |
849 850 851 |
* Note that we can't risk to recursing back into the filesystem * here as we might be asked to write out the same inode that we * complete here and might deadlock on the iolock. |
1da177e4c Linux-2.6.12-rc2 |
852 |
*/ |
253f4911f xfs: better xfs_t... |
853 854 855 |
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, XFS_TRANS_RESERVE | XFS_TRANS_NOFS, &tp); if (error) |
b474c7ae4 xfs: Nuke XFS_ERR... |
856 |
return error; |
1da177e4c Linux-2.6.12-rc2 |
857 858 |
xfs_ilock(ip, XFS_ILOCK_EXCL); |
ddc3415ab xfs: simplify xfs... |
859 |
xfs_trans_ijoin(tp, ip, 0); |
1da177e4c Linux-2.6.12-rc2 |
860 861 862 863 |
/* * Modify the unwritten extent state of the buffer. */ |
2c3234d1e xfs: rename flist... |
864 |
xfs_defer_init(&dfops, &firstfsb); |
1da177e4c Linux-2.6.12-rc2 |
865 |
nimaps = 1; |
c0dc7828a xfs: rename xfs_b... |
866 |
error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, |
dbd5c8c9a xfs: pass total b... |
867 |
XFS_BMAPI_CONVERT, &firstfsb, resblks, |
2c3234d1e xfs: rename flist... |
868 |
&imap, &nimaps, &dfops); |
1da177e4c Linux-2.6.12-rc2 |
869 870 |
if (error) goto error_on_bmapi_transaction; |
84803fb78 xfs: log file siz... |
871 872 873 874 875 876 877 878 |
/* * Log the updated inode size as we go. We have to be careful * to only log it up to the actual write offset if it is * halfway into a block. */ i_size = XFS_FSB_TO_B(mp, offset_fsb + count_fsb); if (i_size > offset + count) i_size = offset + count; |
ee70daaba xfs: update i_siz... |
879 880 |
if (update_isize && i_size > i_size_read(inode)) i_size_write(inode, i_size); |
84803fb78 xfs: log file siz... |
881 882 883 884 885 |
i_size = xfs_new_eof(ip, i_size); if (i_size) { ip->i_d.di_size = i_size; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); } |
8ad7c629b xfs: remove the i... |
886 |
error = xfs_defer_finish(&tp, &dfops); |
1da177e4c Linux-2.6.12-rc2 |
887 888 |
if (error) goto error_on_bmapi_transaction; |
70393313d xfs: saner xfs_tr... |
889 |
error = xfs_trans_commit(tp); |
1da177e4c Linux-2.6.12-rc2 |
890 891 |
xfs_iunlock(ip, XFS_ILOCK_EXCL); if (error) |
b474c7ae4 xfs: Nuke XFS_ERR... |
892 |
return error; |
572d95f49 [XFS] Improve err... |
893 |
|
86c4d6230 [XFS] Fix check f... |
894 |
if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip))) |
6d4a8ecb3 xfs: rename xfs_c... |
895 |
return xfs_alert_fsblock_zero(ip, &imap); |
1da177e4c Linux-2.6.12-rc2 |
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 |
if ((numblks_fsb = imap.br_blockcount) == 0) { /* * The numblks_fsb value should always get * smaller, otherwise the loop is stuck. */ ASSERT(imap.br_blockcount); break; } offset_fsb += numblks_fsb; count_fsb -= numblks_fsb; } while (count_fsb > 0); return 0; error_on_bmapi_transaction: |
2c3234d1e xfs: rename flist... |
912 |
xfs_defer_cancel(&dfops); |
4906e2154 xfs: remove the f... |
913 |
xfs_trans_cancel(tp); |
1da177e4c Linux-2.6.12-rc2 |
914 |
xfs_iunlock(ip, XFS_ILOCK_EXCL); |
b474c7ae4 xfs: Nuke XFS_ERR... |
915 |
return error; |
1da177e4c Linux-2.6.12-rc2 |
916 |
} |
3b3dce052 xfs: make xfs_bmb... |
917 |
|
6c31f495d xfs: use iomap to... |
918 919 |
static inline bool imap_needs_alloc(struct inode *inode, struct xfs_bmbt_irec *imap, int nimaps) |
68a9f5e70 xfs: implement io... |
920 921 922 |
{ return !nimaps || imap->br_startblock == HOLESTARTBLOCK || |
6c31f495d xfs: use iomap to... |
923 |
imap->br_startblock == DELAYSTARTBLOCK || |
63fbb4c18 xfs: remove the I... |
924 |
(IS_DAX(inode) && imap->br_state == XFS_EXT_UNWRITTEN); |
68a9f5e70 xfs: implement io... |
925 |
} |
acdda3aae xfs: use iomap_di... |
926 927 928 929 930 931 932 933 934 935 936 937 |
static inline bool need_excl_ilock(struct xfs_inode *ip, unsigned flags) { /* * COW writes will allocate delalloc space, so we need to make sure * to take the lock exclusively here. */ if (xfs_is_reflink_inode(ip) && (flags & (IOMAP_WRITE | IOMAP_ZERO))) return true; if ((flags & IOMAP_DIRECT) && (flags & IOMAP_WRITE)) return true; return false; } |
68a9f5e70 xfs: implement io... |
938 939 940 941 942 943 944 945 946 947 948 949 950 |
static int xfs_file_iomap_begin( struct inode *inode, loff_t offset, loff_t length, unsigned flags, struct iomap *iomap) { struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; struct xfs_bmbt_irec imap; xfs_fileoff_t offset_fsb, end_fsb; int nimaps = 1, error = 0; |
3ba020bef xfs: optimize wri... |
951 |
bool shared = false, trimmed = false; |
66642c5c1 xfs: take the ilo... |
952 |
unsigned lockmode; |
68a9f5e70 xfs: implement io... |
953 954 955 |
if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; |
acdda3aae xfs: use iomap_di... |
956 957 |
if (((flags & (IOMAP_WRITE | IOMAP_DIRECT)) == IOMAP_WRITE) && !IS_DAX(inode) && !xfs_get_extsz_hint(ip)) { |
2a06705cd xfs: create delal... |
958 |
/* Reserve delalloc blocks for regular writeback. */ |
f91fb956f xfs: remove unuse... |
959 |
return xfs_file_iomap_begin_delay(inode, offset, length, iomap); |
51446f5ba xfs: rewrite and ... |
960 |
} |
acdda3aae xfs: use iomap_di... |
961 |
if (need_excl_ilock(ip, flags)) { |
3ba020bef xfs: optimize wri... |
962 963 964 965 966 |
lockmode = XFS_ILOCK_EXCL; xfs_ilock(ip, XFS_ILOCK_EXCL); } else { lockmode = xfs_ilock_data_map_shared(ip); } |
68a9f5e70 xfs: implement io... |
967 |
|
29a5d29ec xfs: nowait aio s... |
968 969 970 971 |
if ((flags & IOMAP_NOWAIT) && !(ip->i_df.if_flags & XFS_IFEXTENTS)) { error = -EAGAIN; goto out_unlock; } |
68a9f5e70 xfs: implement io... |
972 973 974 975 976 977 978 |
ASSERT(offset <= mp->m_super->s_maxbytes); if ((xfs_fsize_t)offset + length > mp->m_super->s_maxbytes) length = mp->m_super->s_maxbytes - offset; offset_fsb = XFS_B_TO_FSBT(mp, offset); end_fsb = XFS_B_TO_FSB(mp, offset + length); error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap, |
db1327b16 xfs: report share... |
979 |
&nimaps, 0); |
3ba020bef xfs: optimize wri... |
980 981 |
if (error) goto out_unlock; |
db1327b16 xfs: report share... |
982 |
|
3c68d44a2 xfs: allocate dir... |
983 |
if (flags & IOMAP_REPORT) { |
5f9268ca5 xfs: don't bother... |
984 985 986 |
/* Trim the mapping to the nearest shared extent boundary. */ error = xfs_reflink_trim_around_shared(ip, &imap, &shared, &trimmed); |
3ba020bef xfs: optimize wri... |
987 988 989 990 991 |
if (error) goto out_unlock; } if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { |
3c68d44a2 xfs: allocate dir... |
992 |
if (flags & IOMAP_DIRECT) { |
29a5d29ec xfs: nowait aio s... |
993 994 995 996 997 998 999 1000 1001 |
/* * A reflinked inode will result in CoW alloc. * FIXME: It could still overwrite on unshared extents * and not need allocation. */ if (flags & IOMAP_NOWAIT) { error = -EAGAIN; goto out_unlock; } |
3c68d44a2 xfs: allocate dir... |
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 |
/* may drop and re-acquire the ilock */ error = xfs_reflink_allocate_cow(ip, &imap, &shared, &lockmode); if (error) goto out_unlock; } else { error = xfs_reflink_reserve_cow(ip, &imap, &shared); if (error) goto out_unlock; } |
3ba020bef xfs: optimize wri... |
1012 1013 1014 |
end_fsb = imap.br_startoff + imap.br_blockcount; length = XFS_FSB_TO_B(mp, end_fsb) - offset; |
68a9f5e70 xfs: implement io... |
1015 |
} |
6c31f495d xfs: use iomap to... |
1016 |
if ((flags & IOMAP_WRITE) && imap_needs_alloc(inode, &imap, nimaps)) { |
68a9f5e70 xfs: implement io... |
1017 |
/* |
29a5d29ec xfs: nowait aio s... |
1018 1019 1020 1021 1022 1023 1024 1025 |
* If nowait is set bail since we are going to make * allocations. */ if (flags & IOMAP_NOWAIT) { error = -EAGAIN; goto out_unlock; } /* |
68a9f5e70 xfs: implement io... |
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 |
* We cap the maximum length we map here to MAX_WRITEBACK_PAGES * pages to keep the chunks of work done where somewhat symmetric * with the work writeback does. This is a completely arbitrary * number pulled out of thin air as a best guess for initial * testing. * * Note that the values needs to be less than 32-bits wide until * the lower level functions are updated. */ length = min_t(loff_t, length, 1024 * PAGE_SIZE); |
51446f5ba xfs: rewrite and ... |
1036 1037 1038 1039 |
/* * xfs_iomap_write_direct() expects the shared lock. It * is unlocked on return. */ |
66642c5c1 xfs: take the ilo... |
1040 1041 |
if (lockmode == XFS_ILOCK_EXCL) xfs_ilock_demote(ip, lockmode); |
51446f5ba xfs: rewrite and ... |
1042 1043 |
error = xfs_iomap_write_direct(ip, offset, length, &imap, nimaps); |
68a9f5e70 xfs: implement io... |
1044 1045 |
if (error) return error; |
ecd50729f iomap: add IOMAP_... |
1046 |
iomap->flags = IOMAP_F_NEW; |
68a9f5e70 xfs: implement io... |
1047 |
trace_xfs_iomap_alloc(ip, offset, length, 0, &imap); |
68a9f5e70 xfs: implement io... |
1048 |
} else { |
b95a21271 xfs: simplify xfs... |
1049 |
ASSERT(nimaps); |
66642c5c1 xfs: take the ilo... |
1050 |
xfs_iunlock(ip, lockmode); |
b95a21271 xfs: simplify xfs... |
1051 |
trace_xfs_iomap_found(ip, offset, length, 0, &imap); |
68a9f5e70 xfs: implement io... |
1052 |
} |
b95a21271 xfs: simplify xfs... |
1053 |
xfs_bmbt_to_iomap(ip, iomap, &imap); |
fa5d932c3 ext2, ext4, xfs: ... |
1054 |
|
db1327b16 xfs: report share... |
1055 1056 |
if (shared) iomap->flags |= IOMAP_F_SHARED; |
68a9f5e70 xfs: implement io... |
1057 |
return 0; |
3ba020bef xfs: optimize wri... |
1058 1059 1060 |
out_unlock: xfs_iunlock(ip, lockmode); return error; |
68a9f5e70 xfs: implement io... |
1061 1062 1063 1064 1065 1066 1067 |
} static int xfs_file_iomap_end_delalloc( struct xfs_inode *ip, loff_t offset, loff_t length, |
f65e6fad2 xfs: use iomap ne... |
1068 1069 |
ssize_t written, struct iomap *iomap) |
68a9f5e70 xfs: implement io... |
1070 1071 1072 1073 1074 |
{ struct xfs_mount *mp = ip->i_mount; xfs_fileoff_t start_fsb; xfs_fileoff_t end_fsb; int error = 0; |
f65e6fad2 xfs: use iomap ne... |
1075 1076 1077 1078 |
/* * Behave as if the write failed if drop writes is enabled. Set the NEW * flag to force delalloc cleanup. */ |
f8c47250b xfs: convert drop... |
1079 |
if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_DROP_WRITES)) { |
f65e6fad2 xfs: use iomap ne... |
1080 |
iomap->flags |= IOMAP_F_NEW; |
9dbddd7b0 xfs: resurrect de... |
1081 |
written = 0; |
f65e6fad2 xfs: use iomap ne... |
1082 |
} |
9dbddd7b0 xfs: resurrect de... |
1083 |
|
fa7f138ac xfs: clear delall... |
1084 1085 1086 1087 1088 1089 1090 1091 1092 |
/* * start_fsb refers to the first unused block after a short write. If * nothing was written, round offset down to point at the first block in * the range. */ if (unlikely(!written)) start_fsb = XFS_B_TO_FSBT(mp, offset); else start_fsb = XFS_B_TO_FSB(mp, offset + written); |
68a9f5e70 xfs: implement io... |
1093 1094 1095 |
end_fsb = XFS_B_TO_FSB(mp, offset + length); /* |
f65e6fad2 xfs: use iomap ne... |
1096 1097 |
* Trim delalloc blocks if they were allocated by this write and we * didn't manage to write the whole range. |
68a9f5e70 xfs: implement io... |
1098 1099 1100 1101 1102 |
* * We don't need to care about racing delalloc as we hold i_mutex * across the reserve/allocate/unreserve calls. If there are delalloc * blocks in the range, they are ours. */ |
f65e6fad2 xfs: use iomap ne... |
1103 |
if ((iomap->flags & IOMAP_F_NEW) && start_fsb < end_fsb) { |
fa7f138ac xfs: clear delall... |
1104 1105 |
truncate_pagecache_range(VFS_I(ip), XFS_FSB_TO_B(mp, start_fsb), XFS_FSB_TO_B(mp, end_fsb) - 1); |
68a9f5e70 xfs: implement io... |
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 |
xfs_ilock(ip, XFS_ILOCK_EXCL); error = xfs_bmap_punch_delalloc_range(ip, start_fsb, end_fsb - start_fsb); xfs_iunlock(ip, XFS_ILOCK_EXCL); if (error && !XFS_FORCED_SHUTDOWN(mp)) { xfs_alert(mp, "%s: unable to clean up ino %lld", __func__, ip->i_ino); return error; } } return 0; } static int xfs_file_iomap_end( struct inode *inode, loff_t offset, loff_t length, ssize_t written, unsigned flags, struct iomap *iomap) { if ((flags & IOMAP_WRITE) && iomap->type == IOMAP_DELALLOC) return xfs_file_iomap_end_delalloc(XFS_I(inode), offset, |
f65e6fad2 xfs: use iomap ne... |
1132 |
length, written, iomap); |
68a9f5e70 xfs: implement io... |
1133 1134 |
return 0; } |
8ff6daa17 iomap: constify s... |
1135 |
const struct iomap_ops xfs_iomap_ops = { |
68a9f5e70 xfs: implement io... |
1136 1137 1138 |
.iomap_begin = xfs_file_iomap_begin, .iomap_end = xfs_file_iomap_end, }; |
1d4795e7b xfs: (re-)impleme... |
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 |
static int xfs_xattr_iomap_begin( struct inode *inode, loff_t offset, loff_t length, unsigned flags, struct iomap *iomap) { struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, offset + length); struct xfs_bmbt_irec imap; int nimaps = 1, error = 0; unsigned lockmode; if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; |
84358536d xfs: actually rep... |
1158 |
lockmode = xfs_ilock_attr_map_shared(ip); |
1d4795e7b xfs: (re-)impleme... |
1159 1160 |
/* if there are no attribute fork or extents, return ENOENT */ |
84358536d xfs: actually rep... |
1161 |
if (!XFS_IFORK_Q(ip) || !ip->i_d.di_anextents) { |
1d4795e7b xfs: (re-)impleme... |
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 |
error = -ENOENT; goto out_unlock; } ASSERT(ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL); error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap, &nimaps, XFS_BMAPI_ENTIRE | XFS_BMAPI_ATTRFORK); out_unlock: xfs_iunlock(ip, lockmode); if (!error) { ASSERT(nimaps); xfs_bmbt_to_iomap(ip, iomap, &imap); } return error; } |
8ff6daa17 iomap: constify s... |
1179 |
const struct iomap_ops xfs_xattr_iomap_ops = { |
1d4795e7b xfs: (re-)impleme... |
1180 1181 |
.iomap_begin = xfs_xattr_iomap_begin, }; |