Skip to content

Commit

Permalink
fs: Enable bmap() function to properly return errors
Browse files Browse the repository at this point in the history
By now, bmap() will either return the physical block number related to
the requested file offset or 0 in case of error or the requested offset
maps into a hole.
This patch makes the needed changes to enable bmap() to proper return
errors, using the return value as an error return, and now, a pointer
must be passed to bmap() to be filled with the mapped physical block.

It will change the behavior of bmap() on return:

- negative value in case of error
- zero on success or map fell into a hole

In case of a hole, the *block will be zero too

Since this is a prep patch, by now, the only error return is -EINVAL if
->bmap doesn't exist.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
Change-Id: I9be0b1fe8b7db55258464e8acec61b75d685b788
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: TogoFire <togofire@mailfence.com>
  • Loading branch information
cmaiolino authored and TogoFire committed Jul 25, 2023
1 parent a33007f commit 1e363de
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 35 deletions.
16 changes: 10 additions & 6 deletions drivers/md/bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ static int read_page(struct file *file, unsigned long index,
int ret = 0;
struct inode *inode = file_inode(file);
struct buffer_head *bh;
sector_t block;
sector_t block, blk_cur;

pr_debug("read bitmap file (%dB @ %llu)\n", (int)PAGE_SIZE,
(unsigned long long)index << PAGE_SHIFT);
Expand All @@ -370,17 +370,21 @@ static int read_page(struct file *file, unsigned long index,
goto out;
}
attach_page_buffers(page, bh);
block = index << (PAGE_SHIFT - inode->i_blkbits);
blk_cur = index << (PAGE_SHIFT - inode->i_blkbits);
while (bh) {
block = blk_cur;

if (count == 0)
bh->b_blocknr = 0;
else {
bh->b_blocknr = bmap(inode, block);
if (bh->b_blocknr == 0) {
/* Cannot use this file! */
ret = bmap(inode, &block);
if (ret || !block) {
ret = -EINVAL;
bh->b_blocknr = 0;
goto out;
}

bh->b_blocknr = block;
bh->b_bdev = inode->i_sb->s_bdev;
if (count < (1<<inode->i_blkbits))
count = 0;
Expand All @@ -394,7 +398,7 @@ static int read_page(struct file *file, unsigned long index,
set_buffer_mapped(bh);
submit_bh(REQ_OP_READ, 0, bh);
}
block++;
blk_cur++;
bh = bh->b_this_page;
}
page->index = index;
Expand Down
16 changes: 11 additions & 5 deletions fs/f2fs/data.c
Original file line number Diff line number Diff line change
Expand Up @@ -3286,12 +3286,16 @@ static int check_swap_activate(struct swap_info_struct *sis,
page_no < sis->max) {
unsigned block_in_page;
sector_t first_block;
sector_t block = 0;
int err = 0;

cond_resched();

first_block = bmap(inode, probe_block);
if (first_block == 0)
block = probe_block;
err = bmap(inode, &block);
if (err || !block)
goto bad_bmap;
first_block = block;

/*
* It must be PAGE_SIZE aligned on-disk
Expand All @@ -3303,11 +3307,13 @@ static int check_swap_activate(struct swap_info_struct *sis,

for (block_in_page = 1; block_in_page < blocks_per_page;
block_in_page++) {
sector_t block;

block = bmap(inode, probe_block + block_in_page);
if (block == 0)
block = probe_block + block_in_page;
err = bmap(inode, &block);

if (err || !block)
goto bad_bmap;

if (block != first_block + block_in_page) {
/* Discontiguity */
probe_block++;
Expand Down
30 changes: 18 additions & 12 deletions fs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1545,25 +1545,31 @@ void iput(struct inode *inode)
}
EXPORT_SYMBOL(iput);

#ifdef CONFIG_BLOCK
/**
* bmap - find a block number in a file
* @inode: inode of file
* @block: block to find
* @inode: inode owning the block number being requested
* @block: pointer containing the block to find
*
* Returns the block number on the device holding the inode that
* is the disk block number for the block of the file requested.
* That is, asked for block 4 of inode 1 the function will return the
* disk block relative to the disk start that holds that block of the
* file.
* Replaces the value in *block with the block number on the device holding
* corresponding to the requested block number in the file.
* That is, asked for block 4 of inode 1 the function will replace the
* 4 in *block, with disk block relative to the disk start that holds that
* block of the file.
*
* Returns -EINVAL in case of error, 0 otherwise. If mapping falls into a
* hole, returns 0 and *block is also set to 0.
*/
sector_t bmap(struct inode *inode, sector_t block)
int bmap(struct inode *inode, sector_t *block)
{
sector_t res = 0;
if (inode->i_mapping->a_ops->bmap)
res = inode->i_mapping->a_ops->bmap(inode->i_mapping, block);
return res;
if (!inode->i_mapping->a_ops->bmap)
return -EINVAL;

*block = inode->i_mapping->a_ops->bmap(inode->i_mapping, *block);
return 0;
}
EXPORT_SYMBOL(bmap);
#endif

/*
* Update times in overlayed inode from underlying real inode
Expand Down
22 changes: 15 additions & 7 deletions fs/jbd2/journal.c
Original file line number Diff line number Diff line change
Expand Up @@ -792,18 +792,23 @@ int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr,
{
int err = 0;
unsigned long long ret;
sector_t block = 0;

if (journal->j_inode) {
ret = bmap(journal->j_inode, blocknr);
if (ret)
*retp = ret;
else {
block = blocknr;
ret = bmap(journal->j_inode, &block);

if (ret || !block) {
printk(KERN_ALERT "%s: journal block not found "
"at offset %lu on %s\n",
__func__, blocknr, journal->j_devname);
err = -EIO;
__journal_abort_soft(journal, err);

} else {
*retp = block;
}

} else {
*retp = blocknr; /* +journal->j_blk_offset */
}
Expand Down Expand Up @@ -1228,11 +1233,14 @@ journal_t *jbd2_journal_init_dev(struct block_device *bdev,
journal_t *jbd2_journal_init_inode(struct inode *inode)
{
journal_t *journal;
sector_t blocknr;
char *p;
unsigned long long blocknr;
int err = 0;

blocknr = 0;
err = bmap(inode, &blocknr);

blocknr = bmap(inode, 0);
if (!blocknr) {
if (err || !blocknr) {
pr_err("%s: Cannot locate journal superblock\n",
__func__);
return NULL;
Expand Down
9 changes: 8 additions & 1 deletion include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2666,9 +2666,16 @@ static inline ssize_t generic_write_sync(struct kiocb *iocb, ssize_t count)

extern void emergency_sync(void);
extern void emergency_remount(void);

#ifdef CONFIG_BLOCK
extern sector_t bmap(struct inode *, sector_t);
extern int bmap(struct inode *inode, sector_t *block);
#else
static inline int bmap(struct inode *inode, sector_t *block)
{
return -EINVAL;
}
#endif

extern int notify_change(struct dentry *, struct iattr *, struct inode **);
extern int notify_change2(struct vfsmount *, struct dentry *, struct iattr *, struct inode **);
extern int inode_permission(struct inode *, int);
Expand Down
11 changes: 7 additions & 4 deletions mm/page_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,9 @@ int generic_swapfile_activate(struct swap_info_struct *sis,

cond_resched();

first_block = bmap(inode, probe_block);
if (first_block == 0)
first_block = probe_block;
ret = bmap(inode, &first_block);
if (ret || !first_block)
goto bad_bmap;

/*
Expand All @@ -184,9 +185,11 @@ int generic_swapfile_activate(struct swap_info_struct *sis,
block_in_page++) {
sector_t block;

block = bmap(inode, probe_block + block_in_page);
if (block == 0)
block = probe_block + block_in_page;
ret = bmap(inode, &block);
if (ret || !block)
goto bad_bmap;

if (block != first_block + block_in_page) {
/* Discontiguity */
probe_block++;
Expand Down

0 comments on commit 1e363de

Please sign in to comment.