[Btrfs-devel] [RFC] fsync patch take 5?

Josef Bacik jwhiter at redhat.com
Fri Aug 10 08:58:45 PDT 2007


Hello,

Ok here's the new patch, all tested and pretty with the suggestions you made
yesterday.  As always, let me know if you need me to change anything.  If there
are no objections I'll move on to fixing block accounting.  Thank you,

Josef

diff -r f6da57af2473 btrfs_inode.h
--- a/btrfs_inode.h	Wed Aug 08 20:17:12 2007 -0400
+++ b/btrfs_inode.h	Thu Aug 09 16:04:17 2007 -0400
@@ -25,6 +25,11 @@ struct btrfs_inode {
 	struct btrfs_block_group_cache *block_group;
 	struct btrfs_key location;
 	struct inode vfs_inode;
+
+	/*
+	 * transid of the trans_handle that last modified this inode
+	 */
+	u64 last_trans;
 };
 static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
 {
diff -r f6da57af2473 ctree.h
--- a/ctree.h	Wed Aug 08 20:17:12 2007 -0400
+++ b/ctree.h	Fri Aug 10 10:49:15 2007 -0400
@@ -301,6 +301,7 @@ struct btrfs_fs_info {
 	struct radix_tree_root extent_map_radix;
 	struct radix_tree_root extent_ins_radix;
 	u64 generation;
+	u64 last_trans_committed;
 	struct btrfs_transaction *running_transaction;
 	struct btrfs_super_block *disk_super;
 	struct btrfs_super_block super_copy;
diff -r f6da57af2473 disk-io.c
--- a/disk-io.c	Wed Aug 08 20:17:12 2007 -0400
+++ b/disk-io.c	Fri Aug 10 10:59:09 2007 -0400
@@ -435,6 +435,7 @@ struct btrfs_root *open_ctree(struct sup
 	INIT_LIST_HEAD(&fs_info->dead_roots);
 	sb_set_blocksize(sb, 4096);
 	fs_info->running_transaction = NULL;
+	fs_info->last_trans_committed = 0;
 	fs_info->tree_root = tree_root;
 	fs_info->extent_root = extent_root;
 	fs_info->sb = sb;
diff -r f6da57af2473 file.c
--- a/file.c	Wed Aug 08 20:17:12 2007 -0400
+++ b/file.c	Fri Aug 10 11:01:06 2007 -0400
@@ -694,22 +694,36 @@ static int btrfs_sync_file(struct file *
 {
 	struct inode *inode = dentry->d_inode;
 	struct btrfs_root *root = BTRFS_I(inode)->root;
-	int ret;
+	int ret = 0;
 	struct btrfs_trans_handle *trans;
 
 	/*
-	 * FIXME, use inode generation number to check if we can skip the
-	 * commit
+	 * check the transaction that last modified this inode
+	 * and see if its already been committed
 	 */
 	mutex_lock(&root->fs_info->fs_mutex);
+	if (!BTRFS_I(inode)->last_trans)
+		goto out;
+	mutex_lock(&root->fs_info->trans_mutex);
+	if (BTRFS_I(inode)->last_trans <=
+	    root->fs_info->last_trans_committed) {
+		BTRFS_I(inode)->last_trans = 0;
+		mutex_unlock(&root->fs_info->trans_mutex);
+		goto out;
+	}
+	mutex_unlock(&root->fs_info->trans_mutex);
+
+	/*
+ 	 * ok we haven't committed the transaction yet, lets do a commit
+ 	 */
 	trans = btrfs_start_transaction(root, 1);
 	if (!trans) {
 		ret = -ENOMEM;
 		goto out;
 	}
 	ret = btrfs_commit_transaction(trans, root);
+out:
 	mutex_unlock(&root->fs_info->fs_mutex);
-out:
 	return ret > 0 ? EIO : ret;
 }
 
diff -r f6da57af2473 inode.c
--- a/inode.c	Wed Aug 08 20:17:12 2007 -0400
+++ b/inode.c	Thu Aug 09 17:23:57 2007 -0400
@@ -193,6 +193,7 @@ static int btrfs_update_inode(struct btr
 
 	fill_inode_item(inode_item, inode);
 	btrfs_mark_buffer_dirty(path->nodes[0]);
+	btrfs_set_inode_last_trans(trans, inode);
 	ret = 0;
 failed:
 	btrfs_release_path(root, path);
@@ -2253,6 +2254,7 @@ struct inode *btrfs_alloc_inode(struct s
 	ei = kmem_cache_alloc(btrfs_inode_cachep, GFP_NOFS);
 	if (!ei)
 		return NULL;
+	ei->last_trans = 0;
 	return &ei->vfs_inode;
 }
 
diff -r f6da57af2473 transaction.c
--- a/transaction.c	Wed Aug 08 20:17:12 2007 -0400
+++ b/transaction.c	Fri Aug 10 11:53:50 2007 -0400
@@ -55,7 +55,8 @@ static int join_transaction(struct btrfs
 		BUG_ON(!cur_trans);
 		root->fs_info->generation++;
 		root->fs_info->running_transaction = cur_trans;
-		cur_trans->num_writers = 0;
+		cur_trans->num_writers = 1;
+		cur_trans->num_joined = 0;
 		cur_trans->transid = root->fs_info->generation;
 		init_waitqueue_head(&cur_trans->writer_wait);
 		init_waitqueue_head(&cur_trans->commit_wait);
@@ -65,8 +66,11 @@ static int join_transaction(struct btrfs
 		cur_trans->start_time = get_seconds();
 		list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
 		init_bit_radix(&cur_trans->dirty_pages);
-	}
-	cur_trans->num_writers++;
+	} else {
+		cur_trans->num_writers++;
+		cur_trans->num_joined++;
+	}
+
 	return 0;
 }
 
@@ -426,7 +430,8 @@ int btrfs_commit_transaction(struct btrf
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 			     struct btrfs_root *root)
 {
-	int ret = 0;
+	int ret = 0, joined = 0;
+	unsigned long timeout = 1;
 	struct btrfs_transaction *cur_trans;
 	struct btrfs_transaction *prev_trans = NULL;
 	struct list_head dirty_fs_roots;
@@ -446,7 +451,11 @@ int btrfs_commit_transaction(struct btrf
 		mutex_unlock(&root->fs_info->fs_mutex);
 		ret = wait_for_commit(root, cur_trans);
 		BUG_ON(ret);
+
+		mutex_lock(&root->fs_info->trans_mutex);
 		put_transaction(cur_trans);
+		mutex_unlock(&root->fs_info->trans_mutex);
+
 		mutex_lock(&root->fs_info->fs_mutex);
 		return 0;
 	}
@@ -461,25 +470,35 @@ int btrfs_commit_transaction(struct btrf
 			mutex_unlock(&root->fs_info->trans_mutex);
 
 			wait_for_commit(root, prev_trans);
-			put_transaction(prev_trans);
 
 			mutex_lock(&root->fs_info->fs_mutex);
 			mutex_lock(&root->fs_info->trans_mutex);
+			put_transaction(prev_trans);
 		}
 	}
-	while (trans->transaction->num_writers > 1) {
+	
+	do {
+		joined = cur_trans->num_joined;
 		WARN_ON(cur_trans != trans->transaction);
-		prepare_to_wait(&trans->transaction->writer_wait, &wait,
+		prepare_to_wait(&cur_trans->writer_wait, &wait,
 				TASK_UNINTERRUPTIBLE);
-		if (trans->transaction->num_writers <= 1)
-			break;
+		if (cur_trans->num_writers <= 1 && 
+		    (cur_trans->num_joined != joined))
+			break;
+
+		if (cur_trans->num_writers > 1)
+			timeout = MAX_SCHEDULE_TIMEOUT;
+		else
+			timeout = 1;
 		mutex_unlock(&root->fs_info->fs_mutex);
 		mutex_unlock(&root->fs_info->trans_mutex);
-		schedule();
+		schedule_timeout(timeout);
 		mutex_lock(&root->fs_info->fs_mutex);
 		mutex_lock(&root->fs_info->trans_mutex);
-		finish_wait(&trans->transaction->writer_wait, &wait);
-	}
+		finish_wait(&cur_trans->writer_wait, &wait);
+	} while (cur_trans->num_writers > 1 || 
+		 (cur_trans->num_joined != joined));
+
 	finish_wait(&trans->transaction->writer_wait, &wait);
 	WARN_ON(cur_trans != trans->transaction);
 	ret = add_dirty_roots(trans, &root->fs_info->fs_roots_radix,
@@ -509,6 +528,7 @@ int btrfs_commit_transaction(struct btrf
 	btrfs_finish_extent_commit(trans, root, &pinned_copy);
 	mutex_lock(&root->fs_info->trans_mutex);
 	cur_trans->commit_done = 1;
+	root->fs_info->last_trans_committed = cur_trans->transid;
 	wake_up(&cur_trans->commit_wait);
 	put_transaction(cur_trans);
 	put_transaction(cur_trans);
diff -r f6da57af2473 transaction.h
--- a/transaction.h	Wed Aug 08 20:17:12 2007 -0400
+++ b/transaction.h	Thu Aug 09 16:32:04 2007 -0400
@@ -23,6 +23,7 @@ struct btrfs_transaction {
 struct btrfs_transaction {
 	u64 transid;
 	unsigned long num_writers;
+	unsigned long num_joined;
 	int in_commit;
 	int use_count;
 	int commit_done;
@@ -57,6 +58,12 @@ static inline void btrfs_update_inode_bl
 	BTRFS_I(inode)->block_group = trans->block_group;
 }
 
+static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans,
+					      struct inode *inode)
+{
+	BTRFS_I(inode)->last_trans = trans->transaction->transid;
+}
+
 int btrfs_end_transaction(struct btrfs_trans_handle *trans,
 			  struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,



More information about the Btrfs-devel mailing list