Commit eab71b80 authored by Anton Altaparmakov's avatar Anton Altaparmakov

NTFS: 2.0.10 - There can only be 2^32 - 1 inodes on an NTFS volume.

- Add check at mount time to verify that the number of inodes on the
  volume does not exceed 2^32 - 1, which is the maximum allowed for
  NTFS according to Microsoft.
- Change mft_no member of ntfs_inode structure to be unsigned long.
  Update all users. This makes ntfs_inode->mft_no just a copy of struct
  inode->i_ino. But we can't just always use struct inode->i_ino and
  remove mft_no because extent inodes do not have an attached struct
  inode.
parent 915c0d2e
...@@ -247,6 +247,10 @@ ChangeLog ...@@ -247,6 +247,10 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.0.10:
- Microsoft says that the maximum number of inodes is 2^32 - 1. Update
the driver accordingly to only use 32-bits to store inode numbers on
32-bit architectures. This improves the speed of the driver a little.
2.0.9: 2.0.9:
- Change decompression engine to use a single buffer. This should not - Change decompression engine to use a single buffer. This should not
affect performance except perhaps on the most heavy i/o on SMP affect performance except perhaps on the most heavy i/o on SMP
......
...@@ -23,6 +23,17 @@ ToDo: ...@@ -23,6 +23,17 @@ ToDo:
them cleaner and make code reuse easier. them cleaner and make code reuse easier.
- Want to use dummy inodes for address space i/o. - Want to use dummy inodes for address space i/o.
2.0.10 - There can only be 2^32 - 1 inodes on an NTFS volume.
- Add check at mount time to verify that the number of inodes on the
volume does not exceed 2^32 - 1, which is the maximum allowed for
NTFS according to Microsoft.
- Change mft_no member of ntfs_inode structure to be unsigned long.
Update all users. This makes ntfs_inode->mft_no just a copy of struct
inode->i_ino. But we can't just always use struct inode->i_ino and
remove mft_no because extent inodes do not have an attached struct
inode.
2.0.9 - Decompression engine now uses a single buffer and other cleanups. 2.0.9 - Decompression engine now uses a single buffer and other cleanups.
- Change decompression engine to use a single buffer protected by a - Change decompression engine to use a single buffer protected by a
......
...@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o ...@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \ ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.9\" EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.10\"
ifeq ($(CONFIG_NTFS_DEBUG),y) ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG EXTRA_CFLAGS += -DDEBUG
......
...@@ -1243,8 +1243,7 @@ static BOOL find_external_attr(const ATTR_TYPES type, const uchar_t *name, ...@@ -1243,8 +1243,7 @@ static BOOL find_external_attr(const ATTR_TYPES type, const uchar_t *name,
ni = ctx->ntfs_ino; ni = ctx->ntfs_ino;
base_ni = ctx->base_ntfs_ino; base_ni = ctx->base_ntfs_ino;
ntfs_debug("Entering for inode 0x%Lx, type 0x%x.", ntfs_debug("Entering for inode 0x%lx, type 0x%x.", ni->mft_no, type);
(unsigned long long)ni->mft_no, type);
if (!base_ni) { if (!base_ni) {
/* First call happens with the base mft record. */ /* First call happens with the base mft record. */
base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino; base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino;
......
...@@ -748,9 +748,9 @@ int ntfs_file_read_compressed_block(struct page *page) ...@@ -748,9 +748,9 @@ int ntfs_file_read_compressed_block(struct page *page)
*/ */
if (err) { if (err) {
ntfs_error(vol->sb, "ntfs_decompress() failed in inode " ntfs_error(vol->sb, "ntfs_decompress() failed in inode "
"0x%Lx with error code %i. Skipping " "0x%lx with error code %i. Skipping "
"this compression block.\n", "this compression block.\n",
(unsigned long long)ni->mft_no, -err); ni->mft_no, -err);
/* Release the unfinished pages. */ /* Release the unfinished pages. */
for (; prev_cur_page < cur_page; prev_cur_page++) { for (; prev_cur_page < cur_page; prev_cur_page++) {
page = pages[prev_cur_page]; page = pages[prev_cur_page];
......
...@@ -64,7 +64,7 @@ const uchar_t I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'), ...@@ -64,7 +64,7 @@ const uchar_t I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'),
* work but we don't care for how quickly one can access them. This also fixes * work but we don't care for how quickly one can access them. This also fixes
* the dcache aliasing issues. * the dcache aliasing issues.
*/ */
u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
const int uname_len, ntfs_name **res) const int uname_len, ntfs_name **res)
{ {
ntfs_volume *vol = dir_ni->vol; ntfs_volume *vol = dir_ni->vol;
...@@ -98,8 +98,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -98,8 +98,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0, if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
ctx)) { ctx)) {
ntfs_error(sb, "Index root attribute missing in directory " ntfs_error(sb, "Index root attribute missing in directory "
"inode 0x%Lx.", "inode 0x%lx.", dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto put_unm_err_out; goto put_unm_err_out;
} }
...@@ -278,9 +277,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -278,9 +277,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
/* Consistency check: Verify that an index allocation exists. */ /* Consistency check: Verify that an index allocation exists. */
if (!NInoIndexAllocPresent(dir_ni)) { if (!NInoIndexAllocPresent(dir_ni)) {
ntfs_error(sb, "No index allocation attribute but index entry " ntfs_error(sb, "No index allocation attribute but index entry "
"requires one. Directory inode 0x%Lx is " "requires one. Directory inode 0x%lx is "
"corrupt or driver bug.", "corrupt or driver bug.", dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto put_unm_err_out; goto put_unm_err_out;
} }
...@@ -308,30 +306,27 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -308,30 +306,27 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
/* Bounds checks. */ /* Bounds checks. */
if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) { if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) {
ntfs_error(sb, "Out of bounds check failed. Corrupt directory " ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
"inode 0x%Lx or driver bug.", "inode 0x%lx or driver bug.", dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
if (sle64_to_cpu(ia->index_block_vcn) != vcn) { if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is " ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
"different from expected VCN (0x%Lx). " "different from expected VCN (0x%Lx). "
"Directory inode 0x%Lx is corrupt or driver " "Directory inode 0x%lx is corrupt or driver "
"bug.", "bug.",
(long long)sle64_to_cpu(ia->index_block_vcn), (long long)sle64_to_cpu(ia->index_block_vcn),
(long long)vcn, (long long)vcn, dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
if (le32_to_cpu(ia->index.allocated_size) + 0x18 != if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
dir_ni->_IDM(index_block_size)) { dir_ni->_IDM(index_block_size)) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%Lx has a size (%u) differing from the " "0x%lx has a size (%u) differing from the "
"directory specified size (%u). Directory " "directory specified size (%u). Directory "
"inode is corrupt or driver bug.", "inode is corrupt or driver bug.",
(long long)vcn, (long long)vcn, dir_ni->mft_no,
(unsigned long long)dir_ni->mft_no,
le32_to_cpu(ia->index.allocated_size) + 0x18, le32_to_cpu(ia->index.allocated_size) + 0x18,
dir_ni->_IDM(index_block_size)); dir_ni->_IDM(index_block_size));
err = -EIO; err = -EIO;
...@@ -340,19 +335,17 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -340,19 +335,17 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
index_end = (u8*)ia + dir_ni->_IDM(index_block_size); index_end = (u8*)ia + dir_ni->_IDM(index_block_size);
if (index_end > kaddr + PAGE_CACHE_SIZE) { if (index_end > kaddr + PAGE_CACHE_SIZE) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%Lx crosses page boundary. Impossible! " "0x%lx crosses page boundary. Impossible! "
"Cannot access! This is probably a bug in the " "Cannot access! This is probably a bug in the "
"driver.", (long long)vcn, "driver.", (long long)vcn, dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) { if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) {
ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory " ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory "
"inode 0x%Lx exceeds maximum size.", "inode 0x%lx exceeds maximum size.",
(long long)vcn, (long long)vcn, dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
...@@ -371,8 +364,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -371,8 +364,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) > (u8*)ie + le16_to_cpu(ie->_IEH(key_length)) >
index_end) { index_end) {
ntfs_error(sb, "Index entry out of bounds in " ntfs_error(sb, "Index entry out of bounds in "
"directory inode 0x%Lx.", "directory inode 0x%lx.",
(unsigned long long)dir_ni->mft_no); dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
...@@ -523,8 +516,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -523,8 +516,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if (ie->_IEH(flags) & INDEX_ENTRY_NODE) { if (ie->_IEH(flags) & INDEX_ENTRY_NODE) {
if ((ia->index.flags & NODE_MASK) == LEAF_NODE) { if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
ntfs_error(sb, "Index entry with child node found in " ntfs_error(sb, "Index entry with child node found in "
"a leaf node in directory inode 0x%Lx.", "a leaf node in directory inode 0x%lx.",
(unsigned long long)dir_ni->mft_no); dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
...@@ -544,7 +537,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -544,7 +537,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
goto descend_into_child_node; goto descend_into_child_node;
} }
ntfs_error(sb, "Negative child node vcn in directory inode " ntfs_error(sb, "Negative child node vcn in directory inode "
"0x%Lx.", (unsigned long long)dir_ni->mft_no); "0x%lx.", dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
...@@ -643,8 +636,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -643,8 +636,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0, if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
ctx)) { ctx)) {
ntfs_error(sb, "Index root attribute missing in directory " ntfs_error(sb, "Index root attribute missing in directory "
"inode 0x%Lx.", "inode 0x%lx.", dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto put_unm_err_out; goto put_unm_err_out;
} }
...@@ -750,9 +742,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -750,9 +742,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
/* Consistency check: Verify that an index allocation exists. */ /* Consistency check: Verify that an index allocation exists. */
if (!NInoIndexAllocPresent(dir_ni)) { if (!NInoIndexAllocPresent(dir_ni)) {
ntfs_error(sb, "No index allocation attribute but index entry " ntfs_error(sb, "No index allocation attribute but index entry "
"requires one. Directory inode 0x%Lx is " "requires one. Directory inode 0x%lx is "
"corrupt or driver bug.", "corrupt or driver bug.", dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto put_unm_err_out; goto put_unm_err_out;
} }
...@@ -780,30 +771,27 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -780,30 +771,27 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
/* Bounds checks. */ /* Bounds checks. */
if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) { if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) {
ntfs_error(sb, "Out of bounds check failed. Corrupt directory " ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
"inode 0x%Lx or driver bug.", "inode 0x%lx or driver bug.", dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
if (sle64_to_cpu(ia->index_block_vcn) != vcn) { if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is " ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
"different from expected VCN (0x%Lx). " "different from expected VCN (0x%Lx). "
"Directory inode 0x%Lx is corrupt or driver " "Directory inode 0x%lx is corrupt or driver "
"bug.", "bug.",
(long long)sle64_to_cpu(ia->index_block_vcn), (long long)sle64_to_cpu(ia->index_block_vcn),
(long long)vcn, (long long)vcn, dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
if (le32_to_cpu(ia->index.allocated_size) + 0x18 != if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
dir_ni->_IDM(index_block_size)) { dir_ni->_IDM(index_block_size)) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%Lx has a size (%u) differing from the " "0x%lx has a size (%u) differing from the "
"directory specified size (%u). Directory " "directory specified size (%u). Directory "
"inode is corrupt or driver bug.", "inode is corrupt or driver bug.",
(long long)vcn, (long long)vcn, dir_ni->mft_no,
(unsigned long long)dir_ni->mft_no,
le32_to_cpu(ia->index.allocated_size) + 0x18, le32_to_cpu(ia->index.allocated_size) + 0x18,
dir_ni->_IDM(index_block_size)); dir_ni->_IDM(index_block_size));
err = -EIO; err = -EIO;
...@@ -812,19 +800,17 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -812,19 +800,17 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
index_end = (u8*)ia + dir_ni->_IDM(index_block_size); index_end = (u8*)ia + dir_ni->_IDM(index_block_size);
if (index_end > kaddr + PAGE_CACHE_SIZE) { if (index_end > kaddr + PAGE_CACHE_SIZE) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%Lx crosses page boundary. Impossible! " "0x%lx crosses page boundary. Impossible! "
"Cannot access! This is probably a bug in the " "Cannot access! This is probably a bug in the "
"driver.", (long long)vcn, "driver.", (long long)vcn, dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) { if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) {
ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory " ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory "
"inode 0x%Lx exceeds maximum size.", "inode 0x%lx exceeds maximum size.",
(long long)vcn, (long long)vcn, dir_ni->mft_no);
(unsigned long long)dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
...@@ -843,8 +829,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -843,8 +829,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) > (u8*)ie + le16_to_cpu(ie->_IEH(key_length)) >
index_end) { index_end) {
ntfs_error(sb, "Index entry out of bounds in " ntfs_error(sb, "Index entry out of bounds in "
"directory inode 0x%Lx.", "directory inode 0x%lx.",
(unsigned long long)dir_ni->mft_no); dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
...@@ -928,8 +914,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -928,8 +914,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if (ie->_IEH(flags) & INDEX_ENTRY_NODE) { if (ie->_IEH(flags) & INDEX_ENTRY_NODE) {
if ((ia->index.flags & NODE_MASK) == LEAF_NODE) { if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
ntfs_error(sb, "Index entry with child node found in " ntfs_error(sb, "Index entry with child node found in "
"a leaf node in directory inode 0x%Lx.", "a leaf node in directory inode 0x%lx.",
(unsigned long long)dir_ni->mft_no); dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
...@@ -949,7 +935,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -949,7 +935,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
goto descend_into_child_node; goto descend_into_child_node;
} }
ntfs_error(sb, "Negative child node vcn in directory inode " ntfs_error(sb, "Negative child node vcn in directory inode "
"0x%Lx.", (unsigned long long)dir_ni->mft_no); "0x%lx.", dir_ni->mft_no);
err = -EIO; err = -EIO;
goto unm_unm_err_out; goto unm_unm_err_out;
} }
...@@ -1044,12 +1030,11 @@ static inline int ntfs_filldir(ntfs_volume *vol, struct file *filp, ...@@ -1044,12 +1030,11 @@ static inline int ntfs_filldir(ntfs_volume *vol, struct file *filp,
else else
dt_type = DT_REG; dt_type = DT_REG;
ntfs_debug("Calling filldir for %s with len %i, f_pos 0x%Lx, inode " ntfs_debug("Calling filldir for %s with len %i, f_pos 0x%Lx, inode "
"0x%Lx, DT_%s.", name, name_len, filp->f_pos, "0x%lx, DT_%s.", name, name_len, filp->f_pos,
(unsigned long long)MREF_LE(ie->_IIF(indexed_file)), MREF_LE(ie->_IIF(indexed_file)),
dt_type == DT_DIR ? "DIR" : "REG"); dt_type == DT_DIR ? "DIR" : "REG");
return filldir(dirent, name, name_len, filp->f_pos, return filldir(dirent, name, name_len, filp->f_pos,
(unsigned long)MREF_LE(ie->_IIF(indexed_file)), MREF_LE(ie->_IIF(indexed_file)), dt_type);
dt_type);
} }
/* /*
...@@ -1083,8 +1068,8 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1083,8 +1068,8 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
u8 *kaddr, *bmp, *index_end; u8 *kaddr, *bmp, *index_end;
attr_search_context *ctx; attr_search_context *ctx;
ntfs_debug("Entering for inode 0x%Lx, f_pos 0x%Lx.", ntfs_debug("Entering for inode 0x%lx, f_pos 0x%Lx.",
(unsigned long long)ndir->mft_no, filp->f_pos); vdir->i_ino, filp->f_pos);
rc = err = 0; rc = err = 0;
/* Are we at end of dir yet? */ /* Are we at end of dir yet? */
if (filp->f_pos >= vdir->i_size + vol->mft_record_size) if (filp->f_pos >= vdir->i_size + vol->mft_record_size)
...@@ -1092,8 +1077,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1092,8 +1077,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* Emulate . and .. for all directories. */ /* Emulate . and .. for all directories. */
if (!filp->f_pos) { if (!filp->f_pos) {
ntfs_debug("Calling filldir for . with len 1, f_pos 0x0, " ntfs_debug("Calling filldir for . with len 1, f_pos 0x0, "
"inode 0x%Lx, DT_DIR.", "inode 0x%lx, DT_DIR.", vdir->i_ino);
(unsigned long long)ndir->mft_no);
rc = filldir(dirent, ".", 1, filp->f_pos, vdir->i_ino, DT_DIR); rc = filldir(dirent, ".", 1, filp->f_pos, vdir->i_ino, DT_DIR);
if (rc) if (rc)
goto done; goto done;
...@@ -1141,8 +1125,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1141,8 +1125,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0, if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
ctx)) { ctx)) {
ntfs_error(sb, "Index root attribute missing in directory " ntfs_error(sb, "Index root attribute missing in directory "
"inode 0x%Lx.", "inode 0x%lx.", vdir->i_ino);
(unsigned long long)ndir->mft_no);
err = -EIO; err = -EIO;
goto kf_unm_err_out; goto kf_unm_err_out;
} }
...@@ -1201,8 +1184,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1201,8 +1184,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (!lookup_attr(AT_BITMAP, I30, 4, CASE_SENSITIVE, 0, NULL, 0, if (!lookup_attr(AT_BITMAP, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
ctx)) { ctx)) {
ntfs_error(sb, "Index bitmap attribute missing in " ntfs_error(sb, "Index bitmap attribute missing in "
"directory inode 0x%Lx.", "directory inode 0x%lx.", vdir->i_ino);
(unsigned long long)ndir->mft_no);
err = -EIO; err = -EIO;
goto kf_unm_err_out; goto kf_unm_err_out;
} }
...@@ -1251,8 +1233,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1251,8 +1233,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* Bounds checks. */ /* Bounds checks. */
if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) { if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) {
ntfs_error(sb, "Out of bounds check failed. Corrupt directory " ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
"inode 0x%Lx or driver bug.", "inode 0x%lx or driver bug.", vdir->i_ino);
(unsigned long long)ndir->mft_no);
err = -EIO; err = -EIO;
goto unm_dir_err_out; goto unm_dir_err_out;
} }
...@@ -1261,23 +1242,22 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1261,23 +1242,22 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
ndir->_IDM(index_vcn_size_bits)) { ndir->_IDM(index_vcn_size_bits)) {
ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is " ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
"different from expected VCN (0x%Lx). " "different from expected VCN (0x%Lx). "
"Directory inode 0x%Lx is corrupt or driver " "Directory inode 0x%lx is corrupt or driver "
"bug. ", "bug. ",
(long long)sle64_to_cpu(ia->index_block_vcn), (long long)sle64_to_cpu(ia->index_block_vcn),
(long long)ia_pos >> (long long)ia_pos >>
ndir->_IDM(index_vcn_size_bits), ndir->_IDM(index_vcn_size_bits), vdir->i_ino);
(unsigned long long)ndir->mft_no);
err = -EIO; err = -EIO;
goto unm_dir_err_out; goto unm_dir_err_out;
} }
if (le32_to_cpu(ia->index.allocated_size) + 0x18 != if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
ndir->_IDM(index_block_size)) { ndir->_IDM(index_block_size)) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%Lx has a size (%u) differing from the " "0x%lx has a size (%u) differing from the "
"directory specified size (%u). Directory " "directory specified size (%u). Directory "
"inode is corrupt or driver bug.", "inode is corrupt or driver bug.",
(long long)ia_pos >> ndir->_IDM(index_vcn_size_bits), (long long)ia_pos >>
(unsigned long long)ndir->mft_no, ndir->_IDM(index_vcn_size_bits), vdir->i_ino,
le32_to_cpu(ia->index.allocated_size) + 0x18, le32_to_cpu(ia->index.allocated_size) + 0x18,
ndir->_IDM(index_block_size)); ndir->_IDM(index_block_size));
err = -EIO; err = -EIO;
...@@ -1286,11 +1266,10 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1286,11 +1266,10 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
index_end = (u8*)ia + ndir->_IDM(index_block_size); index_end = (u8*)ia + ndir->_IDM(index_block_size);
if (index_end > kaddr + PAGE_CACHE_SIZE) { if (index_end > kaddr + PAGE_CACHE_SIZE) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%Lx crosses page boundary. Impossible! " "0x%lx crosses page boundary. Impossible! "
"Cannot access! This is probably a bug in the " "Cannot access! This is probably a bug in the "
"driver.", (long long)ia_pos >> "driver.", (long long)ia_pos >>
ndir->_IDM(index_vcn_size_bits), ndir->_IDM(index_vcn_size_bits), vdir->i_ino);
(unsigned long long)ndir->mft_no);
err = -EIO; err = -EIO;
goto unm_dir_err_out; goto unm_dir_err_out;
} }
...@@ -1298,10 +1277,9 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1298,10 +1277,9 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + ndir->_IDM(index_block_size)) { if (index_end > (u8*)ia + ndir->_IDM(index_block_size)) {
ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory " ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory "
"inode 0x%Lx exceeds maximum size.", "inode 0x%lx exceeds maximum size.",
(long long)ia_pos >> (long long)ia_pos >>
ndir->_IDM(index_vcn_size_bits), ndir->_IDM(index_vcn_size_bits), vdir->i_ino);
(unsigned long long)ndir->mft_no);
err = -EIO; err = -EIO;
goto unm_dir_err_out; goto unm_dir_err_out;
} }
......
...@@ -40,8 +40,8 @@ typedef struct { ...@@ -40,8 +40,8 @@ typedef struct {
/* The little endian Unicode string $I30 as a global constant. */ /* The little endian Unicode string $I30 as a global constant. */
extern const uchar_t I30[5]; extern const uchar_t I30[5];
extern u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, extern MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni,
const int uname_len, ntfs_name **res); const uchar_t *uname, const int uname_len, ntfs_name **res);
#endif /* _LINUX_NTFS_FS_DIR_H */ #endif /* _LINUX_NTFS_FS_DIR_H */
...@@ -357,8 +357,7 @@ void ntfs_read_inode(struct inode *vi) ...@@ -357,8 +357,7 @@ void ntfs_read_inode(struct inode *vi)
if (lookup_attr(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx)) { if (lookup_attr(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx)) {
if (vi->i_ino == FILE_MFT) if (vi->i_ino == FILE_MFT)
goto skip_attr_list_load; goto skip_attr_list_load;
ntfs_debug("Attribute list found in inode %li (0x%lx).", ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
vi->i_ino, vi->i_ino);
ni->state |= 1 << NI_AttrList; ni->state |= 1 << NI_AttrList;
if (ctx->attr->flags & ATTR_IS_ENCRYPTED || if (ctx->attr->flags & ATTR_IS_ENCRYPTED ||
ctx->attr->flags & ATTR_COMPRESSION_MASK) { ctx->attr->flags & ATTR_COMPRESSION_MASK) {
...@@ -805,8 +804,8 @@ void ntfs_read_inode(struct inode *vi) ...@@ -805,8 +804,8 @@ void ntfs_read_inode(struct inode *vi)
ec_unm_err_out: ec_unm_err_out:
unmap_mft_record(READ, ni); unmap_mft_record(READ, ni);
err_out: err_out:
ntfs_error(vi->i_sb, "Failed with error code %i. Marking inode " ntfs_error(vi->i_sb, "Failed with error code %i. Marking inode 0x%lx "
"%li (0x%lx) as bad.", -err, vi->i_ino, vi->i_ino); "as bad.", -err, vi->i_ino);
make_bad_inode(vi); make_bad_inode(vi);
return; return;
} }
...@@ -857,7 +856,7 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -857,7 +856,7 @@ void ntfs_read_inode_mount(struct inode *vi)
ntfs_init_big_inode(vi); ntfs_init_big_inode(vi);
ni = NTFS_I(vi); ni = NTFS_I(vi);
if (vi->i_ino != FILE_MFT) { if (vi->i_ino != FILE_MFT) {
ntfs_error(sb, "Called for inode %ld but only inode %d " ntfs_error(sb, "Called for inode 0x%lx but only inode %d "
"allowed.", vi->i_ino, FILE_MFT); "allowed.", vi->i_ino, FILE_MFT);
goto err_out; goto err_out;
} }
...@@ -1034,7 +1033,7 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1034,7 +1033,7 @@ void ntfs_read_inode_mount(struct inode *vi)
if (al_entry->lowest_vcn) if (al_entry->lowest_vcn)
goto em_put_err_out; goto em_put_err_out;
/* First entry has to be in the base mft record. */ /* First entry has to be in the base mft record. */
if (MREF_LE(al_entry->mft_reference) != ni->mft_no) { if (MREF_LE(al_entry->mft_reference) != vi->i_ino) {
/* MFT references do not match, logic fails. */ /* MFT references do not match, logic fails. */
ntfs_error(sb, "BUG: The first $DATA extent " ntfs_error(sb, "BUG: The first $DATA extent "
"of $MFT is not in the base " "of $MFT is not in the base "
...@@ -1096,6 +1095,8 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1096,6 +1095,8 @@ void ntfs_read_inode_mount(struct inode *vi)
/* Are we in the first extent? */ /* Are we in the first extent? */
if (!next_vcn) { if (!next_vcn) {
u64 ll;
if (attr->_ANR(lowest_vcn)) { if (attr->_ANR(lowest_vcn)) {
ntfs_error(sb, "First extent of $DATA " ntfs_error(sb, "First extent of $DATA "
"attribute has non zero " "attribute has non zero "
...@@ -1113,8 +1114,16 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1113,8 +1114,16 @@ void ntfs_read_inode_mount(struct inode *vi)
ni->allocated_size = sle64_to_cpu( ni->allocated_size = sle64_to_cpu(
attr->_ANR(allocated_size)); attr->_ANR(allocated_size));
/* Set the number of mft records. */ /* Set the number of mft records. */
vol->_VMM(nr_mft_records) = vi->i_size >> ll = vi->i_size >> vol->mft_record_size_bits;
vol->mft_record_size_bits; /*
* Verify the number of mft records does not exceed
* 2^32 - 1.
*/
if (ll >= (1ULL << 32)) {
ntfs_error(sb, "$MFT is too big! Aborting.");
goto put_err_out;
}
vol->_VMM(nr_mft_records) = ll;
/* /*
* We have got the first extent of the run_list for * We have got the first extent of the run_list for
* $MFT which means it is now relatively safe to call * $MFT which means it is now relatively safe to call
...@@ -1255,8 +1264,7 @@ void ntfs_dirty_inode(struct inode *vi) ...@@ -1255,8 +1264,7 @@ void ntfs_dirty_inode(struct inode *vi)
*/ */
int ntfs_commit_inode(ntfs_inode *ni) int ntfs_commit_inode(ntfs_inode *ni)
{ {
ntfs_debug("Entering for inode 0x%Lx.", ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
(unsigned long long)ni->mft_no);
NInoClearDirty(ni); NInoClearDirty(ni);
return 0; return 0;
} }
...@@ -1265,8 +1273,7 @@ void __ntfs_clear_inode(ntfs_inode *ni) ...@@ -1265,8 +1273,7 @@ void __ntfs_clear_inode(ntfs_inode *ni)
{ {
int err; int err;
ntfs_debug("Entering for inode 0x%Lx.", ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
(unsigned long long)ni->mft_no);
if (NInoDirty(ni)) { if (NInoDirty(ni)) {
err = ntfs_commit_inode(ni); err = ntfs_commit_inode(ni);
if (err) { if (err) {
......
...@@ -39,7 +39,7 @@ struct _ntfs_inode { ...@@ -39,7 +39,7 @@ struct _ntfs_inode {
s64 allocated_size; /* Copy from $DATA/$INDEX_ALLOCATION. */ s64 allocated_size; /* Copy from $DATA/$INDEX_ALLOCATION. */
unsigned long state; /* NTFS specific flags describing this inode. unsigned long state; /* NTFS specific flags describing this inode.
See fs/ntfs/ntfs.h:ntfs_inode_state_bits. */ See fs/ntfs/ntfs.h:ntfs_inode_state_bits. */
u64 mft_no; /* Mft record number (inode number). */ unsigned long mft_no; /* Number of the mft record / inode. */
u16 seq_no; /* Sequence number of the mft record. */ u16 seq_no; /* Sequence number of the mft record. */
atomic_t count; /* Inode reference count for book keeping. */ atomic_t count; /* Inode reference count for book keeping. */
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */ ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
......
...@@ -278,9 +278,9 @@ typedef enum { ...@@ -278,9 +278,9 @@ typedef enum {
typedef u64 MFT_REF; typedef u64 MFT_REF;
#define MREF(x) ((u64)((x) & MFT_REF_MASK_CPU)) #define MREF(x) ((unsigned long)((x) & MFT_REF_MASK_CPU))
#define MSEQNO(x) ((u16)(((x) >> 48) & 0xffff)) #define MSEQNO(x) ((u16)(((x) >> 48) & 0xffff))
#define MREF_LE(x) ((u64)(le64_to_cpu(x) & MFT_REF_MASK_CPU)) #define MREF_LE(x) ((unsigned long)(le64_to_cpu(x) & MFT_REF_MASK_CPU))
#define MSEQNO_LE(x) ((u16)((le64_to_cpu(x) >> 48) & 0xffff)) #define MSEQNO_LE(x) ((u16)((le64_to_cpu(x) >> 48) & 0xffff))
#define IS_ERR_MREF(x) (((x) & 0x0000800000000000ULL) ? 1 : 0) #define IS_ERR_MREF(x) (((x) & 0x0000800000000000ULL) ? 1 : 0)
......
...@@ -240,8 +240,7 @@ static inline void unmap_mft_record_page(ntfs_inode *ni) ...@@ -240,8 +240,7 @@ static inline void unmap_mft_record_page(ntfs_inode *ni)
* *
* The mft record is now ours and we return a pointer to it. You need to check * The mft record is now ours and we return a pointer to it. You need to check
* the returned pointer with IS_ERR() and if that is true, PTR_ERR() will return * the returned pointer with IS_ERR() and if that is true, PTR_ERR() will return
* the error code. The following error codes are defined: * the error code.
* TODO: Fill in the possible error codes.
* *
* NOTE: Caller is responsible for setting the mft record dirty before calling * NOTE: Caller is responsible for setting the mft record dirty before calling
* unmap_mft_record(). This is obviously only necessary if the caller really * unmap_mft_record(). This is obviously only necessary if the caller really
...@@ -254,8 +253,7 @@ MFT_RECORD *map_mft_record(const int rw, ntfs_inode *ni) ...@@ -254,8 +253,7 @@ MFT_RECORD *map_mft_record(const int rw, ntfs_inode *ni)
{ {
MFT_RECORD *m; MFT_RECORD *m;
ntfs_debug("Entering for i_ino 0x%Lx, mapping for %s.", ntfs_debug("Entering for mft_no 0x%lx, mapping for %s.", ni->mft_no,
(unsigned long long)ni->mft_no,
rw == READ ? "READ" : "WRITE"); rw == READ ? "READ" : "WRITE");
/* Make sure the ntfs inode doesn't go away. */ /* Make sure the ntfs inode doesn't go away. */
...@@ -318,8 +316,7 @@ void unmap_mft_record(const int rw, ntfs_inode *ni) ...@@ -318,8 +316,7 @@ void unmap_mft_record(const int rw, ntfs_inode *ni)
BUG_ON(!atomic_read(&ni->mft_count) || !page); BUG_ON(!atomic_read(&ni->mft_count) || !page);
ntfs_debug("Entering for mft_no 0x%Lx, unmapping from %s.", ntfs_debug("Entering for mft_no 0x%lx, unmapping from %s.", ni->mft_no,
(unsigned long long)ni->mft_no,
rw == READ ? "READ" : "WRITE"); rw == READ ? "READ" : "WRITE");
/* Only release the actual page mapping if this is the last one. */ /* Only release the actual page mapping if this is the last one. */
...@@ -369,13 +366,12 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -369,13 +366,12 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
ntfs_inode *ni = NULL; ntfs_inode *ni = NULL;
ntfs_inode **extent_nis = NULL; ntfs_inode **extent_nis = NULL;
int i; int i;
u64 mft_no = MREF_LE(mref); unsigned long mft_no = MREF_LE(mref);
u16 seq_no = MSEQNO_LE(mref); u16 seq_no = MSEQNO_LE(mref);
BOOL destroy_ni = FALSE; BOOL destroy_ni = FALSE;
ntfs_debug("Mapping extent mft record 0x%Lx (base mft record 0x%Lx).", ntfs_debug("Mapping extent mft record 0x%lx (base mft record 0x%lx).",
(unsigned long long)mft_no, mft_no, base_ni->mft_no);
(unsigned long long)base_ni->mft_no);
/* Make sure the base ntfs inode doesn't go away. */ /* Make sure the base ntfs inode doesn't go away. */
atomic_inc(&base_ni->count); atomic_inc(&base_ni->count);
/* /*
......
...@@ -93,7 +93,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent) ...@@ -93,7 +93,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
struct inode *dent_inode; struct inode *dent_inode;
uchar_t *uname; uchar_t *uname;
ntfs_name *name = NULL; ntfs_name *name = NULL;
u64 mref; MFT_REF mref;
unsigned long dent_ino; unsigned long dent_ino;
int uname_len; int uname_len;
...@@ -110,7 +110,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent) ...@@ -110,7 +110,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
&name); &name);
kmem_cache_free(ntfs_name_cache, uname); kmem_cache_free(ntfs_name_cache, uname);
if (!IS_ERR_MREF(mref)) { if (!IS_ERR_MREF(mref)) {
dent_ino = (unsigned long)MREF(mref); dent_ino = MREF(mref);
ntfs_debug("Found inode 0x%lx. Calling iget.", dent_ino); ntfs_debug("Found inode 0x%lx. Calling iget.", dent_ino);
dent_inode = iget(vol->sb, dent_ino); dent_inode = iget(vol->sb, dent_ino);
if (dent_inode) { if (dent_inode) {
...@@ -130,17 +130,15 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent) ...@@ -130,17 +130,15 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
goto handle_name; goto handle_name;
} }
ntfs_error(vol->sb, "Found stale reference to inode " ntfs_error(vol->sb, "Found stale reference to inode "
"0x%Lx (reference sequence number = " "0x%lx (reference sequence number = "
"0x%x, inode sequence number = 0x%x, " "0x%x, inode sequence number = 0x%x, "
"returning -EACCES. Run chkdsk.", "returning -EACCES. Run chkdsk.",
(unsigned long long)MREF(mref), dent_ino, MSEQNO(mref),
MSEQNO(mref),
NTFS_I(dent_inode)->seq_no); NTFS_I(dent_inode)->seq_no);
iput(dent_inode); iput(dent_inode);
} else } else
ntfs_error(vol->sb, "iget(0x%Lx) failed, returning " ntfs_error(vol->sb, "iget(0x%lx) failed, returning "
"-EACCES.", "-EACCES.", dent_ino);
(unsigned long long)MREF(mref));
if (name) if (name)
kfree(name); kfree(name);
return ERR_PTR(-EACCES); return ERR_PTR(-EACCES);
......
...@@ -1236,14 +1236,13 @@ s64 get_nr_free_clusters(ntfs_volume *vol) ...@@ -1236,14 +1236,13 @@ s64 get_nr_free_clusters(ntfs_volume *vol)
* Errors are ignored and we just return the number of free inodes we have * Errors are ignored and we just return the number of free inodes we have
* found. This means we return an underestimate on error. * found. This means we return an underestimate on error.
*/ */
s64 get_nr_free_mft_records(ntfs_volume *vol) unsigned long get_nr_free_mft_records(ntfs_volume *vol)
{ {
struct address_space *mapping; struct address_space *mapping;
filler_t *readpage; filler_t *readpage;
struct page *page; struct page *page;
unsigned long index, max_index; unsigned long index, max_index, nr_free = 0;
unsigned int max_size, i; unsigned int max_size, i;
s64 nr_free = 0LL;
u32 *b; u32 *b;
ntfs_debug("Entering."); ntfs_debug("Entering.");
...@@ -1285,7 +1284,7 @@ s64 get_nr_free_mft_records(ntfs_volume *vol) ...@@ -1285,7 +1284,7 @@ s64 get_nr_free_mft_records(ntfs_volume *vol)
b = (u32*)kmap(page); b = (u32*)kmap(page);
/* For each 4 bytes, add up the number of zero bits. */ /* For each 4 bytes, add up the number of zero bits. */
for (i = 0; i < max_size; i++) for (i = 0; i < max_size; i++)
nr_free += (s64)(32 - hweight32(b[i])); nr_free += 32 - hweight32(b[i]);
kunmap(page); kunmap(page);
page_cache_release(page); page_cache_release(page);
} }
...@@ -1300,7 +1299,7 @@ s64 get_nr_free_mft_records(ntfs_volume *vol) ...@@ -1300,7 +1299,7 @@ s64 get_nr_free_mft_records(ntfs_volume *vol)
if (max_size) { if (max_size) {
/* Compensate for out of bounds zero bits. */ /* Compensate for out of bounds zero bits. */
if ((i = vol->_VMM(nr_mft_records) & 31)) if ((i = vol->_VMM(nr_mft_records) & 31))
nr_free -= (s64)(32 - i); nr_free -= 32 - i;
ntfs_debug("Handling partial page, max_size = 0x%x", ntfs_debug("Handling partial page, max_size = 0x%x",
max_size); max_size);
goto handle_partial_page; goto handle_partial_page;
...@@ -1358,10 +1357,7 @@ int ntfs_statfs(struct super_block *sb, struct statfs *sfs) ...@@ -1358,10 +1357,7 @@ int ntfs_statfs(struct super_block *sb, struct statfs *sfs)
/* Total file nodes in file system (at this moment in time). */ /* Total file nodes in file system (at this moment in time). */
sfs->f_files = vol->mft_ino->i_size >> vol->mft_record_size_bits; sfs->f_files = vol->mft_ino->i_size >> vol->mft_record_size_bits;
/* Free file nodes in fs (based on current total count). */ /* Free file nodes in fs (based on current total count). */
size = get_nr_free_mft_records(vol); sfs->f_ffree = get_nr_free_mft_records(vol);
if (size < 0LL)
size = 0LL;
sfs->f_ffree = size;
/* /*
* File system id. This is extremely *nix flavour dependent and even * File system id. This is extremely *nix flavour dependent and even
* within Linux itself all fs do their own thing. I interpret this to * within Linux itself all fs do their own thing. I interpret this to
......
...@@ -105,8 +105,8 @@ typedef struct { ...@@ -105,8 +105,8 @@ typedef struct {
struct rw_semaphore mftbmp_lock; /* Lock for serializing accesses to the struct rw_semaphore mftbmp_lock; /* Lock for serializing accesses to the
mft record bitmap ($MFT/$BITMAP). */ mft record bitmap ($MFT/$BITMAP). */
union { union {
s64 nr_mft_records; /* Number of records in the mft. */ unsigned long nr_mft_records; /* Number of mft records. */
s64 nr_mft_bits; /* Number of bits in mft bitmap. */ unsigned long nr_mft_bits; /* Number of bits in mft bitmap. */
} SN(vmm); } SN(vmm);
struct address_space mftbmp_mapping; /* Page cache for $MFT/$BITMAP. */ struct address_space mftbmp_mapping; /* Page cache for $MFT/$BITMAP. */
run_list mftbmp_rl; /* Run list for $MFT/$BITMAP. */ run_list mftbmp_rl; /* Run list for $MFT/$BITMAP. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment