diff options
-rw-r--r-- | fs/gfs2/bmap.c | 170 | ||||
-rw-r--r-- | fs/gfs2/bmap.h | 5 | ||||
-rw-r--r-- | fs/gfs2/dir.c | 8 | ||||
-rw-r--r-- | fs/gfs2/glock.c | 2 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 5 | ||||
-rw-r--r-- | fs/gfs2/log.c | 4 | ||||
-rw-r--r-- | fs/gfs2/ops_address.c | 145 | ||||
-rw-r--r-- | fs/gfs2/ops_super.c | 3 | ||||
-rw-r--r-- | fs/gfs2/ops_vm.c | 8 | ||||
-rw-r--r-- | fs/gfs2/quota.c | 5 | ||||
-rw-r--r-- | fs/gfs2/recovery.c | 8 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 15 | ||||
-rw-r--r-- | fs/gfs2/unlinked.c | 5 |
13 files changed, 254 insertions, 129 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 | ||
diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h index 23fb6589d5e3..bc46c1149120 100644 --- a/fs/gfs2/bmap.h +++ b/fs/gfs2/bmap.h | |||
@@ -16,9 +16,8 @@ typedef int (*gfs2_unstuffer_t) (struct gfs2_inode * ip, | |||
16 | int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, | 16 | int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer, |
17 | void *private); | 17 | void *private); |
18 | 18 | ||
19 | int gfs2_block_map(struct gfs2_inode *ip, | 19 | int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary); |
20 | uint64_t lblock, int *new, | 20 | int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen); |
21 | uint64_t *dblock, uint32_t *extlen); | ||
22 | 21 | ||
23 | int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size); | 22 | int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size); |
24 | int gfs2_truncatei_resume(struct gfs2_inode *ip); | 23 | int gfs2_truncatei_resume(struct gfs2_inode *ip); |
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 0404783f39b3..7f8b27e40916 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c | |||
@@ -197,8 +197,8 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, | |||
197 | 197 | ||
198 | if (!extlen) { | 198 | if (!extlen) { |
199 | new = 1; | 199 | new = 1; |
200 | error = gfs2_block_map(ip, lblock, &new, &dblock, | 200 | error = gfs2_extent_map(ip->i_vnode, lblock, &new, |
201 | &extlen); | 201 | &dblock, &extlen); |
202 | if (error) | 202 | if (error) |
203 | goto fail; | 203 | goto fail; |
204 | error = -EIO; | 204 | error = -EIO; |
@@ -314,8 +314,8 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, | |||
314 | 314 | ||
315 | if (!extlen) { | 315 | if (!extlen) { |
316 | new = 0; | 316 | new = 0; |
317 | error = gfs2_block_map(ip, lblock, &new, &dblock, | 317 | error = gfs2_extent_map(ip->i_vnode, lblock, &new, |
318 | &extlen); | 318 | &dblock, &extlen); |
319 | if (error) | 319 | if (error) |
320 | goto fail; | 320 | goto fail; |
321 | } | 321 | } |
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 4fb8066dc745..9d4ae094fa2d 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -2125,7 +2125,7 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait) | |||
2125 | mutex_lock(&sdp->sd_invalidate_inodes_mutex); | 2125 | mutex_lock(&sdp->sd_invalidate_inodes_mutex); |
2126 | invalidate_inodes(sdp->sd_vfs); | 2126 | invalidate_inodes(sdp->sd_vfs); |
2127 | mutex_unlock(&sdp->sd_invalidate_inodes_mutex); | 2127 | mutex_unlock(&sdp->sd_invalidate_inodes_mutex); |
2128 | yield(); | 2128 | msleep(10); |
2129 | } | 2129 | } |
2130 | } | 2130 | } |
2131 | 2131 | ||
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 9084d6037a0c..0817f6ede188 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -1606,9 +1606,8 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh) | |||
1606 | curtime = get_seconds(); | 1606 | curtime = get_seconds(); |
1607 | if (curtime - ip->i_di.di_atime >= quantum) { | 1607 | if (curtime - ip->i_di.di_atime >= quantum) { |
1608 | gfs2_glock_dq(gh); | 1608 | gfs2_glock_dq(gh); |
1609 | gfs2_holder_reinit(LM_ST_EXCLUSIVE, | 1609 | gfs2_holder_reinit(LM_ST_EXCLUSIVE, gh->gh_flags & ~LM_FLAG_ANY, |
1610 | gh->gh_flags & ~LM_FLAG_ANY, | 1610 | gh); |
1611 | gh); | ||
1612 | error = gfs2_glock_nq(gh); | 1611 | error = gfs2_glock_nq(gh); |
1613 | if (error) | 1612 | if (error) |
1614 | return error; | 1613 | return error; |
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 134fc57e21d3..02d31e35f0ca 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
@@ -211,9 +211,9 @@ static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) | |||
211 | int new = 0; | 211 | int new = 0; |
212 | uint64_t dbn; | 212 | uint64_t dbn; |
213 | int error; | 213 | int error; |
214 | int bdy; | ||
214 | 215 | ||
215 | error = gfs2_block_map(sdp->sd_jdesc->jd_inode->u.generic_ip, | 216 | error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, &new, &dbn, &bdy); |
216 | lbn, &new, &dbn, NULL); | ||
217 | gfs2_assert_withdraw(sdp, !error && dbn); | 217 | gfs2_assert_withdraw(sdp, !error && dbn); |
218 | 218 | ||
219 | return dbn; | 219 | return dbn; |
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index afcc12a00a3c..d89179b316fe 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/completion.h> | 13 | #include <linux/completion.h> |
14 | #include <linux/buffer_head.h> | 14 | #include <linux/buffer_head.h> |
15 | #include <linux/pagemap.h> | 15 | #include <linux/pagemap.h> |
16 | #include <linux/pagevec.h> | ||
16 | #include <linux/mpage.h> | 17 | #include <linux/mpage.h> |
17 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
18 | #include <linux/gfs2_ondisk.h> | 19 | #include <linux/gfs2_ondisk.h> |
@@ -47,12 +48,12 @@ | |||
47 | int gfs2_get_block(struct inode *inode, sector_t lblock, | 48 | int gfs2_get_block(struct inode *inode, sector_t lblock, |
48 | struct buffer_head *bh_result, int create) | 49 | struct buffer_head *bh_result, int create) |
49 | { | 50 | { |
50 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
51 | int new = create; | 51 | int new = create; |
52 | uint64_t dblock; | 52 | uint64_t dblock; |
53 | int error; | 53 | int error; |
54 | int boundary; | ||
54 | 55 | ||
55 | error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); | 56 | error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary); |
56 | if (error) | 57 | if (error) |
57 | return error; | 58 | return error; |
58 | 59 | ||
@@ -62,6 +63,8 @@ int gfs2_get_block(struct inode *inode, sector_t lblock, | |||
62 | map_bh(bh_result, inode->i_sb, dblock); | 63 | map_bh(bh_result, inode->i_sb, dblock); |
63 | if (new) | 64 | if (new) |
64 | set_buffer_new(bh_result); | 65 | set_buffer_new(bh_result); |
66 | if (boundary) | ||
67 | set_buffer_boundary(bh_result); | ||
65 | 68 | ||
66 | return 0; | 69 | return 0; |
67 | } | 70 | } |
@@ -83,8 +86,9 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock, | |||
83 | int new = 0; | 86 | int new = 0; |
84 | uint64_t dblock; | 87 | uint64_t dblock; |
85 | int error; | 88 | int error; |
89 | int boundary; | ||
86 | 90 | ||
87 | error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); | 91 | error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary); |
88 | if (error) | 92 | if (error) |
89 | return error; | 93 | return error; |
90 | 94 | ||
@@ -92,6 +96,8 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock, | |||
92 | map_bh(bh_result, inode->i_sb, dblock); | 96 | map_bh(bh_result, inode->i_sb, dblock); |
93 | else if (gfs2_assert_withdraw(ip->i_sbd, !create)) | 97 | else if (gfs2_assert_withdraw(ip->i_sbd, !create)) |
94 | error = -EIO; | 98 | error = -EIO; |
99 | if (boundary) | ||
100 | set_buffer_boundary(bh_result); | ||
95 | 101 | ||
96 | return error; | 102 | return error; |
97 | } | 103 | } |
@@ -151,6 +157,19 @@ out_ignore: | |||
151 | return 0; | 157 | return 0; |
152 | } | 158 | } |
153 | 159 | ||
160 | static int zero_readpage(struct page *page) | ||
161 | { | ||
162 | void *kaddr; | ||
163 | |||
164 | kaddr = kmap_atomic(page, KM_USER0); | ||
165 | memset(kaddr, 0, PAGE_CACHE_SIZE); | ||
166 | kunmap_atomic(page, KM_USER0); | ||
167 | |||
168 | SetPageUptodate(page); | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
154 | /** | 173 | /** |
155 | * stuffed_readpage - Fill in a Linux page with stuffed file data | 174 | * stuffed_readpage - Fill in a Linux page with stuffed file data |
156 | * @ip: the inode | 175 | * @ip: the inode |
@@ -165,17 +184,18 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) | |||
165 | void *kaddr; | 184 | void *kaddr; |
166 | int error; | 185 | int error; |
167 | 186 | ||
187 | /* Only the first page of a stuffed file might contain data */ | ||
188 | if (unlikely(page->index)) | ||
189 | return zero_readpage(page); | ||
190 | |||
168 | error = gfs2_meta_inode_buffer(ip, &dibh); | 191 | error = gfs2_meta_inode_buffer(ip, &dibh); |
169 | if (error) | 192 | if (error) |
170 | return error; | 193 | return error; |
171 | 194 | ||
172 | kaddr = kmap_atomic(page, KM_USER0); | 195 | kaddr = kmap_atomic(page, KM_USER0); |
173 | memcpy((char *)kaddr, | 196 | memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), |
174 | dibh->b_data + sizeof(struct gfs2_dinode), | ||
175 | ip->i_di.di_size); | 197 | ip->i_di.di_size); |
176 | memset((char *)kaddr + ip->i_di.di_size, | 198 | memset(kaddr + ip->i_di.di_size, 0, PAGE_CACHE_SIZE - ip->i_di.di_size); |
177 | 0, | ||
178 | PAGE_CACHE_SIZE - ip->i_di.di_size); | ||
179 | kunmap_atomic(page, KM_USER0); | 199 | kunmap_atomic(page, KM_USER0); |
180 | 200 | ||
181 | brelse(dibh); | 201 | brelse(dibh); |
@@ -185,19 +205,6 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) | |||
185 | return 0; | 205 | return 0; |
186 | } | 206 | } |
187 | 207 | ||
188 | static int zero_readpage(struct page *page) | ||
189 | { | ||
190 | void *kaddr; | ||
191 | |||
192 | kaddr = kmap_atomic(page, KM_USER0); | ||
193 | memset(kaddr, 0, PAGE_CACHE_SIZE); | ||
194 | kunmap_atomic(page, KM_USER0); | ||
195 | |||
196 | SetPageUptodate(page); | ||
197 | unlock_page(page); | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | 208 | ||
202 | /** | 209 | /** |
203 | * gfs2_readpage - readpage with locking | 210 | * gfs2_readpage - readpage with locking |
@@ -215,19 +222,16 @@ static int gfs2_readpage(struct file *file, struct page *page) | |||
215 | struct gfs2_holder gh; | 222 | struct gfs2_holder gh; |
216 | int error; | 223 | int error; |
217 | 224 | ||
218 | if (file != &gfs2_internal_file_sentinal) { | 225 | if (likely(file != &gfs2_internal_file_sentinal)) { |
219 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh); | 226 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh); |
220 | error = gfs2_glock_nq_m_atime(1, &gh); | 227 | error = gfs2_glock_nq_m_atime(1, &gh); |
221 | if (error) | 228 | if (unlikely(error)) |
222 | goto out_unlock; | 229 | goto out_unlock; |
223 | } | 230 | } |
224 | 231 | ||
225 | if (gfs2_is_stuffed(ip)) { | 232 | if (gfs2_is_stuffed(ip)) { |
226 | if (!page->index) { | 233 | error = stuffed_readpage(ip, page); |
227 | error = stuffed_readpage(ip, page); | 234 | unlock_page(page); |
228 | unlock_page(page); | ||
229 | } else | ||
230 | error = zero_readpage(page); | ||
231 | } else | 235 | } else |
232 | error = mpage_readpage(page, gfs2_get_block); | 236 | error = mpage_readpage(page, gfs2_get_block); |
233 | 237 | ||
@@ -242,6 +246,90 @@ out: | |||
242 | return error; | 246 | return error; |
243 | out_unlock: | 247 | out_unlock: |
244 | unlock_page(page); | 248 | unlock_page(page); |
249 | if (file != &gfs2_internal_file_sentinal) | ||
250 | gfs2_holder_uninit(&gh); | ||
251 | goto out; | ||
252 | } | ||
253 | |||
254 | #define list_to_page(head) (list_entry((head)->prev, struct page, lru)) | ||
255 | |||
256 | /** | ||
257 | * gfs2_readpages - Read a bunch of pages at once | ||
258 | * | ||
259 | * Some notes: | ||
260 | * 1. This is only for readahead, so we can simply ignore any things | ||
261 | * which are slightly inconvenient (such as locking conflicts between | ||
262 | * the page lock and the glock) and return having done no I/O. Its | ||
263 | * obviously not something we'd want to do on too regular a basis. | ||
264 | * Any I/O we ignore at this time will be done via readpage later. | ||
265 | * 2. We have to handle stuffed files here too. | ||
266 | * 3. mpage_readpages() does most of the heavy lifting in the common case. | ||
267 | * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places. | ||
268 | * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as | ||
269 | * well as read-ahead. | ||
270 | */ | ||
271 | static int gfs2_readpages(struct file *file, struct address_space *mapping, | ||
272 | struct list_head *pages, unsigned nr_pages) | ||
273 | { | ||
274 | struct inode *inode = mapping->host; | ||
275 | struct gfs2_inode *ip = inode->u.generic_ip; | ||
276 | struct gfs2_sbd *sdp = ip->i_sbd; | ||
277 | struct gfs2_holder gh; | ||
278 | unsigned page_idx; | ||
279 | int ret; | ||
280 | |||
281 | if (likely(file != &gfs2_internal_file_sentinal)) { | ||
282 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, | ||
283 | LM_FLAG_TRY_1CB|GL_ATIME|GL_AOP, &gh); | ||
284 | ret = gfs2_glock_nq_m_atime(1, &gh); | ||
285 | if (ret == GLR_TRYFAILED) | ||
286 | goto out_noerror; | ||
287 | if (unlikely(ret)) | ||
288 | goto out_unlock; | ||
289 | } | ||
290 | |||
291 | if (gfs2_is_stuffed(ip)) { | ||
292 | struct pagevec lru_pvec; | ||
293 | pagevec_init(&lru_pvec, 0); | ||
294 | for (page_idx = 0; page_idx < nr_pages; page_idx++) { | ||
295 | struct page *page = list_to_page(pages); | ||
296 | list_del(&page->lru); | ||
297 | if (!add_to_page_cache(page, mapping, | ||
298 | page->index, GFP_KERNEL)) { | ||
299 | ret = stuffed_readpage(ip, page); | ||
300 | unlock_page(page); | ||
301 | if (!pagevec_add(&lru_pvec, page)) | ||
302 | __pagevec_lru_add(&lru_pvec); | ||
303 | } | ||
304 | page_cache_release(page); | ||
305 | } | ||
306 | pagevec_lru_add(&lru_pvec); | ||
307 | ret = 0; | ||
308 | } else { | ||
309 | /* What we really want to do .... */ | ||
310 | ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block); | ||
311 | } | ||
312 | |||
313 | if (likely(file != &gfs2_internal_file_sentinal)) { | ||
314 | gfs2_glock_dq_m(1, &gh); | ||
315 | gfs2_holder_uninit(&gh); | ||
316 | } | ||
317 | out: | ||
318 | if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) | ||
319 | ret = -EIO; | ||
320 | return ret; | ||
321 | out_noerror: | ||
322 | ret = 0; | ||
323 | out_unlock: | ||
324 | /* unlock all pages, we can't do any I/O right now */ | ||
325 | for (page_idx = 0; page_idx < nr_pages; page_idx++) { | ||
326 | struct page *page = list_to_page(pages); | ||
327 | list_del(&page->lru); | ||
328 | unlock_page(page); | ||
329 | page_cache_release(page); | ||
330 | } | ||
331 | if (likely(file != &gfs2_internal_file_sentinal)) | ||
332 | gfs2_holder_uninit(&gh); | ||
245 | goto out; | 333 | goto out; |
246 | } | 334 | } |
247 | 335 | ||
@@ -572,6 +660,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, | |||
572 | struct address_space_operations gfs2_file_aops = { | 660 | struct address_space_operations gfs2_file_aops = { |
573 | .writepage = gfs2_writepage, | 661 | .writepage = gfs2_writepage, |
574 | .readpage = gfs2_readpage, | 662 | .readpage = gfs2_readpage, |
663 | .readpages = gfs2_readpages, | ||
575 | .sync_page = block_sync_page, | 664 | .sync_page = block_sync_page, |
576 | .prepare_write = gfs2_prepare_write, | 665 | .prepare_write = gfs2_prepare_write, |
577 | .commit_write = gfs2_commit_write, | 666 | .commit_write = gfs2_commit_write, |
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 60bf2563c7b4..5910c7b5c846 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c | |||
@@ -92,7 +92,6 @@ static void gfs2_put_super(struct super_block *sb) | |||
92 | if (error) | 92 | if (error) |
93 | gfs2_io_error(sdp); | 93 | gfs2_io_error(sdp); |
94 | } | 94 | } |
95 | |||
96 | /* At this point, we're through modifying the disk */ | 95 | /* At this point, we're through modifying the disk */ |
97 | 96 | ||
98 | /* Release stuff */ | 97 | /* Release stuff */ |
@@ -125,12 +124,10 @@ static void gfs2_put_super(struct super_block *sb) | |||
125 | gfs2_jindex_free(sdp); | 124 | gfs2_jindex_free(sdp); |
126 | /* Take apart glock structures and buffer lists */ | 125 | /* Take apart glock structures and buffer lists */ |
127 | gfs2_gl_hash_clear(sdp, WAIT); | 126 | gfs2_gl_hash_clear(sdp, WAIT); |
128 | |||
129 | /* Unmount the locking protocol */ | 127 | /* Unmount the locking protocol */ |
130 | gfs2_lm_unmount(sdp); | 128 | gfs2_lm_unmount(sdp); |
131 | 129 | ||
132 | /* At this point, we're through participating in the lockspace */ | 130 | /* At this point, we're through participating in the lockspace */ |
133 | |||
134 | gfs2_sys_fs_del(sdp); | 131 | gfs2_sys_fs_del(sdp); |
135 | vfree(sdp); | 132 | vfree(sdp); |
136 | sb->s_fs_info = NULL; | 133 | sb->s_fs_info = NULL; |
diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index dbc57071e7bb..d67248cae9b9 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c | |||
@@ -90,8 +90,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) | |||
90 | if (error) | 90 | if (error) |
91 | goto out_gunlock_q; | 91 | goto out_gunlock_q; |
92 | 92 | ||
93 | gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, | 93 | gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks); |
94 | &data_blocks, &ind_blocks); | ||
95 | 94 | ||
96 | al->al_requested = data_blocks + ind_blocks; | 95 | al->al_requested = data_blocks + ind_blocks; |
97 | 96 | ||
@@ -99,8 +98,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) | |||
99 | if (error) | 98 | if (error) |
100 | goto out_gunlock_q; | 99 | goto out_gunlock_q; |
101 | 100 | ||
102 | error = gfs2_trans_begin(sdp, | 101 | error = gfs2_trans_begin(sdp, al->al_rgd->rd_ri.ri_length + |
103 | al->al_rgd->rd_ri.ri_length + | ||
104 | ind_blocks + RES_DINODE + | 102 | ind_blocks + RES_DINODE + |
105 | RES_STATFS + RES_QUOTA, 0); | 103 | RES_STATFS + RES_QUOTA, 0); |
106 | if (error) | 104 | if (error) |
@@ -117,7 +115,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) | |||
117 | unsigned int extlen; | 115 | unsigned int extlen; |
118 | int new = 1; | 116 | int new = 1; |
119 | 117 | ||
120 | error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen); | 118 | error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen); |
121 | if (error) | 119 | if (error) |
122 | goto out_trans; | 120 | goto out_trans; |
123 | 121 | ||
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 942c4c8b9f56..d49ff43b3a86 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c | |||
@@ -255,6 +255,7 @@ static int bh_get(struct gfs2_quota_data *qd) | |||
255 | int new = 0; | 255 | int new = 0; |
256 | struct buffer_head *bh; | 256 | struct buffer_head *bh; |
257 | int error; | 257 | int error; |
258 | int boundary; | ||
258 | 259 | ||
259 | mutex_lock(&sdp->sd_quota_mutex); | 260 | mutex_lock(&sdp->sd_quota_mutex); |
260 | 261 | ||
@@ -266,7 +267,7 @@ static int bh_get(struct gfs2_quota_data *qd) | |||
266 | block = qd->qd_slot / sdp->sd_qc_per_block; | 267 | block = qd->qd_slot / sdp->sd_qc_per_block; |
267 | offset = qd->qd_slot % sdp->sd_qc_per_block;; | 268 | offset = qd->qd_slot % sdp->sd_qc_per_block;; |
268 | 269 | ||
269 | error = gfs2_block_map(ip, block, &new, &dblock, NULL); | 270 | error = gfs2_block_map(ip->i_vnode, block, &new, &dblock, &boundary); |
270 | if (error) | 271 | if (error) |
271 | goto fail; | 272 | goto fail; |
272 | error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); | 273 | error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); |
@@ -1162,7 +1163,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) | |||
1162 | 1163 | ||
1163 | if (!extlen) { | 1164 | if (!extlen) { |
1164 | int new = 0; | 1165 | int new = 0; |
1165 | error = gfs2_block_map(ip, x, &new, &dblock, &extlen); | 1166 | error = gfs2_extent_map(ip->i_vnode, x, &new, &dblock, &extlen); |
1166 | if (error) | 1167 | if (error) |
1167 | goto fail; | 1168 | goto fail; |
1168 | } | 1169 | } |
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index d916817fb6e3..87adebea3bc3 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c | |||
@@ -40,8 +40,7 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk, | |||
40 | uint32_t extlen; | 40 | uint32_t extlen; |
41 | int error; | 41 | int error; |
42 | 42 | ||
43 | error = gfs2_block_map(ip, blk, &new, &dblock, | 43 | error = gfs2_extent_map(ip->i_vnode, blk, &new, &dblock, &extlen); |
44 | &extlen); | ||
45 | if (error) | 44 | if (error) |
46 | return error; | 45 | return error; |
47 | if (!dblock) { | 46 | if (!dblock) { |
@@ -378,10 +377,11 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head) | |||
378 | uint32_t hash; | 377 | uint32_t hash; |
379 | struct buffer_head *bh; | 378 | struct buffer_head *bh; |
380 | int error; | 379 | int error; |
381 | 380 | int boundary; | |
381 | |||
382 | lblock = head->lh_blkno; | 382 | lblock = head->lh_blkno; |
383 | gfs2_replay_incr_blk(sdp, &lblock); | 383 | gfs2_replay_incr_blk(sdp, &lblock); |
384 | error = gfs2_block_map(ip, lblock, &new, &dblock, NULL); | 384 | error = gfs2_block_map(ip->i_vnode, lblock, &new, &dblock, &boundary); |
385 | if (error) | 385 | if (error) |
386 | return error; | 386 | return error; |
387 | if (!dblock) { | 387 | if (!dblock) { |
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 4ae559694396..15c326ce13d1 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -956,8 +956,7 @@ static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal, | |||
956 | search in the first part of our first-searched bit block. */ | 956 | search in the first part of our first-searched bit block. */ |
957 | for (x = 0; x <= length; x++) { | 957 | for (x = 0; x <= length; x++) { |
958 | if (bi->bi_clone) | 958 | if (bi->bi_clone) |
959 | blk = gfs2_bitfit(rgd, | 959 | blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset, |
960 | bi->bi_clone + bi->bi_offset, | ||
961 | bi->bi_len, goal, old_state); | 960 | bi->bi_len, goal, old_state); |
962 | else | 961 | else |
963 | blk = gfs2_bitfit(rgd, | 962 | blk = gfs2_bitfit(rgd, |
@@ -976,12 +975,10 @@ static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal, | |||
976 | blk = 0; | 975 | blk = 0; |
977 | 976 | ||
978 | gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); | 977 | gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); |
979 | gfs2_setbit(rgd, | 978 | gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, |
980 | bi->bi_bh->b_data + bi->bi_offset, | ||
981 | bi->bi_len, blk, new_state); | 979 | bi->bi_len, blk, new_state); |
982 | if (bi->bi_clone) | 980 | if (bi->bi_clone) |
983 | gfs2_setbit(rgd, | 981 | gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset, |
984 | bi->bi_clone + bi->bi_offset, | ||
985 | bi->bi_len, blk, new_state); | 982 | bi->bi_len, blk, new_state); |
986 | 983 | ||
987 | return bi->bi_start * GFS2_NBBY + blk; | 984 | return bi->bi_start * GFS2_NBBY + blk; |
@@ -1064,8 +1061,7 @@ uint64_t gfs2_alloc_data(struct gfs2_inode *ip) | |||
1064 | else | 1061 | else |
1065 | goal = rgd->rd_last_alloc_data; | 1062 | goal = rgd->rd_last_alloc_data; |
1066 | 1063 | ||
1067 | blk = rgblk_search(rgd, goal, | 1064 | blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED); |
1068 | GFS2_BLKST_FREE, GFS2_BLKST_USED); | ||
1069 | rgd->rd_last_alloc_data = blk; | 1065 | rgd->rd_last_alloc_data = blk; |
1070 | 1066 | ||
1071 | block = rgd->rd_ri.ri_data0 + blk; | 1067 | block = rgd->rd_ri.ri_data0 + blk; |
@@ -1109,8 +1105,7 @@ uint64_t gfs2_alloc_meta(struct gfs2_inode *ip) | |||
1109 | else | 1105 | else |
1110 | goal = rgd->rd_last_alloc_meta; | 1106 | goal = rgd->rd_last_alloc_meta; |
1111 | 1107 | ||
1112 | blk = rgblk_search(rgd, goal, | 1108 | blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED); |
1113 | GFS2_BLKST_FREE, GFS2_BLKST_USED); | ||
1114 | rgd->rd_last_alloc_meta = blk; | 1109 | rgd->rd_last_alloc_meta = blk; |
1115 | 1110 | ||
1116 | block = rgd->rd_ri.ri_data0 + blk; | 1111 | block = rgd->rd_ri.ri_data0 + blk; |
diff --git a/fs/gfs2/unlinked.c b/fs/gfs2/unlinked.c index 24b91c23bc2d..0d2314a5252c 100644 --- a/fs/gfs2/unlinked.c +++ b/fs/gfs2/unlinked.c | |||
@@ -35,11 +35,12 @@ static int munge_ondisk(struct gfs2_sbd *sdp, unsigned int slot, | |||
35 | int new = 0; | 35 | int new = 0; |
36 | struct buffer_head *bh; | 36 | struct buffer_head *bh; |
37 | int error; | 37 | int error; |
38 | int boundary; | ||
38 | 39 | ||
39 | block = slot / sdp->sd_ut_per_block; | 40 | block = slot / sdp->sd_ut_per_block; |
40 | offset = slot % sdp->sd_ut_per_block; | 41 | offset = slot % sdp->sd_ut_per_block; |
41 | 42 | ||
42 | error = gfs2_block_map(ip, block, &new, &dblock, NULL); | 43 | error = gfs2_block_map(ip->i_vnode, block, &new, &dblock, &boundary); |
43 | if (error) | 44 | if (error) |
44 | return error; | 45 | return error; |
45 | error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); | 46 | error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh); |
@@ -354,7 +355,7 @@ int gfs2_unlinked_init(struct gfs2_sbd *sdp) | |||
354 | 355 | ||
355 | if (!extlen) { | 356 | if (!extlen) { |
356 | int new = 0; | 357 | int new = 0; |
357 | error = gfs2_block_map(ip, x, &new, &dblock, &extlen); | 358 | error = gfs2_extent_map(ip->i_vnode, x, &new, &dblock, &extlen); |
358 | if (error) | 359 | if (error) |
359 | goto fail; | 360 | goto fail; |
360 | } | 361 | } |