Loading fs/ntfs/aops.c +124 −0 Original line number Diff line number Diff line Loading @@ -1537,6 +1537,129 @@ err_out: #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 * Loading @@ -1549,6 +1672,7 @@ const struct address_space_operations ntfs_normal_aops = { .writepage = ntfs_writepage, .set_page_dirty = __set_page_dirty_buffers, #endif /* NTFS_RW */ .bmap = ntfs_bmap, .migratepage = buffer_migrate_page, .is_partially_uptodate = block_is_partially_uptodate, .error_remove_page = generic_error_remove_page, Loading Loading
fs/ntfs/aops.c +124 −0 Original line number Diff line number Diff line Loading @@ -1537,6 +1537,129 @@ err_out: #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 * Loading @@ -1549,6 +1672,7 @@ const struct address_space_operations ntfs_normal_aops = { .writepage = ntfs_writepage, .set_page_dirty = __set_page_dirty_buffers, #endif /* NTFS_RW */ .bmap = ntfs_bmap, .migratepage = buffer_migrate_page, .is_partially_uptodate = block_is_partially_uptodate, .error_remove_page = generic_error_remove_page, Loading