Skip to content

Commit

Permalink
fat: permit to return phy block number by fibmap in fallocated region
Browse files Browse the repository at this point in the history
Make the fibmap call return the proper physical block number for any
offset request in the fallocated range.

Signed-off-by: Namjae Jeon <[email protected]>
Signed-off-by: Amit Sahrawat <[email protected]>
Cc: OGAWA Hirofumi <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
namjaejeon authored and torvalds committed Jan 21, 2016
1 parent 7e0f236 commit 16fab20
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 30 deletions.
79 changes: 54 additions & 25 deletions fs/fat/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,15 +301,59 @@ static int fat_bmap_cluster(struct inode *inode, int cluster)
return dclus;
}

int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
unsigned long *mapped_blocks, int create)
int fat_get_mapped_cluster(struct inode *inode, sector_t sector,
sector_t last_block,
unsigned long *mapped_blocks, sector_t *bmap)
{
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
int cluster, offset;

cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
offset = sector & (sbi->sec_per_clus - 1);
cluster = fat_bmap_cluster(inode, cluster);
if (cluster < 0)
return cluster;
else if (cluster) {
*bmap = fat_clus_to_blknr(sbi, cluster) + offset;
*mapped_blocks = sbi->sec_per_clus - offset;
if (*mapped_blocks > last_block - sector)
*mapped_blocks = last_block - sector;
}

return 0;
}

static int is_exceed_eof(struct inode *inode, sector_t sector,
sector_t *last_block, int create)
{
struct super_block *sb = inode->i_sb;
const unsigned long blocksize = sb->s_blocksize;
const unsigned char blocksize_bits = sb->s_blocksize_bits;

*last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
if (sector >= *last_block) {
if (!create)
return 1;

/*
* ->mmu_private can access on only allocation path.
* (caller must hold ->i_mutex)
*/
*last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
>> blocksize_bits;
if (sector >= *last_block)
return 1;
}

return 0;
}

int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
unsigned long *mapped_blocks, int create, bool from_bmap)
{
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
sector_t last_block;
int cluster, offset;

*phys = 0;
*mapped_blocks = 0;
Expand All @@ -321,31 +365,16 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
return 0;
}

last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
if (sector >= last_block) {
if (!create)
if (!from_bmap) {
if (is_exceed_eof(inode, sector, &last_block, create))
return 0;

/*
* ->mmu_private can access on only allocation path.
* (caller must hold ->i_mutex)
*/
last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
>> blocksize_bits;
} else {
last_block = inode->i_blocks >>
(inode->i_sb->s_blocksize_bits - 9);
if (sector >= last_block)
return 0;
}

cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
offset = sector & (sbi->sec_per_clus - 1);
cluster = fat_bmap_cluster(inode, cluster);
if (cluster < 0)
return cluster;
else if (cluster) {
*phys = fat_clus_to_blknr(sbi, cluster) + offset;
*mapped_blocks = sbi->sec_per_clus - offset;
if (*mapped_blocks > last_block - sector)
*mapped_blocks = last_block - sector;
}
return 0;
return fat_get_mapped_cluster(inode, sector, last_block, mapped_blocks,
phys);
}
2 changes: 1 addition & 1 deletion fs/fat/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ static int fat__get_entry(struct inode *dir, loff_t *pos,

*bh = NULL;
iblock = *pos >> sb->s_blocksize_bits;
err = fat_bmap(dir, iblock, &phys, &mapped_blocks, 0);
err = fat_bmap(dir, iblock, &phys, &mapped_blocks, 0, false);
if (err || !phys)
return -1; /* beyond EOF or error */

Expand Down
5 changes: 4 additions & 1 deletion fs/fat/fat.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,11 @@ static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len)
extern void fat_cache_inval_inode(struct inode *inode);
extern int fat_get_cluster(struct inode *inode, int cluster,
int *fclus, int *dclus);
extern int fat_get_mapped_cluster(struct inode *inode, sector_t sector,
sector_t last_block,
unsigned long *mapped_blocks, sector_t *bmap);
extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
unsigned long *mapped_blocks, int create);
unsigned long *mapped_blocks, int create, bool from_bmap);

/* fat/dir.c */
extern const struct file_operations fat_dir_operations;
Expand Down
31 changes: 28 additions & 3 deletions fs/fat/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
sector_t phys, last_block;
int err, offset;

err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
if (err)
return err;
if (phys) {
Expand Down Expand Up @@ -154,7 +154,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
*max_blocks = min(mapped_blocks, *max_blocks);
MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits;

err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
if (err)
return err;

Expand Down Expand Up @@ -279,13 +279,38 @@ static ssize_t fat_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
return ret;
}

static int fat_get_block_bmap(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
struct super_block *sb = inode->i_sb;
unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
int err;
sector_t bmap;
unsigned long mapped_blocks;

BUG_ON(create != 0);

err = fat_bmap(inode, iblock, &bmap, &mapped_blocks, create, true);
if (err)
return err;

if (bmap) {
map_bh(bh_result, sb, bmap);
max_blocks = min(mapped_blocks, max_blocks);
}

bh_result->b_size = max_blocks << sb->s_blocksize_bits;

return 0;
}

static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
{
sector_t blocknr;

/* fat_get_cluster() assumes the requested blocknr isn't truncated. */
down_read(&MSDOS_I(mapping->host)->truncate_lock);
blocknr = generic_block_bmap(mapping, block, fat_get_block);
blocknr = generic_block_bmap(mapping, block, fat_get_block_bmap);
up_read(&MSDOS_I(mapping->host)->truncate_lock);

return blocknr;
Expand Down

0 comments on commit 16fab20

Please sign in to comment.