Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 322232
b: refs/heads/master
c: 676ce6d
h: refs/heads/master
v: v3
  • Loading branch information
Hugh Dickins authored and Jens Axboe committed Aug 23, 2012
1 parent adb5ada commit 7881213
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 37 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 79df9b40b3d0fd275b4d6eae6068706871e95da5
refs/heads/master: 676ce6d5ca3098339c028d44fe0427d1566a4d2d
66 changes: 30 additions & 36 deletions trunk/fs/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ link_dev_buffers(struct page *page, struct buffer_head *head)
/*
* Initialise the state of a blockdev page's buffers.
*/
static void
static sector_t
init_page_buffers(struct page *page, struct block_device *bdev,
sector_t block, int size)
{
Expand All @@ -936,33 +936,41 @@ init_page_buffers(struct page *page, struct block_device *bdev,
block++;
bh = bh->b_this_page;
} while (bh != head);

/*
* Caller needs to validate requested block against end of device.
*/
return end_block;
}

/*
* Create the page-cache page that contains the requested block.
*
* This is user purely for blockdev mappings.
* This is used purely for blockdev mappings.
*/
static struct page *
static int
grow_dev_page(struct block_device *bdev, sector_t block,
pgoff_t index, int size)
pgoff_t index, int size, int sizebits)
{
struct inode *inode = bdev->bd_inode;
struct page *page;
struct buffer_head *bh;
sector_t end_block;
int ret = 0; /* Will call free_more_memory() */

page = find_or_create_page(inode->i_mapping, index,
(mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE);
if (!page)
return NULL;
return ret;

BUG_ON(!PageLocked(page));

if (page_has_buffers(page)) {
bh = page_buffers(page);
if (bh->b_size == size) {
init_page_buffers(page, bdev, block, size);
return page;
end_block = init_page_buffers(page, bdev,
index << sizebits, size);
goto done;
}
if (!try_to_free_buffers(page))
goto failed;
Expand All @@ -982,14 +990,14 @@ grow_dev_page(struct block_device *bdev, sector_t block,
*/
spin_lock(&inode->i_mapping->private_lock);
link_dev_buffers(page, bh);
init_page_buffers(page, bdev, block, size);
end_block = init_page_buffers(page, bdev, index << sizebits, size);
spin_unlock(&inode->i_mapping->private_lock);
return page;

done:
ret = (block < end_block) ? 1 : -ENXIO;
failed:
unlock_page(page);
page_cache_release(page);
return NULL;
return ret;
}

/*
Expand All @@ -999,7 +1007,6 @@ grow_dev_page(struct block_device *bdev, sector_t block,
static int
grow_buffers(struct block_device *bdev, sector_t block, int size)
{
struct page *page;
pgoff_t index;
int sizebits;

Expand All @@ -1023,22 +1030,14 @@ grow_buffers(struct block_device *bdev, sector_t block, int size)
bdevname(bdev, b));
return -EIO;
}
block = index << sizebits;

/* Create a page with the proper size buffers.. */
page = grow_dev_page(bdev, block, index, size);
if (!page)
return 0;
unlock_page(page);
page_cache_release(page);
return 1;
return grow_dev_page(bdev, block, index, size, sizebits);
}

static struct buffer_head *
__getblk_slow(struct block_device *bdev, sector_t block, int size)
{
int ret;
struct buffer_head *bh;

/* Size must be multiple of hard sectorsize */
if (unlikely(size & (bdev_logical_block_size(bdev)-1) ||
(size < 512 || size > PAGE_SIZE))) {
Expand All @@ -1051,21 +1050,20 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
return NULL;
}

retry:
bh = __find_get_block(bdev, block, size);
if (bh)
return bh;
for (;;) {
struct buffer_head *bh;
int ret;

ret = grow_buffers(bdev, block, size);
if (ret == 0) {
free_more_memory();
goto retry;
} else if (ret > 0) {
bh = __find_get_block(bdev, block, size);
if (bh)
return bh;

ret = grow_buffers(bdev, block, size);
if (ret < 0)
return NULL;
if (ret == 0)
free_more_memory();
}
return NULL;
}

/*
Expand Down Expand Up @@ -1321,10 +1319,6 @@ EXPORT_SYMBOL(__find_get_block);
* which corresponds to the passed block_device, block and size. The
* returned buffer has its reference count incremented.
*
* __getblk() cannot fail - it just keeps trying. If you pass it an
* illegal block number, __getblk() will happily return a buffer_head
* which represents the non-existent block. Very weird.
*
* __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers()
* attempt is failing. FIXME, perhaps?
*/
Expand Down

0 comments on commit 7881213

Please sign in to comment.