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 { |
