aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAnton Altaparmakov <anton@tuxera.com>2014-10-16 07:50:52 -0400
committerAnton Altaparmakov <anton@tuxera.com>2014-10-16 07:50:52 -0400
commit3f7fc6f2a2ba0f72a09e9f9999c3812fdee8fe70 (patch)
tree532bc0daf483485adf13dacb5ae69aa824848b48 /fs
parent2b522cc16000c33d16bc76ee37e99ff9002a27be (diff)
NTFS: Add bmap address space operation needed for FIBMAP ioctl.
Signed-off-by: Anton Altaparmakov <anton@tuxera.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ntfs/aops.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index 6f0f98176b10..7521e11db728 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -1538,6 +1538,129 @@ err_out:
1538#endif /* NTFS_RW */ 1538#endif /* NTFS_RW */
1539 1539
1540/** 1540/**
1541 * ntfs_bmap - map logical file block to physical device block
1542 * @mapping: address space mapping to which the block to be mapped belongs
1543 * @block: logical block to map to its physical device block
1544 *
1545 * For regular, non-resident files (i.e. not compressed and not encrypted), map
1546 * the logical @block belonging to the file described by the address space
1547 * mapping @mapping to its physical device block.
1548 *
1549 * The size of the block is equal to the @s_blocksize field of the super block
1550 * of the mounted file system which is guaranteed to be smaller than or equal
1551 * to the cluster size thus the block is guaranteed to fit entirely inside the
1552 * cluster which means we do not need to care how many contiguous bytes are
1553 * available after the beginning of the block.
1554 *
1555 * Return the physical device block if the mapping succeeded or 0 if the block
1556 * is sparse or there was an error.
1557 *
1558 * Note: This is a problem if someone tries to run bmap() on $Boot system file
1559 * as that really is in block zero but there is nothing we can do. bmap() is
1560 * just broken in that respect (just like it cannot distinguish sparse from
1561 * not available or error).
1562 */
1563static sector_t ntfs_bmap(struct address_space *mapping, sector_t block)
1564{
1565 s64 ofs, size;
1566 loff_t i_size;
1567 LCN lcn;
1568 unsigned long blocksize, flags;
1569 ntfs_inode *ni = NTFS_I(mapping->host);
1570 ntfs_volume *vol = ni->vol;
1571 unsigned delta;
1572 unsigned char blocksize_bits, cluster_size_shift;
1573
1574 ntfs_debug("Entering for mft_no 0x%lx, logical block 0x%llx.",
1575 ni->mft_no, (unsigned long long)block);
1576 if (ni->type != AT_DATA || !NInoNonResident(ni) || NInoEncrypted(ni)) {
1577 ntfs_error(vol->sb, "BMAP does not make sense for %s "
1578 "attributes, returning 0.",
1579 (ni->type != AT_DATA) ? "non-data" :
1580 (!NInoNonResident(ni) ? "resident" :
1581 "encrypted"));
1582 return 0;
1583 }
1584 /* None of these can happen. */
1585 BUG_ON(NInoCompressed(ni));
1586 BUG_ON(NInoMstProtected(ni));
1587 blocksize = vol->sb->s_blocksize;
1588 blocksize_bits = vol->sb->s_blocksize_bits;
1589 ofs = (s64)block << blocksize_bits;
1590 read_lock_irqsave(&ni->size_lock, flags);
1591 size = ni->initialized_size;
1592 i_size = i_size_read(VFS_I(ni));
1593 read_unlock_irqrestore(&ni->size_lock, flags);
1594 /*
1595 * If the offset is outside the initialized size or the block straddles
1596 * the initialized size then pretend it is a hole unless the
1597 * initialized size equals the file size.
1598 */
1599 if (unlikely(ofs >= size || (ofs + blocksize > size && size < i_size)))
1600 goto hole;
1601 cluster_size_shift = vol->cluster_size_bits;
1602 down_read(&ni->runlist.lock);
1603 lcn = ntfs_attr_vcn_to_lcn_nolock(ni, ofs >> cluster_size_shift, false);
1604 up_read(&ni->runlist.lock);
1605 if (unlikely(lcn < LCN_HOLE)) {
1606 /*
1607 * Step down to an integer to avoid gcc doing a long long
1608 * comparision in the switch when we know @lcn is between
1609 * LCN_HOLE and LCN_EIO (i.e. -1 to -5).
1610 *
1611 * Otherwise older gcc (at least on some architectures) will
1612 * try to use __cmpdi2() which is of course not available in
1613 * the kernel.
1614 */
1615 switch ((int)lcn) {
1616 case LCN_ENOENT:
1617 /*
1618 * If the offset is out of bounds then pretend it is a
1619 * hole.
1620 */
1621 goto hole;
1622 case LCN_ENOMEM:
1623 ntfs_error(vol->sb, "Not enough memory to complete "
1624 "mapping for inode 0x%lx. "
1625 "Returning 0.", ni->mft_no);
1626 break;
1627 default:
1628 ntfs_error(vol->sb, "Failed to complete mapping for "
1629 "inode 0x%lx. Run chkdsk. "
1630 "Returning 0.", ni->mft_no);
1631 break;
1632 }
1633 return 0;
1634 }
1635 if (lcn < 0) {
1636 /* It is a hole. */
1637hole:
1638 ntfs_debug("Done (returning hole).");
1639 return 0;
1640 }
1641 /*
1642 * The block is really allocated and fullfils all our criteria.
1643 * Convert the cluster to units of block size and return the result.
1644 */
1645 delta = ofs & vol->cluster_size_mask;
1646 if (unlikely(sizeof(block) < sizeof(lcn))) {
1647 block = lcn = ((lcn << cluster_size_shift) + delta) >>
1648 blocksize_bits;
1649 /* If the block number was truncated return 0. */
1650 if (unlikely(block != lcn)) {
1651 ntfs_error(vol->sb, "Physical block 0x%llx is too "
1652 "large to be returned, returning 0.",
1653 (long long)lcn);
1654 return 0;
1655 }
1656 } else
1657 block = ((lcn << cluster_size_shift) + delta) >>
1658 blocksize_bits;
1659 ntfs_debug("Done (returning block 0x%llx).", (unsigned long long)lcn);
1660 return block;
1661}
1662
1663/**
1541 * ntfs_normal_aops - address space operations for normal inodes and attributes 1664 * ntfs_normal_aops - address space operations for normal inodes and attributes
1542 * 1665 *
1543 * Note these are not used for compressed or mst protected inodes and 1666 * Note these are not used for compressed or mst protected inodes and
@@ -1549,6 +1672,7 @@ const struct address_space_operations ntfs_normal_aops = {
1549 .writepage = ntfs_writepage, 1672 .writepage = ntfs_writepage,
1550 .set_page_dirty = __set_page_dirty_buffers, 1673 .set_page_dirty = __set_page_dirty_buffers,
1551#endif /* NTFS_RW */ 1674#endif /* NTFS_RW */
1675 .bmap = ntfs_bmap,
1552 .migratepage = buffer_migrate_page, 1676 .migratepage = buffer_migrate_page,
1553 .is_partially_uptodate = block_is_partially_uptodate, 1677 .is_partially_uptodate = block_is_partially_uptodate,
1554 .error_remove_page = generic_error_remove_page, 1678 .error_remove_page = generic_error_remove_page,