diff options
author | Namjae Jeon <namjae.jeon@samsung.com> | 2016-01-20 17:59:46 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-20 20:09:18 -0500 |
commit | 16fab2015099a937e1a771f2785c5dd3445fe483 (patch) | |
tree | ae61dae3b71d44c4d1de3be2b5ff9e45c71260f5 /fs/fat | |
parent | 7e0f236b5b9cc23aa004eb58ee2201f294d0422a (diff) |
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 <namjae.jeon@samsung.com>
Signed-off-by: Amit Sahrawat <a.sahrawat@samsung.com>
Cc: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/cache.c | 79 | ||||
-rw-r--r-- | fs/fat/dir.c | 2 | ||||
-rw-r--r-- | fs/fat/fat.h | 5 | ||||
-rw-r--r-- | fs/fat/inode.c | 31 |
4 files changed, 87 insertions, 30 deletions
diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 93fc62232ec2..5d384921524d 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c | |||
@@ -301,15 +301,59 @@ static int fat_bmap_cluster(struct inode *inode, int cluster) | |||
301 | return dclus; | 301 | return dclus; |
302 | } | 302 | } |
303 | 303 | ||
304 | int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, | 304 | int fat_get_mapped_cluster(struct inode *inode, sector_t sector, |
305 | unsigned long *mapped_blocks, int create) | 305 | sector_t last_block, |
306 | unsigned long *mapped_blocks, sector_t *bmap) | ||
306 | { | 307 | { |
307 | struct super_block *sb = inode->i_sb; | 308 | struct super_block *sb = inode->i_sb; |
308 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 309 | 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; | ||
309 | const unsigned long blocksize = sb->s_blocksize; | 331 | const unsigned long blocksize = sb->s_blocksize; |
310 | const unsigned char blocksize_bits = sb->s_blocksize_bits; | 332 | 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); | ||
311 | sector_t last_block; | 356 | sector_t last_block; |
312 | int cluster, offset; | ||
313 | 357 | ||
314 | *phys = 0; | 358 | *phys = 0; |
315 | *mapped_blocks = 0; | 359 | *mapped_blocks = 0; |
@@ -321,31 +365,16 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, | |||
321 | return 0; | 365 | return 0; |
322 | } | 366 | } |
323 | 367 | ||
324 | last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; | 368 | if (!from_bmap) { |
325 | if (sector >= last_block) { | 369 | if (is_exceed_eof(inode, sector, &last_block, create)) |
326 | if (!create) | ||
327 | return 0; | 370 | return 0; |
328 | 371 | } else { | |
329 | /* | 372 | last_block = inode->i_blocks >> |
330 | * ->mmu_private can access on only allocation path. | 373 | (inode->i_sb->s_blocksize_bits - 9); |
331 | * (caller must hold ->i_mutex) | ||
332 | */ | ||
333 | last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1)) | ||
334 | >> blocksize_bits; | ||
335 | if (sector >= last_block) | 374 | if (sector >= last_block) |
336 | return 0; | 375 | return 0; |
337 | } | 376 | } |
338 | 377 | ||
339 | cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits); | 378 | return fat_get_mapped_cluster(inode, sector, last_block, mapped_blocks, |
340 | offset = sector & (sbi->sec_per_clus - 1); | 379 | phys); |
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; | ||
351 | } | 380 | } |
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 8b2127ffb226..7def96caec5f 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
@@ -91,7 +91,7 @@ next: | |||
91 | 91 | ||
92 | *bh = NULL; | 92 | *bh = NULL; |
93 | iblock = *pos >> sb->s_blocksize_bits; | 93 | 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); |
95 | if (err || !phys) | 95 | if (err || !phys) |
96 | return -1; /* beyond EOF or error */ | 96 | return -1; /* beyond EOF or error */ |
97 | 97 | ||
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index eed04c0efb11..4307cd4f8da0 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
@@ -285,8 +285,11 @@ static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len) | |||
285 | extern void fat_cache_inval_inode(struct inode *inode); | 285 | extern void fat_cache_inval_inode(struct inode *inode); |
286 | extern int fat_get_cluster(struct inode *inode, int cluster, | 286 | extern int fat_get_cluster(struct inode *inode, int cluster, |
287 | int *fclus, int *dclus); | 287 | 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); | ||
288 | extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, | 291 | 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); |
290 | 293 | ||
291 | /* fat/dir.c */ | 294 | /* fat/dir.c */ |
292 | extern const struct file_operations fat_dir_operations; | 295 | extern const struct file_operations fat_dir_operations; |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 0e5bc19c67b1..a5599052116c 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -118,7 +118,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock, | |||
118 | sector_t phys, last_block; | 118 | sector_t phys, last_block; |
119 | int err, offset; | 119 | int err, offset; |
120 | 120 | ||
121 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create); | 121 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false); |
122 | if (err) | 122 | if (err) |
123 | return err; | 123 | return err; |
124 | if (phys) { | 124 | if (phys) { |
@@ -154,7 +154,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock, | |||
154 | *max_blocks = min(mapped_blocks, *max_blocks); | 154 | *max_blocks = min(mapped_blocks, *max_blocks); |
155 | MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits; | 155 | MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits; |
156 | 156 | ||
157 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create); | 157 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false); |
158 | if (err) | 158 | if (err) |
159 | return err; | 159 | return err; |
160 | 160 | ||
@@ -279,13 +279,38 @@ static ssize_t fat_direct_IO(struct kiocb *iocb, struct iov_iter *iter, | |||
279 | return ret; | 279 | return ret; |
280 | } | 280 | } |
281 | 281 | ||
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 | |||
282 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) | 307 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) |
283 | { | 308 | { |
284 | sector_t blocknr; | 309 | sector_t blocknr; |
285 | 310 | ||
286 | /* fat_get_cluster() assumes the requested blocknr isn't truncated. */ | 311 | /* fat_get_cluster() assumes the requested blocknr isn't truncated. */ |
287 | down_read(&MSDOS_I(mapping->host)->truncate_lock); | 312 | 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); |
289 | up_read(&MSDOS_I(mapping->host)->truncate_lock); | 314 | up_read(&MSDOS_I(mapping->host)->truncate_lock); |
290 | 315 | ||
291 | return blocknr; | 316 | return blocknr; |