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 | */ |
