diff options
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 2e993cf1766e..92ac5192c518 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -1865,7 +1865,7 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num, | |||
1865 | bio_get(bio); | 1865 | bio_get(bio); |
1866 | 1866 | ||
1867 | if (tree->ops && tree->ops->submit_bio_hook) | 1867 | if (tree->ops && tree->ops->submit_bio_hook) |
1868 | tree->ops->submit_bio_hook(page->mapping->host, rw, bio, | 1868 | ret = tree->ops->submit_bio_hook(page->mapping->host, rw, bio, |
1869 | mirror_num, bio_flags, start); | 1869 | mirror_num, bio_flags, start); |
1870 | else | 1870 | else |
1871 | submit_bio(rw, bio); | 1871 | submit_bio(rw, bio); |
@@ -1920,6 +1920,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, | |||
1920 | nr = bio_get_nr_vecs(bdev); | 1920 | nr = bio_get_nr_vecs(bdev); |
1921 | 1921 | ||
1922 | bio = btrfs_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH); | 1922 | bio = btrfs_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH); |
1923 | if (!bio) | ||
1924 | return -ENOMEM; | ||
1923 | 1925 | ||
1924 | bio_add_page(bio, page, page_size, offset); | 1926 | bio_add_page(bio, page, page_size, offset); |
1925 | bio->bi_end_io = end_io_func; | 1927 | bio->bi_end_io = end_io_func; |
@@ -1944,6 +1946,7 @@ void set_page_extent_mapped(struct page *page) | |||
1944 | 1946 | ||
1945 | static void set_page_extent_head(struct page *page, unsigned long len) | 1947 | static void set_page_extent_head(struct page *page, unsigned long len) |
1946 | { | 1948 | { |
1949 | WARN_ON(!PagePrivate(page)); | ||
1947 | set_page_private(page, EXTENT_PAGE_PRIVATE_FIRST_PAGE | len << 2); | 1950 | set_page_private(page, EXTENT_PAGE_PRIVATE_FIRST_PAGE | len << 2); |
1948 | } | 1951 | } |
1949 | 1952 | ||
@@ -2126,7 +2129,7 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page, | |||
2126 | ret = __extent_read_full_page(tree, page, get_extent, &bio, 0, | 2129 | ret = __extent_read_full_page(tree, page, get_extent, &bio, 0, |
2127 | &bio_flags); | 2130 | &bio_flags); |
2128 | if (bio) | 2131 | if (bio) |
2129 | submit_one_bio(READ, bio, 0, bio_flags); | 2132 | ret = submit_one_bio(READ, bio, 0, bio_flags); |
2130 | return ret; | 2133 | return ret; |
2131 | } | 2134 | } |
2132 | 2135 | ||
@@ -2819,9 +2822,17 @@ int try_release_extent_state(struct extent_map_tree *map, | |||
2819 | * at this point we can safely clear everything except the | 2822 | * at this point we can safely clear everything except the |
2820 | * locked bit and the nodatasum bit | 2823 | * locked bit and the nodatasum bit |
2821 | */ | 2824 | */ |
2822 | clear_extent_bit(tree, start, end, | 2825 | ret = clear_extent_bit(tree, start, end, |
2823 | ~(EXTENT_LOCKED | EXTENT_NODATASUM), | 2826 | ~(EXTENT_LOCKED | EXTENT_NODATASUM), |
2824 | 0, 0, NULL, mask); | 2827 | 0, 0, NULL, mask); |
2828 | |||
2829 | /* if clear_extent_bit failed for enomem reasons, | ||
2830 | * we can't allow the release to continue. | ||
2831 | */ | ||
2832 | if (ret < 0) | ||
2833 | ret = 0; | ||
2834 | else | ||
2835 | ret = 1; | ||
2825 | } | 2836 | } |
2826 | return ret; | 2837 | return ret; |
2827 | } | 2838 | } |
@@ -3192,7 +3203,13 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | |||
3192 | } | 3203 | } |
3193 | if (!PageUptodate(p)) | 3204 | if (!PageUptodate(p)) |
3194 | uptodate = 0; | 3205 | uptodate = 0; |
3195 | unlock_page(p); | 3206 | |
3207 | /* | ||
3208 | * see below about how we avoid a nasty race with release page | ||
3209 | * and why we unlock later | ||
3210 | */ | ||
3211 | if (i != 0) | ||
3212 | unlock_page(p); | ||
3196 | } | 3213 | } |
3197 | if (uptodate) | 3214 | if (uptodate) |
3198 | set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); | 3215 | set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); |
@@ -3216,9 +3233,26 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | |||
3216 | atomic_inc(&eb->refs); | 3233 | atomic_inc(&eb->refs); |
3217 | spin_unlock(&tree->buffer_lock); | 3234 | spin_unlock(&tree->buffer_lock); |
3218 | radix_tree_preload_end(); | 3235 | radix_tree_preload_end(); |
3236 | |||
3237 | /* | ||
3238 | * there is a race where release page may have | ||
3239 | * tried to find this extent buffer in the radix | ||
3240 | * but failed. It will tell the VM it is safe to | ||
3241 | * reclaim the, and it will clear the page private bit. | ||
3242 | * We must make sure to set the page private bit properly | ||
3243 | * after the extent buffer is in the radix tree so | ||
3244 | * it doesn't get lost | ||
3245 | */ | ||
3246 | set_page_extent_mapped(eb->first_page); | ||
3247 | set_page_extent_head(eb->first_page, eb->len); | ||
3248 | if (!page0) | ||
3249 | unlock_page(eb->first_page); | ||
3219 | return eb; | 3250 | return eb; |
3220 | 3251 | ||
3221 | free_eb: | 3252 | free_eb: |
3253 | if (eb->first_page && !page0) | ||
3254 | unlock_page(eb->first_page); | ||
3255 | |||
3222 | if (!atomic_dec_and_test(&eb->refs)) | 3256 | if (!atomic_dec_and_test(&eb->refs)) |
3223 | return exists; | 3257 | return exists; |
3224 | btrfs_release_extent_buffer(eb); | 3258 | btrfs_release_extent_buffer(eb); |
@@ -3269,10 +3303,11 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree, | |||
3269 | continue; | 3303 | continue; |
3270 | 3304 | ||
3271 | lock_page(page); | 3305 | lock_page(page); |
3306 | WARN_ON(!PagePrivate(page)); | ||
3307 | |||
3308 | set_page_extent_mapped(page); | ||
3272 | if (i == 0) | 3309 | if (i == 0) |
3273 | set_page_extent_head(page, eb->len); | 3310 | set_page_extent_head(page, eb->len); |
3274 | else | ||
3275 | set_page_private(page, EXTENT_PAGE_PRIVATE); | ||
3276 | 3311 | ||
3277 | clear_page_dirty_for_io(page); | 3312 | clear_page_dirty_for_io(page); |
3278 | spin_lock_irq(&page->mapping->tree_lock); | 3313 | spin_lock_irq(&page->mapping->tree_lock); |
@@ -3462,6 +3497,13 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, | |||
3462 | 3497 | ||
3463 | for (i = start_i; i < num_pages; i++) { | 3498 | for (i = start_i; i < num_pages; i++) { |
3464 | page = extent_buffer_page(eb, i); | 3499 | page = extent_buffer_page(eb, i); |
3500 | |||
3501 | WARN_ON(!PagePrivate(page)); | ||
3502 | |||
3503 | set_page_extent_mapped(page); | ||
3504 | if (i == 0) | ||
3505 | set_page_extent_head(page, eb->len); | ||
3506 | |||
3465 | if (inc_all_pages) | 3507 | if (inc_all_pages) |
3466 | page_cache_get(page); | 3508 | page_cache_get(page); |
3467 | if (!PageUptodate(page)) { | 3509 | if (!PageUptodate(page)) { |