diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-14 13:20:42 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-14 13:20:42 -0400 |
| commit | 5dcd07b9f39ca3e9be5bcc387d193fc0674e1c81 (patch) | |
| tree | 8cd651b2743b8af4805e0ae45b660ce8758960ae | |
| parent | 51414d41084496aaefd06d7f19eb8206e8bfac2d (diff) | |
| parent | 380f7c65a7eb3288e4b6812acf3474a1de230707 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes
* git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes:
GFS2: Resolve inode eviction and ail list interaction bug
GFS2: Fix race during filesystem mount
GFS2: force a log flush when invalidating the rindex glock
| -rw-r--r-- | fs/gfs2/aops.c | 3 | ||||
| -rw-r--r-- | fs/gfs2/glops.c | 8 | ||||
| -rw-r--r-- | fs/gfs2/incore.h | 2 | ||||
| -rw-r--r-- | fs/gfs2/log.c | 1 | ||||
| -rw-r--r-- | fs/gfs2/ops_fstype.c | 3 | ||||
| -rw-r--r-- | fs/gfs2/super.c | 36 | ||||
| -rw-r--r-- | fs/gfs2/sys.c | 7 |
7 files changed, 50 insertions, 10 deletions
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 802ac5eeba28..f9fbbe96c222 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c | |||
| @@ -1069,6 +1069,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) | |||
| 1069 | return 0; | 1069 | return 0; |
| 1070 | 1070 | ||
| 1071 | gfs2_log_lock(sdp); | 1071 | gfs2_log_lock(sdp); |
| 1072 | spin_lock(&sdp->sd_ail_lock); | ||
| 1072 | head = bh = page_buffers(page); | 1073 | head = bh = page_buffers(page); |
| 1073 | do { | 1074 | do { |
| 1074 | if (atomic_read(&bh->b_count)) | 1075 | if (atomic_read(&bh->b_count)) |
| @@ -1080,6 +1081,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) | |||
| 1080 | goto not_possible; | 1081 | goto not_possible; |
| 1081 | bh = bh->b_this_page; | 1082 | bh = bh->b_this_page; |
| 1082 | } while(bh != head); | 1083 | } while(bh != head); |
| 1084 | spin_unlock(&sdp->sd_ail_lock); | ||
| 1083 | gfs2_log_unlock(sdp); | 1085 | gfs2_log_unlock(sdp); |
| 1084 | 1086 | ||
| 1085 | head = bh = page_buffers(page); | 1087 | head = bh = page_buffers(page); |
| @@ -1112,6 +1114,7 @@ not_possible: /* Should never happen */ | |||
| 1112 | WARN_ON(buffer_dirty(bh)); | 1114 | WARN_ON(buffer_dirty(bh)); |
| 1113 | WARN_ON(buffer_pinned(bh)); | 1115 | WARN_ON(buffer_pinned(bh)); |
| 1114 | cannot_release: | 1116 | cannot_release: |
| 1117 | spin_unlock(&sdp->sd_ail_lock); | ||
| 1115 | gfs2_log_unlock(sdp); | 1118 | gfs2_log_unlock(sdp); |
| 1116 | return 0; | 1119 | return 0; |
| 1117 | } | 1120 | } |
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 8ef70f464731..2cca29316bd6 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c | |||
| @@ -47,10 +47,10 @@ static void __gfs2_ail_flush(struct gfs2_glock *gl) | |||
| 47 | bd_ail_gl_list); | 47 | bd_ail_gl_list); |
| 48 | bh = bd->bd_bh; | 48 | bh = bd->bd_bh; |
| 49 | gfs2_remove_from_ail(bd); | 49 | gfs2_remove_from_ail(bd); |
| 50 | spin_unlock(&sdp->sd_ail_lock); | ||
| 51 | |||
| 52 | bd->bd_bh = NULL; | 50 | bd->bd_bh = NULL; |
| 53 | bh->b_private = NULL; | 51 | bh->b_private = NULL; |
| 52 | spin_unlock(&sdp->sd_ail_lock); | ||
| 53 | |||
| 54 | bd->bd_blkno = bh->b_blocknr; | 54 | bd->bd_blkno = bh->b_blocknr; |
| 55 | gfs2_log_lock(sdp); | 55 | gfs2_log_lock(sdp); |
| 56 | gfs2_assert_withdraw(sdp, !buffer_busy(bh)); | 56 | gfs2_assert_withdraw(sdp, !buffer_busy(bh)); |
| @@ -221,8 +221,10 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) | |||
| 221 | } | 221 | } |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) | 224 | if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) { |
| 225 | gfs2_log_flush(gl->gl_sbd, NULL); | ||
| 225 | gl->gl_sbd->sd_rindex_uptodate = 0; | 226 | gl->gl_sbd->sd_rindex_uptodate = 0; |
| 227 | } | ||
| 226 | if (ip && S_ISREG(ip->i_inode.i_mode)) | 228 | if (ip && S_ISREG(ip->i_inode.i_mode)) |
| 227 | truncate_inode_pages(ip->i_inode.i_mapping, 0); | 229 | truncate_inode_pages(ip->i_inode.i_mapping, 0); |
| 228 | } | 230 | } |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 0a064e91ac70..81206e70cbf6 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/buffer_head.h> | 17 | #include <linux/buffer_head.h> |
| 18 | #include <linux/rcupdate.h> | 18 | #include <linux/rcupdate.h> |
| 19 | #include <linux/rculist_bl.h> | 19 | #include <linux/rculist_bl.h> |
| 20 | #include <linux/completion.h> | ||
| 20 | 21 | ||
| 21 | #define DIO_WAIT 0x00000010 | 22 | #define DIO_WAIT 0x00000010 |
| 22 | #define DIO_METADATA 0x00000020 | 23 | #define DIO_METADATA 0x00000020 |
| @@ -546,6 +547,7 @@ struct gfs2_sbd { | |||
| 546 | struct gfs2_glock *sd_trans_gl; | 547 | struct gfs2_glock *sd_trans_gl; |
| 547 | wait_queue_head_t sd_glock_wait; | 548 | wait_queue_head_t sd_glock_wait; |
| 548 | atomic_t sd_glock_disposal; | 549 | atomic_t sd_glock_disposal; |
| 550 | struct completion sd_locking_init; | ||
| 549 | 551 | ||
| 550 | /* Inode Stuff */ | 552 | /* Inode Stuff */ |
| 551 | 553 | ||
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 903115f2bb34..85c62923ee29 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
| @@ -903,6 +903,7 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp) | |||
| 903 | if (gfs2_ail1_empty(sdp)) | 903 | if (gfs2_ail1_empty(sdp)) |
| 904 | break; | 904 | break; |
| 905 | } | 905 | } |
| 906 | gfs2_log_flush(sdp, NULL); | ||
| 906 | } | 907 | } |
| 907 | 908 | ||
| 908 | static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp) | 909 | static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp) |
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 8ac9ae189b53..2a77071fb7b6 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
| @@ -72,6 +72,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) | |||
| 72 | 72 | ||
| 73 | init_waitqueue_head(&sdp->sd_glock_wait); | 73 | init_waitqueue_head(&sdp->sd_glock_wait); |
| 74 | atomic_set(&sdp->sd_glock_disposal, 0); | 74 | atomic_set(&sdp->sd_glock_disposal, 0); |
| 75 | init_completion(&sdp->sd_locking_init); | ||
| 75 | spin_lock_init(&sdp->sd_statfs_spin); | 76 | spin_lock_init(&sdp->sd_statfs_spin); |
| 76 | 77 | ||
| 77 | spin_lock_init(&sdp->sd_rindex_spin); | 78 | spin_lock_init(&sdp->sd_rindex_spin); |
| @@ -1017,11 +1018,13 @@ hostdata_error: | |||
| 1017 | fsname++; | 1018 | fsname++; |
| 1018 | if (lm->lm_mount == NULL) { | 1019 | if (lm->lm_mount == NULL) { |
| 1019 | fs_info(sdp, "Now mounting FS...\n"); | 1020 | fs_info(sdp, "Now mounting FS...\n"); |
| 1021 | complete(&sdp->sd_locking_init); | ||
| 1020 | return 0; | 1022 | return 0; |
| 1021 | } | 1023 | } |
| 1022 | ret = lm->lm_mount(sdp, fsname); | 1024 | ret = lm->lm_mount(sdp, fsname); |
| 1023 | if (ret == 0) | 1025 | if (ret == 0) |
| 1024 | fs_info(sdp, "Joined cluster. Now mounting FS...\n"); | 1026 | fs_info(sdp, "Joined cluster. Now mounting FS...\n"); |
| 1027 | complete(&sdp->sd_locking_init); | ||
| 1025 | return ret; | 1028 | return ret; |
| 1026 | } | 1029 | } |
| 1027 | 1030 | ||
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index ed540e7018be..fb0edf735483 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
| @@ -757,13 +757,17 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 757 | struct timespec atime; | 757 | struct timespec atime; |
| 758 | struct gfs2_dinode *di; | 758 | struct gfs2_dinode *di; |
| 759 | int ret = -EAGAIN; | 759 | int ret = -EAGAIN; |
| 760 | int unlock_required = 0; | ||
| 760 | 761 | ||
| 761 | /* Skip timestamp update, if this is from a memalloc */ | 762 | /* Skip timestamp update, if this is from a memalloc */ |
| 762 | if (current->flags & PF_MEMALLOC) | 763 | if (current->flags & PF_MEMALLOC) |
| 763 | goto do_flush; | 764 | goto do_flush; |
| 764 | ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | 765 | if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { |
| 765 | if (ret) | 766 | ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); |
| 766 | goto do_flush; | 767 | if (ret) |
| 768 | goto do_flush; | ||
| 769 | unlock_required = 1; | ||
| 770 | } | ||
| 767 | ret = gfs2_trans_begin(sdp, RES_DINODE, 0); | 771 | ret = gfs2_trans_begin(sdp, RES_DINODE, 0); |
| 768 | if (ret) | 772 | if (ret) |
| 769 | goto do_unlock; | 773 | goto do_unlock; |
| @@ -780,7 +784,8 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 780 | } | 784 | } |
| 781 | gfs2_trans_end(sdp); | 785 | gfs2_trans_end(sdp); |
| 782 | do_unlock: | 786 | do_unlock: |
| 783 | gfs2_glock_dq_uninit(&gh); | 787 | if (unlock_required) |
| 788 | gfs2_glock_dq_uninit(&gh); | ||
| 784 | do_flush: | 789 | do_flush: |
| 785 | if (wbc->sync_mode == WB_SYNC_ALL) | 790 | if (wbc->sync_mode == WB_SYNC_ALL) |
| 786 | gfs2_log_flush(GFS2_SB(inode), ip->i_gl); | 791 | gfs2_log_flush(GFS2_SB(inode), ip->i_gl); |
| @@ -1427,7 +1432,20 @@ out: | |||
| 1427 | return error; | 1432 | return error; |
| 1428 | } | 1433 | } |
| 1429 | 1434 | ||
| 1430 | /* | 1435 | /** |
| 1436 | * gfs2_evict_inode - Remove an inode from cache | ||
| 1437 | * @inode: The inode to evict | ||
| 1438 | * | ||
| 1439 | * There are three cases to consider: | ||
| 1440 | * 1. i_nlink == 0, we are final opener (and must deallocate) | ||
| 1441 | * 2. i_nlink == 0, we are not the final opener (and cannot deallocate) | ||
| 1442 | * 3. i_nlink > 0 | ||
| 1443 | * | ||
| 1444 | * If the fs is read only, then we have to treat all cases as per #3 | ||
| 1445 | * since we are unable to do any deallocation. The inode will be | ||
| 1446 | * deallocated by the next read/write node to attempt an allocation | ||
| 1447 | * in the same resource group | ||
| 1448 | * | ||
| 1431 | * We have to (at the moment) hold the inodes main lock to cover | 1449 | * We have to (at the moment) hold the inodes main lock to cover |
| 1432 | * the gap between unlocking the shared lock on the iopen lock and | 1450 | * the gap between unlocking the shared lock on the iopen lock and |
| 1433 | * taking the exclusive lock. I'd rather do a shared -> exclusive | 1451 | * taking the exclusive lock. I'd rather do a shared -> exclusive |
| @@ -1470,6 +1488,8 @@ static void gfs2_evict_inode(struct inode *inode) | |||
| 1470 | if (error) | 1488 | if (error) |
| 1471 | goto out_truncate; | 1489 | goto out_truncate; |
| 1472 | 1490 | ||
| 1491 | /* Case 1 starts here */ | ||
| 1492 | |||
| 1473 | if (S_ISDIR(inode->i_mode) && | 1493 | if (S_ISDIR(inode->i_mode) && |
| 1474 | (ip->i_diskflags & GFS2_DIF_EXHASH)) { | 1494 | (ip->i_diskflags & GFS2_DIF_EXHASH)) { |
| 1475 | error = gfs2_dir_exhash_dealloc(ip); | 1495 | error = gfs2_dir_exhash_dealloc(ip); |
| @@ -1493,13 +1513,16 @@ static void gfs2_evict_inode(struct inode *inode) | |||
| 1493 | goto out_unlock; | 1513 | goto out_unlock; |
| 1494 | 1514 | ||
| 1495 | out_truncate: | 1515 | out_truncate: |
| 1516 | /* Case 2 starts here */ | ||
| 1496 | error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); | 1517 | error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); |
| 1497 | if (error) | 1518 | if (error) |
| 1498 | goto out_unlock; | 1519 | goto out_unlock; |
| 1499 | gfs2_final_release_pages(ip); | 1520 | /* Needs to be done before glock release & also in a transaction */ |
| 1521 | truncate_inode_pages(&inode->i_data, 0); | ||
| 1500 | gfs2_trans_end(sdp); | 1522 | gfs2_trans_end(sdp); |
| 1501 | 1523 | ||
| 1502 | out_unlock: | 1524 | out_unlock: |
| 1525 | /* Error path for case 1 */ | ||
| 1503 | if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) | 1526 | if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) |
| 1504 | gfs2_glock_dq(&ip->i_iopen_gh); | 1527 | gfs2_glock_dq(&ip->i_iopen_gh); |
| 1505 | gfs2_holder_uninit(&ip->i_iopen_gh); | 1528 | gfs2_holder_uninit(&ip->i_iopen_gh); |
| @@ -1507,6 +1530,7 @@ out_unlock: | |||
| 1507 | if (error && error != GLR_TRYFAILED && error != -EROFS) | 1530 | if (error && error != GLR_TRYFAILED && error != -EROFS) |
| 1508 | fs_warn(sdp, "gfs2_evict_inode: %d\n", error); | 1531 | fs_warn(sdp, "gfs2_evict_inode: %d\n", error); |
| 1509 | out: | 1532 | out: |
| 1533 | /* Case 3 starts here */ | ||
| 1510 | truncate_inode_pages(&inode->i_data, 0); | 1534 | truncate_inode_pages(&inode->i_data, 0); |
| 1511 | end_writeback(inode); | 1535 | end_writeback(inode); |
| 1512 | 1536 | ||
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index e20eab37bc80..443cabcfcd23 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c | |||
| @@ -338,6 +338,9 @@ static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len) | |||
| 338 | rv = sscanf(buf, "%u", &first); | 338 | rv = sscanf(buf, "%u", &first); |
| 339 | if (rv != 1 || first > 1) | 339 | if (rv != 1 || first > 1) |
| 340 | return -EINVAL; | 340 | return -EINVAL; |
| 341 | rv = wait_for_completion_killable(&sdp->sd_locking_init); | ||
| 342 | if (rv) | ||
| 343 | return rv; | ||
| 341 | spin_lock(&sdp->sd_jindex_spin); | 344 | spin_lock(&sdp->sd_jindex_spin); |
| 342 | rv = -EBUSY; | 345 | rv = -EBUSY; |
| 343 | if (test_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0) | 346 | if (test_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0) |
| @@ -414,7 +417,9 @@ static ssize_t jid_store(struct gfs2_sbd *sdp, const char *buf, size_t len) | |||
| 414 | rv = sscanf(buf, "%d", &jid); | 417 | rv = sscanf(buf, "%d", &jid); |
| 415 | if (rv != 1) | 418 | if (rv != 1) |
| 416 | return -EINVAL; | 419 | return -EINVAL; |
| 417 | 420 | rv = wait_for_completion_killable(&sdp->sd_locking_init); | |
| 421 | if (rv) | ||
| 422 | return rv; | ||
| 418 | spin_lock(&sdp->sd_jindex_spin); | 423 | spin_lock(&sdp->sd_jindex_spin); |
| 419 | rv = -EINVAL; | 424 | rv = -EINVAL; |
| 420 | if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL) | 425 | if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL) |
