Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dba898b0 authored by Steven Whitehouse's avatar Steven Whitehouse
Browse files

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: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent efc1a9c2
Loading
Loading
Loading
Loading
+13 −23
Original line number Diff line number Diff line
@@ -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)
 * @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
 * about metadata here. For journaled data, we just do a log flush
 * 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.
 * The VFS will flush data for us. We only need to worry
 * about metadata here.
 *
 * Returns: errno
 */
@@ -565,22 +557,20 @@ static int gfs2_fsync(struct file *file, int datasync)
{
	struct inode *inode = file->f_mapping->host;
	int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
	int ret = 0;

	if (gfs2_is_jdata(GFS2_I(inode))) {
		gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl);
		return 0;
	}
	struct gfs2_inode *ip = GFS2_I(inode);
	int ret;

	if (sync_state != 0) {
		if (!datasync)
			ret = write_inode_now(inode, 0);
	if (datasync)
		sync_state &= ~I_DIRTY_SYNC;

		if (gfs2_is_stuffed(GFS2_I(inode)))
			gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl);
	if (sync_state) {
		ret = sync_inode_metadata(inode, 1);
		if (ret)
			return ret;
		gfs2_ail_flush(ip->i_gl);
	}

	return ret;
	return 0;
}

/**
+42 −17
Original line number Diff line number Diff line
@@ -28,33 +28,18 @@
#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
 *
 * 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 list_head *head = &gl->gl_ail_list;
	struct gfs2_bufdata *bd;
	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);
	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));
	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_log_flush(sdp, NULL);
}
+2 −0
Original line number Diff line number Diff line
@@ -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_glops_list[];

extern void gfs2_ail_flush(struct gfs2_glock *gl);

#endif /* __GLOPS_DOT_H__ */