buffer: hoist GFP flags from grow_dev_page() to __getblk_gfp()
grow_dev_page() is only called by grow_buffers(). grow_buffers() is only called by __getblk_slow() and __getblk_slow() is only called from __getblk_gfp(), so it is safe to move the GFP flags setting all the way up. With that done, add a new bdev_getblk() entry point that leaves the GFP flags the way the caller specified them. [willy@infradead.org: fix grow_dev_page() error handling] Link: https://lkml.kernel.org/r/ZRREEIwqiy5DijKB@casper.infradead.org Link: https://lkml.kernel.org/r/20230914150011.843330-3-willy@infradead.org Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Hui Zhu <teawater@antgroup.com> Cc: Dan Carpenter <dan.carpenter@linaro.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
committed by
Andrew Morton
parent
2a41815784
commit
3ed65f04aa
61
fs/buffer.c
61
fs/buffer.c
@@ -1043,20 +1043,11 @@ grow_dev_page(struct block_device *bdev, sector_t block,
|
|||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
sector_t end_block;
|
sector_t end_block;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
gfp_t gfp_mask;
|
|
||||||
|
|
||||||
gfp_mask = mapping_gfp_constraint(inode->i_mapping, ~__GFP_FS) | gfp;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX: __getblk_slow() can not really deal with failure and
|
|
||||||
* will endlessly loop on improvised global reclaim. Prefer
|
|
||||||
* looping in the allocator rather than here, at least that
|
|
||||||
* code knows what it's doing.
|
|
||||||
*/
|
|
||||||
gfp_mask |= __GFP_NOFAIL;
|
|
||||||
|
|
||||||
folio = __filemap_get_folio(inode->i_mapping, index,
|
folio = __filemap_get_folio(inode->i_mapping, index,
|
||||||
FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp_mask);
|
FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp);
|
||||||
|
if (IS_ERR(folio))
|
||||||
|
return PTR_ERR(folio);
|
||||||
|
|
||||||
bh = folio_buffers(folio);
|
bh = folio_buffers(folio);
|
||||||
if (bh) {
|
if (bh) {
|
||||||
@@ -1069,7 +1060,10 @@ grow_dev_page(struct block_device *bdev, sector_t block,
|
|||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bh = folio_alloc_buffers(folio, size, gfp_mask | __GFP_ACCOUNT);
|
ret = -ENOMEM;
|
||||||
|
bh = folio_alloc_buffers(folio, size, gfp | __GFP_ACCOUNT);
|
||||||
|
if (!bh)
|
||||||
|
goto failed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Link the folio to the buffers and initialise them. Take the
|
* Link the folio to the buffers and initialise them. Take the
|
||||||
@@ -1420,24 +1414,49 @@ __find_get_block(struct block_device *bdev, sector_t block, unsigned size)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__find_get_block);
|
EXPORT_SYMBOL(__find_get_block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdev_getblk - Get a buffer_head in a block device's buffer cache.
|
||||||
|
* @bdev: The block device.
|
||||||
|
* @block: The block number.
|
||||||
|
* @size: The size of buffer_heads for this @bdev.
|
||||||
|
* @gfp: The memory allocation flags to use.
|
||||||
|
*
|
||||||
|
* In contrast to __getblk_gfp(), the @gfp flags must be all of the flags;
|
||||||
|
* they are not augmented with the mapping's GFP flags.
|
||||||
|
*
|
||||||
|
* Return: The buffer head, or NULL if memory could not be allocated.
|
||||||
|
*/
|
||||||
|
struct buffer_head *bdev_getblk(struct block_device *bdev, sector_t block,
|
||||||
|
unsigned size, gfp_t gfp)
|
||||||
|
{
|
||||||
|
struct buffer_head *bh = __find_get_block(bdev, block, size);
|
||||||
|
|
||||||
|
might_alloc(gfp);
|
||||||
|
if (bh)
|
||||||
|
return bh;
|
||||||
|
|
||||||
|
return __getblk_slow(bdev, block, size, gfp);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(bdev_getblk);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* __getblk_gfp() will locate (and, if necessary, create) the buffer_head
|
* __getblk_gfp() will locate (and, if necessary, create) the buffer_head
|
||||||
* which corresponds to the passed block_device, block and size. The
|
* which corresponds to the passed block_device, block and size. The
|
||||||
* returned buffer has its reference count incremented.
|
* returned buffer has its reference count incremented.
|
||||||
*
|
|
||||||
* __getblk_gfp() will lock up the machine if grow_dev_page's
|
|
||||||
* try_to_free_buffers() attempt is failing. FIXME, perhaps?
|
|
||||||
*/
|
*/
|
||||||
struct buffer_head *
|
struct buffer_head *
|
||||||
__getblk_gfp(struct block_device *bdev, sector_t block,
|
__getblk_gfp(struct block_device *bdev, sector_t block,
|
||||||
unsigned size, gfp_t gfp)
|
unsigned size, gfp_t gfp)
|
||||||
{
|
{
|
||||||
struct buffer_head *bh = __find_get_block(bdev, block, size);
|
gfp |= mapping_gfp_constraint(bdev->bd_inode->i_mapping, ~__GFP_FS);
|
||||||
|
|
||||||
might_sleep();
|
/*
|
||||||
if (bh == NULL)
|
* Prefer looping in the allocator rather than here, at least that
|
||||||
bh = __getblk_slow(bdev, block, size, gfp);
|
* code knows what it's doing.
|
||||||
return bh;
|
*/
|
||||||
|
gfp |= __GFP_NOFAIL;
|
||||||
|
|
||||||
|
return bdev_getblk(bdev, block, size, gfp);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__getblk_gfp);
|
EXPORT_SYMBOL(__getblk_gfp);
|
||||||
|
|
||||||
|
|||||||
@@ -227,6 +227,8 @@ void __wait_on_buffer(struct buffer_head *);
|
|||||||
wait_queue_head_t *bh_waitq_head(struct buffer_head *bh);
|
wait_queue_head_t *bh_waitq_head(struct buffer_head *bh);
|
||||||
struct buffer_head *__find_get_block(struct block_device *bdev, sector_t block,
|
struct buffer_head *__find_get_block(struct block_device *bdev, sector_t block,
|
||||||
unsigned size);
|
unsigned size);
|
||||||
|
struct buffer_head *bdev_getblk(struct block_device *bdev, sector_t block,
|
||||||
|
unsigned size, gfp_t gfp);
|
||||||
struct buffer_head *__getblk_gfp(struct block_device *bdev, sector_t block,
|
struct buffer_head *__getblk_gfp(struct block_device *bdev, sector_t block,
|
||||||
unsigned size, gfp_t gfp);
|
unsigned size, gfp_t gfp);
|
||||||
void __brelse(struct buffer_head *);
|
void __brelse(struct buffer_head *);
|
||||||
|
|||||||
Reference in New Issue
Block a user