fat: permit to return phy block number by fibmap in fallocated region
[cascardo/linux.git] / fs / fat / cache.c
index 93fc622..5d38492 100644 (file)
@@ -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;
@@ -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);
 }