diff options
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/bmap.c | 68 |
1 files changed, 52 insertions, 16 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 7f72564e0597..6780aa5841b2 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -422,6 +422,42 @@ static void release_metapath(struct metapath *mp) | |||
422 | brelse(mp->mp_bh[i]); | 422 | brelse(mp->mp_bh[i]); |
423 | } | 423 | } |
424 | 424 | ||
425 | /** | ||
426 | * gfs2_extent_length - Returns length of an extent of blocks | ||
427 | * @start: Start of the buffer | ||
428 | * @len: Length of the buffer in bytes | ||
429 | * @ptr: Current position in the buffer | ||
430 | * @limit: Max extent length to return (0 = unlimited) | ||
431 | * @eob: Set to 1 if we hit "end of block" | ||
432 | * | ||
433 | * If the first block is zero (unallocated) it will return the number of | ||
434 | * unallocated blocks in the extent, otherwise it will return the number | ||
435 | * of contiguous blocks in the extent. | ||
436 | * | ||
437 | * Returns: The length of the extent (minimum of one block) | ||
438 | */ | ||
439 | |||
440 | static inline unsigned int gfs2_extent_length(void *start, unsigned int len, __be64 *ptr, unsigned limit, int *eob) | ||
441 | { | ||
442 | const __be64 *end = (start + len); | ||
443 | const __be64 *first = ptr; | ||
444 | u64 d = be64_to_cpu(*ptr); | ||
445 | |||
446 | *eob = 0; | ||
447 | do { | ||
448 | ptr++; | ||
449 | if (ptr >= end) | ||
450 | break; | ||
451 | if (limit && --limit == 0) | ||
452 | break; | ||
453 | if (d) | ||
454 | d++; | ||
455 | } while(be64_to_cpu(*ptr) == d); | ||
456 | if (ptr >= end) | ||
457 | *eob = 1; | ||
458 | return (ptr - first); | ||
459 | } | ||
460 | |||
425 | static inline void bmap_lock(struct inode *inode, int create) | 461 | static inline void bmap_lock(struct inode *inode, int create) |
426 | { | 462 | { |
427 | struct gfs2_inode *ip = GFS2_I(inode); | 463 | struct gfs2_inode *ip = GFS2_I(inode); |
@@ -499,26 +535,26 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, | |||
499 | goto out_fail; | 535 | goto out_fail; |
500 | boundary = error; | 536 | boundary = error; |
501 | 537 | ||
538 | if (new) { | ||
539 | map_bh(bh_map, inode->i_sb, dblock); | ||
540 | if (boundary) | ||
541 | set_buffer_boundary(bh_map); | ||
542 | gfs2_trans_add_bh(ip->i_gl, mp.mp_bh[0], 1); | ||
543 | gfs2_dinode_out(ip, mp.mp_bh[0]->b_data); | ||
544 | set_buffer_new(bh_map); | ||
545 | goto out_ok; | ||
546 | } | ||
547 | |||
502 | if (dblock) { | 548 | if (dblock) { |
549 | unsigned int len; | ||
550 | struct buffer_head *bh = mp.mp_bh[ip->i_height - 1]; | ||
551 | __be64 *ptr = metapointer(&boundary, ip->i_height - 1, &mp); | ||
503 | map_bh(bh_map, inode->i_sb, dblock); | 552 | map_bh(bh_map, inode->i_sb, dblock); |
553 | len = gfs2_extent_length(bh->b_data, bh->b_size, ptr, maxlen, | ||
554 | &boundary); | ||
555 | bh_map->b_size = (len << inode->i_blkbits); | ||
504 | if (boundary) | 556 | if (boundary) |
505 | set_buffer_boundary(bh_map); | 557 | set_buffer_boundary(bh_map); |
506 | if (new) { | ||
507 | gfs2_trans_add_bh(ip->i_gl, mp.mp_bh[0], 1); | ||
508 | gfs2_dinode_out(ip, mp.mp_bh[0]->b_data); | ||
509 | set_buffer_new(bh_map); | ||
510 | goto out_ok; | ||
511 | } | ||
512 | while(--maxlen && !buffer_boundary(bh_map)) { | ||
513 | u64 eblock; | ||
514 | mp.mp_list[ip->i_height - 1]++; | ||
515 | boundary = lookup_block(ip, ip->i_height - 1, &mp, 0, &new, &eblock); | ||
516 | if (eblock != ++dblock) | ||
517 | break; | ||
518 | bh_map->b_size += (1 << inode->i_blkbits); | ||
519 | if (boundary) | ||
520 | set_buffer_boundary(bh_map); | ||
521 | } | ||
522 | } | 558 | } |
523 | out_ok: | 559 | out_ok: |
524 | error = 0; | 560 | error = 0; |