NTFS: Add bmap address space operation needed for FIBMAP ioctl.
Signed-off-by: Anton Altaparmakov <anton@tuxera.com>
This commit is contained in:
parent
2b522cc160
commit
3f7fc6f2a2
124
fs/ntfs/aops.c
124
fs/ntfs/aops.c
@ -1537,6 +1537,129 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
|
|||||||
|
|
||||||
#endif /* NTFS_RW */
|
#endif /* NTFS_RW */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ntfs_bmap - map logical file block to physical device block
|
||||||
|
* @mapping: address space mapping to which the block to be mapped belongs
|
||||||
|
* @block: logical block to map to its physical device block
|
||||||
|
*
|
||||||
|
* For regular, non-resident files (i.e. not compressed and not encrypted), map
|
||||||
|
* the logical @block belonging to the file described by the address space
|
||||||
|
* mapping @mapping to its physical device block.
|
||||||
|
*
|
||||||
|
* The size of the block is equal to the @s_blocksize field of the super block
|
||||||
|
* of the mounted file system which is guaranteed to be smaller than or equal
|
||||||
|
* to the cluster size thus the block is guaranteed to fit entirely inside the
|
||||||
|
* cluster which means we do not need to care how many contiguous bytes are
|
||||||
|
* available after the beginning of the block.
|
||||||
|
*
|
||||||
|
* Return the physical device block if the mapping succeeded or 0 if the block
|
||||||
|
* is sparse or there was an error.
|
||||||
|
*
|
||||||
|
* Note: This is a problem if someone tries to run bmap() on $Boot system file
|
||||||
|
* as that really is in block zero but there is nothing we can do. bmap() is
|
||||||
|
* just broken in that respect (just like it cannot distinguish sparse from
|
||||||
|
* not available or error).
|
||||||
|
*/
|
||||||
|
static sector_t ntfs_bmap(struct address_space *mapping, sector_t block)
|
||||||
|
{
|
||||||
|
s64 ofs, size;
|
||||||
|
loff_t i_size;
|
||||||
|
LCN lcn;
|
||||||
|
unsigned long blocksize, flags;
|
||||||
|
ntfs_inode *ni = NTFS_I(mapping->host);
|
||||||
|
ntfs_volume *vol = ni->vol;
|
||||||
|
unsigned delta;
|
||||||
|
unsigned char blocksize_bits, cluster_size_shift;
|
||||||
|
|
||||||
|
ntfs_debug("Entering for mft_no 0x%lx, logical block 0x%llx.",
|
||||||
|
ni->mft_no, (unsigned long long)block);
|
||||||
|
if (ni->type != AT_DATA || !NInoNonResident(ni) || NInoEncrypted(ni)) {
|
||||||
|
ntfs_error(vol->sb, "BMAP does not make sense for %s "
|
||||||
|
"attributes, returning 0.",
|
||||||
|
(ni->type != AT_DATA) ? "non-data" :
|
||||||
|
(!NInoNonResident(ni) ? "resident" :
|
||||||
|
"encrypted"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* None of these can happen. */
|
||||||
|
BUG_ON(NInoCompressed(ni));
|
||||||
|
BUG_ON(NInoMstProtected(ni));
|
||||||
|
blocksize = vol->sb->s_blocksize;
|
||||||
|
blocksize_bits = vol->sb->s_blocksize_bits;
|
||||||
|
ofs = (s64)block << blocksize_bits;
|
||||||
|
read_lock_irqsave(&ni->size_lock, flags);
|
||||||
|
size = ni->initialized_size;
|
||||||
|
i_size = i_size_read(VFS_I(ni));
|
||||||
|
read_unlock_irqrestore(&ni->size_lock, flags);
|
||||||
|
/*
|
||||||
|
* If the offset is outside the initialized size or the block straddles
|
||||||
|
* the initialized size then pretend it is a hole unless the
|
||||||
|
* initialized size equals the file size.
|
||||||
|
*/
|
||||||
|
if (unlikely(ofs >= size || (ofs + blocksize > size && size < i_size)))
|
||||||
|
goto hole;
|
||||||
|
cluster_size_shift = vol->cluster_size_bits;
|
||||||
|
down_read(&ni->runlist.lock);
|
||||||
|
lcn = ntfs_attr_vcn_to_lcn_nolock(ni, ofs >> cluster_size_shift, false);
|
||||||
|
up_read(&ni->runlist.lock);
|
||||||
|
if (unlikely(lcn < LCN_HOLE)) {
|
||||||
|
/*
|
||||||
|
* Step down to an integer to avoid gcc doing a long long
|
||||||
|
* comparision in the switch when we know @lcn is between
|
||||||
|
* LCN_HOLE and LCN_EIO (i.e. -1 to -5).
|
||||||
|
*
|
||||||
|
* Otherwise older gcc (at least on some architectures) will
|
||||||
|
* try to use __cmpdi2() which is of course not available in
|
||||||
|
* the kernel.
|
||||||
|
*/
|
||||||
|
switch ((int)lcn) {
|
||||||
|
case LCN_ENOENT:
|
||||||
|
/*
|
||||||
|
* If the offset is out of bounds then pretend it is a
|
||||||
|
* hole.
|
||||||
|
*/
|
||||||
|
goto hole;
|
||||||
|
case LCN_ENOMEM:
|
||||||
|
ntfs_error(vol->sb, "Not enough memory to complete "
|
||||||
|
"mapping for inode 0x%lx. "
|
||||||
|
"Returning 0.", ni->mft_no);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ntfs_error(vol->sb, "Failed to complete mapping for "
|
||||||
|
"inode 0x%lx. Run chkdsk. "
|
||||||
|
"Returning 0.", ni->mft_no);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (lcn < 0) {
|
||||||
|
/* It is a hole. */
|
||||||
|
hole:
|
||||||
|
ntfs_debug("Done (returning hole).");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The block is really allocated and fullfils all our criteria.
|
||||||
|
* Convert the cluster to units of block size and return the result.
|
||||||
|
*/
|
||||||
|
delta = ofs & vol->cluster_size_mask;
|
||||||
|
if (unlikely(sizeof(block) < sizeof(lcn))) {
|
||||||
|
block = lcn = ((lcn << cluster_size_shift) + delta) >>
|
||||||
|
blocksize_bits;
|
||||||
|
/* If the block number was truncated return 0. */
|
||||||
|
if (unlikely(block != lcn)) {
|
||||||
|
ntfs_error(vol->sb, "Physical block 0x%llx is too "
|
||||||
|
"large to be returned, returning 0.",
|
||||||
|
(long long)lcn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
block = ((lcn << cluster_size_shift) + delta) >>
|
||||||
|
blocksize_bits;
|
||||||
|
ntfs_debug("Done (returning block 0x%llx).", (unsigned long long)lcn);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_normal_aops - address space operations for normal inodes and attributes
|
* ntfs_normal_aops - address space operations for normal inodes and attributes
|
||||||
*
|
*
|
||||||
@ -1549,6 +1672,7 @@ const struct address_space_operations ntfs_normal_aops = {
|
|||||||
.writepage = ntfs_writepage,
|
.writepage = ntfs_writepage,
|
||||||
.set_page_dirty = __set_page_dirty_buffers,
|
.set_page_dirty = __set_page_dirty_buffers,
|
||||||
#endif /* NTFS_RW */
|
#endif /* NTFS_RW */
|
||||||
|
.bmap = ntfs_bmap,
|
||||||
.migratepage = buffer_migrate_page,
|
.migratepage = buffer_migrate_page,
|
||||||
.is_partially_uptodate = block_is_partially_uptodate,
|
.is_partially_uptodate = block_is_partially_uptodate,
|
||||||
.error_remove_page = generic_error_remove_page,
|
.error_remove_page = generic_error_remove_page,
|
||||||
|
Loading…
Reference in New Issue
Block a user