Skip to content

Commit 16fab20

Browse files
namjaejeontorvalds
authored andcommitted
fat: permit to return phy block number by fibmap in fallocated region
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]>
1 parent 7e0f236 commit 16fab20

File tree

4 files changed

+87
-30
lines changed

4 files changed

+87
-30
lines changed

fs/fat/cache.c

+54-25
Original file line numberDiff line numberDiff line change
@@ -301,15 +301,59 @@ static int fat_bmap_cluster(struct inode *inode, int cluster)
301301
return dclus;
302302
}
303303

304-
int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
305-
unsigned long *mapped_blocks, int create)
304+
int fat_get_mapped_cluster(struct inode *inode, sector_t sector,
305+
sector_t last_block,
306+
unsigned long *mapped_blocks, sector_t *bmap)
306307
{
307308
struct super_block *sb = inode->i_sb;
308309
struct msdos_sb_info *sbi = MSDOS_SB(sb);
310+
int cluster, offset;
311+
312+
cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
313+
offset = sector & (sbi->sec_per_clus - 1);
314+
cluster = fat_bmap_cluster(inode, cluster);
315+
if (cluster < 0)
316+
return cluster;
317+
else if (cluster) {
318+
*bmap = fat_clus_to_blknr(sbi, cluster) + offset;
319+
*mapped_blocks = sbi->sec_per_clus - offset;
320+
if (*mapped_blocks > last_block - sector)
321+
*mapped_blocks = last_block - sector;
322+
}
323+
324+
return 0;
325+
}
326+
327+
static int is_exceed_eof(struct inode *inode, sector_t sector,
328+
sector_t *last_block, int create)
329+
{
330+
struct super_block *sb = inode->i_sb;
309331
const unsigned long blocksize = sb->s_blocksize;
310332
const unsigned char blocksize_bits = sb->s_blocksize_bits;
333+
334+
*last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
335+
if (sector >= *last_block) {
336+
if (!create)
337+
return 1;
338+
339+
/*
340+
* ->mmu_private can access on only allocation path.
341+
* (caller must hold ->i_mutex)
342+
*/
343+
*last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
344+
>> blocksize_bits;
345+
if (sector >= *last_block)
346+
return 1;
347+
}
348+
349+
return 0;
350+
}
351+
352+
int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
353+
unsigned long *mapped_blocks, int create, bool from_bmap)
354+
{
355+
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
311356
sector_t last_block;
312-
int cluster, offset;
313357

314358
*phys = 0;
315359
*mapped_blocks = 0;
@@ -321,31 +365,16 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
321365
return 0;
322366
}
323367

324-
last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
325-
if (sector >= last_block) {
326-
if (!create)
368+
if (!from_bmap) {
369+
if (is_exceed_eof(inode, sector, &last_block, create))
327370
return 0;
328-
329-
/*
330-
* ->mmu_private can access on only allocation path.
331-
* (caller must hold ->i_mutex)
332-
*/
333-
last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
334-
>> blocksize_bits;
371+
} else {
372+
last_block = inode->i_blocks >>
373+
(inode->i_sb->s_blocksize_bits - 9);
335374
if (sector >= last_block)
336375
return 0;
337376
}
338377

339-
cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
340-
offset = sector & (sbi->sec_per_clus - 1);
341-
cluster = fat_bmap_cluster(inode, cluster);
342-
if (cluster < 0)
343-
return cluster;
344-
else if (cluster) {
345-
*phys = fat_clus_to_blknr(sbi, cluster) + offset;
346-
*mapped_blocks = sbi->sec_per_clus - offset;
347-
if (*mapped_blocks > last_block - sector)
348-
*mapped_blocks = last_block - sector;
349-
}
350-
return 0;
378+
return fat_get_mapped_cluster(inode, sector, last_block, mapped_blocks,
379+
phys);
351380
}

fs/fat/dir.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ static int fat__get_entry(struct inode *dir, loff_t *pos,
9191

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

fs/fat/fat.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,11 @@ static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len)
285285
extern void fat_cache_inval_inode(struct inode *inode);
286286
extern int fat_get_cluster(struct inode *inode, int cluster,
287287
int *fclus, int *dclus);
288+
extern int fat_get_mapped_cluster(struct inode *inode, sector_t sector,
289+
sector_t last_block,
290+
unsigned long *mapped_blocks, sector_t *bmap);
288291
extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
289-
unsigned long *mapped_blocks, int create);
292+
unsigned long *mapped_blocks, int create, bool from_bmap);
290293

291294
/* fat/dir.c */
292295
extern const struct file_operations fat_dir_operations;

fs/fat/inode.c

+28-3
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
118118
sector_t phys, last_block;
119119
int err, offset;
120120

121-
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
121+
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
122122
if (err)
123123
return err;
124124
if (phys) {
@@ -154,7 +154,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
154154
*max_blocks = min(mapped_blocks, *max_blocks);
155155
MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits;
156156

157-
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create);
157+
err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
158158
if (err)
159159
return err;
160160

@@ -279,13 +279,38 @@ static ssize_t fat_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
279279
return ret;
280280
}
281281

282+
static int fat_get_block_bmap(struct inode *inode, sector_t iblock,
283+
struct buffer_head *bh_result, int create)
284+
{
285+
struct super_block *sb = inode->i_sb;
286+
unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
287+
int err;
288+
sector_t bmap;
289+
unsigned long mapped_blocks;
290+
291+
BUG_ON(create != 0);
292+
293+
err = fat_bmap(inode, iblock, &bmap, &mapped_blocks, create, true);
294+
if (err)
295+
return err;
296+
297+
if (bmap) {
298+
map_bh(bh_result, sb, bmap);
299+
max_blocks = min(mapped_blocks, max_blocks);
300+
}
301+
302+
bh_result->b_size = max_blocks << sb->s_blocksize_bits;
303+
304+
return 0;
305+
}
306+
282307
static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
283308
{
284309
sector_t blocknr;
285310

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

291316
return blocknr;

0 commit comments

Comments
 (0)