mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
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>
This commit is contained in:
parent
efc1a9c2a7
commit
dba898b02d
@ -545,18 +545,10 @@ static int gfs2_close(struct inode *inode, struct file *file)
|
|||||||
/**
|
/**
|
||||||
* gfs2_fsync - sync the dirty data for a file (across the cluster)
|
* gfs2_fsync - sync the dirty data for a file (across the cluster)
|
||||||
* @file: the file that points to the dentry (we ignore this)
|
* @file: the file that points to the dentry (we ignore this)
|
||||||
* @dentry: the dentry that points to the inode to sync
|
* @datasync: set if we can ignore timestamp changes
|
||||||
*
|
*
|
||||||
* The VFS will flush "normal" data for us. We only need to worry
|
* The VFS will flush data for us. We only need to worry
|
||||||
* about metadata here. For journaled data, we just do a log flush
|
* about metadata here.
|
||||||
* as we can't avoid it. Otherwise we can just bale out if datasync
|
|
||||||
* is set. For stuffed inodes we must flush the log in order to
|
|
||||||
* ensure that all data is on disk.
|
|
||||||
*
|
|
||||||
* The call to write_inode_now() is there to write back metadata and
|
|
||||||
* the inode itself. It does also try and write the data, but thats
|
|
||||||
* (hopefully) a no-op due to the VFS having already called filemap_fdatawrite()
|
|
||||||
* for us.
|
|
||||||
*
|
*
|
||||||
* Returns: errno
|
* Returns: errno
|
||||||
*/
|
*/
|
||||||
@ -565,22 +557,20 @@ static int gfs2_fsync(struct file *file, int datasync)
|
|||||||
{
|
{
|
||||||
struct inode *inode = file->f_mapping->host;
|
struct inode *inode = file->f_mapping->host;
|
||||||
int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
|
int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
|
||||||
int ret = 0;
|
struct gfs2_inode *ip = GFS2_I(inode);
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (gfs2_is_jdata(GFS2_I(inode))) {
|
if (datasync)
|
||||||
gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl);
|
sync_state &= ~I_DIRTY_SYNC;
|
||||||
return 0;
|
|
||||||
|
if (sync_state) {
|
||||||
|
ret = sync_inode_metadata(inode, 1);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
gfs2_ail_flush(ip->i_gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sync_state != 0) {
|
return 0;
|
||||||
if (!datasync)
|
|
||||||
ret = write_inode_now(inode, 0);
|
|
||||||
|
|
||||||
if (gfs2_is_stuffed(GFS2_I(inode)))
|
|
||||||
gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,33 +28,18 @@
|
|||||||
#include "trans.h"
|
#include "trans.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ail_empty_gl - remove all buffers for a given lock from the AIL
|
* __gfs2_ail_flush - remove all buffers for a given lock from the AIL
|
||||||
* @gl: the glock
|
* @gl: the glock
|
||||||
*
|
*
|
||||||
* None of the buffers should be dirty, locked, or pinned.
|
* None of the buffers should be dirty, locked, or pinned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
|
static void __gfs2_ail_flush(struct gfs2_glock *gl)
|
||||||
{
|
{
|
||||||
struct gfs2_sbd *sdp = gl->gl_sbd;
|
struct gfs2_sbd *sdp = gl->gl_sbd;
|
||||||
struct list_head *head = &gl->gl_ail_list;
|
struct list_head *head = &gl->gl_ail_list;
|
||||||
struct gfs2_bufdata *bd;
|
struct gfs2_bufdata *bd;
|
||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
struct gfs2_trans tr;
|
|
||||||
|
|
||||||
memset(&tr, 0, sizeof(tr));
|
|
||||||
tr.tr_revokes = atomic_read(&gl->gl_ail_count);
|
|
||||||
|
|
||||||
if (!tr.tr_revokes)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* A shortened, inline version of gfs2_trans_begin() */
|
|
||||||
tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64));
|
|
||||||
tr.tr_ip = (unsigned long)__builtin_return_address(0);
|
|
||||||
INIT_LIST_HEAD(&tr.tr_list_buf);
|
|
||||||
gfs2_log_reserve(sdp, tr.tr_reserved);
|
|
||||||
BUG_ON(current->journal_info);
|
|
||||||
current->journal_info = &tr;
|
|
||||||
|
|
||||||
spin_lock(&sdp->sd_ail_lock);
|
spin_lock(&sdp->sd_ail_lock);
|
||||||
while (!list_empty(head)) {
|
while (!list_empty(head)) {
|
||||||
@ -76,7 +61,47 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
|
|||||||
}
|
}
|
||||||
gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
|
gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
|
||||||
spin_unlock(&sdp->sd_ail_lock);
|
spin_unlock(&sdp->sd_ail_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
|
||||||
|
{
|
||||||
|
struct gfs2_sbd *sdp = gl->gl_sbd;
|
||||||
|
struct gfs2_trans tr;
|
||||||
|
|
||||||
|
memset(&tr, 0, sizeof(tr));
|
||||||
|
tr.tr_revokes = atomic_read(&gl->gl_ail_count);
|
||||||
|
|
||||||
|
if (!tr.tr_revokes)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* A shortened, inline version of gfs2_trans_begin() */
|
||||||
|
tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64));
|
||||||
|
tr.tr_ip = (unsigned long)__builtin_return_address(0);
|
||||||
|
INIT_LIST_HEAD(&tr.tr_list_buf);
|
||||||
|
gfs2_log_reserve(sdp, tr.tr_reserved);
|
||||||
|
BUG_ON(current->journal_info);
|
||||||
|
current->journal_info = &tr;
|
||||||
|
|
||||||
|
__gfs2_ail_flush(gl);
|
||||||
|
|
||||||
|
gfs2_trans_end(sdp);
|
||||||
|
gfs2_log_flush(sdp, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gfs2_ail_flush(struct gfs2_glock *gl)
|
||||||
|
{
|
||||||
|
struct gfs2_sbd *sdp = gl->gl_sbd;
|
||||||
|
unsigned int revokes = atomic_read(&gl->gl_ail_count);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!revokes)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ret = gfs2_trans_begin(sdp, 0, revokes);
|
||||||
|
if (ret)
|
||||||
|
return;
|
||||||
|
__gfs2_ail_flush(gl);
|
||||||
gfs2_trans_end(sdp);
|
gfs2_trans_end(sdp);
|
||||||
gfs2_log_flush(sdp, NULL);
|
gfs2_log_flush(sdp, NULL);
|
||||||
}
|
}
|
||||||
|
@ -23,4 +23,6 @@ extern const struct gfs2_glock_operations gfs2_quota_glops;
|
|||||||
extern const struct gfs2_glock_operations gfs2_journal_glops;
|
extern const struct gfs2_glock_operations gfs2_journal_glops;
|
||||||
extern const struct gfs2_glock_operations *gfs2_glops_list[];
|
extern const struct gfs2_glock_operations *gfs2_glops_list[];
|
||||||
|
|
||||||
|
extern void gfs2_ail_flush(struct gfs2_glock *gl);
|
||||||
|
|
||||||
#endif /* __GLOPS_DOT_H__ */
|
#endif /* __GLOPS_DOT_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user