aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/gfs2/bmap.c97
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 */
35struct metapath { 35struct 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
188static int build_height(struct inode *inode, unsigned height) 189static 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
326static inline __be64 *metapointer(struct buffer_head *bh, int *boundary, 325static 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
355static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, 354static 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
387static int lookup_metapath(struct inode *inode, struct metapath *mp, 386static 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
412static 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
416static inline void bmap_lock(struct inode *inode, int create) 421static 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 }
517out_brelse:
518 if (bh)
519 brelse(bh);
520out_ok: 519out_ok:
521 error = 0; 520 error = 0;
522out_fail: 521out_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)