diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2010-05-16 10:49:59 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-05-25 10:34:53 -0400 |
commit | 4a500fd178c89b96fa166a2d9e7855df33429841 (patch) | |
tree | b97fe0b0c1cb19388fcf28f77cd74a645ec69a61 /fs | |
parent | d68fc57b7e3245cfacf2e3b47acfed1946a11786 (diff) |
Btrfs: Metadata ENOSPC handling for tree log
Previous patches make the allocater return -ENOSPC if there is no
unreserved free metadata space. This patch updates tree log code
and various other places to propagate/handle the ENOSPC error.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/disk-io.c | 36 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 2 | ||||
-rw-r--r-- | fs/btrfs/file-item.c | 3 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 241 | ||||
-rw-r--r-- | fs/btrfs/tree-log.h | 2 |
5 files changed, 156 insertions, 128 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 82955b73a962..a8772b5a9cb5 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -972,42 +972,6 @@ static int find_and_setup_root(struct btrfs_root *tree_root, | |||
972 | return 0; | 972 | return 0; |
973 | } | 973 | } |
974 | 974 | ||
975 | int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, | ||
976 | struct btrfs_fs_info *fs_info) | ||
977 | { | ||
978 | struct extent_buffer *eb; | ||
979 | struct btrfs_root *log_root_tree = fs_info->log_root_tree; | ||
980 | u64 start = 0; | ||
981 | u64 end = 0; | ||
982 | int ret; | ||
983 | |||
984 | if (!log_root_tree) | ||
985 | return 0; | ||
986 | |||
987 | while (1) { | ||
988 | ret = find_first_extent_bit(&log_root_tree->dirty_log_pages, | ||
989 | 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW); | ||
990 | if (ret) | ||
991 | break; | ||
992 | |||
993 | clear_extent_bits(&log_root_tree->dirty_log_pages, start, end, | ||
994 | EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS); | ||
995 | } | ||
996 | eb = fs_info->log_root_tree->node; | ||
997 | |||
998 | WARN_ON(btrfs_header_level(eb) != 0); | ||
999 | WARN_ON(btrfs_header_nritems(eb) != 0); | ||
1000 | |||
1001 | ret = btrfs_free_reserved_extent(fs_info->tree_root, | ||
1002 | eb->start, eb->len); | ||
1003 | BUG_ON(ret); | ||
1004 | |||
1005 | free_extent_buffer(eb); | ||
1006 | kfree(fs_info->log_root_tree); | ||
1007 | fs_info->log_root_tree = NULL; | ||
1008 | return 0; | ||
1009 | } | ||
1010 | |||
1011 | static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, | 975 | static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, |
1012 | struct btrfs_fs_info *fs_info) | 976 | struct btrfs_fs_info *fs_info) |
1013 | { | 977 | { |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index c958ecbc1916..2c064eba6f09 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -95,8 +95,6 @@ int btrfs_congested_async(struct btrfs_fs_info *info, int iodone); | |||
95 | unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info); | 95 | unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info); |
96 | int btrfs_write_tree_block(struct extent_buffer *buf); | 96 | int btrfs_write_tree_block(struct extent_buffer *buf); |
97 | int btrfs_wait_tree_block_writeback(struct extent_buffer *buf); | 97 | int btrfs_wait_tree_block_writeback(struct extent_buffer *buf); |
98 | int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, | ||
99 | struct btrfs_fs_info *fs_info); | ||
100 | int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, | 98 | int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, |
101 | struct btrfs_fs_info *fs_info); | 99 | struct btrfs_fs_info *fs_info); |
102 | int btrfs_add_log_tree(struct btrfs_trans_handle *trans, | 100 | int btrfs_add_log_tree(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 54a255065aa3..21aead39a76c 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -657,6 +657,9 @@ again: | |||
657 | goto found; | 657 | goto found; |
658 | } | 658 | } |
659 | ret = PTR_ERR(item); | 659 | ret = PTR_ERR(item); |
660 | if (ret != -EFBIG && ret != -ENOENT) | ||
661 | goto fail_unlock; | ||
662 | |||
660 | if (ret == -EFBIG) { | 663 | if (ret == -EFBIG) { |
661 | u32 item_size; | 664 | u32 item_size; |
662 | /* we found one, but it isn't big enough yet */ | 665 | /* we found one, but it isn't big enough yet */ |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index af57dd2b43d4..fb102a9aee9c 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -135,6 +135,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans, | |||
135 | struct btrfs_root *root) | 135 | struct btrfs_root *root) |
136 | { | 136 | { |
137 | int ret; | 137 | int ret; |
138 | int err = 0; | ||
138 | 139 | ||
139 | mutex_lock(&root->log_mutex); | 140 | mutex_lock(&root->log_mutex); |
140 | if (root->log_root) { | 141 | if (root->log_root) { |
@@ -155,17 +156,19 @@ static int start_log_trans(struct btrfs_trans_handle *trans, | |||
155 | mutex_lock(&root->fs_info->tree_log_mutex); | 156 | mutex_lock(&root->fs_info->tree_log_mutex); |
156 | if (!root->fs_info->log_root_tree) { | 157 | if (!root->fs_info->log_root_tree) { |
157 | ret = btrfs_init_log_root_tree(trans, root->fs_info); | 158 | ret = btrfs_init_log_root_tree(trans, root->fs_info); |
158 | BUG_ON(ret); | 159 | if (ret) |
160 | err = ret; | ||
159 | } | 161 | } |
160 | if (!root->log_root) { | 162 | if (err == 0 && !root->log_root) { |
161 | ret = btrfs_add_log_tree(trans, root); | 163 | ret = btrfs_add_log_tree(trans, root); |
162 | BUG_ON(ret); | 164 | if (ret) |
165 | err = ret; | ||
163 | } | 166 | } |
164 | mutex_unlock(&root->fs_info->tree_log_mutex); | 167 | mutex_unlock(&root->fs_info->tree_log_mutex); |
165 | root->log_batch++; | 168 | root->log_batch++; |
166 | atomic_inc(&root->log_writers); | 169 | atomic_inc(&root->log_writers); |
167 | mutex_unlock(&root->log_mutex); | 170 | mutex_unlock(&root->log_mutex); |
168 | return 0; | 171 | return err; |
169 | } | 172 | } |
170 | 173 | ||
171 | /* | 174 | /* |
@@ -376,7 +379,7 @@ insert: | |||
376 | BUG_ON(ret); | 379 | BUG_ON(ret); |
377 | } | 380 | } |
378 | } else if (ret) { | 381 | } else if (ret) { |
379 | BUG(); | 382 | return ret; |
380 | } | 383 | } |
381 | dst_ptr = btrfs_item_ptr_offset(path->nodes[0], | 384 | dst_ptr = btrfs_item_ptr_offset(path->nodes[0], |
382 | path->slots[0]); | 385 | path->slots[0]); |
@@ -1699,9 +1702,9 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, | |||
1699 | 1702 | ||
1700 | next = btrfs_find_create_tree_block(root, bytenr, blocksize); | 1703 | next = btrfs_find_create_tree_block(root, bytenr, blocksize); |
1701 | 1704 | ||
1702 | wc->process_func(root, next, wc, ptr_gen); | ||
1703 | |||
1704 | if (*level == 1) { | 1705 | if (*level == 1) { |
1706 | wc->process_func(root, next, wc, ptr_gen); | ||
1707 | |||
1705 | path->slots[*level]++; | 1708 | path->slots[*level]++; |
1706 | if (wc->free) { | 1709 | if (wc->free) { |
1707 | btrfs_read_buffer(next, ptr_gen); | 1710 | btrfs_read_buffer(next, ptr_gen); |
@@ -1734,35 +1737,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, | |||
1734 | WARN_ON(*level < 0); | 1737 | WARN_ON(*level < 0); |
1735 | WARN_ON(*level >= BTRFS_MAX_LEVEL); | 1738 | WARN_ON(*level >= BTRFS_MAX_LEVEL); |
1736 | 1739 | ||
1737 | if (path->nodes[*level] == root->node) | 1740 | path->slots[*level] = btrfs_header_nritems(path->nodes[*level]); |
1738 | parent = path->nodes[*level]; | ||
1739 | else | ||
1740 | parent = path->nodes[*level + 1]; | ||
1741 | |||
1742 | bytenr = path->nodes[*level]->start; | ||
1743 | |||
1744 | blocksize = btrfs_level_size(root, *level); | ||
1745 | root_owner = btrfs_header_owner(parent); | ||
1746 | root_gen = btrfs_header_generation(parent); | ||
1747 | |||
1748 | wc->process_func(root, path->nodes[*level], wc, | ||
1749 | btrfs_header_generation(path->nodes[*level])); | ||
1750 | |||
1751 | if (wc->free) { | ||
1752 | next = path->nodes[*level]; | ||
1753 | btrfs_tree_lock(next); | ||
1754 | clean_tree_block(trans, root, next); | ||
1755 | btrfs_set_lock_blocking(next); | ||
1756 | btrfs_wait_tree_block_writeback(next); | ||
1757 | btrfs_tree_unlock(next); | ||
1758 | |||
1759 | WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID); | ||
1760 | ret = btrfs_free_reserved_extent(root, bytenr, blocksize); | ||
1761 | BUG_ON(ret); | ||
1762 | } | ||
1763 | free_extent_buffer(path->nodes[*level]); | ||
1764 | path->nodes[*level] = NULL; | ||
1765 | *level += 1; | ||
1766 | 1741 | ||
1767 | cond_resched(); | 1742 | cond_resched(); |
1768 | return 0; | 1743 | return 0; |
@@ -1781,7 +1756,7 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, | |||
1781 | 1756 | ||
1782 | for (i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { | 1757 | for (i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { |
1783 | slot = path->slots[i]; | 1758 | slot = path->slots[i]; |
1784 | if (slot < btrfs_header_nritems(path->nodes[i]) - 1) { | 1759 | if (slot + 1 < btrfs_header_nritems(path->nodes[i])) { |
1785 | struct extent_buffer *node; | 1760 | struct extent_buffer *node; |
1786 | node = path->nodes[i]; | 1761 | node = path->nodes[i]; |
1787 | path->slots[i]++; | 1762 | path->slots[i]++; |
@@ -2047,7 +2022,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2047 | mutex_unlock(&log_root_tree->log_mutex); | 2022 | mutex_unlock(&log_root_tree->log_mutex); |
2048 | 2023 | ||
2049 | ret = update_log_root(trans, log); | 2024 | ret = update_log_root(trans, log); |
2050 | BUG_ON(ret); | ||
2051 | 2025 | ||
2052 | mutex_lock(&log_root_tree->log_mutex); | 2026 | mutex_lock(&log_root_tree->log_mutex); |
2053 | if (atomic_dec_and_test(&log_root_tree->log_writers)) { | 2027 | if (atomic_dec_and_test(&log_root_tree->log_writers)) { |
@@ -2056,6 +2030,15 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2056 | wake_up(&log_root_tree->log_writer_wait); | 2030 | wake_up(&log_root_tree->log_writer_wait); |
2057 | } | 2031 | } |
2058 | 2032 | ||
2033 | if (ret) { | ||
2034 | BUG_ON(ret != -ENOSPC); | ||
2035 | root->fs_info->last_trans_log_full_commit = trans->transid; | ||
2036 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | ||
2037 | mutex_unlock(&log_root_tree->log_mutex); | ||
2038 | ret = -EAGAIN; | ||
2039 | goto out; | ||
2040 | } | ||
2041 | |||
2059 | index2 = log_root_tree->log_transid % 2; | 2042 | index2 = log_root_tree->log_transid % 2; |
2060 | if (atomic_read(&log_root_tree->log_commit[index2])) { | 2043 | if (atomic_read(&log_root_tree->log_commit[index2])) { |
2061 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2044 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); |
@@ -2129,15 +2112,10 @@ out: | |||
2129 | return 0; | 2112 | return 0; |
2130 | } | 2113 | } |
2131 | 2114 | ||
2132 | /* | 2115 | static void free_log_tree(struct btrfs_trans_handle *trans, |
2133 | * free all the extents used by the tree log. This should be called | 2116 | struct btrfs_root *log) |
2134 | * at commit time of the full transaction | ||
2135 | */ | ||
2136 | int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root) | ||
2137 | { | 2117 | { |
2138 | int ret; | 2118 | int ret; |
2139 | struct btrfs_root *log; | ||
2140 | struct key; | ||
2141 | u64 start; | 2119 | u64 start; |
2142 | u64 end; | 2120 | u64 end; |
2143 | struct walk_control wc = { | 2121 | struct walk_control wc = { |
@@ -2145,10 +2123,6 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root) | |||
2145 | .process_func = process_one_buffer | 2123 | .process_func = process_one_buffer |
2146 | }; | 2124 | }; |
2147 | 2125 | ||
2148 | if (!root->log_root || root->fs_info->log_root_recovering) | ||
2149 | return 0; | ||
2150 | |||
2151 | log = root->log_root; | ||
2152 | ret = walk_log_tree(trans, log, &wc); | 2126 | ret = walk_log_tree(trans, log, &wc); |
2153 | BUG_ON(ret); | 2127 | BUG_ON(ret); |
2154 | 2128 | ||
@@ -2162,14 +2136,30 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root) | |||
2162 | EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS); | 2136 | EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS); |
2163 | } | 2137 | } |
2164 | 2138 | ||
2165 | if (log->log_transid > 0) { | ||
2166 | ret = btrfs_del_root(trans, root->fs_info->log_root_tree, | ||
2167 | &log->root_key); | ||
2168 | BUG_ON(ret); | ||
2169 | } | ||
2170 | root->log_root = NULL; | ||
2171 | free_extent_buffer(log->node); | 2139 | free_extent_buffer(log->node); |
2172 | kfree(log); | 2140 | kfree(log); |
2141 | } | ||
2142 | |||
2143 | /* | ||
2144 | * free all the extents used by the tree log. This should be called | ||
2145 | * at commit time of the full transaction | ||
2146 | */ | ||
2147 | int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root) | ||
2148 | { | ||
2149 | if (root->log_root) { | ||
2150 | free_log_tree(trans, root->log_root); | ||
2151 | root->log_root = NULL; | ||
2152 | } | ||
2153 | return 0; | ||
2154 | } | ||
2155 | |||
2156 | int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, | ||
2157 | struct btrfs_fs_info *fs_info) | ||
2158 | { | ||
2159 | if (fs_info->log_root_tree) { | ||
2160 | free_log_tree(trans, fs_info->log_root_tree); | ||
2161 | fs_info->log_root_tree = NULL; | ||
2162 | } | ||
2173 | return 0; | 2163 | return 0; |
2174 | } | 2164 | } |
2175 | 2165 | ||
@@ -2203,6 +2193,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, | |||
2203 | struct btrfs_dir_item *di; | 2193 | struct btrfs_dir_item *di; |
2204 | struct btrfs_path *path; | 2194 | struct btrfs_path *path; |
2205 | int ret; | 2195 | int ret; |
2196 | int err = 0; | ||
2206 | int bytes_del = 0; | 2197 | int bytes_del = 0; |
2207 | 2198 | ||
2208 | if (BTRFS_I(dir)->logged_trans < trans->transid) | 2199 | if (BTRFS_I(dir)->logged_trans < trans->transid) |
@@ -2218,7 +2209,11 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, | |||
2218 | path = btrfs_alloc_path(); | 2209 | path = btrfs_alloc_path(); |
2219 | di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino, | 2210 | di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino, |
2220 | name, name_len, -1); | 2211 | name, name_len, -1); |
2221 | if (di && !IS_ERR(di)) { | 2212 | if (IS_ERR(di)) { |
2213 | err = PTR_ERR(di); | ||
2214 | goto fail; | ||
2215 | } | ||
2216 | if (di) { | ||
2222 | ret = btrfs_delete_one_dir_name(trans, log, path, di); | 2217 | ret = btrfs_delete_one_dir_name(trans, log, path, di); |
2223 | bytes_del += name_len; | 2218 | bytes_del += name_len; |
2224 | BUG_ON(ret); | 2219 | BUG_ON(ret); |
@@ -2226,7 +2221,11 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, | |||
2226 | btrfs_release_path(log, path); | 2221 | btrfs_release_path(log, path); |
2227 | di = btrfs_lookup_dir_index_item(trans, log, path, dir->i_ino, | 2222 | di = btrfs_lookup_dir_index_item(trans, log, path, dir->i_ino, |
2228 | index, name, name_len, -1); | 2223 | index, name, name_len, -1); |
2229 | if (di && !IS_ERR(di)) { | 2224 | if (IS_ERR(di)) { |
2225 | err = PTR_ERR(di); | ||
2226 | goto fail; | ||
2227 | } | ||
2228 | if (di) { | ||
2230 | ret = btrfs_delete_one_dir_name(trans, log, path, di); | 2229 | ret = btrfs_delete_one_dir_name(trans, log, path, di); |
2231 | bytes_del += name_len; | 2230 | bytes_del += name_len; |
2232 | BUG_ON(ret); | 2231 | BUG_ON(ret); |
@@ -2244,6 +2243,10 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, | |||
2244 | btrfs_release_path(log, path); | 2243 | btrfs_release_path(log, path); |
2245 | 2244 | ||
2246 | ret = btrfs_search_slot(trans, log, &key, path, 0, 1); | 2245 | ret = btrfs_search_slot(trans, log, &key, path, 0, 1); |
2246 | if (ret < 0) { | ||
2247 | err = ret; | ||
2248 | goto fail; | ||
2249 | } | ||
2247 | if (ret == 0) { | 2250 | if (ret == 0) { |
2248 | struct btrfs_inode_item *item; | 2251 | struct btrfs_inode_item *item; |
2249 | u64 i_size; | 2252 | u64 i_size; |
@@ -2261,9 +2264,13 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, | |||
2261 | ret = 0; | 2264 | ret = 0; |
2262 | btrfs_release_path(log, path); | 2265 | btrfs_release_path(log, path); |
2263 | } | 2266 | } |
2264 | 2267 | fail: | |
2265 | btrfs_free_path(path); | 2268 | btrfs_free_path(path); |
2266 | mutex_unlock(&BTRFS_I(dir)->log_mutex); | 2269 | mutex_unlock(&BTRFS_I(dir)->log_mutex); |
2270 | if (ret == -ENOSPC) { | ||
2271 | root->fs_info->last_trans_log_full_commit = trans->transid; | ||
2272 | ret = 0; | ||
2273 | } | ||
2267 | btrfs_end_log_trans(root); | 2274 | btrfs_end_log_trans(root); |
2268 | 2275 | ||
2269 | return 0; | 2276 | return 0; |
@@ -2291,6 +2298,10 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans, | |||
2291 | ret = btrfs_del_inode_ref(trans, log, name, name_len, inode->i_ino, | 2298 | ret = btrfs_del_inode_ref(trans, log, name, name_len, inode->i_ino, |
2292 | dirid, &index); | 2299 | dirid, &index); |
2293 | mutex_unlock(&BTRFS_I(inode)->log_mutex); | 2300 | mutex_unlock(&BTRFS_I(inode)->log_mutex); |
2301 | if (ret == -ENOSPC) { | ||
2302 | root->fs_info->last_trans_log_full_commit = trans->transid; | ||
2303 | ret = 0; | ||
2304 | } | ||
2294 | btrfs_end_log_trans(root); | 2305 | btrfs_end_log_trans(root); |
2295 | 2306 | ||
2296 | return ret; | 2307 | return ret; |
@@ -2318,7 +2329,8 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans, | |||
2318 | else | 2329 | else |
2319 | key.type = BTRFS_DIR_LOG_INDEX_KEY; | 2330 | key.type = BTRFS_DIR_LOG_INDEX_KEY; |
2320 | ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*item)); | 2331 | ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*item)); |
2321 | BUG_ON(ret); | 2332 | if (ret) |
2333 | return ret; | ||
2322 | 2334 | ||
2323 | item = btrfs_item_ptr(path->nodes[0], path->slots[0], | 2335 | item = btrfs_item_ptr(path->nodes[0], path->slots[0], |
2324 | struct btrfs_dir_log_item); | 2336 | struct btrfs_dir_log_item); |
@@ -2343,6 +2355,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | |||
2343 | struct btrfs_key max_key; | 2355 | struct btrfs_key max_key; |
2344 | struct btrfs_root *log = root->log_root; | 2356 | struct btrfs_root *log = root->log_root; |
2345 | struct extent_buffer *src; | 2357 | struct extent_buffer *src; |
2358 | int err = 0; | ||
2346 | int ret; | 2359 | int ret; |
2347 | int i; | 2360 | int i; |
2348 | int nritems; | 2361 | int nritems; |
@@ -2405,6 +2418,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | |||
2405 | ret = overwrite_item(trans, log, dst_path, | 2418 | ret = overwrite_item(trans, log, dst_path, |
2406 | path->nodes[0], path->slots[0], | 2419 | path->nodes[0], path->slots[0], |
2407 | &tmp); | 2420 | &tmp); |
2421 | if (ret) { | ||
2422 | err = ret; | ||
2423 | goto done; | ||
2424 | } | ||
2408 | } | 2425 | } |
2409 | } | 2426 | } |
2410 | btrfs_release_path(root, path); | 2427 | btrfs_release_path(root, path); |
@@ -2432,7 +2449,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | |||
2432 | goto done; | 2449 | goto done; |
2433 | ret = overwrite_item(trans, log, dst_path, src, i, | 2450 | ret = overwrite_item(trans, log, dst_path, src, i, |
2434 | &min_key); | 2451 | &min_key); |
2435 | BUG_ON(ret); | 2452 | if (ret) { |
2453 | err = ret; | ||
2454 | goto done; | ||
2455 | } | ||
2436 | } | 2456 | } |
2437 | path->slots[0] = nritems; | 2457 | path->slots[0] = nritems; |
2438 | 2458 | ||
@@ -2454,22 +2474,30 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | |||
2454 | ret = overwrite_item(trans, log, dst_path, | 2474 | ret = overwrite_item(trans, log, dst_path, |
2455 | path->nodes[0], path->slots[0], | 2475 | path->nodes[0], path->slots[0], |
2456 | &tmp); | 2476 | &tmp); |
2457 | 2477 | if (ret) | |
2458 | BUG_ON(ret); | 2478 | err = ret; |
2459 | last_offset = tmp.offset; | 2479 | else |
2480 | last_offset = tmp.offset; | ||
2460 | goto done; | 2481 | goto done; |
2461 | } | 2482 | } |
2462 | } | 2483 | } |
2463 | done: | 2484 | done: |
2464 | *last_offset_ret = last_offset; | ||
2465 | btrfs_release_path(root, path); | 2485 | btrfs_release_path(root, path); |
2466 | btrfs_release_path(log, dst_path); | 2486 | btrfs_release_path(log, dst_path); |
2467 | 2487 | ||
2468 | /* insert the log range keys to indicate where the log is valid */ | 2488 | if (err == 0) { |
2469 | ret = insert_dir_log_key(trans, log, path, key_type, inode->i_ino, | 2489 | *last_offset_ret = last_offset; |
2470 | first_offset, last_offset); | 2490 | /* |
2471 | BUG_ON(ret); | 2491 | * insert the log range keys to indicate where the log |
2472 | return 0; | 2492 | * is valid |
2493 | */ | ||
2494 | ret = insert_dir_log_key(trans, log, path, key_type, | ||
2495 | inode->i_ino, first_offset, | ||
2496 | last_offset); | ||
2497 | if (ret) | ||
2498 | err = ret; | ||
2499 | } | ||
2500 | return err; | ||
2473 | } | 2501 | } |
2474 | 2502 | ||
2475 | /* | 2503 | /* |
@@ -2501,7 +2529,8 @@ again: | |||
2501 | ret = log_dir_items(trans, root, inode, path, | 2529 | ret = log_dir_items(trans, root, inode, path, |
2502 | dst_path, key_type, min_key, | 2530 | dst_path, key_type, min_key, |
2503 | &max_key); | 2531 | &max_key); |
2504 | BUG_ON(ret); | 2532 | if (ret) |
2533 | return ret; | ||
2505 | if (max_key == (u64)-1) | 2534 | if (max_key == (u64)-1) |
2506 | break; | 2535 | break; |
2507 | min_key = max_key + 1; | 2536 | min_key = max_key + 1; |
@@ -2535,8 +2564,8 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans, | |||
2535 | 2564 | ||
2536 | while (1) { | 2565 | while (1) { |
2537 | ret = btrfs_search_slot(trans, log, &key, path, -1, 1); | 2566 | ret = btrfs_search_slot(trans, log, &key, path, -1, 1); |
2538 | 2567 | BUG_ON(ret == 0); | |
2539 | if (ret != 1) | 2568 | if (ret < 0) |
2540 | break; | 2569 | break; |
2541 | 2570 | ||
2542 | if (path->slots[0] == 0) | 2571 | if (path->slots[0] == 0) |
@@ -2554,7 +2583,7 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans, | |||
2554 | btrfs_release_path(log, path); | 2583 | btrfs_release_path(log, path); |
2555 | } | 2584 | } |
2556 | btrfs_release_path(log, path); | 2585 | btrfs_release_path(log, path); |
2557 | return 0; | 2586 | return ret; |
2558 | } | 2587 | } |
2559 | 2588 | ||
2560 | static noinline int copy_items(struct btrfs_trans_handle *trans, | 2589 | static noinline int copy_items(struct btrfs_trans_handle *trans, |
@@ -2587,7 +2616,10 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
2587 | } | 2616 | } |
2588 | ret = btrfs_insert_empty_items(trans, log, dst_path, | 2617 | ret = btrfs_insert_empty_items(trans, log, dst_path, |
2589 | ins_keys, ins_sizes, nr); | 2618 | ins_keys, ins_sizes, nr); |
2590 | BUG_ON(ret); | 2619 | if (ret) { |
2620 | kfree(ins_data); | ||
2621 | return ret; | ||
2622 | } | ||
2591 | 2623 | ||
2592 | for (i = 0; i < nr; i++, dst_path->slots[0]++) { | 2624 | for (i = 0; i < nr; i++, dst_path->slots[0]++) { |
2593 | dst_offset = btrfs_item_ptr_offset(dst_path->nodes[0], | 2625 | dst_offset = btrfs_item_ptr_offset(dst_path->nodes[0], |
@@ -2660,16 +2692,17 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
2660 | * we have to do this after the loop above to avoid changing the | 2692 | * we have to do this after the loop above to avoid changing the |
2661 | * log tree while trying to change the log tree. | 2693 | * log tree while trying to change the log tree. |
2662 | */ | 2694 | */ |
2695 | ret = 0; | ||
2663 | while (!list_empty(&ordered_sums)) { | 2696 | while (!list_empty(&ordered_sums)) { |
2664 | struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next, | 2697 | struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next, |
2665 | struct btrfs_ordered_sum, | 2698 | struct btrfs_ordered_sum, |
2666 | list); | 2699 | list); |
2667 | ret = btrfs_csum_file_blocks(trans, log, sums); | 2700 | if (!ret) |
2668 | BUG_ON(ret); | 2701 | ret = btrfs_csum_file_blocks(trans, log, sums); |
2669 | list_del(&sums->list); | 2702 | list_del(&sums->list); |
2670 | kfree(sums); | 2703 | kfree(sums); |
2671 | } | 2704 | } |
2672 | return 0; | 2705 | return ret; |
2673 | } | 2706 | } |
2674 | 2707 | ||
2675 | /* log a single inode in the tree log. | 2708 | /* log a single inode in the tree log. |
@@ -2697,6 +2730,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
2697 | struct btrfs_root *log = root->log_root; | 2730 | struct btrfs_root *log = root->log_root; |
2698 | struct extent_buffer *src = NULL; | 2731 | struct extent_buffer *src = NULL; |
2699 | u32 size; | 2732 | u32 size; |
2733 | int err = 0; | ||
2700 | int ret; | 2734 | int ret; |
2701 | int nritems; | 2735 | int nritems; |
2702 | int ins_start_slot = 0; | 2736 | int ins_start_slot = 0; |
@@ -2739,7 +2773,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
2739 | } else { | 2773 | } else { |
2740 | ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0); | 2774 | ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0); |
2741 | } | 2775 | } |
2742 | BUG_ON(ret); | 2776 | if (ret) { |
2777 | err = ret; | ||
2778 | goto out_unlock; | ||
2779 | } | ||
2743 | path->keep_locks = 1; | 2780 | path->keep_locks = 1; |
2744 | 2781 | ||
2745 | while (1) { | 2782 | while (1) { |
@@ -2768,7 +2805,10 @@ again: | |||
2768 | 2805 | ||
2769 | ret = copy_items(trans, log, dst_path, src, ins_start_slot, | 2806 | ret = copy_items(trans, log, dst_path, src, ins_start_slot, |
2770 | ins_nr, inode_only); | 2807 | ins_nr, inode_only); |
2771 | BUG_ON(ret); | 2808 | if (ret) { |
2809 | err = ret; | ||
2810 | goto out_unlock; | ||
2811 | } | ||
2772 | ins_nr = 1; | 2812 | ins_nr = 1; |
2773 | ins_start_slot = path->slots[0]; | 2813 | ins_start_slot = path->slots[0]; |
2774 | next_slot: | 2814 | next_slot: |
@@ -2784,7 +2824,10 @@ next_slot: | |||
2784 | ret = copy_items(trans, log, dst_path, src, | 2824 | ret = copy_items(trans, log, dst_path, src, |
2785 | ins_start_slot, | 2825 | ins_start_slot, |
2786 | ins_nr, inode_only); | 2826 | ins_nr, inode_only); |
2787 | BUG_ON(ret); | 2827 | if (ret) { |
2828 | err = ret; | ||
2829 | goto out_unlock; | ||
2830 | } | ||
2788 | ins_nr = 0; | 2831 | ins_nr = 0; |
2789 | } | 2832 | } |
2790 | btrfs_release_path(root, path); | 2833 | btrfs_release_path(root, path); |
@@ -2802,7 +2845,10 @@ next_slot: | |||
2802 | ret = copy_items(trans, log, dst_path, src, | 2845 | ret = copy_items(trans, log, dst_path, src, |
2803 | ins_start_slot, | 2846 | ins_start_slot, |
2804 | ins_nr, inode_only); | 2847 | ins_nr, inode_only); |
2805 | BUG_ON(ret); | 2848 | if (ret) { |
2849 | err = ret; | ||
2850 | goto out_unlock; | ||
2851 | } | ||
2806 | ins_nr = 0; | 2852 | ins_nr = 0; |
2807 | } | 2853 | } |
2808 | WARN_ON(ins_nr); | 2854 | WARN_ON(ins_nr); |
@@ -2810,14 +2856,18 @@ next_slot: | |||
2810 | btrfs_release_path(root, path); | 2856 | btrfs_release_path(root, path); |
2811 | btrfs_release_path(log, dst_path); | 2857 | btrfs_release_path(log, dst_path); |
2812 | ret = log_directory_changes(trans, root, inode, path, dst_path); | 2858 | ret = log_directory_changes(trans, root, inode, path, dst_path); |
2813 | BUG_ON(ret); | 2859 | if (ret) { |
2860 | err = ret; | ||
2861 | goto out_unlock; | ||
2862 | } | ||
2814 | } | 2863 | } |
2815 | BTRFS_I(inode)->logged_trans = trans->transid; | 2864 | BTRFS_I(inode)->logged_trans = trans->transid; |
2865 | out_unlock: | ||
2816 | mutex_unlock(&BTRFS_I(inode)->log_mutex); | 2866 | mutex_unlock(&BTRFS_I(inode)->log_mutex); |
2817 | 2867 | ||
2818 | btrfs_free_path(path); | 2868 | btrfs_free_path(path); |
2819 | btrfs_free_path(dst_path); | 2869 | btrfs_free_path(dst_path); |
2820 | return 0; | 2870 | return err; |
2821 | } | 2871 | } |
2822 | 2872 | ||
2823 | /* | 2873 | /* |
@@ -2942,10 +2992,13 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
2942 | goto end_no_trans; | 2992 | goto end_no_trans; |
2943 | } | 2993 | } |
2944 | 2994 | ||
2945 | start_log_trans(trans, root); | 2995 | ret = start_log_trans(trans, root); |
2996 | if (ret) | ||
2997 | goto end_trans; | ||
2946 | 2998 | ||
2947 | ret = btrfs_log_inode(trans, root, inode, inode_only); | 2999 | ret = btrfs_log_inode(trans, root, inode, inode_only); |
2948 | BUG_ON(ret); | 3000 | if (ret) |
3001 | goto end_trans; | ||
2949 | 3002 | ||
2950 | /* | 3003 | /* |
2951 | * for regular files, if its inode is already on disk, we don't | 3004 | * for regular files, if its inode is already on disk, we don't |
@@ -2955,8 +3008,10 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
2955 | */ | 3008 | */ |
2956 | if (S_ISREG(inode->i_mode) && | 3009 | if (S_ISREG(inode->i_mode) && |
2957 | BTRFS_I(inode)->generation <= last_committed && | 3010 | BTRFS_I(inode)->generation <= last_committed && |
2958 | BTRFS_I(inode)->last_unlink_trans <= last_committed) | 3011 | BTRFS_I(inode)->last_unlink_trans <= last_committed) { |
2959 | goto no_parent; | 3012 | ret = 0; |
3013 | goto end_trans; | ||
3014 | } | ||
2960 | 3015 | ||
2961 | inode_only = LOG_INODE_EXISTS; | 3016 | inode_only = LOG_INODE_EXISTS; |
2962 | while (1) { | 3017 | while (1) { |
@@ -2970,15 +3025,21 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
2970 | if (BTRFS_I(inode)->generation > | 3025 | if (BTRFS_I(inode)->generation > |
2971 | root->fs_info->last_trans_committed) { | 3026 | root->fs_info->last_trans_committed) { |
2972 | ret = btrfs_log_inode(trans, root, inode, inode_only); | 3027 | ret = btrfs_log_inode(trans, root, inode, inode_only); |
2973 | BUG_ON(ret); | 3028 | if (ret) |
3029 | goto end_trans; | ||
2974 | } | 3030 | } |
2975 | if (IS_ROOT(parent)) | 3031 | if (IS_ROOT(parent)) |
2976 | break; | 3032 | break; |
2977 | 3033 | ||
2978 | parent = parent->d_parent; | 3034 | parent = parent->d_parent; |
2979 | } | 3035 | } |
2980 | no_parent: | ||
2981 | ret = 0; | 3036 | ret = 0; |
3037 | end_trans: | ||
3038 | if (ret < 0) { | ||
3039 | BUG_ON(ret != -ENOSPC); | ||
3040 | root->fs_info->last_trans_log_full_commit = trans->transid; | ||
3041 | ret = 1; | ||
3042 | } | ||
2982 | btrfs_end_log_trans(root); | 3043 | btrfs_end_log_trans(root); |
2983 | end_no_trans: | 3044 | end_no_trans: |
2984 | return ret; | 3045 | return ret; |
@@ -3020,7 +3081,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) | |||
3020 | path = btrfs_alloc_path(); | 3081 | path = btrfs_alloc_path(); |
3021 | BUG_ON(!path); | 3082 | BUG_ON(!path); |
3022 | 3083 | ||
3023 | trans = btrfs_start_transaction(fs_info->tree_root, 1); | 3084 | trans = btrfs_start_transaction(fs_info->tree_root, 0); |
3024 | 3085 | ||
3025 | wc.trans = trans; | 3086 | wc.trans = trans; |
3026 | wc.pin = 1; | 3087 | wc.pin = 1; |
diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h index 0776eacb5083..3dfae84c8cc8 100644 --- a/fs/btrfs/tree-log.h +++ b/fs/btrfs/tree-log.h | |||
@@ -25,6 +25,8 @@ | |||
25 | int btrfs_sync_log(struct btrfs_trans_handle *trans, | 25 | int btrfs_sync_log(struct btrfs_trans_handle *trans, |
26 | struct btrfs_root *root); | 26 | struct btrfs_root *root); |
27 | int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root); | 27 | int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root); |
28 | int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, | ||
29 | struct btrfs_fs_info *fs_info); | ||
28 | int btrfs_recover_log_trees(struct btrfs_root *tree_root); | 30 | int btrfs_recover_log_trees(struct btrfs_root *tree_root); |
29 | int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, | 31 | int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, |
30 | struct btrfs_root *root, struct dentry *dentry); | 32 | struct btrfs_root *root, struct dentry *dentry); |