diff options
Diffstat (limited to 'fs/gfs2/bmap.c')
| -rw-r--r-- | fs/gfs2/bmap.c | 170 |
1 files changed, 108 insertions, 62 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index cfe1a428c668..474b9a16f0f5 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
| @@ -314,13 +314,17 @@ static void find_metapath(struct gfs2_inode *ip, uint64_t block, | |||
| 314 | * metadata tree. | 314 | * metadata tree. |
| 315 | */ | 315 | */ |
| 316 | 316 | ||
| 317 | static inline uint64_t *metapointer(struct buffer_head *bh, | 317 | static inline u64 *metapointer(struct buffer_head *bh, int *boundary, |
| 318 | unsigned int height, struct metapath *mp) | 318 | unsigned int height, const struct metapath *mp) |
| 319 | { | 319 | { |
| 320 | unsigned int head_size = (height > 0) ? | 320 | unsigned int head_size = (height > 0) ? |
| 321 | sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode); | 321 | sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode); |
| 322 | 322 | u64 *ptr; | |
| 323 | return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height]; | 323 | *boundary = 0; |
| 324 | ptr = ((u64 *)(bh->b_data + head_size)) + mp->mp_list[height]; | ||
| 325 | if (ptr + 1 == (u64*)(bh->b_data + bh->b_size)) | ||
| 326 | *boundary = 1; | ||
| 327 | return ptr; | ||
| 324 | } | 328 | } |
| 325 | 329 | ||
| 326 | /** | 330 | /** |
| @@ -339,24 +343,24 @@ static inline uint64_t *metapointer(struct buffer_head *bh, | |||
| 339 | * | 343 | * |
| 340 | */ | 344 | */ |
| 341 | 345 | ||
| 342 | static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, | 346 | static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, |
| 343 | unsigned int height, struct metapath *mp, int create, | 347 | unsigned int height, struct metapath *mp, int create, |
| 344 | int *new, uint64_t *block) | 348 | int *new, uint64_t *block) |
| 345 | { | 349 | { |
| 346 | uint64_t *ptr = metapointer(bh, height, mp); | 350 | int boundary; |
| 351 | uint64_t *ptr = metapointer(bh, &boundary, height, mp); | ||
| 347 | 352 | ||
| 348 | if (*ptr) { | 353 | if (*ptr) { |
| 349 | *block = be64_to_cpu(*ptr); | 354 | *block = be64_to_cpu(*ptr); |
| 350 | return; | 355 | return boundary; |
| 351 | } | 356 | } |
| 352 | 357 | ||
| 353 | *block = 0; | 358 | *block = 0; |
| 354 | 359 | ||
| 355 | if (!create) | 360 | if (!create) |
| 356 | return; | 361 | return 0; |
| 357 | 362 | ||
| 358 | if (height == ip->i_di.di_height - 1 && | 363 | if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip)) |
| 359 | !gfs2_is_dir(ip)) | ||
| 360 | *block = gfs2_alloc_data(ip); | 364 | *block = gfs2_alloc_data(ip); |
| 361 | else | 365 | else |
| 362 | *block = gfs2_alloc_meta(ip); | 366 | *block = gfs2_alloc_meta(ip); |
| @@ -367,15 +371,16 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 367 | ip->i_di.di_blocks++; | 371 | ip->i_di.di_blocks++; |
| 368 | 372 | ||
| 369 | *new = 1; | 373 | *new = 1; |
| 374 | return 0; | ||
| 370 | } | 375 | } |
| 371 | 376 | ||
| 372 | /** | 377 | /** |
| 373 | * gfs2_block_map - Map a block from an inode to a disk block | 378 | * gfs2_block_pointers - Map a block from an inode to a disk block |
| 374 | * @ip: The GFS2 inode | 379 | * @inode: The inode |
| 375 | * @lblock: The logical block number | 380 | * @lblock: The logical block number |
| 376 | * @new: Value/Result argument (1 = may create/did create new blocks) | 381 | * @new: Value/Result argument (1 = may create/did create new blocks) |
| 377 | * @dblock: the disk block number of the start of an extent | 382 | * @boundary: gets set if we've hit a block boundary |
| 378 | * @extlen: the size of the extent | 383 | * @mp: metapath to use |
| 379 | * | 384 | * |
| 380 | * Find the block number on the current device which corresponds to an | 385 | * Find the block number on the current device which corresponds to an |
| 381 | * inode's block. If the block had to be created, "new" will be set. | 386 | * inode's block. If the block had to be created, "new" will be set. |
| @@ -383,12 +388,14 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 383 | * Returns: errno | 388 | * Returns: errno |
| 384 | */ | 389 | */ |
| 385 | 390 | ||
| 386 | int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, | 391 | static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock, |
| 387 | uint64_t *dblock, uint32_t *extlen) | 392 | int *new, u64 *dblock, |
| 393 | int *boundary, | ||
| 394 | struct metapath *mp) | ||
| 388 | { | 395 | { |
| 396 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
| 389 | struct gfs2_sbd *sdp = ip->i_sbd; | 397 | struct gfs2_sbd *sdp = ip->i_sbd; |
| 390 | struct buffer_head *bh; | 398 | struct buffer_head *bh; |
| 391 | struct metapath mp; | ||
| 392 | int create = *new; | 399 | int create = *new; |
| 393 | unsigned int bsize; | 400 | unsigned int bsize; |
| 394 | unsigned int height; | 401 | unsigned int height; |
| @@ -398,13 +405,6 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, | |||
| 398 | 405 | ||
| 399 | *new = 0; | 406 | *new = 0; |
| 400 | *dblock = 0; | 407 | *dblock = 0; |
| 401 | if (extlen) | ||
| 402 | *extlen = 0; | ||
| 403 | |||
| 404 | if (create) | ||
| 405 | down_write(&ip->i_rw_mutex); | ||
| 406 | else | ||
| 407 | down_read(&ip->i_rw_mutex); | ||
| 408 | 408 | ||
| 409 | if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) | 409 | if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) |
| 410 | goto out; | 410 | goto out; |
| @@ -421,7 +421,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, | |||
| 421 | goto out; | 421 | goto out; |
| 422 | } | 422 | } |
| 423 | 423 | ||
| 424 | find_metapath(ip, lblock, &mp); | 424 | find_metapath(ip, lblock, mp); |
| 425 | end_of_metadata = ip->i_di.di_height - 1; | 425 | end_of_metadata = ip->i_di.di_height - 1; |
| 426 | 426 | ||
| 427 | error = gfs2_meta_inode_buffer(ip, &bh); | 427 | error = gfs2_meta_inode_buffer(ip, &bh); |
| @@ -429,7 +429,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, | |||
| 429 | goto out; | 429 | goto out; |
| 430 | 430 | ||
| 431 | for (x = 0; x < end_of_metadata; x++) { | 431 | for (x = 0; x < end_of_metadata; x++) { |
| 432 | lookup_block(ip, bh, x, &mp, create, new, dblock); | 432 | lookup_block(ip, bh, x, mp, create, new, dblock); |
| 433 | brelse(bh); | 433 | brelse(bh); |
| 434 | if (!*dblock) | 434 | if (!*dblock) |
| 435 | goto out; | 435 | goto out; |
| @@ -439,49 +439,95 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new, | |||
| 439 | goto out; | 439 | goto out; |
| 440 | } | 440 | } |
| 441 | 441 | ||
| 442 | lookup_block(ip, bh, end_of_metadata, &mp, create, new, dblock); | 442 | *boundary = lookup_block(ip, bh, end_of_metadata, mp, create, new, dblock); |
| 443 | |||
| 444 | if (extlen && *dblock) { | ||
| 445 | *extlen = 1; | ||
| 446 | |||
| 447 | if (!*new) { | ||
| 448 | uint64_t tmp_dblock; | ||
| 449 | int tmp_new; | ||
| 450 | unsigned int nptrs; | ||
| 451 | |||
| 452 | nptrs = (end_of_metadata) ? sdp->sd_inptrs : | ||
| 453 | sdp->sd_diptrs; | ||
| 454 | |||
| 455 | while (++mp.mp_list[end_of_metadata] < nptrs) { | ||
| 456 | lookup_block(ip, bh, end_of_metadata, &mp, | ||
| 457 | 0, &tmp_new, &tmp_dblock); | ||
| 458 | |||
| 459 | if (*dblock + *extlen != tmp_dblock) | ||
| 460 | break; | ||
| 461 | |||
| 462 | (*extlen)++; | ||
| 463 | } | ||
| 464 | } | ||
| 465 | } | ||
| 466 | |||
| 467 | brelse(bh); | ||
| 468 | |||
| 469 | if (*new) { | 443 | if (*new) { |
| 470 | error = gfs2_meta_inode_buffer(ip, &bh); | 444 | struct buffer_head *dibh; |
| 445 | error = gfs2_meta_inode_buffer(ip, &dibh); | ||
| 471 | if (!error) { | 446 | if (!error) { |
| 472 | gfs2_trans_add_bh(ip->i_gl, bh, 1); | 447 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
| 473 | gfs2_dinode_out(&ip->i_di, bh->b_data); | 448 | gfs2_dinode_out(&ip->i_di, dibh->b_data); |
| 474 | brelse(bh); | 449 | brelse(dibh); |
| 475 | } | 450 | } |
| 476 | } | 451 | } |
| 452 | return bh; | ||
| 453 | out: | ||
| 454 | return ERR_PTR(error); | ||
| 455 | } | ||
| 477 | 456 | ||
| 478 | out: | 457 | |
| 458 | static inline void bmap_lock(struct inode *inode, int create) | ||
| 459 | { | ||
| 460 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
| 461 | if (create) | ||
| 462 | down_write(&ip->i_rw_mutex); | ||
| 463 | else | ||
| 464 | down_read(&ip->i_rw_mutex); | ||
| 465 | } | ||
| 466 | |||
| 467 | static inline void bmap_unlock(struct inode *inode, int create) | ||
| 468 | { | ||
| 469 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
| 479 | if (create) | 470 | if (create) |
| 480 | up_write(&ip->i_rw_mutex); | 471 | up_write(&ip->i_rw_mutex); |
| 481 | else | 472 | else |
| 482 | up_read(&ip->i_rw_mutex); | 473 | up_read(&ip->i_rw_mutex); |
| 474 | } | ||
| 483 | 475 | ||
| 484 | return error; | 476 | int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary) |
| 477 | { | ||
| 478 | struct metapath mp; | ||
| 479 | struct buffer_head *bh; | ||
| 480 | int create = *new; | ||
| 481 | |||
| 482 | bmap_lock(inode, create); | ||
| 483 | bh = gfs2_block_pointers(inode, lblock, new, dblock, boundary, &mp); | ||
| 484 | bmap_unlock(inode, create); | ||
| 485 | if (!bh) | ||
| 486 | return 0; | ||
| 487 | if (IS_ERR(bh)) | ||
| 488 | return PTR_ERR(bh); | ||
| 489 | brelse(bh); | ||
| 490 | return 0; | ||
| 491 | } | ||
| 492 | |||
| 493 | int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) | ||
| 494 | { | ||
| 495 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
| 496 | struct gfs2_sbd *sdp = ip->i_sbd; | ||
| 497 | struct metapath mp; | ||
| 498 | struct buffer_head *bh; | ||
| 499 | int boundary; | ||
| 500 | int create = *new; | ||
| 501 | |||
| 502 | BUG_ON(!extlen); | ||
| 503 | BUG_ON(!dblock); | ||
| 504 | BUG_ON(!new); | ||
| 505 | |||
| 506 | bmap_lock(inode, create); | ||
| 507 | bh = gfs2_block_pointers(inode, lblock, new, dblock, &boundary, &mp); | ||
| 508 | *extlen = 1; | ||
| 509 | |||
| 510 | if (bh && !IS_ERR(bh) && *dblock && !*new) { | ||
| 511 | u64 tmp_dblock; | ||
| 512 | int tmp_new; | ||
| 513 | unsigned int nptrs; | ||
| 514 | unsigned end_of_metadata = ip->i_di.di_height - 1; | ||
| 515 | |||
| 516 | nptrs = (end_of_metadata) ? sdp->sd_inptrs : sdp->sd_diptrs; | ||
| 517 | while (++mp.mp_list[end_of_metadata] < nptrs) { | ||
| 518 | lookup_block(ip, bh, end_of_metadata, &mp, 0, &tmp_new, &tmp_dblock); | ||
| 519 | if (*dblock + *extlen != tmp_dblock) | ||
| 520 | break; | ||
| 521 | (*extlen)++; | ||
| 522 | } | ||
| 523 | } | ||
| 524 | bmap_unlock(inode, create); | ||
| 525 | if (!bh) | ||
| 526 | return 0; | ||
| 527 | if (IS_ERR(bh)) | ||
| 528 | return PTR_ERR(bh); | ||
| 529 | brelse(bh); | ||
| 530 | return 0; | ||
| 485 | } | 531 | } |
| 486 | 532 | ||
| 487 | /** | 533 | /** |
| @@ -1053,7 +1099,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset, | |||
| 1053 | } | 1099 | } |
| 1054 | 1100 | ||
| 1055 | for (; lblock < lblock_stop; lblock += extlen) { | 1101 | for (; lblock < lblock_stop; lblock += extlen) { |
| 1056 | error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); | 1102 | error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen); |
| 1057 | if (error) | 1103 | if (error) |
| 1058 | return error; | 1104 | return error; |
| 1059 | 1105 | ||
