diff options
Diffstat (limited to 'fs/xfs/xfs_iomap.c')
-rw-r--r-- | fs/xfs/xfs_iomap.c | 233 |
1 files changed, 83 insertions, 150 deletions
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 20576146369f..55582bd66659 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
@@ -47,127 +47,8 @@ | |||
47 | 47 | ||
48 | #define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ | 48 | #define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ |
49 | << mp->m_writeio_log) | 49 | << mp->m_writeio_log) |
50 | #define XFS_STRAT_WRITE_IMAPS 2 | ||
51 | #define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP | 50 | #define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP |
52 | 51 | ||
53 | STATIC int xfs_iomap_write_direct(struct xfs_inode *, xfs_off_t, size_t, | ||
54 | int, struct xfs_bmbt_irec *, int *); | ||
55 | STATIC int xfs_iomap_write_delay(struct xfs_inode *, xfs_off_t, size_t, int, | ||
56 | struct xfs_bmbt_irec *, int *); | ||
57 | STATIC int xfs_iomap_write_allocate(struct xfs_inode *, xfs_off_t, size_t, | ||
58 | struct xfs_bmbt_irec *, int *); | ||
59 | |||
60 | int | ||
61 | xfs_iomap( | ||
62 | struct xfs_inode *ip, | ||
63 | xfs_off_t offset, | ||
64 | ssize_t count, | ||
65 | int flags, | ||
66 | struct xfs_bmbt_irec *imap, | ||
67 | int *nimaps, | ||
68 | int *new) | ||
69 | { | ||
70 | struct xfs_mount *mp = ip->i_mount; | ||
71 | xfs_fileoff_t offset_fsb, end_fsb; | ||
72 | int error = 0; | ||
73 | int lockmode = 0; | ||
74 | int bmapi_flags = 0; | ||
75 | |||
76 | ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG); | ||
77 | |||
78 | *new = 0; | ||
79 | |||
80 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
81 | return XFS_ERROR(EIO); | ||
82 | |||
83 | trace_xfs_iomap_enter(ip, offset, count, flags, NULL); | ||
84 | |||
85 | switch (flags & (BMAPI_READ | BMAPI_WRITE | BMAPI_ALLOCATE)) { | ||
86 | case BMAPI_READ: | ||
87 | lockmode = xfs_ilock_map_shared(ip); | ||
88 | bmapi_flags = XFS_BMAPI_ENTIRE; | ||
89 | break; | ||
90 | case BMAPI_WRITE: | ||
91 | lockmode = XFS_ILOCK_EXCL; | ||
92 | if (flags & BMAPI_IGNSTATE) | ||
93 | bmapi_flags |= XFS_BMAPI_IGSTATE|XFS_BMAPI_ENTIRE; | ||
94 | xfs_ilock(ip, lockmode); | ||
95 | break; | ||
96 | case BMAPI_ALLOCATE: | ||
97 | lockmode = XFS_ILOCK_SHARED; | ||
98 | bmapi_flags = XFS_BMAPI_ENTIRE; | ||
99 | |||
100 | /* Attempt non-blocking lock */ | ||
101 | if (flags & BMAPI_TRYLOCK) { | ||
102 | if (!xfs_ilock_nowait(ip, lockmode)) | ||
103 | return XFS_ERROR(EAGAIN); | ||
104 | } else { | ||
105 | xfs_ilock(ip, lockmode); | ||
106 | } | ||
107 | break; | ||
108 | default: | ||
109 | BUG(); | ||
110 | } | ||
111 | |||
112 | ASSERT(offset <= mp->m_maxioffset); | ||
113 | if ((xfs_fsize_t)offset + count > mp->m_maxioffset) | ||
114 | count = mp->m_maxioffset - offset; | ||
115 | end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); | ||
116 | offset_fsb = XFS_B_TO_FSBT(mp, offset); | ||
117 | |||
118 | error = xfs_bmapi(NULL, ip, offset_fsb, | ||
119 | (xfs_filblks_t)(end_fsb - offset_fsb), | ||
120 | bmapi_flags, NULL, 0, imap, | ||
121 | nimaps, NULL); | ||
122 | |||
123 | if (error) | ||
124 | goto out; | ||
125 | |||
126 | switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE)) { | ||
127 | case BMAPI_WRITE: | ||
128 | /* If we found an extent, return it */ | ||
129 | if (*nimaps && | ||
130 | (imap->br_startblock != HOLESTARTBLOCK) && | ||
131 | (imap->br_startblock != DELAYSTARTBLOCK)) { | ||
132 | trace_xfs_iomap_found(ip, offset, count, flags, imap); | ||
133 | break; | ||
134 | } | ||
135 | |||
136 | if (flags & BMAPI_DIRECT) { | ||
137 | error = xfs_iomap_write_direct(ip, offset, count, flags, | ||
138 | imap, nimaps); | ||
139 | } else { | ||
140 | error = xfs_iomap_write_delay(ip, offset, count, flags, | ||
141 | imap, nimaps); | ||
142 | } | ||
143 | if (!error) { | ||
144 | trace_xfs_iomap_alloc(ip, offset, count, flags, imap); | ||
145 | } | ||
146 | *new = 1; | ||
147 | break; | ||
148 | case BMAPI_ALLOCATE: | ||
149 | /* If we found an extent, return it */ | ||
150 | xfs_iunlock(ip, lockmode); | ||
151 | lockmode = 0; | ||
152 | |||
153 | if (*nimaps && !isnullstartblock(imap->br_startblock)) { | ||
154 | trace_xfs_iomap_found(ip, offset, count, flags, imap); | ||
155 | break; | ||
156 | } | ||
157 | |||
158 | error = xfs_iomap_write_allocate(ip, offset, count, | ||
159 | imap, nimaps); | ||
160 | break; | ||
161 | } | ||
162 | |||
163 | ASSERT(*nimaps <= 1); | ||
164 | |||
165 | out: | ||
166 | if (lockmode) | ||
167 | xfs_iunlock(ip, lockmode); | ||
168 | return XFS_ERROR(error); | ||
169 | } | ||
170 | |||
171 | STATIC int | 52 | STATIC int |
172 | xfs_iomap_eof_align_last_fsb( | 53 | xfs_iomap_eof_align_last_fsb( |
173 | xfs_mount_t *mp, | 54 | xfs_mount_t *mp, |
@@ -236,14 +117,13 @@ xfs_cmn_err_fsblock_zero( | |||
236 | return EFSCORRUPTED; | 117 | return EFSCORRUPTED; |
237 | } | 118 | } |
238 | 119 | ||
239 | STATIC int | 120 | int |
240 | xfs_iomap_write_direct( | 121 | xfs_iomap_write_direct( |
241 | xfs_inode_t *ip, | 122 | xfs_inode_t *ip, |
242 | xfs_off_t offset, | 123 | xfs_off_t offset, |
243 | size_t count, | 124 | size_t count, |
244 | int flags, | ||
245 | xfs_bmbt_irec_t *imap, | 125 | xfs_bmbt_irec_t *imap, |
246 | int *nmaps) | 126 | int nmaps) |
247 | { | 127 | { |
248 | xfs_mount_t *mp = ip->i_mount; | 128 | xfs_mount_t *mp = ip->i_mount; |
249 | xfs_fileoff_t offset_fsb; | 129 | xfs_fileoff_t offset_fsb; |
@@ -279,7 +159,7 @@ xfs_iomap_write_direct( | |||
279 | if (error) | 159 | if (error) |
280 | goto error_out; | 160 | goto error_out; |
281 | } else { | 161 | } else { |
282 | if (*nmaps && (imap->br_startblock == HOLESTARTBLOCK)) | 162 | if (nmaps && (imap->br_startblock == HOLESTARTBLOCK)) |
283 | last_fsb = MIN(last_fsb, (xfs_fileoff_t) | 163 | last_fsb = MIN(last_fsb, (xfs_fileoff_t) |
284 | imap->br_blockcount + | 164 | imap->br_blockcount + |
285 | imap->br_startoff); | 165 | imap->br_startoff); |
@@ -331,7 +211,7 @@ xfs_iomap_write_direct( | |||
331 | xfs_trans_ijoin(tp, ip); | 211 | xfs_trans_ijoin(tp, ip); |
332 | 212 | ||
333 | bmapi_flag = XFS_BMAPI_WRITE; | 213 | bmapi_flag = XFS_BMAPI_WRITE; |
334 | if ((flags & BMAPI_DIRECT) && (offset < ip->i_size || extsz)) | 214 | if (offset < ip->i_size || extsz) |
335 | bmapi_flag |= XFS_BMAPI_PREALLOC; | 215 | bmapi_flag |= XFS_BMAPI_PREALLOC; |
336 | 216 | ||
337 | /* | 217 | /* |
@@ -370,7 +250,6 @@ xfs_iomap_write_direct( | |||
370 | goto error_out; | 250 | goto error_out; |
371 | } | 251 | } |
372 | 252 | ||
373 | *nmaps = 1; | ||
374 | return 0; | 253 | return 0; |
375 | 254 | ||
376 | error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */ | 255 | error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */ |
@@ -379,7 +258,6 @@ error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */ | |||
379 | 258 | ||
380 | error1: /* Just cancel transaction */ | 259 | error1: /* Just cancel transaction */ |
381 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); | 260 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); |
382 | *nmaps = 0; /* nothing set-up here */ | ||
383 | 261 | ||
384 | error_out: | 262 | error_out: |
385 | return XFS_ERROR(error); | 263 | return XFS_ERROR(error); |
@@ -389,6 +267,9 @@ error_out: | |||
389 | * If the caller is doing a write at the end of the file, then extend the | 267 | * If the caller is doing a write at the end of the file, then extend the |
390 | * allocation out to the file system's write iosize. We clean up any extra | 268 | * allocation out to the file system's write iosize. We clean up any extra |
391 | * space left over when the file is closed in xfs_inactive(). | 269 | * space left over when the file is closed in xfs_inactive(). |
270 | * | ||
271 | * If we find we already have delalloc preallocation beyond EOF, don't do more | ||
272 | * preallocation as it it not needed. | ||
392 | */ | 273 | */ |
393 | STATIC int | 274 | STATIC int |
394 | xfs_iomap_eof_want_preallocate( | 275 | xfs_iomap_eof_want_preallocate( |
@@ -396,7 +277,6 @@ xfs_iomap_eof_want_preallocate( | |||
396 | xfs_inode_t *ip, | 277 | xfs_inode_t *ip, |
397 | xfs_off_t offset, | 278 | xfs_off_t offset, |
398 | size_t count, | 279 | size_t count, |
399 | int ioflag, | ||
400 | xfs_bmbt_irec_t *imap, | 280 | xfs_bmbt_irec_t *imap, |
401 | int nimaps, | 281 | int nimaps, |
402 | int *prealloc) | 282 | int *prealloc) |
@@ -405,6 +285,7 @@ xfs_iomap_eof_want_preallocate( | |||
405 | xfs_filblks_t count_fsb; | 285 | xfs_filblks_t count_fsb; |
406 | xfs_fsblock_t firstblock; | 286 | xfs_fsblock_t firstblock; |
407 | int n, error, imaps; | 287 | int n, error, imaps; |
288 | int found_delalloc = 0; | ||
408 | 289 | ||
409 | *prealloc = 0; | 290 | *prealloc = 0; |
410 | if ((offset + count) <= ip->i_size) | 291 | if ((offset + count) <= ip->i_size) |
@@ -429,20 +310,66 @@ xfs_iomap_eof_want_preallocate( | |||
429 | return 0; | 310 | return 0; |
430 | start_fsb += imap[n].br_blockcount; | 311 | start_fsb += imap[n].br_blockcount; |
431 | count_fsb -= imap[n].br_blockcount; | 312 | count_fsb -= imap[n].br_blockcount; |
313 | |||
314 | if (imap[n].br_startblock == DELAYSTARTBLOCK) | ||
315 | found_delalloc = 1; | ||
432 | } | 316 | } |
433 | } | 317 | } |
434 | *prealloc = 1; | 318 | if (!found_delalloc) |
319 | *prealloc = 1; | ||
435 | return 0; | 320 | return 0; |
436 | } | 321 | } |
437 | 322 | ||
438 | STATIC int | 323 | /* |
324 | * If we don't have a user specified preallocation size, dynamically increase | ||
325 | * the preallocation size as the size of the file grows. Cap the maximum size | ||
326 | * at a single extent or less if the filesystem is near full. The closer the | ||
327 | * filesystem is to full, the smaller the maximum prealocation. | ||
328 | */ | ||
329 | STATIC xfs_fsblock_t | ||
330 | xfs_iomap_prealloc_size( | ||
331 | struct xfs_mount *mp, | ||
332 | struct xfs_inode *ip) | ||
333 | { | ||
334 | xfs_fsblock_t alloc_blocks = 0; | ||
335 | |||
336 | if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) { | ||
337 | int shift = 0; | ||
338 | int64_t freesp; | ||
339 | |||
340 | alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size); | ||
341 | alloc_blocks = XFS_FILEOFF_MIN(MAXEXTLEN, | ||
342 | rounddown_pow_of_two(alloc_blocks)); | ||
343 | |||
344 | xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT); | ||
345 | freesp = mp->m_sb.sb_fdblocks; | ||
346 | if (freesp < mp->m_low_space[XFS_LOWSP_5_PCNT]) { | ||
347 | shift = 2; | ||
348 | if (freesp < mp->m_low_space[XFS_LOWSP_4_PCNT]) | ||
349 | shift++; | ||
350 | if (freesp < mp->m_low_space[XFS_LOWSP_3_PCNT]) | ||
351 | shift++; | ||
352 | if (freesp < mp->m_low_space[XFS_LOWSP_2_PCNT]) | ||
353 | shift++; | ||
354 | if (freesp < mp->m_low_space[XFS_LOWSP_1_PCNT]) | ||
355 | shift++; | ||
356 | } | ||
357 | if (shift) | ||
358 | alloc_blocks >>= shift; | ||
359 | } | ||
360 | |||
361 | if (alloc_blocks < mp->m_writeio_blocks) | ||
362 | alloc_blocks = mp->m_writeio_blocks; | ||
363 | |||
364 | return alloc_blocks; | ||
365 | } | ||
366 | |||
367 | int | ||
439 | xfs_iomap_write_delay( | 368 | xfs_iomap_write_delay( |
440 | xfs_inode_t *ip, | 369 | xfs_inode_t *ip, |
441 | xfs_off_t offset, | 370 | xfs_off_t offset, |
442 | size_t count, | 371 | size_t count, |
443 | int ioflag, | 372 | xfs_bmbt_irec_t *ret_imap) |
444 | xfs_bmbt_irec_t *ret_imap, | ||
445 | int *nmaps) | ||
446 | { | 373 | { |
447 | xfs_mount_t *mp = ip->i_mount; | 374 | xfs_mount_t *mp = ip->i_mount; |
448 | xfs_fileoff_t offset_fsb; | 375 | xfs_fileoff_t offset_fsb; |
@@ -469,16 +396,19 @@ xfs_iomap_write_delay( | |||
469 | extsz = xfs_get_extsz_hint(ip); | 396 | extsz = xfs_get_extsz_hint(ip); |
470 | offset_fsb = XFS_B_TO_FSBT(mp, offset); | 397 | offset_fsb = XFS_B_TO_FSBT(mp, offset); |
471 | 398 | ||
399 | |||
472 | error = xfs_iomap_eof_want_preallocate(mp, ip, offset, count, | 400 | error = xfs_iomap_eof_want_preallocate(mp, ip, offset, count, |
473 | ioflag, imap, XFS_WRITE_IMAPS, &prealloc); | 401 | imap, XFS_WRITE_IMAPS, &prealloc); |
474 | if (error) | 402 | if (error) |
475 | return error; | 403 | return error; |
476 | 404 | ||
477 | retry: | 405 | retry: |
478 | if (prealloc) { | 406 | if (prealloc) { |
407 | xfs_fsblock_t alloc_blocks = xfs_iomap_prealloc_size(mp, ip); | ||
408 | |||
479 | aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1)); | 409 | aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1)); |
480 | ioalign = XFS_B_TO_FSBT(mp, aligned_offset); | 410 | ioalign = XFS_B_TO_FSBT(mp, aligned_offset); |
481 | last_fsb = ioalign + mp->m_writeio_blocks; | 411 | last_fsb = ioalign + alloc_blocks; |
482 | } else { | 412 | } else { |
483 | last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); | 413 | last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); |
484 | } | 414 | } |
@@ -496,22 +426,31 @@ retry: | |||
496 | XFS_BMAPI_DELAY | XFS_BMAPI_WRITE | | 426 | XFS_BMAPI_DELAY | XFS_BMAPI_WRITE | |
497 | XFS_BMAPI_ENTIRE, &firstblock, 1, imap, | 427 | XFS_BMAPI_ENTIRE, &firstblock, 1, imap, |
498 | &nimaps, NULL); | 428 | &nimaps, NULL); |
499 | if (error && (error != ENOSPC)) | 429 | switch (error) { |
430 | case 0: | ||
431 | case ENOSPC: | ||
432 | case EDQUOT: | ||
433 | break; | ||
434 | default: | ||
500 | return XFS_ERROR(error); | 435 | return XFS_ERROR(error); |
436 | } | ||
501 | 437 | ||
502 | /* | 438 | /* |
503 | * If bmapi returned us nothing, and if we didn't get back EDQUOT, | 439 | * If bmapi returned us nothing, we got either ENOSPC or EDQUOT. For |
504 | * then we must have run out of space - flush all other inodes with | 440 | * ENOSPC, * flush all other inodes with delalloc blocks to free up |
505 | * delalloc blocks and retry without EOF preallocation. | 441 | * some of the excess reserved metadata space. For both cases, retry |
442 | * without EOF preallocation. | ||
506 | */ | 443 | */ |
507 | if (nimaps == 0) { | 444 | if (nimaps == 0) { |
508 | trace_xfs_delalloc_enospc(ip, offset, count); | 445 | trace_xfs_delalloc_enospc(ip, offset, count); |
509 | if (flushed) | 446 | if (flushed) |
510 | return XFS_ERROR(ENOSPC); | 447 | return XFS_ERROR(error ? error : ENOSPC); |
511 | 448 | ||
512 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 449 | if (error == ENOSPC) { |
513 | xfs_flush_inodes(ip); | 450 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
514 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 451 | xfs_flush_inodes(ip); |
452 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
453 | } | ||
515 | 454 | ||
516 | flushed = 1; | 455 | flushed = 1; |
517 | error = 0; | 456 | error = 0; |
@@ -523,8 +462,6 @@ retry: | |||
523 | return xfs_cmn_err_fsblock_zero(ip, &imap[0]); | 462 | return xfs_cmn_err_fsblock_zero(ip, &imap[0]); |
524 | 463 | ||
525 | *ret_imap = imap[0]; | 464 | *ret_imap = imap[0]; |
526 | *nmaps = 1; | ||
527 | |||
528 | return 0; | 465 | return 0; |
529 | } | 466 | } |
530 | 467 | ||
@@ -538,13 +475,12 @@ retry: | |||
538 | * We no longer bother to look at the incoming map - all we have to | 475 | * We no longer bother to look at the incoming map - all we have to |
539 | * guarantee is that whatever we allocate fills the required range. | 476 | * guarantee is that whatever we allocate fills the required range. |
540 | */ | 477 | */ |
541 | STATIC int | 478 | int |
542 | xfs_iomap_write_allocate( | 479 | xfs_iomap_write_allocate( |
543 | xfs_inode_t *ip, | 480 | xfs_inode_t *ip, |
544 | xfs_off_t offset, | 481 | xfs_off_t offset, |
545 | size_t count, | 482 | size_t count, |
546 | xfs_bmbt_irec_t *imap, | 483 | xfs_bmbt_irec_t *imap) |
547 | int *retmap) | ||
548 | { | 484 | { |
549 | xfs_mount_t *mp = ip->i_mount; | 485 | xfs_mount_t *mp = ip->i_mount; |
550 | xfs_fileoff_t offset_fsb, last_block; | 486 | xfs_fileoff_t offset_fsb, last_block; |
@@ -557,8 +493,6 @@ xfs_iomap_write_allocate( | |||
557 | int error = 0; | 493 | int error = 0; |
558 | int nres; | 494 | int nres; |
559 | 495 | ||
560 | *retmap = 0; | ||
561 | |||
562 | /* | 496 | /* |
563 | * Make sure that the dquots are there. | 497 | * Make sure that the dquots are there. |
564 | */ | 498 | */ |
@@ -680,7 +614,6 @@ xfs_iomap_write_allocate( | |||
680 | if ((offset_fsb >= imap->br_startoff) && | 614 | if ((offset_fsb >= imap->br_startoff) && |
681 | (offset_fsb < (imap->br_startoff + | 615 | (offset_fsb < (imap->br_startoff + |
682 | imap->br_blockcount))) { | 616 | imap->br_blockcount))) { |
683 | *retmap = 1; | ||
684 | XFS_STATS_INC(xs_xstrat_quick); | 617 | XFS_STATS_INC(xs_xstrat_quick); |
685 | return 0; | 618 | return 0; |
686 | } | 619 | } |