Merge git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs
Pull NTFS update from Anton Altaparmakov: "Here is a small NTFS update notably implementing FIBMAP ioctl for NTFS by adding the bmap address space operation. People seem to still want FIBMAP" * git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs: NTFS: Bump version to 2.1.31. NTFS: Add bmap address space operation needed for FIBMAP ioctl. NTFS: Remove changelog from Documentation/filesystems/ntfs.txt. NTFS: Split ntfs_aops into ntfs_normal_aops and ntfs_compressed_aops in preparation for them diverging.
This commit is contained in:
@@ -8,7 +8,7 @@ ntfs-y := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
|
||||
|
||||
ntfs-$(CONFIG_NTFS_RW) += bitmap.o lcnalloc.o logfile.o quota.o usnjrnl.o
|
||||
|
||||
ccflags-y := -DNTFS_VERSION=\"2.1.30\"
|
||||
ccflags-y := -DNTFS_VERSION=\"2.1.31\"
|
||||
ccflags-$(CONFIG_NTFS_DEBUG) += -DDEBUG
|
||||
ccflags-$(CONFIG_NTFS_RW) += -DNTFS_RW
|
||||
|
||||
|
||||
163
fs/ntfs/aops.c
163
fs/ntfs/aops.c
@@ -1,8 +1,7 @@
|
||||
/**
|
||||
* aops.c - NTFS kernel address space operations and page cache handling.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2007 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc.
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -1539,16 +1538,157 @@ err_out:
|
||||
#endif /* NTFS_RW */
|
||||
|
||||
/**
|
||||
* ntfs_aops - general address space operations for inodes and attributes
|
||||
* 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).
|
||||
*/
|
||||
const struct address_space_operations ntfs_aops = {
|
||||
.readpage = ntfs_readpage, /* Fill page with data. */
|
||||
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
|
||||
*
|
||||
* Note these are not used for compressed or mst protected inodes and
|
||||
* attributes.
|
||||
*/
|
||||
const struct address_space_operations ntfs_normal_aops = {
|
||||
.readpage = ntfs_readpage,
|
||||
#ifdef NTFS_RW
|
||||
.writepage = ntfs_writepage, /* Write dirty page to disk. */
|
||||
.writepage = ntfs_writepage,
|
||||
.set_page_dirty = __set_page_dirty_buffers,
|
||||
#endif /* NTFS_RW */
|
||||
.migratepage = buffer_migrate_page, /* Move a page cache page from
|
||||
one physical page to an
|
||||
other. */
|
||||
.bmap = ntfs_bmap,
|
||||
.migratepage = buffer_migrate_page,
|
||||
.is_partially_uptodate = block_is_partially_uptodate,
|
||||
.error_remove_page = generic_error_remove_page,
|
||||
};
|
||||
|
||||
/**
|
||||
* ntfs_compressed_aops - address space operations for compressed inodes
|
||||
*/
|
||||
const struct address_space_operations ntfs_compressed_aops = {
|
||||
.readpage = ntfs_readpage,
|
||||
#ifdef NTFS_RW
|
||||
.writepage = ntfs_writepage,
|
||||
.set_page_dirty = __set_page_dirty_buffers,
|
||||
#endif /* NTFS_RW */
|
||||
.migratepage = buffer_migrate_page,
|
||||
.is_partially_uptodate = block_is_partially_uptodate,
|
||||
.error_remove_page = generic_error_remove_page,
|
||||
};
|
||||
|
||||
@@ -1564,9 +1704,8 @@ const struct address_space_operations ntfs_mst_aops = {
|
||||
without touching the buffers
|
||||
belonging to the page. */
|
||||
#endif /* NTFS_RW */
|
||||
.migratepage = buffer_migrate_page, /* Move a page cache page from
|
||||
one physical page to an
|
||||
other. */
|
||||
.migratepage = buffer_migrate_page,
|
||||
.is_partially_uptodate = block_is_partially_uptodate,
|
||||
.error_remove_page = generic_error_remove_page,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project.
|
||||
* inode.c - NTFS kernel inode handling.
|
||||
*
|
||||
* Copyright (c) 2001-2007 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc.
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@@ -1012,6 +1012,7 @@ skip_large_dir_stuff:
|
||||
/* Setup the operations for this inode. */
|
||||
vi->i_op = &ntfs_dir_inode_ops;
|
||||
vi->i_fop = &ntfs_dir_ops;
|
||||
vi->i_mapping->a_ops = &ntfs_mst_aops;
|
||||
} else {
|
||||
/* It is a file. */
|
||||
ntfs_attr_reinit_search_ctx(ctx);
|
||||
@@ -1160,11 +1161,12 @@ no_data_attr_special_case:
|
||||
/* Setup the operations for this inode. */
|
||||
vi->i_op = &ntfs_file_inode_ops;
|
||||
vi->i_fop = &ntfs_file_ops;
|
||||
vi->i_mapping->a_ops = &ntfs_normal_aops;
|
||||
if (NInoMstProtected(ni))
|
||||
vi->i_mapping->a_ops = &ntfs_mst_aops;
|
||||
else if (NInoCompressed(ni))
|
||||
vi->i_mapping->a_ops = &ntfs_compressed_aops;
|
||||
}
|
||||
if (NInoMstProtected(ni))
|
||||
vi->i_mapping->a_ops = &ntfs_mst_aops;
|
||||
else
|
||||
vi->i_mapping->a_ops = &ntfs_aops;
|
||||
/*
|
||||
* The number of 512-byte blocks used on disk (for stat). This is in so
|
||||
* far inaccurate as it doesn't account for any named streams or other
|
||||
@@ -1414,10 +1416,11 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
|
||||
ni->allocated_size = sle64_to_cpu(
|
||||
a->data.non_resident.allocated_size);
|
||||
}
|
||||
vi->i_mapping->a_ops = &ntfs_normal_aops;
|
||||
if (NInoMstProtected(ni))
|
||||
vi->i_mapping->a_ops = &ntfs_mst_aops;
|
||||
else
|
||||
vi->i_mapping->a_ops = &ntfs_aops;
|
||||
else if (NInoCompressed(ni))
|
||||
vi->i_mapping->a_ops = &ntfs_compressed_aops;
|
||||
if ((NInoCompressed(ni) || NInoSparse(ni)) && ni->type != AT_INDEX_ROOT)
|
||||
vi->i_blocks = ni->itype.compressed.size >> 9;
|
||||
else
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/*
|
||||
* ntfs.h - Defines for NTFS Linux kernel driver. Part of the Linux-NTFS
|
||||
* project.
|
||||
* ntfs.h - Defines for NTFS Linux kernel driver.
|
||||
*
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc.
|
||||
* Copyright (C) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -57,7 +56,8 @@ extern struct kmem_cache *ntfs_attr_ctx_cache;
|
||||
extern struct kmem_cache *ntfs_index_ctx_cache;
|
||||
|
||||
/* The various operations structs defined throughout the driver files. */
|
||||
extern const struct address_space_operations ntfs_aops;
|
||||
extern const struct address_space_operations ntfs_normal_aops;
|
||||
extern const struct address_space_operations ntfs_compressed_aops;
|
||||
extern const struct address_space_operations ntfs_mst_aops;
|
||||
|
||||
extern const struct file_operations ntfs_file_ops;
|
||||
|
||||
Reference in New Issue
Block a user