diff options
Diffstat (limited to 'fs/xfs/xfs_ialloc.c')
-rw-r--r-- | fs/xfs/xfs_ialloc.c | 74 |
1 files changed, 53 insertions, 21 deletions
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index c8f5ae1debf2..7a0c17d7ec09 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include "xfs_bmap.h" | 38 | #include "xfs_bmap.h" |
39 | #include "xfs_cksum.h" | 39 | #include "xfs_cksum.h" |
40 | #include "xfs_buf_item.h" | 40 | #include "xfs_buf_item.h" |
41 | #include "xfs_icreate_item.h" | ||
41 | 42 | ||
42 | 43 | ||
43 | /* | 44 | /* |
@@ -150,12 +151,16 @@ xfs_check_agi_freecount( | |||
150 | #endif | 151 | #endif |
151 | 152 | ||
152 | /* | 153 | /* |
153 | * Initialise a new set of inodes. | 154 | * Initialise a new set of inodes. When called without a transaction context |
155 | * (e.g. from recovery) we initiate a delayed write of the inode buffers rather | ||
156 | * than logging them (which in a transaction context puts them into the AIL | ||
157 | * for writeback rather than the xfsbufd queue). | ||
154 | */ | 158 | */ |
155 | STATIC int | 159 | int |
156 | xfs_ialloc_inode_init( | 160 | xfs_ialloc_inode_init( |
157 | struct xfs_mount *mp, | 161 | struct xfs_mount *mp, |
158 | struct xfs_trans *tp, | 162 | struct xfs_trans *tp, |
163 | struct list_head *buffer_list, | ||
159 | xfs_agnumber_t agno, | 164 | xfs_agnumber_t agno, |
160 | xfs_agblock_t agbno, | 165 | xfs_agblock_t agbno, |
161 | xfs_agblock_t length, | 166 | xfs_agblock_t length, |
@@ -208,6 +213,18 @@ xfs_ialloc_inode_init( | |||
208 | version = 3; | 213 | version = 3; |
209 | ino = XFS_AGINO_TO_INO(mp, agno, | 214 | ino = XFS_AGINO_TO_INO(mp, agno, |
210 | XFS_OFFBNO_TO_AGINO(mp, agbno, 0)); | 215 | XFS_OFFBNO_TO_AGINO(mp, agbno, 0)); |
216 | |||
217 | /* | ||
218 | * log the initialisation that is about to take place as an | ||
219 | * logical operation. This means the transaction does not | ||
220 | * need to log the physical changes to the inode buffers as log | ||
221 | * recovery will know what initialisation is actually needed. | ||
222 | * Hence we only need to log the buffers as "ordered" buffers so | ||
223 | * they track in the AIL as if they were physically logged. | ||
224 | */ | ||
225 | if (tp) | ||
226 | xfs_icreate_log(tp, agno, agbno, XFS_IALLOC_INODES(mp), | ||
227 | mp->m_sb.sb_inodesize, length, gen); | ||
211 | } else if (xfs_sb_version_hasnlink(&mp->m_sb)) | 228 | } else if (xfs_sb_version_hasnlink(&mp->m_sb)) |
212 | version = 2; | 229 | version = 2; |
213 | else | 230 | else |
@@ -223,13 +240,8 @@ xfs_ialloc_inode_init( | |||
223 | XBF_UNMAPPED); | 240 | XBF_UNMAPPED); |
224 | if (!fbuf) | 241 | if (!fbuf) |
225 | return ENOMEM; | 242 | return ENOMEM; |
226 | /* | 243 | |
227 | * Initialize all inodes in this buffer and then log them. | 244 | /* Initialize the inode buffers and log them appropriately. */ |
228 | * | ||
229 | * XXX: It would be much better if we had just one transaction | ||
230 | * to log a whole cluster of inodes instead of all the | ||
231 | * individual transactions causing a lot of log traffic. | ||
232 | */ | ||
233 | fbuf->b_ops = &xfs_inode_buf_ops; | 245 | fbuf->b_ops = &xfs_inode_buf_ops; |
234 | xfs_buf_zero(fbuf, 0, BBTOB(fbuf->b_length)); | 246 | xfs_buf_zero(fbuf, 0, BBTOB(fbuf->b_length)); |
235 | for (i = 0; i < ninodes; i++) { | 247 | for (i = 0; i < ninodes; i++) { |
@@ -247,18 +259,39 @@ xfs_ialloc_inode_init( | |||
247 | ino++; | 259 | ino++; |
248 | uuid_copy(&free->di_uuid, &mp->m_sb.sb_uuid); | 260 | uuid_copy(&free->di_uuid, &mp->m_sb.sb_uuid); |
249 | xfs_dinode_calc_crc(mp, free); | 261 | xfs_dinode_calc_crc(mp, free); |
250 | } else { | 262 | } else if (tp) { |
251 | /* just log the inode core */ | 263 | /* just log the inode core */ |
252 | xfs_trans_log_buf(tp, fbuf, ioffset, | 264 | xfs_trans_log_buf(tp, fbuf, ioffset, |
253 | ioffset + isize - 1); | 265 | ioffset + isize - 1); |
254 | } | 266 | } |
255 | } | 267 | } |
256 | if (version == 3) { | 268 | |
257 | /* need to log the entire buffer */ | 269 | if (tp) { |
258 | xfs_trans_log_buf(tp, fbuf, 0, | 270 | /* |
259 | BBTOB(fbuf->b_length) - 1); | 271 | * Mark the buffer as an inode allocation buffer so it |
272 | * sticks in AIL at the point of this allocation | ||
273 | * transaction. This ensures the they are on disk before | ||
274 | * the tail of the log can be moved past this | ||
275 | * transaction (i.e. by preventing relogging from moving | ||
276 | * it forward in the log). | ||
277 | */ | ||
278 | xfs_trans_inode_alloc_buf(tp, fbuf); | ||
279 | if (version == 3) { | ||
280 | /* | ||
281 | * Mark the buffer as ordered so that they are | ||
282 | * not physically logged in the transaction but | ||
283 | * still tracked in the AIL as part of the | ||
284 | * transaction and pin the log appropriately. | ||
285 | */ | ||
286 | xfs_trans_ordered_buf(tp, fbuf); | ||
287 | xfs_trans_log_buf(tp, fbuf, 0, | ||
288 | BBTOB(fbuf->b_length) - 1); | ||
289 | } | ||
290 | } else { | ||
291 | fbuf->b_flags |= XBF_DONE; | ||
292 | xfs_buf_delwri_queue(fbuf, buffer_list); | ||
293 | xfs_buf_relse(fbuf); | ||
260 | } | 294 | } |
261 | xfs_trans_inode_alloc_buf(tp, fbuf); | ||
262 | } | 295 | } |
263 | return 0; | 296 | return 0; |
264 | } | 297 | } |
@@ -303,7 +336,7 @@ xfs_ialloc_ag_alloc( | |||
303 | * First try to allocate inodes contiguous with the last-allocated | 336 | * First try to allocate inodes contiguous with the last-allocated |
304 | * chunk of inodes. If the filesystem is striped, this will fill | 337 | * chunk of inodes. If the filesystem is striped, this will fill |
305 | * an entire stripe unit with inodes. | 338 | * an entire stripe unit with inodes. |
306 | */ | 339 | */ |
307 | agi = XFS_BUF_TO_AGI(agbp); | 340 | agi = XFS_BUF_TO_AGI(agbp); |
308 | newino = be32_to_cpu(agi->agi_newino); | 341 | newino = be32_to_cpu(agi->agi_newino); |
309 | agno = be32_to_cpu(agi->agi_seqno); | 342 | agno = be32_to_cpu(agi->agi_seqno); |
@@ -402,7 +435,7 @@ xfs_ialloc_ag_alloc( | |||
402 | * rather than a linear progression to prevent the next generation | 435 | * rather than a linear progression to prevent the next generation |
403 | * number from being easily guessable. | 436 | * number from being easily guessable. |
404 | */ | 437 | */ |
405 | error = xfs_ialloc_inode_init(args.mp, tp, agno, args.agbno, | 438 | error = xfs_ialloc_inode_init(args.mp, tp, NULL, agno, args.agbno, |
406 | args.len, prandom_u32()); | 439 | args.len, prandom_u32()); |
407 | 440 | ||
408 | if (error) | 441 | if (error) |
@@ -615,8 +648,7 @@ xfs_ialloc_get_rec( | |||
615 | struct xfs_btree_cur *cur, | 648 | struct xfs_btree_cur *cur, |
616 | xfs_agino_t agino, | 649 | xfs_agino_t agino, |
617 | xfs_inobt_rec_incore_t *rec, | 650 | xfs_inobt_rec_incore_t *rec, |
618 | int *done, | 651 | int *done) |
619 | int left) | ||
620 | { | 652 | { |
621 | int error; | 653 | int error; |
622 | int i; | 654 | int i; |
@@ -724,12 +756,12 @@ xfs_dialloc_ag( | |||
724 | pag->pagl_leftrec != NULLAGINO && | 756 | pag->pagl_leftrec != NULLAGINO && |
725 | pag->pagl_rightrec != NULLAGINO) { | 757 | pag->pagl_rightrec != NULLAGINO) { |
726 | error = xfs_ialloc_get_rec(tcur, pag->pagl_leftrec, | 758 | error = xfs_ialloc_get_rec(tcur, pag->pagl_leftrec, |
727 | &trec, &doneleft, 1); | 759 | &trec, &doneleft); |
728 | if (error) | 760 | if (error) |
729 | goto error1; | 761 | goto error1; |
730 | 762 | ||
731 | error = xfs_ialloc_get_rec(cur, pag->pagl_rightrec, | 763 | error = xfs_ialloc_get_rec(cur, pag->pagl_rightrec, |
732 | &rec, &doneright, 0); | 764 | &rec, &doneright); |
733 | if (error) | 765 | if (error) |
734 | goto error1; | 766 | goto error1; |
735 | } else { | 767 | } else { |