diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-10-15 16:19:22 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:56 -0400 |
commit | 19c00ddcc31ad4bdfb86b57085e06d6135b9b1d7 (patch) | |
tree | a48cbaac47070057912c1b35d270b61b7e14386c /fs/btrfs/extent_map.c | |
parent | 0f82731fc56448c2733f58e1f5db6c2cbfc90652 (diff) |
Btrfs: Add back metadata checksumming
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent_map.c')
-rw-r--r-- | fs/btrfs/extent_map.c | 83 |
1 files changed, 68 insertions, 15 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index f8aaba8a30a..2a8bc4bd43a 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -81,7 +81,7 @@ void extent_map_tree_init(struct extent_map_tree *tree, | |||
81 | } | 81 | } |
82 | EXPORT_SYMBOL(extent_map_tree_init); | 82 | EXPORT_SYMBOL(extent_map_tree_init); |
83 | 83 | ||
84 | void extent_map_tree_cleanup(struct extent_map_tree *tree) | 84 | void extent_map_tree_empty_lru(struct extent_map_tree *tree) |
85 | { | 85 | { |
86 | struct extent_buffer *eb; | 86 | struct extent_buffer *eb; |
87 | while(!list_empty(&tree->buffer_lru)) { | 87 | while(!list_empty(&tree->buffer_lru)) { |
@@ -91,7 +91,7 @@ void extent_map_tree_cleanup(struct extent_map_tree *tree) | |||
91 | free_extent_buffer(eb); | 91 | free_extent_buffer(eb); |
92 | } | 92 | } |
93 | } | 93 | } |
94 | EXPORT_SYMBOL(extent_map_tree_cleanup); | 94 | EXPORT_SYMBOL(extent_map_tree_empty_lru); |
95 | 95 | ||
96 | struct extent_map *alloc_extent_map(gfp_t mask) | 96 | struct extent_map *alloc_extent_map(gfp_t mask) |
97 | { | 97 | { |
@@ -1464,7 +1464,7 @@ void set_page_extent_mapped(struct page *page) | |||
1464 | if (!PagePrivate(page)) { | 1464 | if (!PagePrivate(page)) { |
1465 | SetPagePrivate(page); | 1465 | SetPagePrivate(page); |
1466 | WARN_ON(!page->mapping->a_ops->invalidatepage); | 1466 | WARN_ON(!page->mapping->a_ops->invalidatepage); |
1467 | set_page_private(page, 1); | 1467 | set_page_private(page, EXTENT_PAGE_PRIVATE); |
1468 | page_cache_get(page); | 1468 | page_cache_get(page); |
1469 | } | 1469 | } |
1470 | } | 1470 | } |
@@ -1979,8 +1979,9 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_map_tree *tree, | |||
1979 | 1979 | ||
1980 | spin_lock(&tree->lru_lock); | 1980 | spin_lock(&tree->lru_lock); |
1981 | eb = find_lru(tree, start, len); | 1981 | eb = find_lru(tree, start, len); |
1982 | if (eb) | 1982 | if (eb) { |
1983 | goto lru_add; | 1983 | goto lru_add; |
1984 | } | ||
1984 | spin_unlock(&tree->lru_lock); | 1985 | spin_unlock(&tree->lru_lock); |
1985 | 1986 | ||
1986 | if (eb) { | 1987 | if (eb) { |
@@ -2007,6 +2008,7 @@ static void __free_extent_buffer(struct extent_buffer *eb) | |||
2007 | 2008 | ||
2008 | struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | 2009 | struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, |
2009 | u64 start, unsigned long len, | 2010 | u64 start, unsigned long len, |
2011 | struct page *page0, | ||
2010 | gfp_t mask) | 2012 | gfp_t mask) |
2011 | { | 2013 | { |
2012 | unsigned long num_pages = num_extent_pages(start, len); | 2014 | unsigned long num_pages = num_extent_pages(start, len); |
@@ -2024,7 +2026,18 @@ struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | |||
2024 | if (eb->flags & EXTENT_BUFFER_FILLED) | 2026 | if (eb->flags & EXTENT_BUFFER_FILLED) |
2025 | return eb; | 2027 | return eb; |
2026 | 2028 | ||
2027 | for (i = 0; i < num_pages; i++, index++) { | 2029 | if (page0) { |
2030 | eb->first_page = page0; | ||
2031 | i = 1; | ||
2032 | index++; | ||
2033 | page_cache_get(page0); | ||
2034 | set_page_extent_mapped(page0); | ||
2035 | set_page_private(page0, EXTENT_PAGE_PRIVATE_FIRST_PAGE | | ||
2036 | len << 2); | ||
2037 | } else { | ||
2038 | i = 0; | ||
2039 | } | ||
2040 | for (; i < num_pages; i++, index++) { | ||
2028 | p = find_or_create_page(mapping, index, mask | __GFP_HIGHMEM); | 2041 | p = find_or_create_page(mapping, index, mask | __GFP_HIGHMEM); |
2029 | if (!p) { | 2042 | if (!p) { |
2030 | WARN_ON(1); | 2043 | WARN_ON(1); |
@@ -2036,8 +2049,13 @@ struct extent_buffer *alloc_extent_buffer(struct extent_map_tree *tree, | |||
2036 | goto fail; | 2049 | goto fail; |
2037 | } | 2050 | } |
2038 | set_page_extent_mapped(p); | 2051 | set_page_extent_mapped(p); |
2039 | if (i == 0) | 2052 | if (i == 0) { |
2040 | eb->first_page = p; | 2053 | eb->first_page = p; |
2054 | set_page_private(p, EXTENT_PAGE_PRIVATE_FIRST_PAGE | | ||
2055 | len << 2); | ||
2056 | } else { | ||
2057 | set_page_private(p, EXTENT_PAGE_PRIVATE); | ||
2058 | } | ||
2041 | if (!PageUptodate(p)) | 2059 | if (!PageUptodate(p)) |
2042 | uptodate = 0; | 2060 | uptodate = 0; |
2043 | unlock_page(p); | 2061 | unlock_page(p); |
@@ -2057,8 +2075,7 @@ struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, | |||
2057 | gfp_t mask) | 2075 | gfp_t mask) |
2058 | { | 2076 | { |
2059 | unsigned long num_pages = num_extent_pages(start, len); | 2077 | unsigned long num_pages = num_extent_pages(start, len); |
2060 | unsigned long i; | 2078 | unsigned long i; unsigned long index = start >> PAGE_CACHE_SHIFT; |
2061 | unsigned long index = start >> PAGE_CACHE_SHIFT; | ||
2062 | struct extent_buffer *eb; | 2079 | struct extent_buffer *eb; |
2063 | struct page *p; | 2080 | struct page *p; |
2064 | struct address_space *mapping = tree->mapping; | 2081 | struct address_space *mapping = tree->mapping; |
@@ -2082,8 +2099,15 @@ struct extent_buffer *find_extent_buffer(struct extent_map_tree *tree, | |||
2082 | goto fail; | 2099 | goto fail; |
2083 | } | 2100 | } |
2084 | set_page_extent_mapped(p); | 2101 | set_page_extent_mapped(p); |
2085 | if (i == 0) | 2102 | |
2103 | if (i == 0) { | ||
2086 | eb->first_page = p; | 2104 | eb->first_page = p; |
2105 | set_page_private(p, EXTENT_PAGE_PRIVATE_FIRST_PAGE | | ||
2106 | len << 2); | ||
2107 | } else { | ||
2108 | set_page_private(p, EXTENT_PAGE_PRIVATE); | ||
2109 | } | ||
2110 | |||
2087 | if (!PageUptodate(p)) | 2111 | if (!PageUptodate(p)) |
2088 | uptodate = 0; | 2112 | uptodate = 0; |
2089 | unlock_page(p); | 2113 | unlock_page(p); |
@@ -2174,7 +2198,21 @@ int set_extent_buffer_dirty(struct extent_map_tree *tree, | |||
2174 | 2198 | ||
2175 | num_pages = num_extent_pages(eb->start, eb->len); | 2199 | num_pages = num_extent_pages(eb->start, eb->len); |
2176 | for (i = 0; i < num_pages; i++) { | 2200 | for (i = 0; i < num_pages; i++) { |
2201 | struct page *page = extent_buffer_page(eb, i); | ||
2202 | /* writepage may need to do something special for the | ||
2203 | * first page, we have to make sure page->private is | ||
2204 | * properly set. releasepage may drop page->private | ||
2205 | * on us if the page isn't already dirty. | ||
2206 | */ | ||
2207 | if (i == 0) { | ||
2208 | lock_page(page); | ||
2209 | set_page_private(page, | ||
2210 | EXTENT_PAGE_PRIVATE_FIRST_PAGE | | ||
2211 | eb->len << 2); | ||
2212 | } | ||
2177 | __set_page_dirty_nobuffers(extent_buffer_page(eb, i)); | 2213 | __set_page_dirty_nobuffers(extent_buffer_page(eb, i)); |
2214 | if (i == 0) | ||
2215 | unlock_page(page); | ||
2178 | } | 2216 | } |
2179 | return set_extent_dirty(tree, eb->start, | 2217 | return set_extent_dirty(tree, eb->start, |
2180 | eb->start + eb->len - 1, GFP_NOFS); | 2218 | eb->start + eb->len - 1, GFP_NOFS); |
@@ -2217,9 +2255,12 @@ int extent_buffer_uptodate(struct extent_map_tree *tree, | |||
2217 | EXPORT_SYMBOL(extent_buffer_uptodate); | 2255 | EXPORT_SYMBOL(extent_buffer_uptodate); |
2218 | 2256 | ||
2219 | int read_extent_buffer_pages(struct extent_map_tree *tree, | 2257 | int read_extent_buffer_pages(struct extent_map_tree *tree, |
2220 | struct extent_buffer *eb, int wait) | 2258 | struct extent_buffer *eb, |
2259 | u64 start, | ||
2260 | int wait) | ||
2221 | { | 2261 | { |
2222 | unsigned long i; | 2262 | unsigned long i; |
2263 | unsigned long start_i; | ||
2223 | struct page *page; | 2264 | struct page *page; |
2224 | int err; | 2265 | int err; |
2225 | int ret = 0; | 2266 | int ret = 0; |
@@ -2232,9 +2273,16 @@ int read_extent_buffer_pages(struct extent_map_tree *tree, | |||
2232 | EXTENT_UPTODATE, 1)) { | 2273 | EXTENT_UPTODATE, 1)) { |
2233 | return 0; | 2274 | return 0; |
2234 | } | 2275 | } |
2276 | if (start) { | ||
2277 | WARN_ON(start < eb->start); | ||
2278 | start_i = (start >> PAGE_CACHE_SHIFT) - | ||
2279 | (eb->start >> PAGE_CACHE_SHIFT); | ||
2280 | } else { | ||
2281 | start_i = 0; | ||
2282 | } | ||
2235 | 2283 | ||
2236 | num_pages = num_extent_pages(eb->start, eb->len); | 2284 | num_pages = num_extent_pages(eb->start, eb->len); |
2237 | for (i = 0; i < num_pages; i++) { | 2285 | for (i = start_i; i < num_pages; i++) { |
2238 | page = extent_buffer_page(eb, i); | 2286 | page = extent_buffer_page(eb, i); |
2239 | if (PageUptodate(page)) { | 2287 | if (PageUptodate(page)) { |
2240 | continue; | 2288 | continue; |
@@ -2260,7 +2308,7 @@ int read_extent_buffer_pages(struct extent_map_tree *tree, | |||
2260 | return ret; | 2308 | return ret; |
2261 | } | 2309 | } |
2262 | 2310 | ||
2263 | for (i = 0; i < num_pages; i++) { | 2311 | for (i = start_i; i < num_pages; i++) { |
2264 | page = extent_buffer_page(eb, i); | 2312 | page = extent_buffer_page(eb, i); |
2265 | wait_on_page_locked(page); | 2313 | wait_on_page_locked(page); |
2266 | if (!PageUptodate(page)) { | 2314 | if (!PageUptodate(page)) { |
@@ -2314,7 +2362,7 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv, | |||
2314 | } | 2362 | } |
2315 | EXPORT_SYMBOL(read_extent_buffer); | 2363 | EXPORT_SYMBOL(read_extent_buffer); |
2316 | 2364 | ||
2317 | static int __map_extent_buffer(struct extent_buffer *eb, unsigned long start, | 2365 | int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, |
2318 | unsigned long min_len, char **token, char **map, | 2366 | unsigned long min_len, char **token, char **map, |
2319 | unsigned long *map_start, | 2367 | unsigned long *map_start, |
2320 | unsigned long *map_len, int km) | 2368 | unsigned long *map_len, int km) |
@@ -2337,6 +2385,10 @@ static int __map_extent_buffer(struct extent_buffer *eb, unsigned long start, | |||
2337 | offset = 0; | 2385 | offset = 0; |
2338 | *map_start = (i << PAGE_CACHE_SHIFT) - start_offset; | 2386 | *map_start = (i << PAGE_CACHE_SHIFT) - start_offset; |
2339 | } | 2387 | } |
2388 | if (start + min_len >= eb->len) { | ||
2389 | printk("bad mapping eb start %Lu len %lu, wanted %lu %lu\n", eb->start, eb->len, start, min_len); | ||
2390 | WARN_ON(1); | ||
2391 | } | ||
2340 | 2392 | ||
2341 | p = extent_buffer_page(eb, i); | 2393 | p = extent_buffer_page(eb, i); |
2342 | WARN_ON(!PageUptodate(p)); | 2394 | WARN_ON(!PageUptodate(p)); |
@@ -2346,6 +2398,7 @@ static int __map_extent_buffer(struct extent_buffer *eb, unsigned long start, | |||
2346 | *map_len = PAGE_CACHE_SIZE - offset; | 2398 | *map_len = PAGE_CACHE_SIZE - offset; |
2347 | return 0; | 2399 | return 0; |
2348 | } | 2400 | } |
2401 | EXPORT_SYMBOL(map_private_extent_buffer); | ||
2349 | 2402 | ||
2350 | int map_extent_buffer(struct extent_buffer *eb, unsigned long start, | 2403 | int map_extent_buffer(struct extent_buffer *eb, unsigned long start, |
2351 | unsigned long min_len, | 2404 | unsigned long min_len, |
@@ -2360,8 +2413,8 @@ int map_extent_buffer(struct extent_buffer *eb, unsigned long start, | |||
2360 | eb->map_token = NULL; | 2413 | eb->map_token = NULL; |
2361 | save = 1; | 2414 | save = 1; |
2362 | } | 2415 | } |
2363 | err = __map_extent_buffer(eb, start, min_len, token, map, | 2416 | err = map_private_extent_buffer(eb, start, min_len, token, map, |
2364 | map_start, map_len, km); | 2417 | map_start, map_len, km); |
2365 | if (!err && save) { | 2418 | if (!err && save) { |
2366 | eb->map_token = *token; | 2419 | eb->map_token = *token; |
2367 | eb->kaddr = *map; | 2420 | eb->kaddr = *map; |