diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-11-07 21:08:16 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:57 -0400 |
commit | 09be207d1ba224531a61de9afdc07a125e45318c (patch) | |
tree | f88b82aa822903f6f86e0ec9f00dc99195949e1e /fs | |
parent | 0da5468f4724a59e745d938395beffe830c424ee (diff) |
Btrfs: Fix failure cleanups when allocating extent buffers fail
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/extent_map.c | 56 |
1 files changed, 30 insertions, 26 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index b0677c84bb75..c976615dcda3 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -2106,25 +2106,17 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_map_tree *tree, | |||
2106 | 2106 | ||
2107 | spin_lock(&tree->lru_lock); | 2107 | spin_lock(&tree->lru_lock); |
2108 | eb = find_lru(tree, start, len); | 2108 | eb = find_lru(tree, start, len); |
2109 | if (eb) { | ||
2110 | goto lru_add; | ||
2111 | } | ||
2112 | spin_unlock(&tree->lru_lock); | 2109 | spin_unlock(&tree->lru_lock); |
2113 | |||
2114 | if (eb) { | 2110 | if (eb) { |
2115 | memset(eb, 0, sizeof(*eb)); | 2111 | return eb; |
2116 | } else { | ||
2117 | eb = kmem_cache_zalloc(extent_buffer_cache, mask); | ||
2118 | } | 2112 | } |
2113 | |||
2114 | eb = kmem_cache_zalloc(extent_buffer_cache, mask); | ||
2119 | INIT_LIST_HEAD(&eb->lru); | 2115 | INIT_LIST_HEAD(&eb->lru); |
2120 | eb->start = start; | 2116 | eb->start = start; |
2121 | eb->len = len; | 2117 | eb->len = len; |
2122 | atomic_set(&eb->refs, 1); | 2118 | atomic_set(&eb->refs, 1); |
2123 | 2119 | ||
2124 | spin_lock(&tree->lru_lock); | ||
2125 | lru_add: | ||
2126 | add_lru(tree, eb); | ||
2127 | spin_unlock(&tree->lru_lock); | ||
2128 | return eb; | 2120 | return eb; |
2129 | } | 2121 | } |
2130 | 2122 | ||
@@ -2151,7 +2143,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | |||
2151 | return NULL; | 2143 | return NULL; |
2152 | 2144 | ||
2153 | if (eb->flags & EXTENT_BUFFER_FILLED) | 2145 | if (eb->flags & EXTENT_BUFFER_FILLED) |
2154 | return eb; | 2146 | goto lru_add; |
2155 | 2147 | ||
2156 | if (page0) { | 2148 | if (page0) { |
2157 | eb->first_page = page0; | 2149 | eb->first_page = page0; |
@@ -2169,11 +2161,6 @@ struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | |||
2169 | p = find_or_create_page(mapping, index, mask | __GFP_HIGHMEM); | 2161 | p = find_or_create_page(mapping, index, mask | __GFP_HIGHMEM); |
2170 | if (!p) { | 2162 | if (!p) { |
2171 | WARN_ON(1); | 2163 | WARN_ON(1); |
2172 | /* make sure the free only frees the pages we've | ||
2173 | * grabbed a reference on | ||
2174 | */ | ||
2175 | eb->len = i << PAGE_CACHE_SHIFT; | ||
2176 | eb->start &= ~((u64)PAGE_CACHE_SIZE - 1); | ||
2177 | goto fail; | 2164 | goto fail; |
2178 | } | 2165 | } |
2179 | set_page_extent_mapped(p); | 2166 | set_page_extent_mapped(p); |
@@ -2192,9 +2179,20 @@ struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | |||
2192 | if (uptodate) | 2179 | if (uptodate) |
2193 | eb->flags |= EXTENT_UPTODATE; | 2180 | eb->flags |= EXTENT_UPTODATE; |
2194 | eb->flags |= EXTENT_BUFFER_FILLED; | 2181 | eb->flags |= EXTENT_BUFFER_FILLED; |
2182 | |||
2183 | lru_add: | ||
2184 | spin_lock(&tree->lru_lock); | ||
2185 | add_lru(tree, eb); | ||
2186 | spin_unlock(&tree->lru_lock); | ||
2195 | return eb; | 2187 | return eb; |
2188 | |||
2196 | fail: | 2189 | fail: |
2197 | free_extent_buffer(eb); | 2190 | if (!atomic_dec_and_test(&eb->refs)) |
2191 | return NULL; | ||
2192 | for (index = 0; index < i; index++) { | ||
2193 | page_cache_release(extent_buffer_page(eb, index)); | ||
2194 | } | ||
2195 | __free_extent_buffer(eb); | ||
2198 | return NULL; | 2196 | return NULL; |
2199 | } | 2197 | } |
2200 | EXPORT_SYMBOL(alloc_extent_buffer); | 2198 | EXPORT_SYMBOL(alloc_extent_buffer); |
@@ -2204,7 +2202,8 @@ struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, | |||
2204 | gfp_t mask) | 2202 | gfp_t mask) |
2205 | { | 2203 | { |
2206 | unsigned long num_pages = num_extent_pages(start, len); | 2204 | unsigned long num_pages = num_extent_pages(start, len); |
2207 | unsigned long i; unsigned long index = start >> PAGE_CACHE_SHIFT; | 2205 | unsigned long i; |
2206 | unsigned long index = start >> PAGE_CACHE_SHIFT; | ||
2208 | struct extent_buffer *eb; | 2207 | struct extent_buffer *eb; |
2209 | struct page *p; | 2208 | struct page *p; |
2210 | struct address_space *mapping = tree->mapping; | 2209 | struct address_space *mapping = tree->mapping; |
@@ -2215,16 +2214,11 @@ struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, | |||
2215 | return NULL; | 2214 | return NULL; |
2216 | 2215 | ||
2217 | if (eb->flags & EXTENT_BUFFER_FILLED) | 2216 | if (eb->flags & EXTENT_BUFFER_FILLED) |
2218 | return eb; | 2217 | goto lru_add; |
2219 | 2218 | ||
2220 | for (i = 0; i < num_pages; i++, index++) { | 2219 | for (i = 0; i < num_pages; i++, index++) { |
2221 | p = find_lock_page(mapping, index); | 2220 | p = find_lock_page(mapping, index); |
2222 | if (!p) { | 2221 | if (!p) { |
2223 | /* make sure the free only frees the pages we've | ||
2224 | * grabbed a reference on | ||
2225 | */ | ||
2226 | eb->len = i << PAGE_CACHE_SHIFT; | ||
2227 | eb->start &= ~((u64)PAGE_CACHE_SIZE - 1); | ||
2228 | goto fail; | 2222 | goto fail; |
2229 | } | 2223 | } |
2230 | set_page_extent_mapped(p); | 2224 | set_page_extent_mapped(p); |
@@ -2245,9 +2239,19 @@ struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, | |||
2245 | if (uptodate) | 2239 | if (uptodate) |
2246 | eb->flags |= EXTENT_UPTODATE; | 2240 | eb->flags |= EXTENT_UPTODATE; |
2247 | eb->flags |= EXTENT_BUFFER_FILLED; | 2241 | eb->flags |= EXTENT_BUFFER_FILLED; |
2242 | |||
2243 | lru_add: | ||
2244 | spin_lock(&tree->lru_lock); | ||
2245 | add_lru(tree, eb); | ||
2246 | spin_unlock(&tree->lru_lock); | ||
2248 | return eb; | 2247 | return eb; |
2249 | fail: | 2248 | fail: |
2250 | free_extent_buffer(eb); | 2249 | if (!atomic_dec_and_test(&eb->refs)) |
2250 | return NULL; | ||
2251 | for (index = 0; index < i; index++) { | ||
2252 | page_cache_release(extent_buffer_page(eb, index)); | ||
2253 | } | ||
2254 | __free_extent_buffer(eb); | ||
2251 | return NULL; | 2255 | return NULL; |
2252 | } | 2256 | } |
2253 | EXPORT_SYMBOL(find_extent_buffer); | 2257 | EXPORT_SYMBOL(find_extent_buffer); |