diff options
author | Anton Altaparmakov <anton@tuxera.com> | 2014-10-16 07:50:52 -0400 |
---|---|---|
committer | Anton Altaparmakov <anton@tuxera.com> | 2014-10-16 07:50:52 -0400 |
commit | 3f7fc6f2a2ba0f72a09e9f9999c3812fdee8fe70 (patch) | |
tree | 532bc0daf483485adf13dacb5ae69aa824848b48 /fs | |
parent | 2b522cc16000c33d16bc76ee37e99ff9002a27be (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.c | 124 |
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 | */ | ||
1563 | static 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. */ | ||
1637 | hole: | ||
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, |