aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-03-23 16:26:56 -0800
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-23 16:26:56 -0800
commita1a051b1870f9e4607526c7e403abab06526c6d9 (patch)
tree08942e39ca8477c4b0f594deac9e966bb376db83
parentaca361c1a0dc0165ac3148137983cb4b1458b5c1 (diff)
parentb425c8c5922562c562dc55a636c3c8d758ed6d17 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs-2.6: NTFS: 2.1.27 - Various bug fixes and cleanups. NTFS: Semaphore to mutex conversion. NTFS: Handle the recently introduced -ENAMETOOLONG return value from NTFS: Add a missing call to flush_dcache_mft_record_page() in NTFS: Fix a bug in fs/ntfs/inode.c::ntfs_read_locked_index_inode() where we NTFS: Improve comments on file attribute flags in fs/ntfs/layout.h. NTFS: Limit name length in fs/ntfs/unistr.c::ntfs_nlstoucs() to maximum NTFS: Remove all the make_bad_inode() calls. This should only be called NTFS: Add support for sparse files which have a compression unit of 0. NTFS: Fix comparison of $MFT and $MFTMirr to not bail out when there are NTFS: Use buffer_migrate_page() for the ->migratepage function of all ntfs NTFS: Fix a buggette in an "should be impossible" case handling where we NTFS: Fix an (innocent) off-by-one error in the runlist code. NTFS: Fix two compiler warnings on Alpha. Thanks to Andrew Morton for
-rw-r--r--Documentation/filesystems/ntfs.txt5
-rw-r--r--fs/ntfs/ChangeLog30
-rw-r--r--fs/ntfs/Makefile2
-rw-r--r--fs/ntfs/aops.c14
-rw-r--r--fs/ntfs/attrib.c35
-rw-r--r--fs/ntfs/compress.c4
-rw-r--r--fs/ntfs/dir.c2
-rw-r--r--fs/ntfs/file.c16
-rw-r--r--fs/ntfs/inode.c111
-rw-r--r--fs/ntfs/inode.h13
-rw-r--r--fs/ntfs/layout.h44
-rw-r--r--fs/ntfs/mft.c68
-rw-r--r--fs/ntfs/mft.h5
-rw-r--r--fs/ntfs/namei.c9
-rw-r--r--fs/ntfs/ntfs.h2
-rw-r--r--fs/ntfs/runlist.c12
-rw-r--r--fs/ntfs/super.c84
-rw-r--r--fs/ntfs/unistr.c51
18 files changed, 294 insertions, 213 deletions
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
index 25116858789..638cbd3d2b0 100644
--- a/Documentation/filesystems/ntfs.txt
+++ b/Documentation/filesystems/ntfs.txt
@@ -457,6 +457,11 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
+2.1.27:
+ - Implement page migration support so the kernel can move memory used
+ by NTFS files and directories around for management purposes.
+ - Add support for writing to sparse files created with Windows XP SP2.
+ - Many minor improvements and bug fixes.
2.1.26:
- Implement support for sector sizes above 512 bytes (up to the maximum
supported by NTFS which is 4096 bytes).
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
index 9d8ffa89e2c..35cc4b1d60f 100644
--- a/fs/ntfs/ChangeLog
+++ b/fs/ntfs/ChangeLog
@@ -16,8 +16,34 @@ ToDo/Notes:
inode having been discarded already. Whether this can actually ever
happen is unclear however so it is worth waiting until someone hits
the problem.
- - Enable the code for setting the NT4 compatibility flag when we start
- making NTFS 1.2 specific modifications.
+
+2.1.27 - Various bug fixes and cleanups.
+
+ - Fix two compiler warnings on Alpha. Thanks to Andrew Morton for
+ reporting them.
+ - Fix an (innocent) off-by-one error in the runlist code.
+ - Fix a buggette in an "should be impossible" case handling where we
+ continued the attribute lookup loop instead of aborting it.
+ - Use buffer_migrate_page() for the ->migratepage function of all ntfs
+ address space operations.
+ - Fix comparison of $MFT and $MFTMirr to not bail out when there are
+ unused, invalid mft records which are the same in both $MFT and
+ $MFTMirr.
+ - Add support for sparse files which have a compression unit of 0.
+ - Remove all the make_bad_inode() calls. This should only be called
+ from read inode and new inode code paths.
+ - Limit name length in fs/ntfs/unistr.c::ntfs_nlstoucs() to maximum
+ allowed by NTFS, i.e. 255 Unicode characters, not including the
+ terminating NULL (which is not stored on disk).
+ - Improve comments on file attribute flags in fs/ntfs/layout.h.
+ - Fix a bug in fs/ntfs/inode.c::ntfs_read_locked_index_inode() where we
+ forgot to update a temporary variable so loading index inodes which
+ have an index allocation attribute failed.
+ - Add a missing call to flush_dcache_mft_record_page() in
+ fs/ntfs/inode.c::ntfs_write_inode().
+ - Handle the recently introduced -ENAMETOOLONG return value from
+ fs/ntfs/unistr.c::ntfs_nlstoucs() in fs/ntfs/namei.c::ntfs_lookup().
+ - Semaphore to mutex conversion. (Ingo Molnar)
2.1.26 - Minor bug fixes and updates.
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
index d95fac7fdeb..e27b4eacffb 100644
--- a/fs/ntfs/Makefile
+++ b/fs/ntfs/Makefile
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
unistr.o upcase.o
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.26\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.27\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index 7e361da770b..580412d330c 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -22,6 +22,7 @@
*/
#include <linux/errno.h>
+#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
@@ -1277,18 +1278,18 @@ unm_done:
tni = locked_nis[nr_locked_nis];
/* Get the base inode. */
- down(&tni->extent_lock);
+ mutex_lock(&tni->extent_lock);
if (tni->nr_extents >= 0)
base_tni = tni;
else {
base_tni = tni->ext.base_ntfs_ino;
BUG_ON(!base_tni);
}
- up(&tni->extent_lock);
+ mutex_unlock(&tni->extent_lock);
ntfs_debug("Unlocking %s inode 0x%lx.",
tni == base_tni ? "base" : "extent",
tni->mft_no);
- up(&tni->mrec_lock);
+ mutex_unlock(&tni->mrec_lock);
atomic_dec(&tni->count);
iput(VFS_I(base_tni));
}
@@ -1529,7 +1530,6 @@ err_out:
"error %i.", err);
SetPageError(page);
NVolSetErrors(ni->vol);
- make_bad_inode(vi);
}
unlock_page(page);
if (ctx)
@@ -1551,6 +1551,9 @@ struct address_space_operations ntfs_aops = {
#ifdef NTFS_RW
.writepage = ntfs_writepage, /* Write dirty page to disk. */
#endif /* NTFS_RW */
+ .migratepage = buffer_migrate_page, /* Move a page cache page from
+ one physical page to an
+ other. */
};
/**
@@ -1567,6 +1570,9 @@ 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. */
};
#ifdef NTFS_RW
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index 9480a0526cd..1663f5c3c6a 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -1,7 +1,7 @@
/**
* attrib.c - NTFS attribute operations. Part of the Linux-NTFS project.
*
- * Copyright (c) 2001-2005 Anton Altaparmakov
+ * Copyright (c) 2001-2006 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
@@ -1048,7 +1048,7 @@ do_next_attr_loop:
le32_to_cpu(ctx->mrec->bytes_allocated))
break;
if (a->type == AT_END)
- continue;
+ break;
if (!a->length)
break;
if (al_entry->instance != a->instance)
@@ -1695,7 +1695,9 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size)
a->data.non_resident.initialized_size =
cpu_to_sle64(attr_size);
if (NInoSparse(ni) || NInoCompressed(ni)) {
- a->data.non_resident.compression_unit = 4;
+ a->data.non_resident.compression_unit = 0;
+ if (NInoCompressed(ni) || vol->major_ver < 3)
+ a->data.non_resident.compression_unit = 4;
a->data.non_resident.compressed_size =
a->data.non_resident.allocated_size;
} else
@@ -1714,13 +1716,20 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size)
ni->allocated_size = new_size;
if (NInoSparse(ni) || NInoCompressed(ni)) {
ni->itype.compressed.size = ni->allocated_size;
- ni->itype.compressed.block_size = 1U <<
- (a->data.non_resident.compression_unit +
- vol->cluster_size_bits);
- ni->itype.compressed.block_size_bits =
- ffs(ni->itype.compressed.block_size) - 1;
- ni->itype.compressed.block_clusters = 1U <<
- a->data.non_resident.compression_unit;
+ if (a->data.non_resident.compression_unit) {
+ ni->itype.compressed.block_size = 1U << (a->data.
+ non_resident.compression_unit +
+ vol->cluster_size_bits);
+ ni->itype.compressed.block_size_bits =
+ ffs(ni->itype.compressed.block_size) -
+ 1;
+ ni->itype.compressed.block_clusters = 1U <<
+ a->data.non_resident.compression_unit;
+ } else {
+ ni->itype.compressed.block_size = 0;
+ ni->itype.compressed.block_size_bits = 0;
+ ni->itype.compressed.block_clusters = 0;
+ }
vi->i_blocks = ni->itype.compressed.size >> 9;
} else
vi->i_blocks = ni->allocated_size >> 9;
@@ -2429,16 +2438,12 @@ undo_alloc:
"chkdsk to recover.", IS_ERR(m) ?
"restore attribute search context" :
"truncate attribute runlist");
- make_bad_inode(vi);
- make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
} else if (mp_rebuilt) {
if (ntfs_attr_record_resize(m, a, attr_len)) {
ntfs_error(vol->sb, "Failed to restore attribute "
"record in error code path. Run "
"chkdsk to recover.");
- make_bad_inode(vi);
- make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
} else /* if (success) */ {
if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(
@@ -2451,8 +2456,6 @@ undo_alloc:
"mapping pairs array in error "
"code path. Run chkdsk to "
"recover.");
- make_bad_inode(vi);
- make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
}
flush_dcache_mft_record_page(ctx->ntfs_ino);
diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c
index 25d24106f89..68a607ff9fd 100644
--- a/fs/ntfs/compress.c
+++ b/fs/ntfs/compress.c
@@ -67,7 +67,7 @@ static DEFINE_SPINLOCK(ntfs_cb_lock);
/**
* allocate_compression_buffers - allocate the decompression buffers
*
- * Caller has to hold the ntfs_lock semaphore.
+ * Caller has to hold the ntfs_lock mutex.
*
* Return 0 on success or -ENOMEM if the allocations failed.
*/
@@ -84,7 +84,7 @@ int allocate_compression_buffers(void)
/**
* free_compression_buffers - free the decompression buffers
*
- * Caller has to hold the ntfs_lock semaphore.
+ * Caller has to hold the ntfs_lock mutex.
*/
void free_compression_buffers(void)
{
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
index b0690d4c890..9d9ed3fe371 100644
--- a/fs/ntfs/dir.c
+++ b/fs/ntfs/dir.c
@@ -1136,7 +1136,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (fpos == 1) {
ntfs_debug("Calling filldir for .. with len 2, fpos 0x1, "
"inode 0x%lx, DT_DIR.",
- parent_ino(filp->f_dentry));
+ (unsigned long)parent_ino(filp->f_dentry));
rc = filldir(dirent, "..", 2, fpos,
parent_ino(filp->f_dentry), DT_DIR);
if (rc)
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 5027d3d1b3f..f5d057e4acc 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -943,7 +943,8 @@ rl_not_mapped_enoent:
}
ni->runlist.rl = rl;
status.runlist_merged = 1;
- ntfs_debug("Allocated cluster, lcn 0x%llx.", lcn);
+ ntfs_debug("Allocated cluster, lcn 0x%llx.",
+ (unsigned long long)lcn);
/* Map and lock the mft record and get the attribute record. */
if (!NInoAttr(ni))
base_ni = ni;
@@ -1206,8 +1207,6 @@ rl_not_mapped_enoent:
"attribute runlist in error code "
"path. Run chkdsk to recover the "
"lost cluster.");
- make_bad_inode(vi);
- make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
} else /* if (success) */ {
status.runlist_merged = 0;
@@ -1238,8 +1237,6 @@ rl_not_mapped_enoent:
ntfs_error(vol->sb, "Failed to restore attribute "
"record in error code path. Run "
"chkdsk to recover.");
- make_bad_inode(vi);
- make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
} else /* if (success) */ {
if (ntfs_mapping_pairs_build(vol, (u8*)a +
@@ -1252,8 +1249,6 @@ rl_not_mapped_enoent:
"mapping pairs array in error "
"code path. Run chkdsk to "
"recover.");
- make_bad_inode(vi);
- make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
}
flush_dcache_mft_record_page(ctx->ntfs_ino);
@@ -1622,11 +1617,8 @@ err_out:
unmap_mft_record(base_ni);
ntfs_error(vi->i_sb, "Failed to update initialized_size/i_size (error "
"code %i).", err);
- if (err != -ENOMEM) {
+ if (err != -ENOMEM)
NVolSetErrors(ni->vol);
- make_bad_inode(VFS_I(base_ni));
- make_bad_inode(vi);
- }
return err;
}
@@ -1801,8 +1793,6 @@ err_out:
ntfs_error(vi->i_sb, "Resident attribute commit write failed "
"with error %i.", err);
NVolSetErrors(ni->vol);
- make_bad_inode(VFS_I(base_ni));
- make_bad_inode(vi);
}
if (ctx)
ntfs_attr_put_search_ctx(ctx);
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 55263b7de9c..4c86b7e1d1e 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1,7 +1,7 @@
/**
* inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project.
*
- * Copyright (c) 2001-2005 Anton Altaparmakov
+ * Copyright (c) 2001-2006 Anton Altaparmakov
*
* 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
@@ -19,13 +19,19 @@
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/pagemap.h>
#include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
-#include <linux/quotaops.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
#include <linux/mount.h>
+#include <linux/mutex.h>
+#include <linux/pagemap.h>
+#include <linux/quotaops.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include "aops.h"
+#include "attrib.h"
+#include "bitmap.h"
#include "dir.h"
#include "debug.h"
#include "inode.h"
@@ -382,7 +388,7 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
atomic_set(&ni->count, 1);
ni->vol = NTFS_SB(sb);
ntfs_init_runlist(&ni->runlist);
- init_MUTEX(&ni->mrec_lock);
+ mutex_init(&ni->mrec_lock);
ni->page = NULL;
ni->page_ofs = 0;
ni->attr_list_size = 0;
@@ -394,7 +400,7 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
ni->itype.index.collation_rule = 0;
ni->itype.index.block_size_bits = 0;
ni->itype.index.vcn_size_bits = 0;
- init_MUTEX(&ni->extent_lock);
+ mutex_init(&ni->extent_lock);
ni->nr_extents = 0;
ni->ext.base_ntfs_ino = NULL;
}
@@ -1064,10 +1070,10 @@ skip_large_dir_stuff:
if (a->non_resident) {
NInoSetNonResident(ni);
if (NInoCompressed(ni) || NInoSparse(ni)) {
- if (a->data.non_resident.compression_unit !=
- 4) {
+ if (NInoCompressed(ni) && a->data.non_resident.
+ compression_unit != 4) {
ntfs_error(vi->i_sb, "Found "
- "nonstandard "
+ "non-standard "
"compression unit (%u "
"instead of 4). "
"Cannot handle this.",
@@ -1076,16 +1082,26 @@ skip_large_dir_stuff:
err = -EOPNOTSUPP;
goto unm_err_out;
}
- ni->itype.compressed.block_clusters = 1U <<
- a->data.non_resident.
- compression_unit;
- ni->itype.compressed.block_size = 1U << (
- a->data.non_resident.
- compression_unit +
- vol->cluster_size_bits);
- ni->itype.compressed.block_size_bits = ffs(
- ni->itype.compressed.
- block_size) - 1;
+ if (a->data.non_resident.compression_unit) {
+ ni->itype.compressed.block_size = 1U <<
+ (a->data.non_resident.
+ compression_unit +
+ vol->cluster_size_bits);
+ ni->itype.compressed.block_size_bits =
+ ffs(ni->itype.
+ compressed.
+ block_size) - 1;
+ ni->itype.compressed.block_clusters =
+ 1U << a->data.
+ non_resident.
+ compression_unit;
+ } else {
+ ni->itype.compressed.block_size = 0;
+ ni->itype.compressed.block_size_bits =
+ 0;
+ ni->itype.compressed.block_clusters =
+ 0;
+ }
ni->itype.compressed.size = sle64_to_cpu(
a->data.non_resident.
compressed_size);
@@ -1338,8 +1354,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
goto unm_err_out;
}
if (NInoCompressed(ni) || NInoSparse(ni)) {
- if (a->data.non_resident.compression_unit != 4) {
- ntfs_error(vi->i_sb, "Found nonstandard "
+ if (NInoCompressed(ni) && a->data.non_resident.
+ compression_unit != 4) {
+ ntfs_error(vi->i_sb, "Found non-standard "
"compression unit (%u instead "
"of 4). Cannot handle this.",
a->data.non_resident.
@@ -1347,13 +1364,22 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
err = -EOPNOTSUPP;
goto unm_err_out;
}
- ni->itype.compressed.block_clusters = 1U <<
- a->data.non_resident.compression_unit;
- ni->itype.compressed.block_size = 1U << (
- a->data.non_resident.compression_unit +
- vol->cluster_size_bits);
- ni->itype.compressed.block_size_bits = ffs(
- ni->itype.compressed.block_size) - 1;
+ if (a->data.non_resident.compression_unit) {
+ ni->itype.compressed.block_size = 1U <<
+ (a->data.non_resident.
+ compression_unit +
+ vol->cluster_size_bits);
+ ni->itype.compressed.block_size_bits =
+ ffs(ni->itype.compressed.
+ block_size) - 1;
+ ni->itype.compressed.block_clusters = 1U <<
+ a->data.non_resident.
+ compression_unit;
+ } else {
+ ni->itype.compressed.block_size = 0;
+ ni->itype.compressed.block_size_bits = 0;
+ ni->itype.compressed.block_clusters = 0;
+ }
ni->itype.compressed.size = sle64_to_cpu(
a->data.non_resident.compressed_size);
}
@@ -1406,7 +1432,6 @@ err_out:
"Run chkdsk.", err, vi->i_ino, ni->type, ni->name_len,
base_vi->i_ino);
make_bad_inode(vi);
- make_bad_inode(base_vi);
if (err != -ENOMEM)
NVolSetErrors(vol);
return err;
@@ -1591,6 +1616,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
"$INDEX_ALLOCATION attribute.");
goto unm_err_out;
}
+ a = ctx->attr;
if (!a->non_resident) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
"resident.");
@@ -2823,11 +2849,8 @@ done:
old_bad_out:
old_size = -1;
bad_out:
- if (err != -ENOMEM && err != -EOPNOTSUPP) {
- make_bad_inode(vi);
- make_bad_inode(VFS_I(base_ni));
+ if (err != -ENOMEM && err != -EOPNOTSUPP)
NVolSetErrors(vol);
- }
if (err != -EOPNOTSUPP)
NInoSetTruncateFailed(ni);
else if (old_size >= 0)
@@ -2842,11 +2865,8 @@ out:
ntfs_debug("Failed. Returning error code %i.", err);
return err;
conv_err_out:
- if (err != -ENOMEM && err != -EOPNOTSUPP) {
- make_bad_inode(vi);
- make_bad_inode(VFS_I(base_ni));
+ if (err != -ENOMEM && err != -EOPNOTSUPP)
NVolSetErrors(vol);
- }
if (err != -EOPNOTSUPP)
NInoSetTruncateFailed(ni);
else
@@ -3044,15 +3064,18 @@ int ntfs_write_inode(struct inode *vi, int sync)
* record will be cleaned and written out to disk below, i.e. before
* this function returns.
*/
- if (modified && !NInoTestSetDirty(ctx->ntfs_ino))
- mark_ntfs_record_dirty(ctx->ntfs_ino->page,
- ctx->ntfs_ino->page_ofs);
+ if (modified) {
+ flush_dcache_mft_record_page(ctx->ntfs_ino);
+ if (!NInoTestSetDirty(ctx->ntfs_ino))
+ mark_ntfs_record_dirty(ctx->ntfs_ino->page,
+ ctx->ntfs_ino->page_ofs);
+ }
ntfs_attr_put_search_ctx(ctx);
/* Now the access times are updated, write the base mft record. */
if (NInoDirty(ni))
err = write_mft_record(ni, m, sync);
/* Write all attached extent mft records. */
- down(&ni->extent_lock);
+ mutex_lock(&ni->extent_lock);
if (ni->nr_extents > 0) {
ntfs_inode **extent_nis = ni->ext.extent_ntfs_inos;
int i;
@@ -3079,7 +3102,7 @@ int ntfs_write_inode(struct inode *vi, int sync)
}
}
}
- up(&ni->extent_lock);
+ mutex_unlock(&ni->extent_lock);
unmap_mft_record(ni);
if (unlikely(err))
goto err_out;
@@ -3094,9 +3117,7 @@ err_out:
"retries later.");
mark_inode_dirty(vi);
} else {
- ntfs_error(vi->i_sb, "Failed (error code %i): Marking inode "
- "as bad. You should run chkdsk.", -err);
- make_bad_inode(vi);
+ ntfs_error(vi->i_sb, "Failed (error %i): Run chkdsk.", -err);
NVolSetErrors(ni->vol);
}
return err;
diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h
index 3de5c023196..f088291e017 100644
--- a/fs/ntfs/inode.h
+++ b/fs/ntfs/inode.h
@@ -24,12 +24,13 @@
#ifndef _LINUX_NTFS_INODE_H
#define _LINUX_NTFS_INODE_H
-#include <linux/mm.h>
+#include <asm/atomic.h>
+
#include <linux/fs.h>
-#include <linux/seq_file.h>
#include <linux/list.h>
-#include <asm/atomic.h>
-#include <asm/semaphore.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/seq_file.h>
#include "layout.h"
#include "volume.h"
@@ -81,7 +82,7 @@ struct _ntfs_inode {
* The following fields are only valid for real inodes and extent
* inodes.
*/
- struct semaphore mrec_lock; /* Lock for serializing access to the
+ struct mutex mrec_lock; /* Lock for serializing access to the
mft record belonging to this inode. */
struct page *page; /* The page containing the mft record of the
inode. This should only be touched by the
@@ -119,7 +120,7 @@ struct _ntfs_inode {
u8 block_clusters; /* Number of clusters per cb. */
} compressed;
} itype;
- struct semaphore extent_lock; /* Lock for accessing/modifying the
+ struct mutex extent_lock; /* Lock for accessing/modifying the
below . */
s32 nr_extents; /* For a base mft record, the number of attached extent
inodes (0 if none), for extent records and for fake
diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h
index bb408d4dcbb..d34b93cb8b4 100644
--- a/fs/ntfs/layout.h
+++ b/fs/ntfs/layout.h
@@ -769,7 +769,7 @@ typedef struct {
compressed. (This effectively limits the
compression unit size to be a power of two
clusters.) WinNT4 only uses a value of 4.
- Sparse files also have this set to 4. */
+ Sparse files have this set to 0 on XPSP2. */
/* 35*/ u8 reserved[5]; /* Align to 8-byte boundary. */
/* The sizes below are only used when lowest_vcn is zero, as otherwise it would
be difficult to keep them up-to-date.*/
@@ -801,13 +801,16 @@ typedef struct {
typedef ATTR_RECORD ATTR_REC;
/*
- * File attribute flags (32-bit).
+ * File attribute flags (32-bit) appearing in the file_attributes fields of the
+ * STANDARD_INFORMATION attribute of MFT_RECORDs and the FILENAME_ATTR
+ * attributes of MFT_RECORDs and directory index entries.
+ *
+ * All of the below flags appear in the directory index entries but only some
+ * appear in the STANDARD_INFORMATION attribute whilst only some others appear
+ * in the FILENAME_ATTR attribute of MFT_RECORDs. Unless otherwise stated the
+ * flags appear in all of the above.
*/
enum {
- /*
- * The following flags are only present in the STANDARD_INFORMATION
- * attribute (in the field file_attributes).
- */
FILE_ATTR_READONLY = const_cpu_to_le32(0x00000001),
FILE_ATTR_HIDDEN = const_cpu_to_le32(0x00000002),
FILE_ATTR_SYSTEM = const_cpu_to_le32(0x00000004),
@@ -839,18 +842,14 @@ enum {
F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask
is used to to obtain all flags that are valid for setting. */
/*
- * The following flag is only present in the FILE_NAME attribute (in
- * the field file_attributes).
+ * The flag FILE_ATTR_DUP_FILENAME_INDEX_PRESENT is present in all
+ * FILENAME_ATTR attributes but not in the STANDARD_INFORMATION
+ * attribute of an mft record.
*/
FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = const_cpu_to_le32(0x10000000),
/* Note, this is a copy of the corresponding bit from the mft record,
telling us whether this is a directory or not, i.e. whether it has
an index root attribute or not. */
- /*
- * The following flag is present both in the STANDARD_INFORMATION
- * attribute and in the FILE_NAME attribute (in the field
- * file_attributes).
- */
FILE_ATTR_DUP_VIEW_INDEX_PRESENT = const_cpu_to_le32(0x20000000),
/* Note, this is a copy of the corresponding bit from the mft record,
telling us whether this file has a view index present (eg. object id
@@ -891,7 +890,7 @@ typedef struct {
Windows this is only updated when
accessed if some time delta has
passed since the last update. Also,
- last access times updates can be
+ last access time updates can be
disabled altogether for speed. */
/* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
/* 36*/ union {
@@ -1076,16 +1075,21 @@ typedef struct {
/* 20*/ sle64 last_access_time; /* Time this mft record was last
accessed. */
/* 28*/ sle64 allocated_size; /* Byte size of on-disk allocated space
- for the data attribute. So for
- normal $DATA, this is the
+ for the unnamed data attribute. So
+ for normal $DATA, this is the
allocated_size from the unnamed
$DATA attribute and for compressed
and/or sparse $DATA, this is the
compressed_size from the unnamed
- $DATA attribute. NOTE: This is a
- multiple of the cluster size. */
-/* 30*/ sle64 data_size; /* Byte size of actual data in data
- attribute. */
+ $DATA attribute. For a directory or
+ other inode without an unnamed $DATA
+ attribute, this is always 0. NOTE:
+ This is a multiple of the cluster
+ size. */
+/* 30*/ sle64 data_size; /* Byte size of actual data in unnamed
+ data attribute. For a directory or
+ other inode without an unnamed $DATA
+ attribute, this is always 0. */
/* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
/* 3c*/ union {
/* 3c*/ struct {
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
index 6499aafc225..4e72bc7afdf 100644
--- a/fs/ntfs/mft.c
+++ b/fs/ntfs/mft.c
@@ -93,6 +93,7 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
"Run chkdsk.", ni->mft_no);
ntfs_unmap_page(page);
page = ERR_PTR(-EIO);
+ NVolSetErrors(vol);
}
err_out:
ni->page = NULL;
@@ -104,8 +105,8 @@ err_out:
* map_mft_record - map, pin and lock an mft record
* @ni: ntfs inode whose MFT record to map
*
- * First, take the mrec_lock semaphore. We might now be sleeping, while waiting
- * for the semaphore if it was already locked by someone else.
+ * First, take the mrec_lock mutex. We might now be sleeping, while waiting
+ * for the mutex if it was already locked by someone else.
*
* The page of the record is mapped using map_mft_record_page() before being
* returned to the caller.
@@ -135,9 +136,9 @@ err_out:
* So that code will end up having to own the mrec_lock of all mft
* records/inodes present in the page before I/O can proceed. In that case we
* wouldn't need to bother with PG_locked and PG_uptodate as nobody will be
- * accessing anything without owning the mrec_lock semaphore. But we do need
- * to use them because of the read_cache_page() invocation and the code becomes
- * so much simpler this way that it is well worth it.
+ * accessing anything without owning the mrec_lock mutex. But we do need to
+ * use them because of the read_cache_page() invocation and the code becomes so
+ * much simpler this way that it is well worth it.
*
* 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
@@ -160,13 +161,13 @@ MFT_RECORD *map_mft_record(ntfs_inode *ni)
atomic_inc(&ni->count);
/* Serialize access to this mft record. */
- down(&ni->mrec_lock);
+ mutex_lock(&ni->mrec_lock);
m = map_mft_record_page(ni);
if (likely(!IS_ERR(m)))
return m;
- up(&ni->mrec_lock);
+ mutex_unlock(&ni->mrec_lock);
atomic_dec(&ni->count);
ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
return m;
@@ -217,7 +218,7 @@ void unmap_mft_record(ntfs_inode *ni)
ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);
unmap_mft_record_page(ni);
- up(&ni->mrec_lock);
+ mutex_unlock(&ni->mrec_lock);
atomic_dec(&ni->count);
/*
* If pure ntfs_inode, i.e. no vfs inode attached, we leave it to
@@ -261,7 +262,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
* in which case just return it. If not found, add it to the base
* inode before returning it.
*/
- down(&base_ni->extent_lock);
+ mutex_lock(&base_ni->extent_lock);
if (base_ni->nr_extents > 0) {
extent_nis = base_ni->ext.extent_ntfs_inos;
for (i = 0; i < base_ni->nr_extents; i++) {
@@ -274,7 +275,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
}
}
if (likely(ni != NULL)) {
- up(&base_ni->extent_lock);
+ mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
/* We found the record; just have to map and return it. */
m = map_mft_record(ni);
@@ -301,7 +302,7 @@ map_err_out:
/* Record wasn't there. Get a new ntfs inode and initialize it. */
ni = ntfs_new_extent_inode(base_ni->vol->sb, mft_no);
if (unlikely(!ni)) {
- up(&base_ni->extent_lock);
+ mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
return ERR_PTR(-ENOMEM);
}
@@ -312,7 +313,7 @@ map_err_out:
/* Now map the record. */
m = map_mft_record(ni);
if (IS_ERR(m)) {
- up(&base_ni->extent_lock);
+ mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
ntfs_clear_extent_inode(ni);
goto map_err_out;
@@ -347,14 +348,14 @@ map_err_out:
base_ni->ext.extent_ntfs_inos = tmp;
}
base_ni->ext.extent_ntfs_inos[base_ni->nr_extents++] = ni;
- up(&base_ni->extent_lock);
+ mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
ntfs_debug("Done 2.");
*ntfs_ino = ni;
return m;
unm_err_out:
unmap_mft_record(ni);
- up(&base_ni->extent_lock);
+ mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
/*
* If the extent inode was not attached to the base inode we need to
@@ -399,12 +400,12 @@ void __mark_mft_record_dirty(ntfs_inode *ni)
BUG_ON(NInoAttr(ni));
mark_ntfs_record_dirty(ni->page, ni->page_ofs);
/* Determine the base vfs inode and mark it dirty, too. */
- down(&ni->extent_lock);
+ mutex_lock(&ni->extent_lock);
if (likely(ni->nr_extents >= 0))
base_ni = ni;
else
base_ni = ni->ext.base_ntfs_ino;
- up(&ni->extent_lock);
+ mutex_unlock(&ni->extent_lock);
__mark_inode_dirty(VFS_I(base_ni), I_DIRTY_SYNC | I_DIRTY_DATASYNC);
}
@@ -650,10 +651,7 @@ err_out:
* fs/ntfs/aops.c::mark_ntfs_record_dirty().
*
* On success, clean the mft record and return 0. On error, leave the mft
- * record dirty and return -errno. The caller should call make_bad_inode() on
- * the base inode to ensure no more access happens to this inode. We do not do
- * it here as the caller may want to finish writing other extent mft records
- * first to minimize on-disk metadata inconsistencies.
+ * record dirty and return -errno.
*
* NOTE: We always perform synchronous i/o and ignore the @sync parameter.
* However, if the mft record has a counterpart in the mft mirror and @sync is
@@ -983,7 +981,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
}
ntfs_debug("Inode 0x%lx is not dirty.", mft_no);
/* The inode is not dirty, try to take the mft record lock. */
- if (unlikely(down_trylock(&ni->mrec_lock))) {
+ if (unlikely(!mutex_trylock(&ni->mrec_lock))) {
ntfs_debug("Mft record 0x%lx is already locked, do "
"not write it.", mft_no);
atomic_dec(&ni->count);
@@ -1043,13 +1041,13 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
* corresponding to this extent mft record attached.
*/
ni = NTFS_I(vi);
- down(&ni->extent_loc