diff options
| author | Steven Whitehouse <swhiteho@redhat.com> | 2011-04-14 04:54:02 -0400 |
|---|---|---|
| committer | Steven Whitehouse <swhiteho@redhat.com> | 2011-04-20 04:00:41 -0400 |
| commit | dba898b02defa66e5fe493d58ec0293a940f9c93 (patch) | |
| tree | 68ef0414a4c0ba677c23dbca6ecab957e9f11c35 /fs/gfs2 | |
| parent | efc1a9c2a70e4e49f4cf179a7ed8064b7a406e4a (diff) | |
GFS2: Clean up fsync()
This patch is designed to clean up GFS2's fsync
implementation and ensure that it really does get everything on
disk. Since ->write_inode() has been updated, we can call that
via the vfs library function sync_inode_metadata() and the only
remaining thing that has to be done is to ensure that we get
any revoke records in the log after the inode has been written back.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
| -rw-r--r-- | fs/gfs2/file.c | 36 | ||||
| -rw-r--r-- | fs/gfs2/glops.c | 59 | ||||
| -rw-r--r-- | fs/gfs2/glops.h | 2 |
3 files changed, 57 insertions, 40 deletions
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index e48310885c4..23eab473f09 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
| @@ -545,18 +545,10 @@ static int gfs2_close(struct inode *inode, struct file *file) | |||
| 545 | /** | 545 | /** |
| 546 | * gfs2_fsync - sync the dirty data for a file (across the cluster) | 546 | * gfs2_fsync - sync the dirty data for a file (across the cluster) |
| 547 | * @file: the file that points to the dentry (we ignore this) | 547 | * @file: the file that points to the dentry (we ignore this) |
| 548 | * @dentry: the dentry that points to the inode to sync | 548 | * @datasync: set if we can ignore timestamp changes |
| 549 | * | 549 | * |
| 550 | * The VFS will flush "normal" data for us. We only need to worry | 550 | * The VFS will flush data for us. We only need to worry |
| 551 | * about metadata here. For journaled data, we just do a log flush | 551 | * about metadata here. |
| 552 | * as we can't avoid it. Otherwise we can just bale out if datasync | ||
| 553 | * is set. For stuffed inodes we must flush the log in order to | ||
| 554 | * ensure that all data is on disk. | ||
| 555 | * | ||
| 556 | * The call to write_inode_now() is there to write back metadata and | ||
| 557 | * the inode itself. It does also try and write the data, but thats | ||
| 558 | * (hopefully) a no-op due to the VFS having already called filemap_fdatawrite() | ||
| 559 | * for us. | ||
| 560 | * | 552 | * |
| 561 | * Returns: errno | 553 | * Returns: errno |
| 562 | */ | 554 | */ |
| @@ -565,22 +557,20 @@ static int gfs2_fsync(struct file *file, int datasync) | |||
| 565 | { | 557 | { |
| 566 | struct inode *inode = file->f_mapping->host; | 558 | struct inode *inode = file->f_mapping->host; |
| 567 | int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC); | 559 | int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC); |
| 568 | int ret = 0; | 560 | struct gfs2_inode *ip = GFS2_I(inode); |
| 569 | 561 | int ret; | |
| 570 | if (gfs2_is_jdata(GFS2_I(inode))) { | ||
| 571 | gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl); | ||
| 572 | return 0; | ||
| 573 | } | ||
| 574 | 562 | ||
| 575 | if (sync_state != 0) { | 563 | if (datasync) |
| 576 | if (!datasync) | 564 | sync_state &= ~I_DIRTY_SYNC; |
| 577 | ret = write_inode_now(inode, 0); | ||
| 578 | 565 | ||
| 579 | if (gfs2_is_stuffed(GFS2_I(inode))) | 566 | if (sync_state) { |
| 580 | gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl); | 567 | ret = sync_inode_metadata(inode, 1); |
| 568 | if (ret) | ||
| 569 | return ret; | ||
| 570 | gfs2_ail_flush(ip->i_gl); | ||
| 581 | } | 571 | } |
| 582 | 572 | ||
| 583 | return ret; | 573 | return 0; |
| 584 | } | 574 | } |
| 585 | 575 | ||
| 586 | /** | 576 | /** |
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 25eeb2bcee4..7c1b08f63dd 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c | |||
| @@ -28,33 +28,18 @@ | |||
| 28 | #include "trans.h" | 28 | #include "trans.h" |
| 29 | 29 | ||
| 30 | /** | 30 | /** |
| 31 | * ail_empty_gl - remove all buffers for a given lock from the AIL | 31 | * __gfs2_ail_flush - remove all buffers for a given lock from the AIL |
| 32 | * @gl: the glock | 32 | * @gl: the glock |
| 33 | * | 33 | * |
| 34 | * None of the buffers should be dirty, locked, or pinned. | 34 | * None of the buffers should be dirty, locked, or pinned. |
| 35 | */ | 35 | */ |
| 36 | 36 | ||
| 37 | static void gfs2_ail_empty_gl(struct gfs2_glock *gl) | 37 | static void __gfs2_ail_flush(struct gfs2_glock *gl) |
| 38 | { | 38 | { |
| 39 | struct gfs2_sbd *sdp = gl->gl_sbd; | 39 | struct gfs2_sbd *sdp = gl->gl_sbd; |
| 40 | struct list_head *head = &gl->gl_ail_list; | 40 | struct list_head *head = &gl->gl_ail_list; |
| 41 | struct gfs2_bufdata *bd; | 41 | struct gfs2_bufdata *bd; |
| 42 | struct buffer_head *bh; | 42 | struct buffer_head *bh; |
| 43 | struct gfs2_trans tr; | ||
| 44 | |||
| 45 | memset(&tr, 0, sizeof(tr)); | ||
| 46 | tr.tr_revokes = atomic_read(&gl->gl_ail_count); | ||
| 47 | |||
| 48 | if (!tr.tr_revokes) | ||
| 49 | return; | ||
| 50 | |||
| 51 | /* A shortened, inline version of gfs2_trans_begin() */ | ||
| 52 | tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64)); | ||
| 53 | tr.tr_ip = (unsigned long)__builtin_return_address(0); | ||
| 54 | INIT_LIST_HEAD(&tr.tr_list_buf); | ||
| 55 | gfs2_log_reserve(sdp, tr.tr_reserved); | ||
| 56 | BUG_ON(current->journal_info); | ||
| 57 | current->journal_info = &tr; | ||
| 58 | 43 | ||
| 59 | spin_lock(&sdp->sd_ail_lock); | 44 | spin_lock(&sdp->sd_ail_lock); |
| 60 | while (!list_empty(head)) { | 45 | while (!list_empty(head)) { |
| @@ -76,7 +61,47 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) | |||
| 76 | } | 61 | } |
| 77 | gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); | 62 | gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); |
| 78 | spin_unlock(&sdp->sd_ail_lock); | 63 | spin_unlock(&sdp->sd_ail_lock); |
| 64 | } | ||
| 65 | |||
| 66 | |||
| 67 | static void gfs2_ail_empty_gl(struct gfs2_glock *gl) | ||
| 68 | { | ||
| 69 | struct gfs2_sbd *sdp = gl->gl_sbd; | ||
| 70 | struct gfs2_trans tr; | ||
| 71 | |||
| 72 | memset(&tr, 0, sizeof(tr)); | ||
| 73 | tr.tr_revokes = atomic_read(&gl->gl_ail_count); | ||
| 74 | |||
| 75 | if (!tr.tr_revokes) | ||
| 76 | return; | ||
| 77 | |||
| 78 | /* A shortened, inline version of gfs2_trans_begin() */ | ||
| 79 | tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64)); | ||
| 80 | tr.tr_ip = (unsigned long)__builtin_return_address(0); | ||
| 81 | INIT_LIST_HEAD(&tr.tr_list_buf); | ||
| 82 | gfs2_log_reserve(sdp, tr.tr_reserved); | ||
| 83 | BUG_ON(current->journal_info); | ||
| 84 | current->journal_info = &tr; | ||
| 85 | |||
| 86 | __gfs2_ail_flush(gl); | ||
| 87 | |||
| 88 | gfs2_trans_end(sdp); | ||
| 89 | gfs2_log_flush(sdp, NULL); | ||
| 90 | } | ||
| 79 | 91 | ||
| 92 | void gfs2_ail_flush(struct gfs2_glock *gl) | ||
| 93 | { | ||
| 94 | struct gfs2_sbd *sdp = gl->gl_sbd; | ||
| 95 | unsigned int revokes = atomic_read(&gl->gl_ail_count); | ||
| 96 | int ret; | ||
| 97 | |||
| 98 | if (!revokes) | ||
| 99 | return; | ||
| 100 | |||
| 101 | ret = gfs2_trans_begin(sdp, 0, revokes); | ||
| 102 | if (ret) | ||
| 103 | return; | ||
| 104 | __gfs2_ail_flush(gl); | ||
| 80 | gfs2_trans_end(sdp); | 105 | gfs2_trans_end(sdp); |
| 81 | gfs2_log_flush(sdp, NULL); | 106 | gfs2_log_flush(sdp, NULL); |
| 82 | } | 107 | } |
diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h index b3aa2e3210f..6fce409b5a5 100644 --- a/fs/gfs2/glops.h +++ b/fs/gfs2/glops.h | |||
| @@ -23,4 +23,6 @@ extern const struct gfs2_glock_operations gfs2_quota_glops; | |||
| 23 | extern const struct gfs2_glock_operations gfs2_journal_glops; | 23 | extern const struct gfs2_glock_operations gfs2_journal_glops; |
| 24 | extern const struct gfs2_glock_operations *gfs2_glops_list[]; | 24 | extern const struct gfs2_glock_operations *gfs2_glops_list[]; |
| 25 | 25 | ||
| 26 | extern void gfs2_ail_flush(struct gfs2_glock *gl); | ||
| 27 | |||
| 26 | #endif /* __GLOPS_DOT_H__ */ | 28 | #endif /* __GLOPS_DOT_H__ */ |
