diff options
Diffstat (limited to 'fs/buffer.c')
-rw-r--r-- | fs/buffer.c | 66 |
1 files changed, 30 insertions, 36 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index 9f6d2e41281d..58e2e7b77372 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -914,7 +914,7 @@ link_dev_buffers(struct page *page, struct buffer_head *head) | |||
914 | /* | 914 | /* |
915 | * Initialise the state of a blockdev page's buffers. | 915 | * Initialise the state of a blockdev page's buffers. |
916 | */ | 916 | */ |
917 | static void | 917 | static sector_t |
918 | init_page_buffers(struct page *page, struct block_device *bdev, | 918 | init_page_buffers(struct page *page, struct block_device *bdev, |
919 | sector_t block, int size) | 919 | sector_t block, int size) |
920 | { | 920 | { |
@@ -936,33 +936,41 @@ init_page_buffers(struct page *page, struct block_device *bdev, | |||
936 | block++; | 936 | block++; |
937 | bh = bh->b_this_page; | 937 | bh = bh->b_this_page; |
938 | } while (bh != head); | 938 | } while (bh != head); |
939 | |||
940 | /* | ||
941 | * Caller needs to validate requested block against end of device. | ||
942 | */ | ||
943 | return end_block; | ||
939 | } | 944 | } |
940 | 945 | ||
941 | /* | 946 | /* |
942 | * Create the page-cache page that contains the requested block. | 947 | * Create the page-cache page that contains the requested block. |
943 | * | 948 | * |
944 | * This is user purely for blockdev mappings. | 949 | * This is used purely for blockdev mappings. |
945 | */ | 950 | */ |
946 | static struct page * | 951 | static int |
947 | grow_dev_page(struct block_device *bdev, sector_t block, | 952 | grow_dev_page(struct block_device *bdev, sector_t block, |
948 | pgoff_t index, int size) | 953 | pgoff_t index, int size, int sizebits) |
949 | { | 954 | { |
950 | struct inode *inode = bdev->bd_inode; | 955 | struct inode *inode = bdev->bd_inode; |
951 | struct page *page; | 956 | struct page *page; |
952 | struct buffer_head *bh; | 957 | struct buffer_head *bh; |
958 | sector_t end_block; | ||
959 | int ret = 0; /* Will call free_more_memory() */ | ||
953 | 960 | ||
954 | page = find_or_create_page(inode->i_mapping, index, | 961 | page = find_or_create_page(inode->i_mapping, index, |
955 | (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE); | 962 | (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE); |
956 | if (!page) | 963 | if (!page) |
957 | return NULL; | 964 | return ret; |
958 | 965 | ||
959 | BUG_ON(!PageLocked(page)); | 966 | BUG_ON(!PageLocked(page)); |
960 | 967 | ||
961 | if (page_has_buffers(page)) { | 968 | if (page_has_buffers(page)) { |
962 | bh = page_buffers(page); | 969 | bh = page_buffers(page); |
963 | if (bh->b_size == size) { | 970 | if (bh->b_size == size) { |
964 | init_page_buffers(page, bdev, block, size); | 971 | end_block = init_page_buffers(page, bdev, |
965 | return page; | 972 | index << sizebits, size); |
973 | goto done; | ||
966 | } | 974 | } |
967 | if (!try_to_free_buffers(page)) | 975 | if (!try_to_free_buffers(page)) |
968 | goto failed; | 976 | goto failed; |
@@ -982,14 +990,14 @@ grow_dev_page(struct block_device *bdev, sector_t block, | |||
982 | */ | 990 | */ |
983 | spin_lock(&inode->i_mapping->private_lock); | 991 | spin_lock(&inode->i_mapping->private_lock); |
984 | link_dev_buffers(page, bh); | 992 | link_dev_buffers(page, bh); |
985 | init_page_buffers(page, bdev, block, size); | 993 | end_block = init_page_buffers(page, bdev, index << sizebits, size); |
986 | spin_unlock(&inode->i_mapping->private_lock); | 994 | spin_unlock(&inode->i_mapping->private_lock); |
987 | return page; | 995 | done: |
988 | 996 | ret = (block < end_block) ? 1 : -ENXIO; | |
989 | failed: | 997 | failed: |
990 | unlock_page(page); | 998 | unlock_page(page); |
991 | page_cache_release(page); | 999 | page_cache_release(page); |
992 | return NULL; | 1000 | return ret; |
993 | } | 1001 | } |
994 | 1002 | ||
995 | /* | 1003 | /* |
@@ -999,7 +1007,6 @@ failed: | |||
999 | static int | 1007 | static int |
1000 | grow_buffers(struct block_device *bdev, sector_t block, int size) | 1008 | grow_buffers(struct block_device *bdev, sector_t block, int size) |
1001 | { | 1009 | { |
1002 | struct page *page; | ||
1003 | pgoff_t index; | 1010 | pgoff_t index; |
1004 | int sizebits; | 1011 | int sizebits; |
1005 | 1012 | ||
@@ -1023,22 +1030,14 @@ grow_buffers(struct block_device *bdev, sector_t block, int size) | |||
1023 | bdevname(bdev, b)); | 1030 | bdevname(bdev, b)); |
1024 | return -EIO; | 1031 | return -EIO; |
1025 | } | 1032 | } |
1026 | block = index << sizebits; | 1033 | |
1027 | /* Create a page with the proper size buffers.. */ | 1034 | /* Create a page with the proper size buffers.. */ |
1028 | page = grow_dev_page(bdev, block, index, size); | 1035 | return grow_dev_page(bdev, block, index, size, sizebits); |
1029 | if (!page) | ||
1030 | return 0; | ||
1031 | unlock_page(page); | ||
1032 | page_cache_release(page); | ||
1033 | return 1; | ||
1034 | } | 1036 | } |
1035 | 1037 | ||
1036 | static struct buffer_head * | 1038 | static struct buffer_head * |
1037 | __getblk_slow(struct block_device *bdev, sector_t block, int size) | 1039 | __getblk_slow(struct block_device *bdev, sector_t block, int size) |
1038 | { | 1040 | { |
1039 | int ret; | ||
1040 | struct buffer_head *bh; | ||
1041 | |||
1042 | /* Size must be multiple of hard sectorsize */ | 1041 | /* Size must be multiple of hard sectorsize */ |
1043 | if (unlikely(size & (bdev_logical_block_size(bdev)-1) || | 1042 | if (unlikely(size & (bdev_logical_block_size(bdev)-1) || |
1044 | (size < 512 || size > PAGE_SIZE))) { | 1043 | (size < 512 || size > PAGE_SIZE))) { |
@@ -1051,21 +1050,20 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) | |||
1051 | return NULL; | 1050 | return NULL; |
1052 | } | 1051 | } |
1053 | 1052 | ||
1054 | retry: | 1053 | for (;;) { |
1055 | bh = __find_get_block(bdev, block, size); | 1054 | struct buffer_head *bh; |
1056 | if (bh) | 1055 | int ret; |
1057 | return bh; | ||
1058 | 1056 | ||
1059 | ret = grow_buffers(bdev, block, size); | ||
1060 | if (ret == 0) { | ||
1061 | free_more_memory(); | ||
1062 | goto retry; | ||
1063 | } else if (ret > 0) { | ||
1064 | bh = __find_get_block(bdev, block, size); | 1057 | bh = __find_get_block(bdev, block, size); |
1065 | if (bh) | 1058 | if (bh) |
1066 | return bh; | 1059 | return bh; |
1060 | |||
1061 | ret = grow_buffers(bdev, block, size); | ||
1062 | if (ret < 0) | ||
1063 | return NULL; | ||
1064 | if (ret == 0) | ||
1065 | free_more_memory(); | ||
1067 | } | 1066 | } |
1068 | return NULL; | ||
1069 | } | 1067 | } |
1070 | 1068 | ||
1071 | /* | 1069 | /* |
@@ -1321,10 +1319,6 @@ EXPORT_SYMBOL(__find_get_block); | |||
1321 | * which corresponds to the passed block_device, block and size. The | 1319 | * which corresponds to the passed block_device, block and size. The |
1322 | * returned buffer has its reference count incremented. | 1320 | * returned buffer has its reference count incremented. |
1323 | * | 1321 | * |
1324 | * __getblk() cannot fail - it just keeps trying. If you pass it an | ||
1325 | * illegal block number, __getblk() will happily return a buffer_head | ||
1326 | * which represents the non-existent block. Very weird. | ||
1327 | * | ||
1328 | * __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers() | 1322 | * __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers() |
1329 | * attempt is failing. FIXME, perhaps? | 1323 | * attempt is failing. FIXME, perhaps? |
1330 | */ | 1324 | */ |