diff options
author | Dave Chinner <david@fromorbit.com> | 2016-10-02 18:52:51 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2016-10-02 18:52:51 -0400 |
commit | a89b3f97bb7c248aea155a90f31d3dfb93b75971 (patch) | |
tree | 274d6f99d2a81b73ba13868a9188b725c918e5b8 | |
parent | 79ad57612495744d3875a6fba25c467a87b3ad64 (diff) | |
parent | 51446f5ba44874db4d2a93a6eb61b133e5ec1b3e (diff) |
Merge branch 'xfs-4.9-delalloc-rework' into for-next
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 89 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.h | 10 | ||||
-rw-r--r-- | fs/xfs/xfs_icache.c | 14 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_iomap.c | 476 | ||||
-rw-r--r-- | fs/xfs/xfs_iomap.h | 2 |
6 files changed, 242 insertions, 350 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 042d7bf9fb60..6fd458674e56 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c | |||
@@ -1389,7 +1389,7 @@ xfs_bmap_search_multi_extents( | |||
1389 | * Else, *lastxp will be set to the index of the found | 1389 | * Else, *lastxp will be set to the index of the found |
1390 | * entry; *gotp will contain the entry. | 1390 | * entry; *gotp will contain the entry. |
1391 | */ | 1391 | */ |
1392 | STATIC xfs_bmbt_rec_host_t * /* pointer to found extent entry */ | 1392 | xfs_bmbt_rec_host_t * /* pointer to found extent entry */ |
1393 | xfs_bmap_search_extents( | 1393 | xfs_bmap_search_extents( |
1394 | xfs_inode_t *ip, /* incore inode pointer */ | 1394 | xfs_inode_t *ip, /* incore inode pointer */ |
1395 | xfs_fileoff_t bno, /* block number searched for */ | 1395 | xfs_fileoff_t bno, /* block number searched for */ |
@@ -4076,7 +4076,7 @@ xfs_bmapi_read( | |||
4076 | return 0; | 4076 | return 0; |
4077 | } | 4077 | } |
4078 | 4078 | ||
4079 | STATIC int | 4079 | int |
4080 | xfs_bmapi_reserve_delalloc( | 4080 | xfs_bmapi_reserve_delalloc( |
4081 | struct xfs_inode *ip, | 4081 | struct xfs_inode *ip, |
4082 | xfs_fileoff_t aoff, | 4082 | xfs_fileoff_t aoff, |
@@ -4172,91 +4172,6 @@ out_unreserve_quota: | |||
4172 | return error; | 4172 | return error; |
4173 | } | 4173 | } |
4174 | 4174 | ||
4175 | /* | ||
4176 | * Map file blocks to filesystem blocks, adding delayed allocations as needed. | ||
4177 | */ | ||
4178 | int | ||
4179 | xfs_bmapi_delay( | ||
4180 | struct xfs_inode *ip, /* incore inode */ | ||
4181 | xfs_fileoff_t bno, /* starting file offs. mapped */ | ||
4182 | xfs_filblks_t len, /* length to map in file */ | ||
4183 | struct xfs_bmbt_irec *mval, /* output: map values */ | ||
4184 | int *nmap, /* i/o: mval size/count */ | ||
4185 | int flags) /* XFS_BMAPI_... */ | ||
4186 | { | ||
4187 | struct xfs_mount *mp = ip->i_mount; | ||
4188 | struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); | ||
4189 | struct xfs_bmbt_irec got; /* current file extent record */ | ||
4190 | struct xfs_bmbt_irec prev; /* previous file extent record */ | ||
4191 | xfs_fileoff_t obno; /* old block number (offset) */ | ||
4192 | xfs_fileoff_t end; /* end of mapped file region */ | ||
4193 | xfs_extnum_t lastx; /* last useful extent number */ | ||
4194 | int eof; /* we've hit the end of extents */ | ||
4195 | int n = 0; /* current extent index */ | ||
4196 | int error = 0; | ||
4197 | |||
4198 | ASSERT(*nmap >= 1); | ||
4199 | ASSERT(*nmap <= XFS_BMAP_MAX_NMAP); | ||
4200 | ASSERT(!(flags & ~XFS_BMAPI_ENTIRE)); | ||
4201 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | ||
4202 | |||
4203 | if (unlikely(XFS_TEST_ERROR( | ||
4204 | (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS && | ||
4205 | XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE), | ||
4206 | mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { | ||
4207 | XFS_ERROR_REPORT("xfs_bmapi_delay", XFS_ERRLEVEL_LOW, mp); | ||
4208 | return -EFSCORRUPTED; | ||
4209 | } | ||
4210 | |||
4211 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
4212 | return -EIO; | ||
4213 | |||
4214 | XFS_STATS_INC(mp, xs_blk_mapw); | ||
4215 | |||
4216 | if (!(ifp->if_flags & XFS_IFEXTENTS)) { | ||
4217 | error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK); | ||
4218 | if (error) | ||
4219 | return error; | ||
4220 | } | ||
4221 | |||
4222 | xfs_bmap_search_extents(ip, bno, XFS_DATA_FORK, &eof, &lastx, &got, &prev); | ||
4223 | end = bno + len; | ||
4224 | obno = bno; | ||
4225 | |||
4226 | while (bno < end && n < *nmap) { | ||
4227 | if (eof || got.br_startoff > bno) { | ||
4228 | error = xfs_bmapi_reserve_delalloc(ip, bno, len, &got, | ||
4229 | &prev, &lastx, eof); | ||
4230 | if (error) { | ||
4231 | if (n == 0) { | ||
4232 | *nmap = 0; | ||
4233 | return error; | ||
4234 | } | ||
4235 | break; | ||
4236 | } | ||
4237 | } | ||
4238 | |||
4239 | /* set up the extent map to return. */ | ||
4240 | xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags); | ||
4241 | xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags); | ||
4242 | |||
4243 | /* If we're done, stop now. */ | ||
4244 | if (bno >= end || n >= *nmap) | ||
4245 | break; | ||
4246 | |||
4247 | /* Else go on to the next record. */ | ||
4248 | prev = got; | ||
4249 | if (++lastx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)) | ||
4250 | xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got); | ||
4251 | else | ||
4252 | eof = 1; | ||
4253 | } | ||
4254 | |||
4255 | *nmap = n; | ||
4256 | return 0; | ||
4257 | } | ||
4258 | |||
4259 | |||
4260 | static int | 4175 | static int |
4261 | xfs_bmapi_allocate( | 4176 | xfs_bmapi_allocate( |
4262 | struct xfs_bmalloca *bma) | 4177 | struct xfs_bmalloca *bma) |
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index 254034f96941..d66006960fbc 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h | |||
@@ -181,9 +181,6 @@ int xfs_bmap_read_extents(struct xfs_trans *tp, struct xfs_inode *ip, | |||
181 | int xfs_bmapi_read(struct xfs_inode *ip, xfs_fileoff_t bno, | 181 | int xfs_bmapi_read(struct xfs_inode *ip, xfs_fileoff_t bno, |
182 | xfs_filblks_t len, struct xfs_bmbt_irec *mval, | 182 | xfs_filblks_t len, struct xfs_bmbt_irec *mval, |
183 | int *nmap, int flags); | 183 | int *nmap, int flags); |
184 | int xfs_bmapi_delay(struct xfs_inode *ip, xfs_fileoff_t bno, | ||
185 | xfs_filblks_t len, struct xfs_bmbt_irec *mval, | ||
186 | int *nmap, int flags); | ||
187 | int xfs_bmapi_write(struct xfs_trans *tp, struct xfs_inode *ip, | 184 | int xfs_bmapi_write(struct xfs_trans *tp, struct xfs_inode *ip, |
188 | xfs_fileoff_t bno, xfs_filblks_t len, int flags, | 185 | xfs_fileoff_t bno, xfs_filblks_t len, int flags, |
189 | xfs_fsblock_t *firstblock, xfs_extlen_t total, | 186 | xfs_fsblock_t *firstblock, xfs_extlen_t total, |
@@ -202,5 +199,12 @@ int xfs_bmap_shift_extents(struct xfs_trans *tp, struct xfs_inode *ip, | |||
202 | struct xfs_defer_ops *dfops, enum shift_direction direction, | 199 | struct xfs_defer_ops *dfops, enum shift_direction direction, |
203 | int num_exts); | 200 | int num_exts); |
204 | int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset); | 201 | int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset); |
202 | struct xfs_bmbt_rec_host * | ||
203 | xfs_bmap_search_extents(struct xfs_inode *ip, xfs_fileoff_t bno, | ||
204 | int fork, int *eofp, xfs_extnum_t *lastxp, | ||
205 | struct xfs_bmbt_irec *gotp, struct xfs_bmbt_irec *prevp); | ||
206 | int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, xfs_fileoff_t aoff, | ||
207 | xfs_filblks_t len, struct xfs_bmbt_irec *got, | ||
208 | struct xfs_bmbt_irec *prev, xfs_extnum_t *lastx, int eof); | ||
205 | 209 | ||
206 | #endif /* __XFS_BMAP_H__ */ | 210 | #endif /* __XFS_BMAP_H__ */ |
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index fb39a66914dd..65b2e3f85f52 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c | |||
@@ -1414,6 +1414,16 @@ xfs_inode_set_eofblocks_tag( | |||
1414 | struct xfs_perag *pag; | 1414 | struct xfs_perag *pag; |
1415 | int tagged; | 1415 | int tagged; |
1416 | 1416 | ||
1417 | /* | ||
1418 | * Don't bother locking the AG and looking up in the radix trees | ||
1419 | * if we already know that we have the tag set. | ||
1420 | */ | ||
1421 | if (ip->i_flags & XFS_IEOFBLOCKS) | ||
1422 | return; | ||
1423 | spin_lock(&ip->i_flags_lock); | ||
1424 | ip->i_flags |= XFS_IEOFBLOCKS; | ||
1425 | spin_unlock(&ip->i_flags_lock); | ||
1426 | |||
1417 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); | 1427 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); |
1418 | spin_lock(&pag->pag_ici_lock); | 1428 | spin_lock(&pag->pag_ici_lock); |
1419 | trace_xfs_inode_set_eofblocks_tag(ip); | 1429 | trace_xfs_inode_set_eofblocks_tag(ip); |
@@ -1449,6 +1459,10 @@ xfs_inode_clear_eofblocks_tag( | |||
1449 | struct xfs_mount *mp = ip->i_mount; | 1459 | struct xfs_mount *mp = ip->i_mount; |
1450 | struct xfs_perag *pag; | 1460 | struct xfs_perag *pag; |
1451 | 1461 | ||
1462 | spin_lock(&ip->i_flags_lock); | ||
1463 | ip->i_flags &= ~XFS_IEOFBLOCKS; | ||
1464 | spin_unlock(&ip->i_flags_lock); | ||
1465 | |||
1452 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); | 1466 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); |
1453 | spin_lock(&pag->pag_ici_lock); | 1467 | spin_lock(&pag->pag_ici_lock); |
1454 | trace_xfs_inode_clear_eofblocks_tag(ip); | 1468 | trace_xfs_inode_clear_eofblocks_tag(ip); |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index e1a411e08f00..8f30d2533b48 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -216,6 +216,7 @@ xfs_get_initial_prid(struct xfs_inode *dp) | |||
216 | #define __XFS_IPINNED_BIT 8 /* wakeup key for zero pin count */ | 216 | #define __XFS_IPINNED_BIT 8 /* wakeup key for zero pin count */ |
217 | #define XFS_IPINNED (1 << __XFS_IPINNED_BIT) | 217 | #define XFS_IPINNED (1 << __XFS_IPINNED_BIT) |
218 | #define XFS_IDONTCACHE (1 << 9) /* don't cache the inode long term */ | 218 | #define XFS_IDONTCACHE (1 << 9) /* don't cache the inode long term */ |
219 | #define XFS_IEOFBLOCKS (1 << 10)/* has the preallocblocks tag set */ | ||
219 | 220 | ||
220 | /* | 221 | /* |
221 | * Per-lifetime flags need to be reset when re-using a reclaimable inode during | 222 | * Per-lifetime flags need to be reset when re-using a reclaimable inode during |
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 2af0dda1c978..f96c8ffce5f4 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
3 | * Copyright (c) 2016 Christoph Hellwig. | ||
3 | * All Rights Reserved. | 4 | * All Rights Reserved. |
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -42,17 +43,40 @@ | |||
42 | 43 | ||
43 | #define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ | 44 | #define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ |
44 | << mp->m_writeio_log) | 45 | << mp->m_writeio_log) |
45 | #define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP | ||
46 | 46 | ||
47 | STATIC int | 47 | void |
48 | xfs_iomap_eof_align_last_fsb( | 48 | xfs_bmbt_to_iomap( |
49 | xfs_mount_t *mp, | 49 | struct xfs_inode *ip, |
50 | xfs_inode_t *ip, | 50 | struct iomap *iomap, |
51 | xfs_extlen_t extsize, | 51 | struct xfs_bmbt_irec *imap) |
52 | xfs_fileoff_t *last_fsb) | 52 | { |
53 | struct xfs_mount *mp = ip->i_mount; | ||
54 | |||
55 | if (imap->br_startblock == HOLESTARTBLOCK) { | ||
56 | iomap->blkno = IOMAP_NULL_BLOCK; | ||
57 | iomap->type = IOMAP_HOLE; | ||
58 | } else if (imap->br_startblock == DELAYSTARTBLOCK) { | ||
59 | iomap->blkno = IOMAP_NULL_BLOCK; | ||
60 | iomap->type = IOMAP_DELALLOC; | ||
61 | } else { | ||
62 | iomap->blkno = xfs_fsb_to_db(ip, imap->br_startblock); | ||
63 | if (imap->br_state == XFS_EXT_UNWRITTEN) | ||
64 | iomap->type = IOMAP_UNWRITTEN; | ||
65 | else | ||
66 | iomap->type = IOMAP_MAPPED; | ||
67 | } | ||
68 | iomap->offset = XFS_FSB_TO_B(mp, imap->br_startoff); | ||
69 | iomap->length = XFS_FSB_TO_B(mp, imap->br_blockcount); | ||
70 | iomap->bdev = xfs_find_bdev_for_inode(VFS_I(ip)); | ||
71 | } | ||
72 | |||
73 | static xfs_extlen_t | ||
74 | xfs_eof_alignment( | ||
75 | struct xfs_inode *ip, | ||
76 | xfs_extlen_t extsize) | ||
53 | { | 77 | { |
54 | xfs_extlen_t align = 0; | 78 | struct xfs_mount *mp = ip->i_mount; |
55 | int eof, error; | 79 | xfs_extlen_t align = 0; |
56 | 80 | ||
57 | if (!XFS_IS_REALTIME_INODE(ip)) { | 81 | if (!XFS_IS_REALTIME_INODE(ip)) { |
58 | /* | 82 | /* |
@@ -83,8 +107,21 @@ xfs_iomap_eof_align_last_fsb( | |||
83 | align = extsize; | 107 | align = extsize; |
84 | } | 108 | } |
85 | 109 | ||
110 | return align; | ||
111 | } | ||
112 | |||
113 | STATIC int | ||
114 | xfs_iomap_eof_align_last_fsb( | ||
115 | struct xfs_inode *ip, | ||
116 | xfs_extlen_t extsize, | ||
117 | xfs_fileoff_t *last_fsb) | ||
118 | { | ||
119 | xfs_extlen_t align = xfs_eof_alignment(ip, extsize); | ||
120 | |||
86 | if (align) { | 121 | if (align) { |
87 | xfs_fileoff_t new_last_fsb = roundup_64(*last_fsb, align); | 122 | xfs_fileoff_t new_last_fsb = roundup_64(*last_fsb, align); |
123 | int eof, error; | ||
124 | |||
88 | error = xfs_bmap_eof(ip, new_last_fsb, XFS_DATA_FORK, &eof); | 125 | error = xfs_bmap_eof(ip, new_last_fsb, XFS_DATA_FORK, &eof); |
89 | if (error) | 126 | if (error) |
90 | return error; | 127 | return error; |
@@ -154,7 +191,7 @@ xfs_iomap_write_direct( | |||
154 | */ | 191 | */ |
155 | ASSERT(XFS_IFORK_PTR(ip, XFS_DATA_FORK)->if_flags & | 192 | ASSERT(XFS_IFORK_PTR(ip, XFS_DATA_FORK)->if_flags & |
156 | XFS_IFEXTENTS); | 193 | XFS_IFEXTENTS); |
157 | error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb); | 194 | error = xfs_iomap_eof_align_last_fsb(ip, extsz, &last_fsb); |
158 | if (error) | 195 | if (error) |
159 | goto out_unlock; | 196 | goto out_unlock; |
160 | } else { | 197 | } else { |
@@ -274,130 +311,6 @@ out_trans_cancel: | |||
274 | goto out_unlock; | 311 | goto out_unlock; |
275 | } | 312 | } |
276 | 313 | ||
277 | /* | ||
278 | * If the caller is doing a write at the end of the file, then extend the | ||
279 | * allocation out to the file system's write iosize. We clean up any extra | ||
280 | * space left over when the file is closed in xfs_inactive(). | ||
281 | * | ||
282 | * If we find we already have delalloc preallocation beyond EOF, don't do more | ||
283 | * preallocation as it it not needed. | ||
284 | */ | ||
285 | STATIC int | ||
286 | xfs_iomap_eof_want_preallocate( | ||
287 | xfs_mount_t *mp, | ||
288 | xfs_inode_t *ip, | ||
289 | xfs_off_t offset, | ||
290 | size_t count, | ||
291 | xfs_bmbt_irec_t *imap, | ||
292 | int nimaps, | ||
293 | int *prealloc) | ||
294 | { | ||
295 | xfs_fileoff_t start_fsb; | ||
296 | xfs_filblks_t count_fsb; | ||
297 | int n, error, imaps; | ||
298 | int found_delalloc = 0; | ||
299 | |||
300 | *prealloc = 0; | ||
301 | if (offset + count <= XFS_ISIZE(ip)) | ||
302 | return 0; | ||
303 | |||
304 | /* | ||
305 | * If the file is smaller than the minimum prealloc and we are using | ||
306 | * dynamic preallocation, don't do any preallocation at all as it is | ||
307 | * likely this is the only write to the file that is going to be done. | ||
308 | */ | ||
309 | if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) && | ||
310 | XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_writeio_blocks)) | ||
311 | return 0; | ||
312 | |||
313 | /* | ||
314 | * If there are any real blocks past eof, then don't | ||
315 | * do any speculative allocation. | ||
316 | */ | ||
317 | start_fsb = XFS_B_TO_FSBT(mp, ((xfs_ufsize_t)(offset + count - 1))); | ||
318 | count_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes); | ||
319 | while (count_fsb > 0) { | ||
320 | imaps = nimaps; | ||
321 | error = xfs_bmapi_read(ip, start_fsb, count_fsb, imap, &imaps, | ||
322 | 0); | ||
323 | if (error) | ||
324 | return error; | ||
325 | for (n = 0; n < imaps; n++) { | ||
326 | if ((imap[n].br_startblock != HOLESTARTBLOCK) && | ||
327 | (imap[n].br_startblock != DELAYSTARTBLOCK)) | ||
328 | return 0; | ||
329 | start_fsb += imap[n].br_blockcount; | ||
330 | count_fsb -= imap[n].br_blockcount; | ||
331 | |||
332 | if (imap[n].br_startblock == DELAYSTARTBLOCK) | ||
333 | found_delalloc = 1; | ||
334 | } | ||
335 | } | ||
336 | if (!found_delalloc) | ||
337 | *prealloc = 1; | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * Determine the initial size of the preallocation. We are beyond the current | ||
343 | * EOF here, but we need to take into account whether this is a sparse write or | ||
344 | * an extending write when determining the preallocation size. Hence we need to | ||
345 | * look up the extent that ends at the current write offset and use the result | ||
346 | * to determine the preallocation size. | ||
347 | * | ||
348 | * If the extent is a hole, then preallocation is essentially disabled. | ||
349 | * Otherwise we take the size of the preceeding data extent as the basis for the | ||
350 | * preallocation size. If the size of the extent is greater than half the | ||
351 | * maximum extent length, then use the current offset as the basis. This ensures | ||
352 | * that for large files the preallocation size always extends to MAXEXTLEN | ||
353 | * rather than falling short due to things like stripe unit/width alignment of | ||
354 | * real extents. | ||
355 | */ | ||
356 | STATIC xfs_fsblock_t | ||
357 | xfs_iomap_eof_prealloc_initial_size( | ||
358 | struct xfs_mount *mp, | ||
359 | struct xfs_inode *ip, | ||
360 | xfs_off_t offset, | ||
361 | xfs_bmbt_irec_t *imap, | ||
362 | int nimaps) | ||
363 | { | ||
364 | xfs_fileoff_t start_fsb; | ||
365 | int imaps = 1; | ||
366 | int error; | ||
367 | |||
368 | ASSERT(nimaps >= imaps); | ||
369 | |||
370 | /* if we are using a specific prealloc size, return now */ | ||
371 | if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) | ||
372 | return 0; | ||
373 | |||
374 | /* If the file is small, then use the minimum prealloc */ | ||
375 | if (XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign)) | ||
376 | return 0; | ||
377 | |||
378 | /* | ||
379 | * As we write multiple pages, the offset will always align to the | ||
380 | * start of a page and hence point to a hole at EOF. i.e. if the size is | ||
381 | * 4096 bytes, we only have one block at FSB 0, but XFS_B_TO_FSB(4096) | ||
382 | * will return FSB 1. Hence if there are blocks in the file, we want to | ||
383 | * point to the block prior to the EOF block and not the hole that maps | ||
384 | * directly at @offset. | ||
385 | */ | ||
386 | start_fsb = XFS_B_TO_FSB(mp, offset); | ||
387 | if (start_fsb) | ||
388 | start_fsb--; | ||
389 | error = xfs_bmapi_read(ip, start_fsb, 1, imap, &imaps, XFS_BMAPI_ENTIRE); | ||
390 | if (error) | ||
391 | return 0; | ||
392 | |||
393 | ASSERT(imaps == 1); | ||
394 | if (imap[0].br_startblock == HOLESTARTBLOCK) | ||
395 | return 0; | ||
396 | if (imap[0].br_blockcount <= (MAXEXTLEN >> 1)) | ||
397 | return imap[0].br_blockcount << 1; | ||
398 | return XFS_B_TO_FSB(mp, offset); | ||
399 | } | ||
400 | |||
401 | STATIC bool | 314 | STATIC bool |
402 | xfs_quota_need_throttle( | 315 | xfs_quota_need_throttle( |
403 | struct xfs_inode *ip, | 316 | struct xfs_inode *ip, |
@@ -459,27 +372,76 @@ xfs_quota_calc_throttle( | |||
459 | } | 372 | } |
460 | 373 | ||
461 | /* | 374 | /* |
375 | * If we are doing a write at the end of the file and there are no allocations | ||
376 | * past this one, then extend the allocation out to the file system's write | ||
377 | * iosize. | ||
378 | * | ||
462 | * If we don't have a user specified preallocation size, dynamically increase | 379 | * If we don't have a user specified preallocation size, dynamically increase |
463 | * the preallocation size as the size of the file grows. Cap the maximum size | 380 | * the preallocation size as the size of the file grows. Cap the maximum size |
464 | * at a single extent or less if the filesystem is near full. The closer the | 381 | * at a single extent or less if the filesystem is near full. The closer the |
465 | * filesystem is to full, the smaller the maximum prealocation. | 382 | * filesystem is to full, the smaller the maximum prealocation. |
383 | * | ||
384 | * As an exception we don't do any preallocation at all if the file is smaller | ||
385 | * than the minimum preallocation and we are using the default dynamic | ||
386 | * preallocation scheme, as it is likely this is the only write to the file that | ||
387 | * is going to be done. | ||
388 | * | ||
389 | * We clean up any extra space left over when the file is closed in | ||
390 | * xfs_inactive(). | ||
466 | */ | 391 | */ |
467 | STATIC xfs_fsblock_t | 392 | STATIC xfs_fsblock_t |
468 | xfs_iomap_prealloc_size( | 393 | xfs_iomap_prealloc_size( |
469 | struct xfs_mount *mp, | ||
470 | struct xfs_inode *ip, | 394 | struct xfs_inode *ip, |
471 | xfs_off_t offset, | 395 | loff_t offset, |
472 | struct xfs_bmbt_irec *imap, | 396 | loff_t count, |
473 | int nimaps) | 397 | xfs_extnum_t idx, |
398 | struct xfs_bmbt_irec *prev) | ||
474 | { | 399 | { |
475 | xfs_fsblock_t alloc_blocks = 0; | 400 | struct xfs_mount *mp = ip->i_mount; |
401 | xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); | ||
476 | int shift = 0; | 402 | int shift = 0; |
477 | int64_t freesp; | 403 | int64_t freesp; |
478 | xfs_fsblock_t qblocks; | 404 | xfs_fsblock_t qblocks; |
479 | int qshift = 0; | 405 | int qshift = 0; |
406 | xfs_fsblock_t alloc_blocks = 0; | ||
480 | 407 | ||
481 | alloc_blocks = xfs_iomap_eof_prealloc_initial_size(mp, ip, offset, | 408 | if (offset + count <= XFS_ISIZE(ip)) |
482 | imap, nimaps); | 409 | return 0; |
410 | |||
411 | if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) && | ||
412 | (XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_writeio_blocks))) | ||
413 | return 0; | ||
414 | |||
415 | /* | ||
416 | * If an explicit allocsize is set, the file is small, or we | ||
417 | * are writing behind a hole, then use the minimum prealloc: | ||
418 | */ | ||
419 | if ((mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) || | ||
420 | XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) || | ||
421 | idx == 0 || | ||
422 | prev->br_startoff + prev->br_blockcount < offset_fsb) | ||
423 | return mp->m_writeio_blocks; | ||
424 | |||
425 | /* | ||
426 | * Determine the initial size of the preallocation. We are beyond the | ||
427 | * current EOF here, but we need to take into account whether this is | ||
428 | * a sparse write or an extending write when determining the | ||
429 | * preallocation size. Hence we need to look up the extent that ends | ||
430 | * at the current write offset and use the result to determine the | ||
431 | * preallocation size. | ||
432 | * | ||
433 | * If the extent is a hole, then preallocation is essentially disabled. | ||
434 | * Otherwise we take the size of the preceding data extent as the basis | ||
435 | * for the preallocation size. If the size of the extent is greater than | ||
436 | * half the maximum extent length, then use the current offset as the | ||
437 | * basis. This ensures that for large files the preallocation size | ||
438 | * always extends to MAXEXTLEN rather than falling short due to things | ||
439 | * like stripe unit/width alignment of real extents. | ||
440 | */ | ||
441 | if (prev->br_blockcount <= (MAXEXTLEN >> 1)) | ||
442 | alloc_blocks = prev->br_blockcount << 1; | ||
443 | else | ||
444 | alloc_blocks = XFS_B_TO_FSB(mp, offset); | ||
483 | if (!alloc_blocks) | 445 | if (!alloc_blocks) |
484 | goto check_writeio; | 446 | goto check_writeio; |
485 | qblocks = alloc_blocks; | 447 | qblocks = alloc_blocks; |
@@ -550,120 +512,145 @@ xfs_iomap_prealloc_size( | |||
550 | */ | 512 | */ |
551 | while (alloc_blocks && alloc_blocks >= freesp) | 513 | while (alloc_blocks && alloc_blocks >= freesp) |
552 | alloc_blocks >>= 4; | 514 | alloc_blocks >>= 4; |
553 | |||
554 | check_writeio: | 515 | check_writeio: |
555 | if (alloc_blocks < mp->m_writeio_blocks) | 516 | if (alloc_blocks < mp->m_writeio_blocks) |
556 | alloc_blocks = mp->m_writeio_blocks; | 517 | alloc_blocks = mp->m_writeio_blocks; |
557 | |||
558 | trace_xfs_iomap_prealloc_size(ip, alloc_blocks, shift, | 518 | trace_xfs_iomap_prealloc_size(ip, alloc_blocks, shift, |
559 | mp->m_writeio_blocks); | 519 | mp->m_writeio_blocks); |
560 | |||
561 | return alloc_blocks; | 520 | return alloc_blocks; |
562 | } | 521 | } |
563 | 522 | ||
564 | int | 523 | static int |
565 | xfs_iomap_write_delay( | 524 | xfs_file_iomap_begin_delay( |
566 | xfs_inode_t *ip, | 525 | struct inode *inode, |
567 | xfs_off_t offset, | 526 | loff_t offset, |
568 | size_t count, | 527 | loff_t count, |
569 | xfs_bmbt_irec_t *ret_imap) | 528 | unsigned flags, |
529 | struct iomap *iomap) | ||
570 | { | 530 | { |
571 | xfs_mount_t *mp = ip->i_mount; | 531 | struct xfs_inode *ip = XFS_I(inode); |
572 | xfs_fileoff_t offset_fsb; | 532 | struct xfs_mount *mp = ip->i_mount; |
573 | xfs_fileoff_t last_fsb; | 533 | struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); |
574 | xfs_off_t aligned_offset; | 534 | xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); |
575 | xfs_fileoff_t ioalign; | 535 | xfs_fileoff_t maxbytes_fsb = |
576 | xfs_extlen_t extsz; | 536 | XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes); |
577 | int nimaps; | 537 | xfs_fileoff_t end_fsb, orig_end_fsb; |
578 | xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS]; | 538 | int error = 0, eof = 0; |
579 | int prealloc; | 539 | struct xfs_bmbt_irec got; |
580 | int error; | 540 | struct xfs_bmbt_irec prev; |
581 | 541 | xfs_extnum_t idx; | |
582 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | ||
583 | |||
584 | /* | ||
585 | * Make sure that the dquots are there. This doesn't hold | ||
586 | * the ilock across a disk read. | ||
587 | */ | ||
588 | error = xfs_qm_dqattach_locked(ip, 0); | ||
589 | if (error) | ||
590 | return error; | ||
591 | 542 | ||
592 | extsz = xfs_get_extsz_hint(ip); | 543 | ASSERT(!XFS_IS_REALTIME_INODE(ip)); |
593 | offset_fsb = XFS_B_TO_FSBT(mp, offset); | 544 | ASSERT(!xfs_get_extsz_hint(ip)); |
594 | 545 | ||
595 | error = xfs_iomap_eof_want_preallocate(mp, ip, offset, count, | 546 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
596 | imap, XFS_WRITE_IMAPS, &prealloc); | ||
597 | if (error) | ||
598 | return error; | ||
599 | 547 | ||
600 | retry: | 548 | if (unlikely(XFS_TEST_ERROR( |
601 | if (prealloc) { | 549 | (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS && |
602 | xfs_fsblock_t alloc_blocks; | 550 | XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE), |
551 | mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { | ||
552 | XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); | ||
553 | error = -EFSCORRUPTED; | ||
554 | goto out_unlock; | ||
555 | } | ||
603 | 556 | ||
604 | alloc_blocks = xfs_iomap_prealloc_size(mp, ip, offset, imap, | 557 | XFS_STATS_INC(mp, xs_blk_mapw); |
605 | XFS_WRITE_IMAPS); | ||
606 | 558 | ||
607 | aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1)); | 559 | if (!(ifp->if_flags & XFS_IFEXTENTS)) { |
608 | ioalign = XFS_B_TO_FSBT(mp, aligned_offset); | 560 | error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK); |
609 | last_fsb = ioalign + alloc_blocks; | 561 | if (error) |
610 | } else { | 562 | goto out_unlock; |
611 | last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); | ||
612 | } | 563 | } |
613 | 564 | ||
614 | if (prealloc || extsz) { | 565 | xfs_bmap_search_extents(ip, offset_fsb, XFS_DATA_FORK, &eof, &idx, |
615 | error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb); | 566 | &got, &prev); |
616 | if (error) | 567 | if (!eof && got.br_startoff <= offset_fsb) { |
617 | return error; | 568 | trace_xfs_iomap_found(ip, offset, count, 0, &got); |
569 | goto done; | ||
618 | } | 570 | } |
619 | 571 | ||
572 | error = xfs_qm_dqattach_locked(ip, 0); | ||
573 | if (error) | ||
574 | goto out_unlock; | ||
575 | |||
620 | /* | 576 | /* |
621 | * Make sure preallocation does not create extents beyond the range we | 577 | * We cap the maximum length we map here to MAX_WRITEBACK_PAGES pages |
622 | * actually support in this filesystem. | 578 | * to keep the chunks of work done where somewhat symmetric with the |
579 | * work writeback does. This is a completely arbitrary number pulled | ||
580 | * out of thin air as a best guess for initial testing. | ||
581 | * | ||
582 | * Note that the values needs to be less than 32-bits wide until | ||
583 | * the lower level functions are updated. | ||
623 | */ | 584 | */ |
624 | if (last_fsb > XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes)) | 585 | count = min_t(loff_t, count, 1024 * PAGE_SIZE); |
625 | last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes); | 586 | end_fsb = orig_end_fsb = |
587 | min(XFS_B_TO_FSB(mp, offset + count), maxbytes_fsb); | ||
588 | |||
589 | if (eof) { | ||
590 | xfs_fsblock_t prealloc_blocks; | ||
626 | 591 | ||
627 | ASSERT(last_fsb > offset_fsb); | 592 | prealloc_blocks = |
593 | xfs_iomap_prealloc_size(ip, offset, count, idx, &prev); | ||
594 | if (prealloc_blocks) { | ||
595 | xfs_extlen_t align; | ||
596 | xfs_off_t end_offset; | ||
628 | 597 | ||
629 | nimaps = XFS_WRITE_IMAPS; | 598 | end_offset = XFS_WRITEIO_ALIGN(mp, offset + count - 1); |
630 | error = xfs_bmapi_delay(ip, offset_fsb, last_fsb - offset_fsb, | 599 | end_fsb = XFS_B_TO_FSBT(mp, end_offset) + |
631 | imap, &nimaps, XFS_BMAPI_ENTIRE); | 600 | prealloc_blocks; |
601 | |||
602 | align = xfs_eof_alignment(ip, 0); | ||
603 | if (align) | ||
604 | end_fsb = roundup_64(end_fsb, align); | ||
605 | |||
606 | end_fsb = min(end_fsb, maxbytes_fsb); | ||
607 | ASSERT(end_fsb > offset_fsb); | ||
608 | } | ||
609 | } | ||
610 | |||
611 | retry: | ||
612 | error = xfs_bmapi_reserve_delalloc(ip, offset_fsb, | ||
613 | end_fsb - offset_fsb, &got, | ||
614 | &prev, &idx, eof); | ||
632 | switch (error) { | 615 | switch (error) { |
633 | case 0: | 616 | case 0: |
617 | break; | ||
634 | case -ENOSPC: | 618 | case -ENOSPC: |
635 | case -EDQUOT: | 619 | case -EDQUOT: |
636 | break; | 620 | /* retry without any preallocation */ |
637 | default: | ||
638 | return error; | ||
639 | } | ||
640 | |||
641 | /* | ||
642 | * If bmapi returned us nothing, we got either ENOSPC or EDQUOT. Retry | ||
643 | * without EOF preallocation. | ||
644 | */ | ||
645 | if (nimaps == 0) { | ||
646 | trace_xfs_delalloc_enospc(ip, offset, count); | 621 | trace_xfs_delalloc_enospc(ip, offset, count); |
647 | if (prealloc) { | 622 | if (end_fsb != orig_end_fsb) { |
648 | prealloc = 0; | 623 | end_fsb = orig_end_fsb; |
649 | error = 0; | ||
650 | goto retry; | 624 | goto retry; |
651 | } | 625 | } |
652 | return error ? error : -ENOSPC; | 626 | /*FALLTHRU*/ |
627 | default: | ||
628 | goto out_unlock; | ||
653 | } | 629 | } |
654 | 630 | ||
655 | if (!(imap[0].br_startblock || XFS_IS_REALTIME_INODE(ip))) | ||
656 | return xfs_alert_fsblock_zero(ip, &imap[0]); | ||
657 | |||
658 | /* | 631 | /* |
659 | * Tag the inode as speculatively preallocated so we can reclaim this | 632 | * Tag the inode as speculatively preallocated so we can reclaim this |
660 | * space on demand, if necessary. | 633 | * space on demand, if necessary. |
661 | */ | 634 | */ |
662 | if (prealloc) | 635 | if (end_fsb != orig_end_fsb) |
663 | xfs_inode_set_eofblocks_tag(ip); | 636 | xfs_inode_set_eofblocks_tag(ip); |
664 | 637 | ||
665 | *ret_imap = imap[0]; | 638 | trace_xfs_iomap_alloc(ip, offset, count, 0, &got); |
666 | return 0; | 639 | done: |
640 | if (isnullstartblock(got.br_startblock)) | ||
641 | got.br_startblock = DELAYSTARTBLOCK; | ||
642 | |||
643 | if (!got.br_startblock) { | ||
644 | error = xfs_alert_fsblock_zero(ip, &got); | ||
645 | if (error) | ||
646 | goto out_unlock; | ||
647 | } | ||
648 | |||
649 | xfs_bmbt_to_iomap(ip, iomap, &got); | ||
650 | |||
651 | out_unlock: | ||
652 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
653 | return error; | ||
667 | } | 654 | } |
668 | 655 | ||
669 | /* | 656 | /* |
@@ -947,32 +934,6 @@ error_on_bmapi_transaction: | |||
947 | return error; | 934 | return error; |
948 | } | 935 | } |
949 | 936 | ||
950 | void | ||
951 | xfs_bmbt_to_iomap( | ||
952 | struct xfs_inode *ip, | ||
953 | struct iomap *iomap, | ||
954 | struct xfs_bmbt_irec *imap) | ||
955 | { | ||
956 | struct xfs_mount *mp = ip->i_mount; | ||
957 | |||
958 | if (imap->br_startblock == HOLESTARTBLOCK) { | ||
959 | iomap->blkno = IOMAP_NULL_BLOCK; | ||
960 | iomap->type = IOMAP_HOLE; | ||
961 | } else if (imap->br_startblock == DELAYSTARTBLOCK) { | ||
962 | iomap->blkno = IOMAP_NULL_BLOCK; | ||
963 | iomap->type = IOMAP_DELALLOC; | ||
964 | } else { | ||
965 | iomap->blkno = xfs_fsb_to_db(ip, imap->br_startblock); | ||
966 | if (imap->br_state == XFS_EXT_UNWRITTEN) | ||
967 | iomap->type = IOMAP_UNWRITTEN; | ||
968 | else | ||
969 | iomap->type = IOMAP_MAPPED; | ||
970 | } | ||
971 | iomap->offset = XFS_FSB_TO_B(mp, imap->br_startoff); | ||
972 | iomap->length = XFS_FSB_TO_B(mp, imap->br_blockcount); | ||
973 | iomap->bdev = xfs_find_bdev_for_inode(VFS_I(ip)); | ||
974 | } | ||
975 | |||
976 | static inline bool imap_needs_alloc(struct xfs_bmbt_irec *imap, int nimaps) | 937 | static inline bool imap_needs_alloc(struct xfs_bmbt_irec *imap, int nimaps) |
977 | { | 938 | { |
978 | return !nimaps || | 939 | return !nimaps || |
@@ -997,6 +958,11 @@ xfs_file_iomap_begin( | |||
997 | if (XFS_FORCED_SHUTDOWN(mp)) | 958 | if (XFS_FORCED_SHUTDOWN(mp)) |
998 | return -EIO; | 959 | return -EIO; |
999 | 960 | ||
961 | if ((flags & IOMAP_WRITE) && !xfs_get_extsz_hint(ip)) { | ||
962 | return xfs_file_iomap_begin_delay(inode, offset, length, flags, | ||
963 | iomap); | ||
964 | } | ||
965 | |||
1000 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 966 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
1001 | 967 | ||
1002 | ASSERT(offset <= mp->m_super->s_maxbytes); | 968 | ASSERT(offset <= mp->m_super->s_maxbytes); |
@@ -1024,19 +990,13 @@ xfs_file_iomap_begin( | |||
1024 | * the lower level functions are updated. | 990 | * the lower level functions are updated. |
1025 | */ | 991 | */ |
1026 | length = min_t(loff_t, length, 1024 * PAGE_SIZE); | 992 | length = min_t(loff_t, length, 1024 * PAGE_SIZE); |
1027 | if (xfs_get_extsz_hint(ip)) { | 993 | /* |
1028 | /* | 994 | * xfs_iomap_write_direct() expects the shared lock. It |
1029 | * xfs_iomap_write_direct() expects the shared lock. It | 995 | * is unlocked on return. |
1030 | * is unlocked on return. | 996 | */ |
1031 | */ | 997 | xfs_ilock_demote(ip, XFS_ILOCK_EXCL); |
1032 | xfs_ilock_demote(ip, XFS_ILOCK_EXCL); | 998 | error = xfs_iomap_write_direct(ip, offset, length, &imap, |
1033 | error = xfs_iomap_write_direct(ip, offset, length, &imap, | 999 | nimaps); |
1034 | nimaps); | ||
1035 | } else { | ||
1036 | error = xfs_iomap_write_delay(ip, offset, length, &imap); | ||
1037 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
1038 | } | ||
1039 | |||
1040 | if (error) | 1000 | if (error) |
1041 | return error; | 1001 | return error; |
1042 | 1002 | ||
diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h index fb8aca3d69ab..6498be485932 100644 --- a/fs/xfs/xfs_iomap.h +++ b/fs/xfs/xfs_iomap.h | |||
@@ -25,8 +25,6 @@ struct xfs_bmbt_irec; | |||
25 | 25 | ||
26 | int xfs_iomap_write_direct(struct xfs_inode *, xfs_off_t, size_t, | 26 | int xfs_iomap_write_direct(struct xfs_inode *, xfs_off_t, size_t, |
27 | struct xfs_bmbt_irec *, int); | 27 | struct xfs_bmbt_irec *, int); |
28 | int xfs_iomap_write_delay(struct xfs_inode *, xfs_off_t, size_t, | ||
29 | struct xfs_bmbt_irec *); | ||
30 | int xfs_iomap_write_allocate(struct xfs_inode *, xfs_off_t, | 28 | int xfs_iomap_write_allocate(struct xfs_inode *, xfs_off_t, |
31 | struct xfs_bmbt_irec *); | 29 | struct xfs_bmbt_irec *); |
32 | int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, xfs_off_t); | 30 | int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, xfs_off_t); |