diff options
-rw-r--r-- | fs/gfs2/bmap.c | 97 |
1 files changed, 48 insertions, 49 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 08d1be492ef7..2011dd27f8d6 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -33,6 +33,7 @@ | |||
33 | * keep it small. | 33 | * keep it small. |
34 | */ | 34 | */ |
35 | struct metapath { | 35 | struct metapath { |
36 | struct buffer_head *mp_bh[GFS2_MAX_META_HEIGHT]; | ||
36 | __u16 mp_list[GFS2_MAX_META_HEIGHT]; | 37 | __u16 mp_list[GFS2_MAX_META_HEIGHT]; |
37 | }; | 38 | }; |
38 | 39 | ||
@@ -185,12 +186,11 @@ out: | |||
185 | * Returns: errno | 186 | * Returns: errno |
186 | */ | 187 | */ |
187 | 188 | ||
188 | static int build_height(struct inode *inode, unsigned height) | 189 | static int build_height(struct inode *inode, struct metapath *mp, unsigned height) |
189 | { | 190 | { |
190 | struct gfs2_inode *ip = GFS2_I(inode); | 191 | struct gfs2_inode *ip = GFS2_I(inode); |
191 | unsigned new_height = height - ip->i_height; | 192 | unsigned new_height = height - ip->i_height; |
192 | struct buffer_head *dibh; | 193 | struct buffer_head *dibh; |
193 | struct buffer_head *blocks[GFS2_MAX_META_HEIGHT]; | ||
194 | struct gfs2_dinode *di; | 194 | struct gfs2_dinode *di; |
195 | int error; | 195 | int error; |
196 | __be64 *bp; | 196 | __be64 *bp; |
@@ -206,29 +206,29 @@ static int build_height(struct inode *inode, unsigned height) | |||
206 | 206 | ||
207 | for(n = 0; n < new_height; n++) { | 207 | for(n = 0; n < new_height; n++) { |
208 | bn = gfs2_alloc_meta(ip); | 208 | bn = gfs2_alloc_meta(ip); |
209 | blocks[n] = gfs2_meta_new(ip->i_gl, bn); | 209 | mp->mp_bh[n] = gfs2_meta_new(ip->i_gl, bn); |
210 | gfs2_trans_add_bh(ip->i_gl, blocks[n], 1); | 210 | gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[n], 1); |
211 | } | 211 | } |
212 | 212 | ||
213 | n = 0; | 213 | n = 0; |
214 | bn = blocks[0]->b_blocknr; | 214 | bn = mp->mp_bh[0]->b_blocknr; |
215 | if (new_height > 1) { | 215 | if (new_height > 1) { |
216 | for(; n < new_height-1; n++) { | 216 | for(; n < new_height-1; n++) { |
217 | gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN, | 217 | gfs2_metatype_set(mp->mp_bh[n], GFS2_METATYPE_IN, |
218 | GFS2_FORMAT_IN); | 218 | GFS2_FORMAT_IN); |
219 | gfs2_buffer_clear_tail(blocks[n], | 219 | gfs2_buffer_clear_tail(mp->mp_bh[n], |
220 | sizeof(struct gfs2_meta_header)); | 220 | sizeof(struct gfs2_meta_header)); |
221 | bp = (__be64 *)(blocks[n]->b_data + | 221 | bp = (__be64 *)(mp->mp_bh[n]->b_data + |
222 | sizeof(struct gfs2_meta_header)); | 222 | sizeof(struct gfs2_meta_header)); |
223 | *bp = cpu_to_be64(blocks[n+1]->b_blocknr); | 223 | *bp = cpu_to_be64(mp->mp_bh[n+1]->b_blocknr); |
224 | brelse(blocks[n]); | 224 | brelse(mp->mp_bh[n]); |
225 | blocks[n] = NULL; | 225 | mp->mp_bh[n] = NULL; |
226 | } | 226 | } |
227 | } | 227 | } |
228 | gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN, GFS2_FORMAT_IN); | 228 | gfs2_metatype_set(mp->mp_bh[n], GFS2_METATYPE_IN, GFS2_FORMAT_IN); |
229 | gfs2_buffer_copy_tail(blocks[n], sizeof(struct gfs2_meta_header), | 229 | gfs2_buffer_copy_tail(mp->mp_bh[n], sizeof(struct gfs2_meta_header), |
230 | dibh, sizeof(struct gfs2_dinode)); | 230 | dibh, sizeof(struct gfs2_dinode)); |
231 | brelse(blocks[n]); | 231 | brelse(mp->mp_bh[n]); |
232 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 232 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
233 | di = (struct gfs2_dinode *)dibh->b_data; | 233 | di = (struct gfs2_dinode *)dibh->b_data; |
234 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); | 234 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); |
@@ -314,7 +314,6 @@ static void find_metapath(struct gfs2_inode *ip, u64 block, | |||
314 | 314 | ||
315 | /** | 315 | /** |
316 | * metapointer - Return pointer to start of metadata in a buffer | 316 | * metapointer - Return pointer to start of metadata in a buffer |
317 | * @bh: The buffer | ||
318 | * @height: The metadata height (0 = dinode) | 317 | * @height: The metadata height (0 = dinode) |
319 | * @mp: The metapath | 318 | * @mp: The metapath |
320 | * | 319 | * |
@@ -323,9 +322,10 @@ static void find_metapath(struct gfs2_inode *ip, u64 block, | |||
323 | * metadata tree. | 322 | * metadata tree. |
324 | */ | 323 | */ |
325 | 324 | ||
326 | static inline __be64 *metapointer(struct buffer_head *bh, int *boundary, | 325 | static inline __be64 *metapointer(int *boundary, unsigned int height, |
327 | unsigned int height, const struct metapath *mp) | 326 | const struct metapath *mp) |
328 | { | 327 | { |
328 | struct buffer_head *bh = mp->mp_bh[height]; | ||
329 | unsigned int head_size = (height > 0) ? | 329 | unsigned int head_size = (height > 0) ? |
330 | sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode); | 330 | sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode); |
331 | __be64 *ptr; | 331 | __be64 *ptr; |
@@ -339,7 +339,6 @@ static inline __be64 *metapointer(struct buffer_head *bh, int *boundary, | |||
339 | /** | 339 | /** |
340 | * lookup_block - Get the next metadata block in metadata tree | 340 | * lookup_block - Get the next metadata block in metadata tree |
341 | * @ip: The GFS2 inode | 341 | * @ip: The GFS2 inode |
342 | * @bh: Buffer containing the pointers to metadata blocks | ||
343 | * @height: The height of the tree (0 = dinode) | 342 | * @height: The height of the tree (0 = dinode) |
344 | * @mp: The metapath | 343 | * @mp: The metapath |
345 | * @create: Non-zero if we may create a new meatdata block | 344 | * @create: Non-zero if we may create a new meatdata block |
@@ -352,12 +351,12 @@ static inline __be64 *metapointer(struct buffer_head *bh, int *boundary, | |||
352 | * | 351 | * |
353 | */ | 352 | */ |
354 | 353 | ||
355 | static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, | 354 | static int lookup_block(struct gfs2_inode *ip, unsigned int height, |
356 | unsigned int height, struct metapath *mp, int create, | 355 | struct metapath *mp, int create, |
357 | int *new, u64 *block) | 356 | int *new, u64 *block) |
358 | { | 357 | { |
359 | int boundary; | 358 | int boundary; |
360 | __be64 *ptr = metapointer(bh, &boundary, height, mp); | 359 | __be64 *ptr = metapointer(&boundary, height, mp); |
361 | 360 | ||
362 | if (*ptr) { | 361 | if (*ptr) { |
363 | *block = be64_to_cpu(*ptr); | 362 | *block = be64_to_cpu(*ptr); |
@@ -374,7 +373,7 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, | |||
374 | else | 373 | else |
375 | *block = gfs2_alloc_meta(ip); | 374 | *block = gfs2_alloc_meta(ip); |
376 | 375 | ||
377 | gfs2_trans_add_bh(ip->i_gl, bh, 1); | 376 | gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[height], 1); |
378 | 377 | ||
379 | *ptr = cpu_to_be64(*block); | 378 | *ptr = cpu_to_be64(*block); |
380 | ip->i_di.di_blocks++; | 379 | ip->i_di.di_blocks++; |
@@ -385,32 +384,38 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, | |||
385 | } | 384 | } |
386 | 385 | ||
387 | static int lookup_metapath(struct inode *inode, struct metapath *mp, | 386 | static int lookup_metapath(struct inode *inode, struct metapath *mp, |
388 | int create, int *new, u64 *dblock, | 387 | int create, int *new, u64 *dblock) |
389 | struct buffer_head **dibh, struct buffer_head **bh) | ||
390 | { | 388 | { |
389 | struct buffer_head *bh; | ||
391 | struct gfs2_inode *ip = GFS2_I(inode); | 390 | struct gfs2_inode *ip = GFS2_I(inode); |
392 | unsigned int end_of_metadata = ip->i_height - 1; | 391 | unsigned int end_of_metadata = ip->i_height - 1; |
393 | unsigned int x; | 392 | unsigned int x; |
394 | int ret = gfs2_meta_inode_buffer(ip, bh); | 393 | int ret = gfs2_meta_inode_buffer(ip, &bh); |
395 | if (ret) | 394 | if (ret) |
396 | return ret; | 395 | return ret; |
397 | 396 | ||
398 | *dibh = *bh; | 397 | mp->mp_bh[0] = bh; |
399 | get_bh(*dibh); | ||
400 | 398 | ||
401 | for (x = 0; x < end_of_metadata; x++) { | 399 | for (x = 0; x < end_of_metadata; x++) { |
402 | lookup_block(ip, *bh, x, mp, create, new, dblock); | 400 | lookup_block(ip, x, mp, create, new, dblock); |
403 | brelse(*bh); | ||
404 | *bh = NULL; | ||
405 | if (!dblock) | 401 | if (!dblock) |
406 | return 0; | 402 | return 0; |
407 | 403 | ||
408 | ret = gfs2_meta_indirect_buffer(ip, x+1, *dblock, *new, bh); | 404 | ret = gfs2_meta_indirect_buffer(ip, x+1, *dblock, *new, &mp->mp_bh[x+1]); |
409 | if (ret) | 405 | if (ret) |
410 | return ret; | 406 | return ret; |
411 | } | 407 | } |
412 | 408 | ||
413 | return lookup_block(ip, *bh, end_of_metadata, mp, create, new, dblock); | 409 | return lookup_block(ip, end_of_metadata, mp, create, new, dblock); |
410 | } | ||
411 | |||
412 | static void release_metapath(struct metapath *mp) | ||
413 | { | ||
414 | int i; | ||
415 | |||
416 | for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) | ||
417 | if (mp->mp_bh[i]) | ||
418 | brelse(mp->mp_bh[i]); | ||
414 | } | 419 | } |
415 | 420 | ||
416 | static inline void bmap_lock(struct inode *inode, int create) | 421 | static inline void bmap_lock(struct inode *inode, int create) |
@@ -449,7 +454,6 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, | |||
449 | struct gfs2_inode *ip = GFS2_I(inode); | 454 | struct gfs2_inode *ip = GFS2_I(inode); |
450 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 455 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
451 | unsigned int bsize = sdp->sd_sb.sb_bsize; | 456 | unsigned int bsize = sdp->sd_sb.sb_bsize; |
452 | struct buffer_head *bh = NULL; | ||
453 | int error = 0; | 457 | int error = 0; |
454 | int new = 0; | 458 | int new = 0; |
455 | u64 dblock = 0; | 459 | u64 dblock = 0; |
@@ -457,13 +461,13 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, | |||
457 | unsigned int maxlen = bh_map->b_size >> inode->i_blkbits; | 461 | unsigned int maxlen = bh_map->b_size >> inode->i_blkbits; |
458 | struct metapath mp; | 462 | struct metapath mp; |
459 | u64 size; | 463 | u64 size; |
460 | struct buffer_head *dibh = NULL; | ||
461 | const u64 *arr = sdp->sd_heightsize; | 464 | const u64 *arr = sdp->sd_heightsize; |
462 | BUG_ON(maxlen == 0); | 465 | BUG_ON(maxlen == 0); |
463 | 466 | ||
464 | if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) | 467 | if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) |
465 | return 0; | 468 | return 0; |
466 | 469 | ||
470 | memset(mp.mp_bh, 0, sizeof(mp.mp_bh)); | ||
467 | bmap_lock(inode, create); | 471 | bmap_lock(inode, create); |
468 | clear_buffer_mapped(bh_map); | 472 | clear_buffer_mapped(bh_map); |
469 | clear_buffer_new(bh_map); | 473 | clear_buffer_new(bh_map); |
@@ -480,13 +484,13 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, | |||
480 | goto out_ok; | 484 | goto out_ok; |
481 | while (size > arr[height]) | 485 | while (size > arr[height]) |
482 | height++; | 486 | height++; |
483 | error = build_height(inode, height); | 487 | error = build_height(inode, &mp, height); |
484 | if (error) | 488 | if (error) |
485 | goto out_fail; | 489 | goto out_fail; |
486 | } | 490 | } |
487 | 491 | ||
488 | find_metapath(ip, lblock, &mp); | 492 | find_metapath(ip, lblock, &mp); |
489 | error = lookup_metapath(inode, &mp, create, &new, &dblock, &dibh, &bh); | 493 | error = lookup_metapath(inode, &mp, create, &new, &dblock); |
490 | if (error < 0) | 494 | if (error < 0) |
491 | goto out_fail; | 495 | goto out_fail; |
492 | boundary = error; | 496 | boundary = error; |
@@ -496,17 +500,15 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, | |||
496 | if (boundary) | 500 | if (boundary) |
497 | set_buffer_boundary(bh_map); | 501 | set_buffer_boundary(bh_map); |
498 | if (new) { | 502 | if (new) { |
499 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 503 | gfs2_trans_add_bh(ip->i_gl, mp.mp_bh[0], 1); |
500 | gfs2_dinode_out(ip, dibh->b_data); | 504 | gfs2_dinode_out(ip, mp.mp_bh[0]->b_data); |
501 | set_buffer_new(bh_map); | 505 | set_buffer_new(bh_map); |
502 | goto out_brelse; | 506 | goto out_ok; |
503 | } | 507 | } |
504 | while(--maxlen && !buffer_boundary(bh_map)) { | 508 | while(--maxlen && !buffer_boundary(bh_map)) { |
505 | unsigned int end_of_metadata = ip->i_height - 1; | ||
506 | u64 eblock; | 509 | u64 eblock; |
507 | 510 | mp.mp_list[ip->i_height - 1]++; | |
508 | mp.mp_list[end_of_metadata]++; | 511 | boundary = lookup_block(ip, ip->i_height - 1, &mp, 0, &new, &eblock); |
509 | boundary = lookup_block(ip, bh, end_of_metadata, &mp, 0, &new, &eblock); | ||
510 | if (eblock != ++dblock) | 512 | if (eblock != ++dblock) |
511 | break; | 513 | break; |
512 | bh_map->b_size += (1 << inode->i_blkbits); | 514 | bh_map->b_size += (1 << inode->i_blkbits); |
@@ -514,14 +516,10 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, | |||
514 | set_buffer_boundary(bh_map); | 516 | set_buffer_boundary(bh_map); |
515 | } | 517 | } |
516 | } | 518 | } |
517 | out_brelse: | ||
518 | if (bh) | ||
519 | brelse(bh); | ||
520 | out_ok: | 519 | out_ok: |
521 | error = 0; | 520 | error = 0; |
522 | out_fail: | 521 | out_fail: |
523 | if (dibh) | 522 | release_metapath(&mp); |
524 | brelse(dibh); | ||
525 | bmap_unlock(inode, create); | 523 | bmap_unlock(inode, create); |
526 | return error; | 524 | return error; |
527 | } | 525 | } |
@@ -819,10 +817,11 @@ static int do_grow(struct gfs2_inode *ip, u64 size) | |||
819 | 817 | ||
820 | down_write(&ip->i_rw_mutex); | 818 | down_write(&ip->i_rw_mutex); |
821 | if (size > arr[ip->i_height]) { | 819 | if (size > arr[ip->i_height]) { |
820 | struct metapath mp; | ||
822 | u8 height = ip->i_height; | 821 | u8 height = ip->i_height; |
823 | while(size > arr[height]) | 822 | while(size > arr[height]) |
824 | height++; | 823 | height++; |
825 | error = build_height(&ip->i_inode, height); | 824 | error = build_height(&ip->i_inode, &mp, height); |
826 | } | 825 | } |
827 | up_write(&ip->i_rw_mutex); | 826 | up_write(&ip->i_rw_mutex); |
828 | if (error) | 827 | if (error) |