xref: /openbmc/linux/fs/btrfs/transaction.c (revision 08607c1b)
179154b1bSChris Mason #include <linux/module.h>
279154b1bSChris Mason #include <linux/fs.h>
379154b1bSChris Mason #include "ctree.h"
479154b1bSChris Mason #include "disk-io.h"
579154b1bSChris Mason #include "transaction.h"
679154b1bSChris Mason 
778fae27eSChris Mason static int total_trans = 0;
82c90e5d6SChris Mason extern struct kmem_cache *btrfs_trans_handle_cachep;
92c90e5d6SChris Mason extern struct kmem_cache *btrfs_transaction_cachep;
102c90e5d6SChris Mason 
1108607c1bSChris Mason static struct workqueue_struct *trans_wq;
1208607c1bSChris Mason 
130f7d52f4SChris Mason #define BTRFS_ROOT_TRANS_TAG 0
140f7d52f4SChris Mason 
152c90e5d6SChris Mason #define TRANS_MAGIC 0xE1E10E
1679154b1bSChris Mason static void put_transaction(struct btrfs_transaction *transaction)
1779154b1bSChris Mason {
182c90e5d6SChris Mason 	WARN_ON(transaction->use_count == 0);
1979154b1bSChris Mason 	transaction->use_count--;
202c90e5d6SChris Mason 	WARN_ON(transaction->magic != TRANS_MAGIC);
2178fae27eSChris Mason 	if (transaction->use_count == 0) {
2278fae27eSChris Mason 		WARN_ON(total_trans == 0);
2378fae27eSChris Mason 		total_trans--;
248fd17795SChris Mason 		list_del_init(&transaction->list);
252c90e5d6SChris Mason 		memset(transaction, 0, sizeof(*transaction));
262c90e5d6SChris Mason 		kmem_cache_free(btrfs_transaction_cachep, transaction);
2779154b1bSChris Mason 	}
2878fae27eSChris Mason }
2979154b1bSChris Mason 
3079154b1bSChris Mason static int join_transaction(struct btrfs_root *root)
3179154b1bSChris Mason {
3279154b1bSChris Mason 	struct btrfs_transaction *cur_trans;
3379154b1bSChris Mason 	cur_trans = root->fs_info->running_transaction;
3479154b1bSChris Mason 	if (!cur_trans) {
352c90e5d6SChris Mason 		cur_trans = kmem_cache_alloc(btrfs_transaction_cachep,
362c90e5d6SChris Mason 					     GFP_NOFS);
3778fae27eSChris Mason 		total_trans++;
3879154b1bSChris Mason 		BUG_ON(!cur_trans);
390f7d52f4SChris Mason 		root->fs_info->generation++;
4079154b1bSChris Mason 		root->fs_info->running_transaction = cur_trans;
4179154b1bSChris Mason 		cur_trans->num_writers = 0;
420f7d52f4SChris Mason 		cur_trans->transid = root->fs_info->generation;
4379154b1bSChris Mason 		init_waitqueue_head(&cur_trans->writer_wait);
4479154b1bSChris Mason 		init_waitqueue_head(&cur_trans->commit_wait);
452c90e5d6SChris Mason 		cur_trans->magic = TRANS_MAGIC;
4679154b1bSChris Mason 		cur_trans->in_commit = 0;
47d5719762SChris Mason 		cur_trans->use_count = 1;
4879154b1bSChris Mason 		cur_trans->commit_done = 0;
4908607c1bSChris Mason 		cur_trans->start_time = get_seconds();
508fd17795SChris Mason 		list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
517c4452b9SChris Mason 		init_bit_radix(&cur_trans->dirty_pages);
5279154b1bSChris Mason 	}
5379154b1bSChris Mason 	cur_trans->num_writers++;
5479154b1bSChris Mason 	return 0;
5579154b1bSChris Mason }
5679154b1bSChris Mason 
5779154b1bSChris Mason struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
5879154b1bSChris Mason 						   int num_blocks)
5979154b1bSChris Mason {
602c90e5d6SChris Mason 	struct btrfs_trans_handle *h =
612c90e5d6SChris Mason 		kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
6279154b1bSChris Mason 	int ret;
630f7d52f4SChris Mason 	u64 running_trans_id;
6479154b1bSChris Mason 
6579154b1bSChris Mason 	mutex_lock(&root->fs_info->trans_mutex);
6679154b1bSChris Mason 	ret = join_transaction(root);
6779154b1bSChris Mason 	BUG_ON(ret);
680f7d52f4SChris Mason 	running_trans_id = root->fs_info->running_transaction->transid;
690f7d52f4SChris Mason 
700f7d52f4SChris Mason 	if (root != root->fs_info->tree_root && root->last_trans <
710f7d52f4SChris Mason 	    running_trans_id) {
720f7d52f4SChris Mason 		radix_tree_tag_set(&root->fs_info->fs_roots_radix,
732619ba1fSChris Mason 				   (unsigned long)root->root_key.objectid,
742619ba1fSChris Mason 				   BTRFS_ROOT_TRANS_TAG);
750f7d52f4SChris Mason 		root->commit_root = root->node;
760f7d52f4SChris Mason 		get_bh(root->node);
770f7d52f4SChris Mason 	}
780f7d52f4SChris Mason 	root->last_trans = running_trans_id;
790f7d52f4SChris Mason 	h->transid = running_trans_id;
8079154b1bSChris Mason 	h->transaction = root->fs_info->running_transaction;
8179154b1bSChris Mason 	h->blocks_reserved = num_blocks;
8279154b1bSChris Mason 	h->blocks_used = 0;
8331f3c99bSChris Mason 	h->block_group = NULL;
8479154b1bSChris Mason 	root->fs_info->running_transaction->use_count++;
8579154b1bSChris Mason 	mutex_unlock(&root->fs_info->trans_mutex);
862c90e5d6SChris Mason 	h->magic = h->magic2 = TRANS_MAGIC;
8779154b1bSChris Mason 	return h;
8879154b1bSChris Mason }
8979154b1bSChris Mason 
9079154b1bSChris Mason int btrfs_end_transaction(struct btrfs_trans_handle *trans,
9179154b1bSChris Mason 			  struct btrfs_root *root)
9279154b1bSChris Mason {
9379154b1bSChris Mason 	struct btrfs_transaction *cur_trans;
94d6e4a428SChris Mason 
952c90e5d6SChris Mason 	WARN_ON(trans->magic != TRANS_MAGIC);
962c90e5d6SChris Mason 	WARN_ON(trans->magic2 != TRANS_MAGIC);
9779154b1bSChris Mason 	mutex_lock(&root->fs_info->trans_mutex);
9879154b1bSChris Mason 	cur_trans = root->fs_info->running_transaction;
99d5719762SChris Mason 	WARN_ON(cur_trans->num_writers < 1);
10079154b1bSChris Mason 	if (waitqueue_active(&cur_trans->writer_wait))
10179154b1bSChris Mason 		wake_up(&cur_trans->writer_wait);
10279154b1bSChris Mason 	cur_trans->num_writers--;
10379154b1bSChris Mason 	put_transaction(cur_trans);
10479154b1bSChris Mason 	mutex_unlock(&root->fs_info->trans_mutex);
105d6025579SChris Mason 	memset(trans, 0, sizeof(*trans));
1062c90e5d6SChris Mason 	kmem_cache_free(btrfs_trans_handle_cachep, trans);
10779154b1bSChris Mason 	return 0;
10879154b1bSChris Mason }
10979154b1bSChris Mason 
11079154b1bSChris Mason 
11179154b1bSChris Mason int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
11279154b1bSChris Mason 				     struct btrfs_root *root)
11379154b1bSChris Mason {
1147c4452b9SChris Mason 	unsigned long gang[16];
1157c4452b9SChris Mason 	int ret;
1167c4452b9SChris Mason 	int i;
1177c4452b9SChris Mason 	int err;
1187c4452b9SChris Mason 	int werr = 0;
1197c4452b9SChris Mason 	struct page *page;
1207c4452b9SChris Mason 	struct radix_tree_root *dirty_pages;
1217c4452b9SChris Mason 	struct inode *btree_inode = root->fs_info->btree_inode;
1227c4452b9SChris Mason 
1237c4452b9SChris Mason 	if (!trans || !trans->transaction) {
1247c4452b9SChris Mason 		return filemap_write_and_wait(btree_inode->i_mapping);
1257c4452b9SChris Mason 	}
1267c4452b9SChris Mason 	dirty_pages = &trans->transaction->dirty_pages;
1277c4452b9SChris Mason 	while(1) {
128e37c9e69SChris Mason 		ret = find_first_radix_bit(dirty_pages, gang,
129e37c9e69SChris Mason 					   0, ARRAY_SIZE(gang));
1307c4452b9SChris Mason 		if (!ret)
1317c4452b9SChris Mason 			break;
1327c4452b9SChris Mason 		for (i = 0; i < ret; i++) {
1337c4452b9SChris Mason 			/* FIXME EIO */
1347c4452b9SChris Mason 			clear_radix_bit(dirty_pages, gang[i]);
1357c4452b9SChris Mason 			page = find_lock_page(btree_inode->i_mapping,
1367c4452b9SChris Mason 					      gang[i]);
1377c4452b9SChris Mason 			if (!page)
1387c4452b9SChris Mason 				continue;
1397c4452b9SChris Mason 			err = write_one_page(page, 0);
1407c4452b9SChris Mason 			if (err)
1417c4452b9SChris Mason 				werr = err;
1427c4452b9SChris Mason 			page_cache_release(page);
1437c4452b9SChris Mason 		}
1447c4452b9SChris Mason 	}
1457c4452b9SChris Mason 	err = filemap_fdatawait(btree_inode->i_mapping);
1467c4452b9SChris Mason 	if (err)
1477c4452b9SChris Mason 		werr = err;
1487c4452b9SChris Mason 	return werr;
14979154b1bSChris Mason }
15079154b1bSChris Mason 
15179154b1bSChris Mason int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
15279154b1bSChris Mason 			    struct btrfs_root *root)
15379154b1bSChris Mason {
15479154b1bSChris Mason 	int ret;
15579154b1bSChris Mason 	u64 old_extent_block;
15679154b1bSChris Mason 	struct btrfs_fs_info *fs_info = root->fs_info;
15779154b1bSChris Mason 	struct btrfs_root *tree_root = fs_info->tree_root;
15879154b1bSChris Mason 	struct btrfs_root *extent_root = fs_info->extent_root;
1598352d8a4SChris Mason 	struct btrfs_root *dev_root = fs_info->dev_root;
16079154b1bSChris Mason 
1618352d8a4SChris Mason 	if (btrfs_super_device_root(fs_info->disk_super) !=
1628352d8a4SChris Mason 	    bh_blocknr(dev_root->node)) {
1638352d8a4SChris Mason 		btrfs_set_super_device_root(fs_info->disk_super,
1648352d8a4SChris Mason 					    bh_blocknr(dev_root->node));
1658352d8a4SChris Mason 	}
1669078a3e1SChris Mason 	btrfs_write_dirty_block_groups(trans, extent_root);
16779154b1bSChris Mason 	while(1) {
16879154b1bSChris Mason 		old_extent_block = btrfs_root_blocknr(&extent_root->root_item);
1697eccb903SChris Mason 		if (old_extent_block == bh_blocknr(extent_root->node))
17079154b1bSChris Mason 			break;
17179154b1bSChris Mason 		btrfs_set_root_blocknr(&extent_root->root_item,
1727eccb903SChris Mason 				       bh_blocknr(extent_root->node));
17379154b1bSChris Mason 		ret = btrfs_update_root(trans, tree_root,
17479154b1bSChris Mason 					&extent_root->root_key,
17579154b1bSChris Mason 					&extent_root->root_item);
17679154b1bSChris Mason 		BUG_ON(ret);
1779078a3e1SChris Mason 		btrfs_write_dirty_block_groups(trans, extent_root);
17879154b1bSChris Mason 	}
17979154b1bSChris Mason 	return 0;
18079154b1bSChris Mason }
18179154b1bSChris Mason 
18279154b1bSChris Mason static int wait_for_commit(struct btrfs_root *root,
18379154b1bSChris Mason 			   struct btrfs_transaction *commit)
18479154b1bSChris Mason {
18579154b1bSChris Mason 	DEFINE_WAIT(wait);
18679154b1bSChris Mason 	while(!commit->commit_done) {
18779154b1bSChris Mason 		prepare_to_wait(&commit->commit_wait, &wait,
18879154b1bSChris Mason 				TASK_UNINTERRUPTIBLE);
18979154b1bSChris Mason 		if (commit->commit_done)
19079154b1bSChris Mason 			break;
19179154b1bSChris Mason 		mutex_unlock(&root->fs_info->trans_mutex);
19279154b1bSChris Mason 		schedule();
19379154b1bSChris Mason 		mutex_lock(&root->fs_info->trans_mutex);
19479154b1bSChris Mason 	}
19579154b1bSChris Mason 	finish_wait(&commit->commit_wait, &wait);
19679154b1bSChris Mason 	return 0;
19779154b1bSChris Mason }
19879154b1bSChris Mason 
1990f7d52f4SChris Mason struct dirty_root {
2000f7d52f4SChris Mason 	struct list_head list;
2010f7d52f4SChris Mason 	struct btrfs_key snap_key;
2020f7d52f4SChris Mason 	struct buffer_head *commit_root;
2030f7d52f4SChris Mason 	struct btrfs_root *root;
2040f7d52f4SChris Mason };
2050f7d52f4SChris Mason 
20635b7e476SChris Mason static int add_dirty_roots(struct btrfs_trans_handle *trans,
20735b7e476SChris Mason 			   struct radix_tree_root *radix,
20835b7e476SChris Mason 			   struct list_head *list)
2090f7d52f4SChris Mason {
2100f7d52f4SChris Mason 	struct dirty_root *dirty;
2110f7d52f4SChris Mason 	struct btrfs_root *gang[8];
2120f7d52f4SChris Mason 	struct btrfs_root *root;
2130f7d52f4SChris Mason 	int i;
2140f7d52f4SChris Mason 	int ret;
2150f7d52f4SChris Mason 	int err;
2160f7d52f4SChris Mason 	while(1) {
2170f7d52f4SChris Mason 		ret = radix_tree_gang_lookup_tag(radix, (void **)gang, 0,
2180f7d52f4SChris Mason 						 ARRAY_SIZE(gang),
2190f7d52f4SChris Mason 						 BTRFS_ROOT_TRANS_TAG);
2200f7d52f4SChris Mason 		if (ret == 0)
2210f7d52f4SChris Mason 			break;
2220f7d52f4SChris Mason 		for (i = 0; i < ret; i++) {
2230f7d52f4SChris Mason 			root = gang[i];
2242619ba1fSChris Mason 			radix_tree_tag_clear(radix,
2252619ba1fSChris Mason 				     (unsigned long)root->root_key.objectid,
2260f7d52f4SChris Mason 				     BTRFS_ROOT_TRANS_TAG);
2270f7d52f4SChris Mason 			if (root->commit_root == root->node) {
2287eccb903SChris Mason 				WARN_ON(bh_blocknr(root->node) !=
2290f7d52f4SChris Mason 					btrfs_root_blocknr(&root->root_item));
2300f7d52f4SChris Mason 				brelse(root->commit_root);
2310f7d52f4SChris Mason 				root->commit_root = NULL;
2320f7d52f4SChris Mason 				continue;
2330f7d52f4SChris Mason 			}
2340f7d52f4SChris Mason 			dirty = kmalloc(sizeof(*dirty), GFP_NOFS);
2350f7d52f4SChris Mason 			BUG_ON(!dirty);
2360f7d52f4SChris Mason 			memcpy(&dirty->snap_key, &root->root_key,
2370f7d52f4SChris Mason 			       sizeof(root->root_key));
2380f7d52f4SChris Mason 			dirty->commit_root = root->commit_root;
2390f7d52f4SChris Mason 			root->commit_root = NULL;
2400f7d52f4SChris Mason 			dirty->root = root;
2410f7d52f4SChris Mason 			root->root_key.offset = root->fs_info->generation;
2420f7d52f4SChris Mason 			btrfs_set_root_blocknr(&root->root_item,
2437eccb903SChris Mason 					       bh_blocknr(root->node));
2440f7d52f4SChris Mason 			err = btrfs_insert_root(trans, root->fs_info->tree_root,
2450f7d52f4SChris Mason 						&root->root_key,
2460f7d52f4SChris Mason 						&root->root_item);
2470f7d52f4SChris Mason 			BUG_ON(err);
2480f7d52f4SChris Mason 			list_add(&dirty->list, list);
2490f7d52f4SChris Mason 		}
2500f7d52f4SChris Mason 	}
2510f7d52f4SChris Mason 	return 0;
2520f7d52f4SChris Mason }
2530f7d52f4SChris Mason 
25435b7e476SChris Mason static int drop_dirty_roots(struct btrfs_root *tree_root,
25535b7e476SChris Mason 			    struct list_head *list)
2560f7d52f4SChris Mason {
2570f7d52f4SChris Mason 	struct dirty_root *dirty;
2580f7d52f4SChris Mason 	struct btrfs_trans_handle *trans;
2590f7d52f4SChris Mason 	int ret;
2600f7d52f4SChris Mason 
2610f7d52f4SChris Mason 	while(!list_empty(list)) {
2620f7d52f4SChris Mason 		dirty = list_entry(list->next, struct dirty_root, list);
2630f7d52f4SChris Mason 		list_del_init(&dirty->list);
2640f7d52f4SChris Mason 		trans = btrfs_start_transaction(tree_root, 1);
2650f7d52f4SChris Mason 		ret = btrfs_drop_snapshot(trans, dirty->root,
2660f7d52f4SChris Mason 					  dirty->commit_root);
2670f7d52f4SChris Mason 		BUG_ON(ret);
2680f7d52f4SChris Mason 
2690f7d52f4SChris Mason 		ret = btrfs_del_root(trans, tree_root, &dirty->snap_key);
2700f7d52f4SChris Mason 		BUG_ON(ret);
2710f7d52f4SChris Mason 		ret = btrfs_end_transaction(trans, tree_root);
2720f7d52f4SChris Mason 		BUG_ON(ret);
2730f7d52f4SChris Mason 		kfree(dirty);
2740f7d52f4SChris Mason 	}
2750f7d52f4SChris Mason 	return 0;
2760f7d52f4SChris Mason }
2770f7d52f4SChris Mason 
27879154b1bSChris Mason int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
27979154b1bSChris Mason 			     struct btrfs_root *root)
28079154b1bSChris Mason {
28179154b1bSChris Mason 	int ret = 0;
28279154b1bSChris Mason 	struct btrfs_transaction *cur_trans;
2838fd17795SChris Mason 	struct btrfs_transaction *prev_trans = NULL;
2840f7d52f4SChris Mason 	struct list_head dirty_fs_roots;
28579154b1bSChris Mason 	DEFINE_WAIT(wait);
28679154b1bSChris Mason 
2870f7d52f4SChris Mason 	INIT_LIST_HEAD(&dirty_fs_roots);
288d6e4a428SChris Mason 
28979154b1bSChris Mason 	mutex_lock(&root->fs_info->trans_mutex);
29079154b1bSChris Mason 	if (trans->transaction->in_commit) {
29179154b1bSChris Mason 		cur_trans = trans->transaction;
29279154b1bSChris Mason 		trans->transaction->use_count++;
29379154b1bSChris Mason 		btrfs_end_transaction(trans, root);
29479154b1bSChris Mason 		ret = wait_for_commit(root, cur_trans);
29579154b1bSChris Mason 		BUG_ON(ret);
29679154b1bSChris Mason 		put_transaction(cur_trans);
29779154b1bSChris Mason 		mutex_unlock(&root->fs_info->trans_mutex);
29879154b1bSChris Mason 		return 0;
29979154b1bSChris Mason 	}
3002c90e5d6SChris Mason 	cur_trans = trans->transaction;
3012c90e5d6SChris Mason 	trans->transaction->in_commit = 1;
30279154b1bSChris Mason 	while (trans->transaction->num_writers > 1) {
3032c90e5d6SChris Mason 		WARN_ON(cur_trans != trans->transaction);
30479154b1bSChris Mason 		prepare_to_wait(&trans->transaction->writer_wait, &wait,
30579154b1bSChris Mason 				TASK_UNINTERRUPTIBLE);
30679154b1bSChris Mason 		if (trans->transaction->num_writers <= 1)
30779154b1bSChris Mason 			break;
30879154b1bSChris Mason 		mutex_unlock(&root->fs_info->trans_mutex);
30979154b1bSChris Mason 		schedule();
31079154b1bSChris Mason 		mutex_lock(&root->fs_info->trans_mutex);
3112c90e5d6SChris Mason 		finish_wait(&trans->transaction->writer_wait, &wait);
31279154b1bSChris Mason 	}
31379154b1bSChris Mason 	finish_wait(&trans->transaction->writer_wait, &wait);
3142c90e5d6SChris Mason 	WARN_ON(cur_trans != trans->transaction);
3150f7d52f4SChris Mason 	add_dirty_roots(trans, &root->fs_info->fs_roots_radix, &dirty_fs_roots);
31679154b1bSChris Mason 	ret = btrfs_commit_tree_roots(trans, root);
31779154b1bSChris Mason 	BUG_ON(ret);
31878fae27eSChris Mason 	cur_trans = root->fs_info->running_transaction;
31978fae27eSChris Mason 	root->fs_info->running_transaction = NULL;
3208fd17795SChris Mason 	if (cur_trans->list.prev != &root->fs_info->trans_list) {
3218fd17795SChris Mason 		prev_trans = list_entry(cur_trans->list.prev,
3228fd17795SChris Mason 					struct btrfs_transaction, list);
3238fd17795SChris Mason 		if (prev_trans->commit_done)
3248fd17795SChris Mason 			prev_trans = NULL;
3258fd17795SChris Mason 		else
3268fd17795SChris Mason 			prev_trans->use_count++;
3278fd17795SChris Mason 	}
32878fae27eSChris Mason 	mutex_unlock(&root->fs_info->trans_mutex);
3298fd17795SChris Mason 	mutex_unlock(&root->fs_info->fs_mutex);
33079154b1bSChris Mason 	ret = btrfs_write_and_wait_transaction(trans, root);
3318fd17795SChris Mason 	if (prev_trans) {
3328fd17795SChris Mason 		mutex_lock(&root->fs_info->trans_mutex);
3338fd17795SChris Mason 		wait_for_commit(root, prev_trans);
3348fd17795SChris Mason 		put_transaction(prev_trans);
3358fd17795SChris Mason 		mutex_unlock(&root->fs_info->trans_mutex);
3368fd17795SChris Mason 	}
3378fd17795SChris Mason 	btrfs_set_super_generation(root->fs_info->disk_super,
3388fd17795SChris Mason 				   cur_trans->transid);
33979154b1bSChris Mason 	BUG_ON(ret);
34079154b1bSChris Mason 	write_ctree_super(trans, root);
3418fd17795SChris Mason 
3428fd17795SChris Mason 	mutex_lock(&root->fs_info->fs_mutex);
34378fae27eSChris Mason 	btrfs_finish_extent_commit(trans, root);
34478fae27eSChris Mason 	mutex_lock(&root->fs_info->trans_mutex);
3452c90e5d6SChris Mason 	cur_trans->commit_done = 1;
3462c90e5d6SChris Mason 	wake_up(&cur_trans->commit_wait);
34779154b1bSChris Mason 	put_transaction(cur_trans);
34878fae27eSChris Mason 	put_transaction(cur_trans);
34978fae27eSChris Mason 	mutex_unlock(&root->fs_info->trans_mutex);
3502c90e5d6SChris Mason 	kmem_cache_free(btrfs_trans_handle_cachep, trans);
35179154b1bSChris Mason 
3520f7d52f4SChris Mason 	drop_dirty_roots(root->fs_info->tree_root, &dirty_fs_roots);
35379154b1bSChris Mason 	return ret;
35479154b1bSChris Mason }
35579154b1bSChris Mason 
35608607c1bSChris Mason void btrfs_transaction_cleaner(struct work_struct *work)
35708607c1bSChris Mason {
35808607c1bSChris Mason 	struct btrfs_fs_info *fs_info = container_of(work,
35908607c1bSChris Mason 						     struct btrfs_fs_info,
36008607c1bSChris Mason 						     trans_work.work);
36108607c1bSChris Mason 
36208607c1bSChris Mason 	struct btrfs_root *root = fs_info->tree_root;
36308607c1bSChris Mason 	struct btrfs_transaction *cur;
36408607c1bSChris Mason 	struct btrfs_trans_handle *trans;
36508607c1bSChris Mason 	unsigned long now;
36608607c1bSChris Mason 	unsigned long delay = HZ * 30;
36708607c1bSChris Mason 	int ret;
36808607c1bSChris Mason 
36908607c1bSChris Mason printk("btrfs transaction cleaner\n");
37008607c1bSChris Mason 	mutex_lock(&root->fs_info->fs_mutex);
37108607c1bSChris Mason 	mutex_lock(&root->fs_info->trans_mutex);
37208607c1bSChris Mason 	cur = root->fs_info->running_transaction;
37308607c1bSChris Mason 	if (!cur) {
37408607c1bSChris Mason 		mutex_unlock(&root->fs_info->trans_mutex);
37508607c1bSChris Mason 		goto out;
37608607c1bSChris Mason 	}
37708607c1bSChris Mason 	now = get_seconds();
37808607c1bSChris Mason 	if (now < cur->start_time || now - cur->start_time < 30) {
37908607c1bSChris Mason 		mutex_unlock(&root->fs_info->trans_mutex);
38008607c1bSChris Mason 		delay = HZ * 5;
38108607c1bSChris Mason 		goto out;
38208607c1bSChris Mason 	}
38308607c1bSChris Mason 	mutex_unlock(&root->fs_info->trans_mutex);
38408607c1bSChris Mason printk("forcing commit\n");
38508607c1bSChris Mason 	trans = btrfs_start_transaction(root, 1);
38608607c1bSChris Mason 	ret = btrfs_commit_transaction(trans, root);
38708607c1bSChris Mason out:
38808607c1bSChris Mason 	mutex_unlock(&root->fs_info->fs_mutex);
38908607c1bSChris Mason 	btrfs_transaction_queue_work(root, delay);
39008607c1bSChris Mason }
39108607c1bSChris Mason 
39208607c1bSChris Mason void btrfs_transaction_queue_work(struct btrfs_root *root, int delay)
39308607c1bSChris Mason {
39408607c1bSChris Mason 	queue_delayed_work(trans_wq, &root->fs_info->trans_work, delay);
39508607c1bSChris Mason }
39608607c1bSChris Mason 
39708607c1bSChris Mason void btrfs_transaction_flush_work(struct btrfs_root *root)
39808607c1bSChris Mason {
39908607c1bSChris Mason 	cancel_rearming_delayed_workqueue(trans_wq, &root->fs_info->trans_work);
40008607c1bSChris Mason 	flush_workqueue(trans_wq);
40108607c1bSChris Mason }
40208607c1bSChris Mason 
40308607c1bSChris Mason void __init btrfs_init_transaction_sys(void)
40408607c1bSChris Mason {
40508607c1bSChris Mason 	trans_wq = create_workqueue("btrfs");
40608607c1bSChris Mason }
40708607c1bSChris Mason 
40808607c1bSChris Mason void __exit btrfs_exit_transaction_sys(void)
40908607c1bSChris Mason {
41008607c1bSChris Mason 	destroy_workqueue(trans_wq);
41108607c1bSChris Mason }
41208607c1bSChris Mason 
413