http://linux-ntfs.bkbits.net/ntfs-2.6
aia21@cantab.net|ChangeSet|20040428101909|56086 aia21

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/04/28 10:14:05+01:00 aia21@cantab.net 
#   NTFS: - Fix compiler warnings related to type casting.
#         - Move %L to %ll as %L is floating point and %ll is integer which
#           is what we want.
#         - Add logfile inode to ntfs_volume structure and the code to clean
#           it up in super.c.
# 
# fs/ntfs/volume.h
#   2004/04/28 10:13:59+01:00 aia21@cantab.net +2 -0
#   Add the logfile inode to the ntfs_volume structure.
# 
# fs/ntfs/super.c
#   2004/04/28 10:13:59+01:00 aia21@cantab.net +27 -16
#   - Move %L to %ll as %L is floating point and %ll is integer which is what we want.
#   - Fix compiler warnings related to type casting.
#   - Add cleaning up of logfile inode.
# 
# fs/ntfs/ntfs.h
#   2004/04/28 10:13:59+01:00 aia21@cantab.net +4 -1
#   Add n2p() macro to convert values to pointers.
# 
# fs/ntfs/inode.c
#   2004/04/28 10:13:58+01:00 aia21@cantab.net +5 -5
#   Move %L to %ll as %L is floating point and %ll is integer which is what we want.
# 
# fs/ntfs/dir.c
#   2004/04/28 10:13:58+01:00 aia21@cantab.net +51 -47
#   Move %L to %ll as %L is floating point and %ll is integer which is what we want.
# 
# fs/ntfs/compress.c
#   2004/04/28 10:13:58+01:00 aia21@cantab.net +3 -2
#   Move %L to %ll as %L is floating point and %ll is integer which is what we want.
# 
# fs/ntfs/attrib.c
#   2004/04/28 10:13:58+01:00 aia21@cantab.net +20 -19
#   Move %L to %ll as %L is floating point and %ll is integer which is what we want.
# 
# fs/ntfs/aops.c
#   2004/04/28 10:13:58+01:00 aia21@cantab.net +26 -20
#   Move %L to %ll as %L is floating point and %ll is integer which is what we want.
# 
# fs/ntfs/ChangeLog
#   2004/04/28 10:13:58+01:00 aia21@cantab.net +4 -0
#   Update ChangeLog.
# 
# ChangeSet
#   2004/04/27 12:27:16+01:00 aia21@cantab.net 
#   NTFS: Load the mft mirror at mount time and compare the mft records
#         stored in it to the ones in the mft (fs/ntfs/super.c).
# 
# fs/ntfs/volume.h
#   2004/04/27 12:27:11+01:00 aia21@cantab.net +3 -1
#   Wrap mftmirr_ino and mftmirr_size in #ifdef NTFS_RW.
# 
# fs/ntfs/super.c
#   2004/04/27 12:27:11+01:00 aia21@cantab.net +214 -24
#   Load the mft mirror at mount time and compare the mft records stored
#   in it to the ones in the mft (fs/ntfs/super.c).
# 
# fs/ntfs/ChangeLog
#   2004/04/27 10:38:02+01:00 aia21@cantab.net +2 -0
#   Update.
# 
# Documentation/filesystems/ntfs.txt
#   2004/04/27 10:38:02+01:00 aia21@cantab.net +1 -0
#   Update.
# 
# fs/ntfs/volume.h
#   2004/04/25 22:12:35+01:00 aia21@cantab.net +1 -1
#   Minor comment update.
# 
# ChangeSet
#   2004/04/25 22:04:57+01:00 aia21@cantab.net 
#   NTFS: Determine the mft mirror size as the number of mirrored mft records
#         and store it in ntfs_volume->mftmirr_size (fs/ntfs/super.c).
# 
# fs/ntfs/volume.h
#   2004/04/25 22:03:23+01:00 aia21@cantab.net +10 -6
#   Add mftmirr_size to ntfs_volume structure.
# 
# fs/ntfs/super.c
#   2004/04/25 22:02:54+01:00 aia21@cantab.net +16 -2
#   Determine the mft mirror size as the number of mirrored mft records
#   and store it in ntfs_volume->mftmirr_size.
# 
# fs/ntfs/ChangeLog
#   2004/04/25 22:02:49+01:00 aia21@cantab.net +2 -0
#   Update
# 
# fs/ntfs/mft.h
#   2004/04/25 15:26:00+01:00 aia21@cantab.net +1 -1
#   Update comment.
# 
# ChangeSet
#   2004/04/25 15:22:09+01:00 aia21@cantab.net 
#   NTFS: Move typedefs for ntfs_attr and test_t from fs/ntfs/inode.c to
#         fs/ntfs/inode.h so they can be used elsewhere.
# 
# fs/ntfs/inode.h
#   2004/04/25 15:21:15+01:00 aia21@cantab.net +24 -0
#   Move typedefs for ntfs_attr and test_t to fs/ntfs/inode.h so
#   they can be used elsewhere.
# 
# fs/ntfs/inode.c
#   2004/04/25 15:20:07+01:00 aia21@cantab.net +1 -22
#    Move typedefs for ntfs_attr and test_t to fs/ntfs/inode.h so
#    they can be used elsewhere.
# 
# fs/ntfs/ChangeLog
#   2004/04/25 15:20:02+01:00 aia21@cantab.net +2 -0
#   Update
# 
# ChangeSet
#   2004/04/25 15:11:52+01:00 aia21@cantab.net 
#   NTFS: Add NInoTestSetFoo() and NInoTestClearFoo() macro magic to
#         fs/ntfs/inode.h and use it to declare NInoTest{Set,Clear}Dirty.
# 
# fs/ntfs/inode.h
#   2004/04/25 15:10:49+01:00 aia21@cantab.net +16 -2
#   Add NInoTestSetFoo() and NInoTestClearFoo() macro magic and
#   use it to declare NInoTest{Set,Clear}Dirty.
# 
# fs/ntfs/ChangeLog
#   2004/04/25 15:10:46+01:00 aia21@cantab.net +2 -0
#   Update
# 
# ChangeSet
#   2004/04/25 15:03:50+01:00 aia21@cantab.net 
#   NTFS: Wrap flush_dcache_mft_record_page() in #ifdef NTFS_RW.
# 
# fs/ntfs/mft.h
#   2004/04/25 15:02:57+01:00 aia21@cantab.net +8 -5
#   Wrap flush_dcache_mft_record_page() in #ifdef NTFS_RW and cleanup trailing whitespace.
# 
# fs/ntfs/ChangeLog
#   2004/04/25 15:02:53+01:00 aia21@cantab.net +1 -0
#   Update
# 
# ChangeSet
#   2004/04/25 14:42:00+01:00 aia21@cantab.net 
#   NTFS: - Remove unused ntfs_dirty_inode().
#         - Cleanup super operations declaration.
# 
# fs/ntfs/super.c
#   2004/04/25 14:39:59+01:00 aia21@cantab.net +44 -32
#   Cleanup super operations declaration and trailing whitespace.
# 
# fs/ntfs/inode.h
#   2004/04/25 14:39:47+01:00 aia21@cantab.net +4 -7
#   Remove unused ntfs_dirty_inode() and cleanup trailing whitespace.
# 
# fs/ntfs/inode.c
#   2004/04/25 14:38:51+01:00 aia21@cantab.net +1 -34
#   Remove unused ntfs_dirty_inode() and cleanup trailing whitespace.
# 
# fs/ntfs/ChangeLog
#   2004/04/25 14:38:47+01:00 aia21@cantab.net +3 -1
#   Update
# 
# ChangeSet
#   2004/04/24 22:52:18+01:00 aia21@cantab.net 
#   NTFS: - Modify fs/ntfs/time.c::ntfs2utc(), get_current_ntfs_time(), and
#           utc2ntfs() to work with struct timespec instead of time_t on the
#           Linux UTC time side thus preserving the full precision of the NTFS
#           time and only loosing up to 99 nano-seconds in the Linux UTC time.
#         - Move fs/ntfs/time.c to fs/ntfs/time.h and make the time functions
#           static inline.
# 
# fs/ntfs/time.h
#   2004/04/24 22:50:07+01:00 aia21@cantab.net +47 -29
#   - Modify fs/ntfs/time.c::ntfs2utc(), get_current_ntfs_time(), and
#     utc2ntfs() to work with struct timespec instead of time_t on the
#     Linux UTC time side thus preserving the full precision of the NTFS
#     time and only loosing up to 99 nano-seconds in the Linux UTC time.
#   - Move fs/ntfs/time.c to fs/ntfs/time.h and make the time functions
#     static inline.
# 
# fs/ntfs/ntfs.h
#   2004/04/24 22:49:50+01:00 aia21@cantab.net +1 -6
#   Remove declarations for ntfs time conversion functions.
# 
# fs/ntfs/inode.c
#   2004/04/24 22:49:25+01:00 aia21@cantab.net +7 -10
#   Update for new ntfs time conversion functions.
# 
# fs/ntfs/Makefile
#   2004/04/24 22:49:09+01:00 aia21@cantab.net +1 -1
#   Remove time.c from build as it no longer exists.
# 
# fs/ntfs/ChangeLog
#   2004/04/24 22:49:05+01:00 aia21@cantab.net +6 -0
#   Update
# 
# fs/ntfs/time.h
#   2004/04/24 22:45:59+01:00 aia21@cantab.net +0 -0
#   Rename: fs/ntfs/time.c -> fs/ntfs/time.h
# 
# ChangeSet
#   2004/04/24 22:32:35+01:00 aia21@cantab.net 
#   NTFS: Use get_bh() instead of manual atomic_inc() in fs/ntfs/compress.c.
# 
# fs/ntfs/compress.c
#   2004/04/24 22:28:50+01:00 aia21@cantab.net +6 -7
#   Use get_bh() instead of manual atomic_inc() in fs/ntfs/compress.c.  Also a few white space cleanups (space at EOL and such like).
# 
# fs/ntfs/Makefile
#   2004/04/24 22:28:40+01:00 aia21@cantab.net +1 -1
#   Update version to 2.1.8-WIP.
# 
# fs/ntfs/ChangeLog
#   2004/04/24 22:28:35+01:00 aia21@cantab.net +4 -0
#   Update
# 
diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
--- a/Documentation/filesystems/ntfs.txt	Thu Apr 29 23:19:49 2004
+++ b/Documentation/filesystems/ntfs.txt	Thu Apr 29 23:19:49 2004
@@ -71,6 +71,7 @@
   compatibility, we implement access to files using their short file names if
   they exist. The driver will not create short file names however, and a rename
   will discard any existing short file name.
+- The new driver supports exporting of mounted NTFS volumes via NFS.
 
 
 Supported mount options
diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
--- a/fs/ntfs/ChangeLog	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/ChangeLog	Thu Apr 29 23:19:49 2004
@@ -19,6 +19,31 @@
 	  sufficient for synchronisation here. We then just need to make sure
 	  ntfs_readpage/writepage/truncate interoperate properly with us.
 
+2.1.8-WIP
+
+	- Use get_bh() instead of manual atomic_inc() in fs/ntfs/compress.c.
+	- Modify fs/ntfs/time.c::ntfs2utc(), get_current_ntfs_time(), and
+	  utc2ntfs() to work with struct timespec instead of time_t on the
+	  Linux UTC time side thus preserving the full precision of the NTFS
+	  time and only loosing up to 99 nano-seconds in the Linux UTC time.
+	- Move fs/ntfs/time.c to fs/ntfs/time.h and make the time functions
+	  static inline.
+	- Remove unused ntfs_dirty_inode().
+	- Cleanup super operations declaration in fs/ntfs/super.c.
+	- Wrap flush_dcache_mft_record_page() in #ifdef NTFS_RW.
+	- Add NInoTestSetFoo() and NInoTestClearFoo() macro magic to
+	  fs/ntfs/inode.h and use it to declare NInoTest{Set,Clear}Dirty.
+	- Move typedefs for ntfs_attr and test_t from fs/ntfs/inode.c to
+	  fs/ntfs/inode.h so they can be used elsewhere.
+	- Determine the mft mirror size as the number of mirrored mft records
+	  and store it in ntfs_volume->mftmirr_size (fs/ntfs/super.c).
+	- Load the mft mirror at mount time and compare the mft records stored
+	  in it to the ones in the mft (fs/ntfs/super.c).
+	- Fix type casting related warnings on 64-bit architectures.  Thanks
+	  to Meelis Roos for reporting them.
+	- Move %L to %ll as %L is floating point and %ll is integer which is
+	  what we want.
+
 2.1.7 - Enable NFS exporting of mounted NTFS volumes.
 
 	- Set i_generation in the VFS inode from the seq_no of the NTFS inode.
diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile
--- a/fs/ntfs/Makefile	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/Makefile	Thu Apr 29 23:19:49 2004
@@ -3,9 +3,9 @@
 obj-$(CONFIG_NTFS_FS) += ntfs.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 unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.7\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.8-WIP\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c
--- a/fs/ntfs/aops.c	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/aops.c	Thu Apr 29 23:19:49 2004
@@ -77,7 +77,7 @@
 		}
 	} else {
 		clear_buffer_uptodate(bh);
-		ntfs_error(ni->vol->sb, "Buffer I/O error, logical block %Lu.",
+		ntfs_error(ni->vol->sb, "Buffer I/O error, logical block %llu.",
 				(unsigned long long)bh->b_blocknr);
 		SetPageError(page);
 	}
@@ -120,10 +120,10 @@
 				continue;
 			nr_err++;
 			ntfs_error(ni->vol->sb, "post_read_mst_fixup() failed, "
-					"corrupt %s record 0x%Lx. Run chkdsk.",
+					"corrupt %s record 0x%llx. Run chkdsk.",
 					ni->mft_no ? "index" : "mft",
-					(long long)(((s64)page->index <<
-					PAGE_CACHE_SHIFT >>
+					(unsigned long long)(((s64)page->index
+					<< PAGE_CACHE_SHIFT >>
 					ni->itype.index.block_size_bits) + i));
 		}
 		flush_dcache_page(page);
@@ -263,9 +263,10 @@
 			}
 			/* Hard error, zero out region. */
 			SetPageError(page);
-			ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%Lx) failed "
-					"with error code 0x%Lx%s.",
-					(long long)vcn, (long long)-lcn,
+			ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%llx) failed "
+					"with error code 0x%llx%s.",
+					(unsigned long long)vcn,
+					(unsigned long long)-lcn,
 					is_retry ? " even after retrying" : "");
 			// FIXME: Depending on vol->on_errors, do something.
 		}
@@ -667,9 +668,10 @@
 		}
 		/* Failed to map the buffer, even after retrying. */
 		bh->b_blocknr = -1UL;
-		ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%Lx) failed "
-				"with error code 0x%Lx%s.",
-				(long long)vcn, (long long)-lcn,
+		ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%llx) failed "
+				"with error code 0x%llx%s.",
+				(unsigned long long)vcn,
+				(unsigned long long)-lcn,
 				is_retry ? " even after retrying" : "");
 		// FIXME: Depending on vol->on_errors, do something.
 		if (!err)
@@ -914,15 +916,16 @@
 	attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
 
 	if (unlikely(vi->i_size != attr_len)) {
-		ntfs_error(vi->i_sb, "BUG()! i_size (0x%Lx) doesn't match "
+		ntfs_error(vi->i_sb, "BUG()! i_size (0x%llx) doesn't match "
 				"attr_len (0x%x). Aborting write.", vi->i_size,
 				attr_len);
 		err = -EIO;
 		goto err_out;
 	}
 	if (unlikely(attr_pos >= attr_len)) {
-		ntfs_error(vi->i_sb, "BUG()! attr_pos (0x%Lx) > attr_len (0x%x)"
-				". Aborting write.", attr_pos, attr_len);
+		ntfs_error(vi->i_sb, "BUG()! attr_pos (0x%llx) > attr_len "
+				"(0x%x). Aborting write.",
+				(unsigned long long)attr_pos, attr_len);
 		err = -EIO;
 		goto err_out;
 	}
@@ -1221,11 +1224,13 @@
 				 * retrying.
 				 */
 				bh->b_blocknr = -1UL;
-				ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%Lx) "
+				ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%llx) "
 						"failed with error code "
-						"0x%Lx%s.", (long long)vcn,
-						(long long)-lcn, is_retry ?
-						" even after retrying" : "");
+						"0x%llx%s.",
+						(unsigned long long)vcn,
+						(unsigned long long)-lcn,
+						is_retry ? " even after "
+						"retrying" : "");
 				// FIXME: Depending on vol->on_errors, do
 				// something.
 				if (!err)
@@ -1675,15 +1680,16 @@
 	attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
 
 	if (unlikely(vi->i_size != attr_len)) {
-		ntfs_error(vi->i_sb, "BUG()! i_size (0x%Lx) doesn't match "
+		ntfs_error(vi->i_sb, "BUG()! i_size (0x%llx) doesn't match "
 				"attr_len (0x%x). Aborting write.", vi->i_size,
 				attr_len);
 		err = -EIO;
 		goto err_out;
 	}
 	if (unlikely(attr_pos >= attr_len)) {
-		ntfs_error(vi->i_sb, "BUG()! attr_pos (0x%Lx) > attr_len (0x%x)"
-				". Aborting write.", attr_pos, attr_len);
+		ntfs_error(vi->i_sb, "BUG()! attr_pos (0x%llx) > attr_len "
+				"(0x%x). Aborting write.",
+				(unsigned long long)attr_pos, attr_len);
 		err = -EIO;
 		goto err_out;
 	}
diff -Nru a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
--- a/fs/ntfs/attrib.c	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/attrib.c	Thu Apr 29 23:19:49 2004
@@ -1,7 +1,7 @@
 /**
  * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2003 Anton Altaparmakov
+ * Copyright (c) 2001-2004 Anton Altaparmakov
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -9,13 +9,13 @@
  * by the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * This program/include file is distributed in the hope that it will be 
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
+ * This program/include file is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS 
+ * along with this program (in the main directory of the Linux-NTFS
  * distribution in the file COPYING); if not, write to the Free Software
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
@@ -623,8 +623,8 @@
 			int slots = 0;
 
 			if (drl[ds].vcn == marker_vcn) {
-				ntfs_debug("Old marker = 0x%Lx, replacing with "
-						"LCN_ENOENT.\n",
+				ntfs_debug("Old marker = 0x%llx, replacing "
+						"with LCN_ENOENT.\n",
 						(unsigned long long)
 						drl[ds].lcn);
 				drl[ds].lcn = (LCN)LCN_ENOENT;
@@ -889,19 +889,19 @@
 		 * likely, there are more extents following this one.
 		 */
 		if (deltaxcn < --max_cluster) {
-			ntfs_debug("More extents to follow; deltaxcn = 0x%Lx, "
-					"max_cluster = 0x%Lx",
-					(long long)deltaxcn,
-					(long long)max_cluster);
+			ntfs_debug("More extents to follow; deltaxcn = 0x%llx, "
+					"max_cluster = 0x%llx",
+					(unsigned long long)deltaxcn,
+					(unsigned long long)max_cluster);
 			rl[rlpos].vcn = vcn;
 			vcn += rl[rlpos].length = max_cluster - deltaxcn;
 			rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
 			rlpos++;
 		} else if (unlikely(deltaxcn > max_cluster)) {
 			ntfs_error(vol->sb, "Corrupt attribute. deltaxcn = "
-					"0x%Lx, max_cluster = 0x%Lx",
-					(long long)deltaxcn,
-					(long long)max_cluster);
+					"0x%llx, max_cluster = 0x%llx",
+					(unsigned long long)deltaxcn,
+					(unsigned long long)max_cluster);
 			goto mpa_err;
 		}
 		rl[rlpos].lcn = (LCN)LCN_ENOENT;
@@ -933,7 +933,7 @@
 
 /**
  * map_run_list - map (a part of) a run list of an ntfs inode
- * @ni:		ntfs inode for which to map (part of) a run list 
+ * @ni:		ntfs inode for which to map (part of) a run list
  * @vcn:	map run list part containing this vcn
  *
  * Map the part of a run list containing the @vcn of an the ntfs inode @ni.
@@ -947,8 +947,8 @@
 	MFT_RECORD *mrec;
 	int err = 0;
 	
-	ntfs_debug("Mapping run list part containing vcn 0x%Lx.",
-			(long long)vcn);
+	ntfs_debug("Mapping run list part containing vcn 0x%llx.",
+			(unsigned long long)vcn);
 
 	if (!NInoAttr(ni))
 		base_ni = ni;
@@ -1136,7 +1136,7 @@
 			break;
 		if (a->type != type)
 			continue;
-		/* 
+		/*
 		 * If @name is present, compare the two names. If @name is
 		 * missing, assume we want an unnamed attribute.
 		 */
@@ -1257,8 +1257,9 @@
 	/* Read all clusters specified by the run list one run at a time. */
 	while (rl->length) {
 		lcn = vcn_to_lcn(rl, rl->vcn);
-		ntfs_debug("Reading vcn = 0x%Lx, lcn = 0x%Lx.",
-				(long long)rl->vcn, (long long)lcn);
+		ntfs_debug("Reading vcn = 0x%llx, lcn = 0x%llx.",
+				(unsigned long long)rl->vcn,
+				(unsigned long long)lcn);
 		/* The attribute list cannot be sparse. */
 		if (lcn < 0) {
 			ntfs_error(sb, "vcn_to_lcn() failed. Cannot read "
diff -Nru a/fs/ntfs/compress.c b/fs/ntfs/compress.c
--- a/fs/ntfs/compress.c	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/compress.c	Thu Apr 29 23:19:49 2004
@@ -2,7 +2,7 @@
  * compress.c - NTFS kernel compressed attributes handling.
  *		Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2003 Anton Altaparmakov
+ * Copyright (c) 2001-2004 Anton Altaparmakov
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -10,13 +10,13 @@
  * by the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * This program/include file is distributed in the hope that it will be 
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
+ * This program/include file is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS 
+ * along with this program (in the main directory of the Linux-NTFS
  * distribution in the file COPYING); if not, write to the Free Software
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
@@ -357,7 +357,7 @@
 			continue;
 		}
 
-		/* 
+		/*
 		 * We have a phrase token. Make sure it is not the first tag in
 		 * the sb as this is illegal and would confuse the code below.
 		 */
@@ -597,8 +597,9 @@
 			lcn = vcn_to_lcn(rl, vcn);
 		} else
 			lcn = (LCN)LCN_RL_NOT_MAPPED;
-		ntfs_debug("Reading vcn = 0x%Lx, lcn = 0x%Lx.",
-				(long long)vcn, (long long)lcn);
+		ntfs_debug("Reading vcn = 0x%llx, lcn = 0x%llx.",
+				(unsigned long long)vcn,
+				(unsigned long long)lcn);
 		if (lcn < 0) {
 			/*
 			 * When we reach the first sparse cluster we have
@@ -643,7 +644,7 @@
 			unlock_buffer(tbh);
 			continue;
 		}
-		atomic_inc(&tbh->b_count);
+		get_bh(tbh);
 		tbh->b_end_io = end_buffer_read_sync;
 		submit_bh(READ, tbh);
 	}
@@ -943,4 +944,3 @@
 	kfree(pages);
 	return -EIO;
 }
-
diff -Nru a/fs/ntfs/dir.c b/fs/ntfs/dir.c
--- a/fs/ntfs/dir.c	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/dir.c	Thu Apr 29 23:19:49 2004
@@ -9,13 +9,13 @@
  * by the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * This program/include file is distributed in the hope that it will be 
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
+ * This program/include file is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS 
+ * along with this program (in the main directory of the Linux-NTFS
  * distribution in the file COPYING); if not, write to the Free Software
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
@@ -322,22 +322,22 @@
 		goto unm_err_out;
 	}
 	if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
-		ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
-				"different from expected VCN (0x%Lx). "
+		ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
+				"different from expected VCN (0x%llx). "
 				"Directory inode 0x%lx is corrupt or driver "
-				"bug.",
-				(long long)sle64_to_cpu(ia->index_block_vcn),
-				(long long)vcn, dir_ni->mft_no);
+				"bug.", (unsigned long long)
+				sle64_to_cpu(ia->index_block_vcn),
+				(unsigned long long)vcn, dir_ni->mft_no);
 		err = -EIO;
 		goto unm_err_out;
 	}
 	if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
 			dir_ni->itype.index.block_size) {
-		ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
+		ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
 				"0x%lx has a size (%u) differing from the "
 				"directory specified size (%u). Directory "
 				"inode is corrupt or driver bug.",
-				(long long)vcn, dir_ni->mft_no,
+				(unsigned long long)vcn, dir_ni->mft_no,
 				le32_to_cpu(ia->index.allocated_size) + 0x18,
 				dir_ni->itype.index.block_size);
 		err = -EIO;
@@ -345,18 +345,19 @@
 	}
 	index_end = (u8*)ia + dir_ni->itype.index.block_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%llx) of directory inode "
 				"0x%lx crosses page boundary. Impossible! "
 				"Cannot access! This is probably a bug in the "
-				"driver.", (long long)vcn, dir_ni->mft_no);
+				"driver.", (unsigned long long)vcn,
+				dir_ni->mft_no);
 		err = -EIO;
 		goto unm_err_out;
 	}
 	index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
 	if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
-		ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory "
+		ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
 				"inode 0x%lx exceeds maximum size.",
-				(long long)vcn, dir_ni->mft_no);
+				(unsigned long long)vcn, dir_ni->mft_no);
 		err = -EIO;
 		goto unm_err_out;
 	}
@@ -790,22 +791,22 @@
 		goto unm_err_out;
 	}
 	if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
-		ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
-				"different from expected VCN (0x%Lx). "
+		ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
+				"different from expected VCN (0x%llx). "
 				"Directory inode 0x%lx is corrupt or driver "
-				"bug.",
-				(long long)sle64_to_cpu(ia->index_block_vcn),
-				(long long)vcn, dir_ni->mft_no);
+				"bug.", (unsigned long long)
+				sle64_to_cpu(ia->index_block_vcn),
+				(unsigned long long)vcn, dir_ni->mft_no);
 		err = -EIO;
 		goto unm_err_out;
 	}
 	if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
 			dir_ni->itype.index.block_size) {
-		ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
+		ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
 				"0x%lx has a size (%u) differing from the "
 				"directory specified size (%u). Directory "
 				"inode is corrupt or driver bug.",
-				(long long)vcn, dir_ni->mft_no,
+				(unsigned long long)vcn, dir_ni->mft_no,
 				le32_to_cpu(ia->index.allocated_size) + 0x18,
 				dir_ni->itype.index.block_size);
 		err = -EIO;
@@ -813,18 +814,19 @@
 	}
 	index_end = (u8*)ia + dir_ni->itype.index.block_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%llx) of directory inode "
 				"0x%lx crosses page boundary. Impossible! "
 				"Cannot access! This is probably a bug in the "
-				"driver.", (long long)vcn, dir_ni->mft_no);
+				"driver.", (unsigned long long)vcn,
+				dir_ni->mft_no);
 		err = -EIO;
 		goto unm_err_out;
 	}
 	index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
 	if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
-		ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory "
+		ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
 				"inode 0x%lx exceeds maximum size.",
-				(long long)vcn, dir_ni->mft_no);
+				(unsigned long long)vcn, dir_ni->mft_no);
 		err = -EIO;
 		goto unm_err_out;
 	}
@@ -1037,7 +1039,7 @@
 		dt_type = DT_DIR;
 	else
 		dt_type = DT_REG;
-	ntfs_debug("Calling filldir for %s with len %i, fpos 0x%Lx, inode "
+	ntfs_debug("Calling filldir for %s with len %i, fpos 0x%llx, inode "
 			"0x%lx, DT_%s.", name, name_len, *fpos,
 			MREF_LE(ie->data.dir.indexed_file),
 			dt_type == DT_DIR ? "DIR" : "REG");
@@ -1076,7 +1078,7 @@
 	attr_search_context *ctx;
 
 	fpos = filp->f_pos;
-	ntfs_debug("Entering for inode 0x%lx, fpos 0x%Lx.",
+	ntfs_debug("Entering for inode 0x%lx, fpos 0x%llx.",
 			vdir->i_ino, fpos);
 	rc = err = 0;
 	/* Are we at end of dir yet? */
@@ -1215,9 +1217,10 @@
 	cur_bmp_pos = bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1);
 	bmp_pos &= ~(u64)((PAGE_CACHE_SIZE * 8) - 1);
 get_next_bmp_page:
-	ntfs_debug("Reading bitmap with page index 0x%Lx, bit ofs 0x%Lx",
-			(long long)bmp_pos >> (3 + PAGE_CACHE_SHIFT),
-			(long long)bmp_pos & ((PAGE_CACHE_SIZE * 8) - 1));
+	ntfs_debug("Reading bitmap with page index 0x%llx, bit ofs 0x%llx",
+			(unsigned long long)bmp_pos >> (3 + PAGE_CACHE_SHIFT),
+			(unsigned long long)bmp_pos &
+			((PAGE_CACHE_SIZE * 8) - 1));
 	bmp_page = ntfs_map_page(bmp_mapping,
 			bmp_pos >> (3 + PAGE_CACHE_SHIFT));
 	if (unlikely(IS_ERR(bmp_page))) {
@@ -1247,8 +1250,8 @@
 		ia_pos = (bmp_pos + cur_bmp_pos) <<
 				ndir->itype.index.block_size_bits;
 	}
-	ntfs_debug("Handling index buffer 0x%Lx.",
-			(long long)bmp_pos + cur_bmp_pos);
+	ntfs_debug("Handling index buffer 0x%llx.",
+			(unsigned long long)bmp_pos + cur_bmp_pos);
 	/* If the current index buffer is in the same page we reuse the page. */
 	if ((prev_ia_pos & PAGE_CACHE_MASK) != (ia_pos & PAGE_CACHE_MASK)) {
 		prev_ia_pos = ia_pos;
@@ -1279,22 +1282,22 @@
 	if (unlikely(sle64_to_cpu(ia->index_block_vcn) != (ia_pos &
 			~(s64)(ndir->itype.index.block_size - 1)) >>
 			ndir->itype.index.vcn_size_bits)) {
-		ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
-				"different from expected VCN (0x%Lx). "
+		ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
+				"different from expected VCN (0x%llx). "
 				"Directory inode 0x%lx is corrupt or driver "
-				"bug. ",
-				(long long)sle64_to_cpu(ia->index_block_vcn),
-				(long long)ia_pos >>
+				"bug. ", (unsigned long long)
+				sle64_to_cpu(ia->index_block_vcn),
+				(unsigned long long)ia_pos >>
 				ndir->itype.index.vcn_size_bits, vdir->i_ino);
 		goto err_out;
 	}
 	if (unlikely(le32_to_cpu(ia->index.allocated_size) + 0x18 !=
 			ndir->itype.index.block_size)) {
-		ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
+		ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
 				"0x%lx has a size (%u) differing from the "
 				"directory specified size (%u). Directory "
 				"inode is corrupt or driver bug.",
-				(long long)ia_pos >>
+				(unsigned long long)ia_pos >>
 				ndir->itype.index.vcn_size_bits, vdir->i_ino,
 				le32_to_cpu(ia->index.allocated_size) + 0x18,
 				ndir->itype.index.block_size);
@@ -1302,19 +1305,19 @@
 	}
 	index_end = (u8*)ia + ndir->itype.index.block_size;
 	if (unlikely(index_end > kaddr + PAGE_CACHE_SIZE)) {
-		ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
+		ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
 				"0x%lx crosses page boundary. Impossible! "
 				"Cannot access! This is probably a bug in the "
-				"driver.", (long long)ia_pos >>
+				"driver.", (unsigned long long)ia_pos >>
 				ndir->itype.index.vcn_size_bits, vdir->i_ino);
 		goto err_out;
 	}
 	ia_start = ia_pos & ~(s64)(ndir->itype.index.block_size - 1);
 	index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
 	if (unlikely(index_end > (u8*)ia + ndir->itype.index.block_size)) {
-		ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory "
+		ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
 				"inode 0x%lx exceeds maximum size.",
-				(long long)ia_pos >>
+				(unsigned long long)ia_pos >>
 				ndir->itype.index.vcn_size_bits, vdir->i_ino);
 		goto err_out;
 	}
@@ -1327,8 +1330,9 @@
 	 * or signals an error (both covered by the rc test).
 	 */
 	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
-		ntfs_debug("In index allocation, offset 0x%Lx.",
-				(long long)ia_start + ((u8*)ie - (u8*)ia));
+		ntfs_debug("In index allocation, offset 0x%llx.",
+				(unsigned long long)ia_start + ((u8*)ie -
+				(u8*)ia));
 		/* Bounds checks. */
 		if (unlikely((u8*)ie < (u8*)ia || (u8*)ie +
 				sizeof(INDEX_ENTRY_HEADER) > index_end ||
@@ -1363,9 +1367,9 @@
 done:
 #ifdef DEBUG
 	if (!rc)
-		ntfs_debug("EOD, fpos 0x%Lx, returning 0.", fpos);
+		ntfs_debug("EOD, fpos 0x%llx, returning 0.", fpos);
 	else
-		ntfs_debug("filldir returned %i, fpos 0x%Lx, returning 0.",
+		ntfs_debug("filldir returned %i, fpos 0x%llx, returning 0.",
 				rc, fpos);
 #endif
 	filp->f_pos = fpos;
diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c
--- a/fs/ntfs/inode.c	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/inode.c	Thu Apr 29 23:19:49 2004
@@ -8,13 +8,13 @@
  * by the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * This program/include file is distributed in the hope that it will be 
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
+ * This program/include file is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS 
+ * along with this program (in the main directory of the Linux-NTFS
  * distribution in the file COPYING); if not, write to the Free Software
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
@@ -29,26 +29,7 @@
 #include "dir.h"
 #include "inode.h"
 #include "attrib.h"
-
-/**
- * ntfs_attr - ntfs in memory attribute structure
- * @mft_no:	mft record number of the base mft record of this attribute
- * @name:	Unicode name of the attribute (NULL if unnamed)
- * @name_len:	length of @name in Unicode characters (0 if unnamed)
- * @type:	attribute type (see layout.h)
- *
- * This structure exists only to provide a small structure for the
- * ntfs_{attr_}iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism.
- *
- * NOTE: Elements are ordered by size to make the structure as compact as
- * possible on all architectures.
- */
-typedef struct {
-	unsigned long mft_no;
-	uchar_t *name;
-	u32 name_len;
-	ATTR_TYPES type;
-} ntfs_attr;
+#include "time.h"
 
 /**
  * ntfs_test_inode - compare two (possibly fake) inodes for equality
@@ -66,7 +47,7 @@
  * NOTE: This function runs with the inode_lock spin lock held so it is not
  * allowed to sleep.
  */
-static int ntfs_test_inode(struct inode *vi, ntfs_attr *na)
+int ntfs_test_inode(struct inode *vi, ntfs_attr *na)
 {
 	ntfs_inode *ni;
 
@@ -150,7 +131,6 @@
 	return 0;
 }
 
-typedef int (*test_t)(struct inode *, void *);
 typedef int (*set_t)(struct inode *, void *);
 static int ntfs_read_locked_inode(struct inode *vi);
 static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi);
@@ -380,7 +360,7 @@
  * Search all file name attributes in the inode described by the attribute
  * search context @ctx and check if any of the names are in the $Extend system
  * directory.
- * 
+ *
  * Return values:
  *	   1: file is in $Extend directory
  *	   0: file is not in $Extend directory
@@ -590,21 +570,18 @@
 	 * mtime is the last change of the data within the file. Not changed
 	 * when only metadata is changed, e.g. a rename doesn't affect mtime.
 	 */
-	vi->i_mtime.tv_sec = ntfs2utc(si->last_data_change_time);
-	vi->i_mtime.tv_nsec = 0;
+	vi->i_mtime = ntfs2utc(si->last_data_change_time);
 	/*
 	 * ctime is the last change of the metadata of the file. This obviously
 	 * always changes, when mtime is changed. ctime can be changed on its
 	 * own, mtime is then not changed, e.g. when a file is renamed.
 	 */
-	vi->i_ctime.tv_sec = ntfs2utc(si->last_mft_change_time);
-	vi->i_ctime.tv_nsec = 0;
+	vi->i_ctime = ntfs2utc(si->last_mft_change_time);
 	/*
 	 * Last access to the data within the file. Not changed during a rename
 	 * for example but changed whenever the file is written to.
 	 */
-	vi->i_atime.tv_sec = ntfs2utc(si->last_access_time);
-	vi->i_atime.tv_nsec = 0;
+	vi->i_atime = ntfs2utc(si->last_access_time);
 
 	/* Find the attribute list attribute if present. */
 	reinit_attr_search_ctx(ctx);
@@ -876,8 +853,8 @@
 		/* Consistency check bitmap size vs. index allocation size. */
 		if ((bvi->i_size << 3) < (vi->i_size >>
 				ni->itype.index.block_size_bits)) {
-			ntfs_error(vi->i_sb, "Index bitmap too small (0x%Lx) "
-					"for index allocation (0x%Lx).",
+			ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) "
+					"for index allocation (0x%llx).",
 					bvi->i_size << 3, vi->i_size);
 			goto unm_err_out;
 		}
@@ -1715,9 +1692,9 @@
 		ntfs_error(sb, "Failed to load the complete run list "
 				"for $MFT/$DATA. Driver bug or "
 				"corrupt $MFT. Run chkdsk.");
-		ntfs_debug("highest_vcn = 0x%Lx, last_vcn - 1 = 0x%Lx",
-				(long long)highest_vcn,
-				(long long)last_vcn - 1);
+		ntfs_debug("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx",
+				(unsigned long long)highest_vcn,
+				(unsigned long long)last_vcn - 1);
 		goto put_err_out;
 	}
 	put_attr_search_ctx(ctx);
@@ -1739,39 +1716,6 @@
 }
 
 /**
- * ntfs_dirty_inode - mark the inode's metadata dirty
- * @vi:		inode to mark dirty
- *
- * This is called from fs/inode.c::__mark_inode_dirty(), when the inode itself
- * is being marked dirty. An example is when update_atime() is invoked.
- *
- * We mark the inode dirty by setting both the page in which the mft record
- * resides and the buffer heads in that page which correspond to the mft record
- * dirty. This ensures that the changes will eventually be propagated to disk
- * when the inode is set dirty.
- *
- * FIXME: Can we do that with the buffer heads? I am not too sure. Because if we
- * do that we need to make sure that the kernel will not write out those buffer
- * heads or we are screwed as it will write corrupt data to disk. The only way
- * a mft record can be written correctly is by mst protecting it, writting it
- * synchronously and fast mst deprotecting it. During this period, obviously,
- * the mft record must be marked as not uptodate, be locked for writing or
- * whatever, so that nobody attempts anything stupid.
- *
- * FIXME: Do we need to check that the fs is not mounted read only? And what
- * about the inode? Anything else?
- *
- * FIXME: As we are only a read only driver it is safe to just return here for
- * the moment.
- */
-void ntfs_dirty_inode(struct inode *vi)
-{
-	ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
-	NInoSetDirty(NTFS_I(vi));
-	return;
-}
-
-/**
  * ntfs_commit_inode - write out a dirty inode
  * @ni:		inode to write out
  *
@@ -2029,4 +1973,3 @@
 }
 
 #endif
-
diff -Nru a/fs/ntfs/inode.h b/fs/ntfs/inode.h
--- a/fs/ntfs/inode.h	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/inode.h	Thu Apr 29 23:19:49 2004
@@ -2,7 +2,7 @@
  * inode.h - Defines for inode structures NTFS Linux kernel driver. Part of
  *	     the Linux-NTFS project.
  *
- * Copyright (c) 2001-2003 Anton Altaparmakov
+ * Copyright (c) 2001-2004 Anton Altaparmakov
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -10,13 +10,13 @@
  * by the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * This program/include file is distributed in the hope that it will be 
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
+ * This program/include file is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS 
+ * along with this program (in the main directory of the Linux-NTFS
  * distribution in the file COPYING); if not, write to the Free Software
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
@@ -181,8 +181,22 @@
 	clear_bit(NI_##flag, &(ni)->state);		\
 }
 
+/*
+ * As above for NInoTestSetFoo() and NInoTestClearFoo().
+ */
+#define TAS_NINO_FNS(flag)					\
+static inline int NInoTestSet##flag(ntfs_inode *ni)		\
+{								\
+	return test_and_set_bit(NI_##flag, &(ni)->state);	\
+}								\
+static inline int NInoTestClear##flag(ntfs_inode *ni)		\
+{								\
+	return test_and_clear_bit(NI_##flag, &(ni)->state);	\
+}
+
 /* Emit the ntfs inode bitops functions. */
 NINO_FNS(Dirty)
+TAS_NINO_FNS(Dirty)
 NINO_FNS(AttrList)
 NINO_FNS(AttrListNonResident)
 NINO_FNS(Attr)
@@ -219,6 +233,30 @@
 	return &((big_ntfs_inode *)ni)->vfs_inode;
 }
 
+/**
+ * ntfs_attr - ntfs in memory attribute structure
+ * @mft_no:	mft record number of the base mft record of this attribute
+ * @name:	Unicode name of the attribute (NULL if unnamed)
+ * @name_len:	length of @name in Unicode characters (0 if unnamed)
+ * @type:	attribute type (see layout.h)
+ *
+ * This structure exists only to provide a small structure for the
+ * ntfs_{attr_}iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism.
+ *
+ * NOTE: Elements are ordered by size to make the structure as compact as
+ * possible on all architectures.
+ */
+typedef struct {
+	unsigned long mft_no;
+	uchar_t *name;
+	u32 name_len;
+	ATTR_TYPES type;
+} ntfs_attr;
+
+typedef int (*test_t)(struct inode *, void *);
+
+extern int ntfs_test_inode(struct inode *vi, ntfs_attr *na);
+
 extern struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no);
 extern struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPES type,
 		uchar_t *name, u32 name_len);
@@ -233,8 +271,6 @@
 
 extern void ntfs_read_inode_mount(struct inode *vi);
 
-extern void ntfs_dirty_inode(struct inode *vi);
-
 extern void ntfs_put_inode(struct inode *vi);
 
 extern int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt);
@@ -245,7 +281,6 @@
 
 extern int ntfs_setattr(struct dentry *dentry, struct iattr *attr);
 
-#endif
-
-#endif /* _LINUX_NTFS_FS_INODE_H */
+#endif /* NTFS_RW */
 
+#endif /* _LINUX_NTFS_INODE_H */
diff -Nru a/fs/ntfs/mft.h b/fs/ntfs/mft.h
--- a/fs/ntfs/mft.h	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/mft.h	Thu Apr 29 23:19:49 2004
@@ -2,20 +2,20 @@
  * mft.h - Defines for mft record handling in NTFS Linux kernel driver.
  *	   Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001,2002 Anton Altaparmakov.
+ * Copyright (c) 2001-2004 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
  * by the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * This program/include file is distributed in the hope that it will be 
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
+ * This program/include file is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS 
+ * along with this program (in the main directory of the Linux-NTFS
  * distribution in the file COPYING); if not, write to the Free Software
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
@@ -43,7 +43,9 @@
 	return;
 }
 
-/*
+#ifdef NTFS_RW
+
+/**
  * flush_dcache_mft_record_page - flush_dcache_page() for mft records
  * @ni:		ntfs inode structure of mft record
  *
@@ -57,5 +59,6 @@
 	flush_dcache_page(ni->page);
 }
 
-#endif /* _LINUX_NTFS_MFT_H */
+#endif /* NTFS_RW */
 
+#endif /* _LINUX_NTFS_MFT_H */
diff -Nru a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
--- a/fs/ntfs/ntfs.h	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/ntfs.h	Thu Apr 29 23:19:49 2004
@@ -2,7 +2,7 @@
  * ntfs.h - Defines for NTFS Linux kernel driver. Part of the Linux-NTFS
  *	    project.
  *
- * Copyright (c) 2001,2002 Anton Altaparmakov.
+ * Copyright (c) 2001-2004 Anton Altaparmakov.
  * Copyright (C) 2002 Richard Russon.
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -75,10 +75,13 @@
 extern struct  file_operations ntfs_empty_file_ops;
 extern struct inode_operations ntfs_empty_inode_ops;
 
-/* Generic macro to convert pointers to values for comparison purposes. */
+/* Generic macros to convert pointers to values and vice versa. */
 #ifndef p2n
 #define p2n(p)          ((ptrdiff_t)((ptrdiff_t*)(p)))
 #endif
+#ifndef n2p
+#define n2p(p)          ((ptrdiff_t*)((ptrdiff_t)(p)))
+#endif
 
 /**
  * NTFS_SB - return the ntfs volume given a vfs super block
@@ -179,11 +182,6 @@
 extern int post_read_mst_fixup(NTFS_RECORD *b, const u32 size);
 extern int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size);
 extern void post_write_mst_fixup(NTFS_RECORD *b);
-
-/* From fs/ntfs/time.c */
-extern inline s64 utc2ntfs(const time_t time);
-extern inline s64 get_current_ntfs_time(void);
-extern time_t ntfs2utc(const s64 time);
 
 /* From fs/ntfs/unistr.c */
 extern BOOL ntfs_are_names_equal(const uchar_t *s1, size_t s1_len,
diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c
--- a/fs/ntfs/super.c	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/super.c	Thu Apr 29 23:19:49 2004
@@ -9,13 +9,13 @@
  * by the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * This program/include file is distributed in the hope that it will be 
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
+ * This program/include file is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS 
+ * along with this program (in the main directory of the Linux-NTFS
  * distribution in the file COPYING); if not, write to the Free Software
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
@@ -102,7 +102,7 @@
 			if (*v)						\
 				goto needs_val;				\
 		}							\
-	} 
+	}
 #define NTFS_GETOPT(option, variable)					\
 	if (!strcmp(p, option)) {					\
 		if (!v || !*v)						\
@@ -110,14 +110,14 @@
 		variable = simple_strtoul(ov = v, &v, 0);		\
 		if (*v)							\
 			goto needs_val;					\
-	} 
+	}
 #define NTFS_GETOPT_BOOL(option, variable)				\
 	if (!strcmp(p, option)) {					\
 		BOOL val;						\
 		if (!simple_getbool(v, &val))				\
 			goto needs_bool;				\
 		variable = val;						\
-	} 
+	}
 #define NTFS_GETOPT_OPTIONS_ARRAY(option, variable, opt_array)		\
 	if (!strcmp(p, option)) {					\
 		int _i;							\
@@ -400,7 +400,7 @@
 			le32_to_cpu(b->bpb.large_sectors) || b->bpb.fats)
 		goto not_ntfs;
 	/* Check clusters per file mft record value is valid. */
-	if ((u8)b->clusters_per_mft_record < 0xe1 || 
+	if ((u8)b->clusters_per_mft_record < 0xe1 ||
 			(u8)b->clusters_per_mft_record > 0xf7)
 		switch (b->clusters_per_mft_record) {
 		case 1: case 2: case 4: case 8: case 16: case 32: case 64:
@@ -409,7 +409,7 @@
 			goto not_ntfs;
 		}
 	/* Check clusters per index block value is valid. */
-	if ((u8)b->clusters_per_index_record < 0xe1 || 
+	if ((u8)b->clusters_per_index_record < 0xe1 ||
 			(u8)b->clusters_per_index_record > 0xf7)
 		switch (b->clusters_per_index_record) {
 		case 1: case 2: case 4: case 8: case 16: case 32: case 64:
@@ -529,7 +529,7 @@
  * parse_ntfs_boot_sector - parse the boot sector and store the data in @vol
  * @vol:	volume structure to initialise with data from boot sector
  * @b:		boot sector to parse
- * 
+ *
  * Parse the ntfs boot sector @b and store all imporant information therein in
  * the ntfs super block @vol. Return TRUE on success and FALSE on error.
  */
@@ -592,10 +592,10 @@
 	ntfs_debug("vol->mft_record_size_mask = 0x%x",
 			vol->mft_record_size_mask);
 	ntfs_debug("vol->mft_record_size_bits = %i (0x%x)",
-			vol->mft_record_size_bits, vol->mft_record_size_bits); 
+			vol->mft_record_size_bits, vol->mft_record_size_bits);
 	clusters_per_index_record = b->clusters_per_index_record;
 	ntfs_debug("clusters_per_index_record = %i (0x%x)",
-			clusters_per_index_record, clusters_per_index_record); 
+			clusters_per_index_record, clusters_per_index_record);
 	if (clusters_per_index_record > 0)
 		vol->index_record_size = vol->cluster_size <<
 				(ffs(clusters_per_index_record) - 1);
@@ -610,7 +610,7 @@
 	vol->index_record_size_mask = vol->index_record_size - 1;
 	vol->index_record_size_bits = ffs(vol->index_record_size) - 1;
 	ntfs_debug("vol->index_record_size = %i (0x%x)",
-			vol->index_record_size, vol->index_record_size); 
+			vol->index_record_size, vol->index_record_size);
 	ntfs_debug("vol->index_record_size_mask = 0x%x",
 			vol->index_record_size_mask);
 	ntfs_debug("vol->index_record_size_bits = %i (0x%x)",
@@ -627,7 +627,7 @@
 		return FALSE;
 	}
 	vol->nr_clusters = ll;
-	ntfs_debug("vol->nr_clusters = 0x%Lx", (long long)vol->nr_clusters);
+	ntfs_debug("vol->nr_clusters = 0x%llx", (long long)vol->nr_clusters);
 	/*
 	 * On an architecture where unsigned long is 32-bits, we restrict the
 	 * volume size to 2TiB (2^41). On a 64-bit architecture, the compiler
@@ -635,10 +635,11 @@
 	 */
 	if (sizeof(unsigned long) < 8) {
 		if ((ll << vol->cluster_size_bits) >= (1ULL << 41)) {
-			ntfs_error(vol->sb, "Volume size (%LuTiB) is too large "
-					"for this architecture. Maximim "
+			ntfs_error(vol->sb, "Volume size (%lluTiB) is too "
+					"large for this architecture. Maximum "
 					"supported is 2TiB. Sorry.",
-					ll >> (40 - vol->cluster_size_bits));
+					(unsigned long long)ll >> (40 -
+					vol->cluster_size_bits));
 			return FALSE;
 		}
 	}
@@ -648,7 +649,7 @@
 		return FALSE;
 	}
 	vol->mft_lcn = ll;
-	ntfs_debug("vol->mft_lcn = 0x%Lx", (long long)vol->mft_lcn);
+	ntfs_debug("vol->mft_lcn = 0x%llx", (long long)vol->mft_lcn);
 	ll = sle64_to_cpu(b->mftmirr_lcn);
 	if (ll >= vol->nr_clusters) {
 		ntfs_error(vol->sb, "MFTMirr LCN is beyond end of volume. "
@@ -656,9 +657,25 @@
 		return FALSE;
 	}
 	vol->mftmirr_lcn = ll;
-	ntfs_debug("vol->mftmirr_lcn = 0x%Lx", (long long)vol->mftmirr_lcn);
+	ntfs_debug("vol->mftmirr_lcn = 0x%llx", (long long)vol->mftmirr_lcn);
+#ifdef NTFS_RW
+	/*
+	 * Work out the size of the mft mirror in number of mft records. If the
+	 * cluster size is less than or equal to the size taken by four mft
+	 * records, the mft mirror stores the first four mft records. If the
+	 * cluster size is bigger than the size taken by four mft records, the
+	 * mft mirror contains as many mft records as will fit into one
+	 * cluster.
+	 */
+	if (vol->cluster_size <= (4 << vol->mft_record_size_bits))
+		vol->mftmirr_size = 4;
+	else
+		vol->mftmirr_size = vol->cluster_size >>
+				vol->mft_record_size_bits;
+	ntfs_debug("vol->mftmirr_size = %i", vol->mftmirr_size);
+#endif /* NTFS_RW */
 	vol->serial_no = le64_to_cpu(b->volume_serial_number);
-	ntfs_debug("vol->serial_no = 0x%Lx",
+	ntfs_debug("vol->serial_no = 0x%llx",
 			(unsigned long long)vol->serial_no);
 	/*
 	 * Determine MFT zone size. This is not strictly the right place to do
@@ -687,15 +704,176 @@
 			vol->mft_zone_multiplier);
 	vol->mft_zone_start = vol->mft_lcn;
 	vol->mft_zone_end += vol->mft_lcn;
-	ntfs_debug("vol->mft_zone_start = 0x%Lx",
+	ntfs_debug("vol->mft_zone_start = 0x%llx",
 			(long long)vol->mft_zone_start);
-	ntfs_debug("vol->mft_zone_end = 0x%Lx", (long long)vol->mft_zone_end);
-	/* And another misplaced defaults setting. */
-	if (!vol->on_errors)
-		vol->on_errors = ON_ERRORS_PANIC;
+	ntfs_debug("vol->mft_zone_end = 0x%llx", (long long)vol->mft_zone_end);
+	return TRUE;
+}
+
+#ifdef NTFS_RW
+
+/**
+ * load_and_init_mft_mirror - load and setup the mft mirror inode for a volume
+ * @vol:	ntfs super block describing device whose mft mirror to load
+ *
+ * Return TRUE on success or FALSE on error.
+ */
+static BOOL load_and_init_mft_mirror(ntfs_volume *vol)
+{
+	struct inode *tmp_ino;
+	ntfs_inode *tmp_ni;
+
+	/* Get mft mirror inode. */
+	tmp_ino = ntfs_iget(vol->sb, FILE_MFTMirr);
+	if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
+		if (!IS_ERR(tmp_ino))
+			iput(tmp_ino);
+		ntfs_error(vol->sb, "Failed to load $MFTMirr.");
+		return FALSE;
+	}
+	/*
+	 * Re-initialize some specifics about $MFTMirr's inode as
+	 * ntfs_read_inode() will have set up the default ones.
+	 */
+	/* Set uid and gid to root. */
+	tmp_ino->i_uid = tmp_ino->i_gid = 0;
+	/* Regular file.  No access for anyone. */
+	tmp_ino->i_mode = S_IFREG;
+	/* No VFS initiated operations allowed for $MFTMirr. */
+	tmp_ino->i_op = &ntfs_empty_inode_ops;
+	tmp_ino->i_fop = &ntfs_empty_file_ops;
+	/* Put back our special address space operations. */
+	tmp_ino->i_mapping->a_ops = &ntfs_mft_aops;
+	tmp_ni = NTFS_I(tmp_ino);
+	/* The $MFTMirr, like the $MFT is multi sector transfer protected. */
+	NInoSetMstProtected(tmp_ni);
+	/*
+	 * Set up our little cheat allowing us to reuse the async io
+	 * completion handler for directories.
+	 */
+	tmp_ni->itype.index.block_size = vol->mft_record_size;
+	tmp_ni->itype.index.block_size_bits = vol->mft_record_size_bits;
+	vol->mftmirr_ino = tmp_ino;
+	return TRUE;
+}
+
+/**
+ * check_mft_mirror - compare contents of the mft mirror with the mft
+ * @vol:	ntfs super block describing device whose mft mirror to check
+ *
+ * Return TRUE on success or FALSE on error.
+ */
+static BOOL check_mft_mirror(ntfs_volume *vol)
+{
+	unsigned long index;
+	struct super_block *sb = vol->sb;
+	ntfs_inode *mirr_ni;
+	struct page *mft_page, *mirr_page;
+	u8 *kmft, *kmirr;
+	run_list_element *rl, rl2[2];
+	int mrecs_per_page, i;
+
+	/* Compare contents of $MFT and $MFTMirr. */
+	mrecs_per_page = PAGE_CACHE_SIZE / vol->mft_record_size;
+	BUG_ON(!mrecs_per_page);
+	BUG_ON(!vol->mftmirr_size);
+	mft_page = mirr_page = NULL;
+	kmft = kmirr = NULL;
+	index = i = 0;
+	do {
+		u32 bytes;
+
+		/* Switch pages if necessary. */
+		if (!(i % mrecs_per_page)) {
+			if (index) {
+				ntfs_unmap_page(mft_page);
+				ntfs_unmap_page(mirr_page);
+			}
+			/* Get the $MFT page. */
+			mft_page = ntfs_map_page(vol->mft_ino->i_mapping,
+					index);
+			if (IS_ERR(mft_page)) {
+				ntfs_error(sb, "Failed to read $MFT.");
+				return FALSE;
+			}
+			kmft = page_address(mft_page);
+			/* Get the $MFTMirr page. */
+			mirr_page = ntfs_map_page(vol->mftmirr_ino->i_mapping,
+					index);
+			if (IS_ERR(mirr_page)) {
+				ntfs_error(sb, "Failed to read $MFTMirr.");
+				goto mft_unmap_out;
+			}
+			kmirr = page_address(mirr_page);
+			++index;
+		}
+		/* Make sure the record is ok. */
+		if (is_baad_recordp(kmft)) {
+			ntfs_error(sb, "Incomplete multi sector transfer "
+					"detected in mft record %i.", i);
+mm_unmap_out:
+			ntfs_unmap_page(mirr_page);
+mft_unmap_out:
+			ntfs_unmap_page(mft_page);
+			return FALSE;
+		}
+		if (is_baad_recordp(kmirr)) {
+			ntfs_error(sb, "Incomplete multi sector transfer "
+					"detected in mft mirror record %i.", i);
+			goto mm_unmap_out;
+		}
+		/* Get the amount of data in the current record. */
+		bytes = le32_to_cpu(((MFT_RECORD*)kmft)->bytes_in_use);
+		if (!bytes || bytes > vol->mft_record_size) {
+			bytes = le32_to_cpu(((MFT_RECORD*)kmirr)->bytes_in_use);
+			if (!bytes || bytes > vol->mft_record_size)
+				bytes = vol->mft_record_size;
+		}
+		/* Compare the two records. */
+		if (memcmp(kmft, kmirr, bytes)) {
+			ntfs_error(sb, "$MFT and $MFTMirr (record %i) do not "
+					"match. Run ntfsfix or chkdsk.", i);
+			goto mm_unmap_out;
+		}
+		kmft += vol->mft_record_size;
+		kmirr += vol->mft_record_size;
+	} while (++i < vol->mftmirr_size);
+	/* Release the last pages. */
+	ntfs_unmap_page(mft_page);
+	ntfs_unmap_page(mirr_page);
+
+	/* Construct the mft mirror run list by hand. */
+	rl2[0].vcn = 0;
+	rl2[0].lcn = vol->mftmirr_lcn;
+	rl2[0].length = (vol->mftmirr_size * vol->mft_record_size +
+			vol->cluster_size - 1) / vol->cluster_size;
+	rl2[1].vcn = rl2[0].length;
+	rl2[1].lcn = LCN_ENOENT;
+	rl2[1].length = 0;
+	/*
+	 * Because we have just read all of the mft mirror, we know we have
+	 * mapped the full run list for it.
+	 */
+	mirr_ni = NTFS_I(vol->mftmirr_ino);
+	down_read(&mirr_ni->run_list.lock);
+	rl = mirr_ni->run_list.rl;
+	/* Compare the two run lists.  They must be identical. */
+	i = 0;
+	do {
+		if (rl2[i].vcn != rl[i].vcn || rl2[i].lcn != rl[i].lcn ||
+				rl2[i].length != rl[i].length) {
+			ntfs_error(sb, "$MFTMirr location mismatch. "
+					"Run chkdsk.");
+			up_read(&mirr_ni->run_list.lock);
+			return FALSE;
+		}
+	} while (rl2[i++].length);
+	up_read(&mirr_ni->run_list.lock);
 	return TRUE;
 }
 
+#endif /* NTFS_RW */
+
 /**
  * load_and_init_upcase - load the upcase table for an ntfs volume
  * @vol:	ntfs super block describing device whose upcase to load
@@ -748,7 +926,7 @@
 			goto read_partial_upcase_page;
 	}
 	vol->upcase_len = ino->i_size >> UCHAR_T_SIZE_BITS;
-	ntfs_debug("Read %Lu bytes from $UpCase (expected %u bytes).",
+	ntfs_debug("Read %lu bytes from $UpCase (expected %u bytes).",
 			ino->i_size, 64 * 1024 * sizeof(uchar_t));
 	iput(ino);
 	down(&ntfs_lock);
@@ -816,28 +994,44 @@
 	attr_search_context *ctx;
 
 	ntfs_debug("Entering.");
+#ifdef NTFS_RW
+	/* Get mft mirror inode compare the contents of $MFT and $MFTMirr. */
+	if (!load_and_init_mft_mirror(vol) || !check_mft_mirror(vol)) {
+		static const char *es1 = "Failed to load $MFTMirr";
+		static const char *es2 = "$MFTMirr does not match $MFT";
+		static const char *es3 = ".  Run ntfsfix and/or chkdsk.";
 
+		/* If a read-write mount, convert it to a read-only mount. */
+		if (!(sb->s_flags & MS_RDONLY)) {
+			if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
+					ON_ERRORS_CONTINUE))) {
+				ntfs_error(sb, "%s and neither on_errors="
+						"continue nor on_errors="
+						"remount-ro was specified%s",
+						!vol->mftmirr_ino ? es1 : es2,
+						es3);
+				goto iput_mirr_err_out;
+			}
+			sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
+			ntfs_error(sb, "%s.  Mounting read-only%s",
+					!vol->mftmirr_ino ? es1 : es2, es3);
+		} else
+			ntfs_warning(sb, "%s.  Will not be able to remount "
+					"read-write%s",
+					!vol->mftmirr_ino ? es1 : es2, es3);
+		/* This will prevent a read-write remount. */
+		NVolSetErrors(vol);
+	}
+#endif /* NTFS_RW */
 	/* Get mft bitmap attribute inode. */
 	vol->mftbmp_ino = ntfs_attr_iget(vol->mft_ino, AT_BITMAP, NULL, 0);
 	if (IS_ERR(vol->mftbmp_ino)) {
 		ntfs_error(sb, "Failed to load $MFT/$BITMAP attribute.");
-		return FALSE;
-	}
-
-	/* Get mft mirror inode. */
-	vol->mftmirr_ino = ntfs_iget(sb, FILE_MFTMirr);
-	if (IS_ERR(vol->mftmirr_ino) || is_bad_inode(vol->mftmirr_ino)) {
-		if (!IS_ERR(vol->mftmirr_ino))
-			iput(vol->mftmirr_ino);
-		ntfs_error(sb, "Failed to load $MFTMirr.");
-		goto iput_mftbmp_err_out;
+		goto iput_mirr_err_out;
 	}
-	// FIXME: Compare mftmirr with mft and repair if appropriate and not
-	// a read-only mount.
-
-	/* Read upcase table and setup vol->upcase and vol->upcase_len. */
+	/* Read upcase table and setup @vol->upcase and @vol->upcase_len. */
 	if (!load_and_init_upcase(vol))
-		goto iput_mirr_err_out;
+		goto iput_mftbmp_err_out;
 	/*
 	 * Get the cluster allocation bitmap inode and verify the size, no
 	 * need for any locking at this stage as we are already running
@@ -904,6 +1098,8 @@
 	 * Get the inode for the logfile and empty it if this is a read-write
 	 * mount.
 	 */
+	// TODO: vol->logfile_ino = ;
+	// TODO: Cleanup for error case at end of function.
 	tmp_ino = ntfs_iget(sb, FILE_LogFile);
 	if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
 		if (!IS_ERR(tmp_ino))
@@ -920,7 +1116,7 @@
 	/*
 	 * Get the inode for the attribute definitions file and parse the
 	 * attribute definitions.
-	 */ 
+	 */
 	tmp_ino = ntfs_iget(sb, FILE_AttrDef);
 	if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
 		if (!IS_ERR(tmp_ino))
@@ -974,10 +1170,13 @@
 	iput(vol->vol_ino);
 iput_lcnbmp_err_out:
 	iput(vol->lcnbmp_ino);
-iput_mirr_err_out:
-	iput(vol->mftmirr_ino);
 iput_mftbmp_err_out:
 	iput(vol->mftbmp_ino);
+iput_mirr_err_out:
+#ifdef NTFS_RW
+	if (vol->mftmirr_ino)
+		iput(vol->mftmirr_ino);
+#endif /* NTFS_RW */
 	return FALSE;
 }
 
@@ -1015,14 +1214,23 @@
 	vol->lcnbmp_ino = NULL;
 	up_write(&vol->lcnbmp_lock);
 
-	iput(vol->mftmirr_ino);
-	vol->mftmirr_ino = NULL;
-
 	down_write(&vol->mftbmp_lock);
 	iput(vol->mftbmp_ino);
 	vol->mftbmp_ino = NULL;
 	up_write(&vol->mftbmp_lock);
 
+#ifdef NTFS_RW
+	if (vol->logfile_ino) {
+		iput(vol->logfile_ino);
+		vol->logfile_ino = NULL;
+	}
+
+	if (vol->mftmirr_ino) {
+		iput(vol->mftmirr_ino);
+		vol->mftmirr_ino = NULL;
+	}
+#endif /* NTFS_RW */
+
 	iput(vol->mft_ino);
 	vol->mft_ino = NULL;
 
@@ -1321,24 +1529,37 @@
 struct super_operations ntfs_sops = {
 	.alloc_inode	= ntfs_alloc_big_inode,	  /* VFS: Allocate new inode. */
 	.destroy_inode	= ntfs_destroy_big_inode, /* VFS: Deallocate inode. */
-	//.dirty_inode	= ntfs_dirty_inode,	  /* VFS: Called from
-	//					     __mark_inode_dirty(). */
-	//.write_inode	= NULL,		  /* VFS: Write dirty inode to disk. */
-	.put_inode	= ntfs_put_inode, /* VFS: Called just before the inode
-					     reference count is decreased. */
-	//.delete_inode	= NULL,		  /* VFS: Delete inode from disk. Called
-	//				     when i_count becomes 0 and i_nlink
-	//				     is also 0. */
-	.put_super	= ntfs_put_super, /* Syscall: umount. */
-	//write_super	= NULL,		  /* Flush dirty super block to disk. */
-	//write_super_lockfs	= NULL,	  /* ? */
-	//unlockfs	= NULL,		  /* ? */
-	.statfs		= ntfs_statfs,	  /* Syscall: statfs */
-	.remount_fs	= ntfs_remount,	  /* Syscall: mount -o remount. */
+	.put_inode	= ntfs_put_inode,	  /* VFS: Called just before
+						     the inode reference count
+						     is decreased. */
+#ifdef NTFS_RW
+	//.dirty_inode	= NULL,			/* VFS: Called from
+	//					   __mark_inode_dirty(). */
+	//.write_inode	= NULL,			/* VFS: Write dirty inode to
+	//					   disk. */
+	//.drop_inode	= NULL,			/* VFS: Called just after the
+	//					   inode reference count has
+	//					   been decreased to zero.
+	//					   NOTE: The inode lock is
+	//					   held. See fs/inode.c::
+	//					   generic_drop_inode(). */
+	//.delete_inode	= NULL,			/* VFS: Delete inode from disk.
+	//					   Called when i_count becomes
+	//					   0 and i_nlink is also 0. */
+	//.write_super	= NULL,			/* Flush dirty super block to
+	//					   disk. */
+	//.sync_fs	= NULL,			/* ? */
+	//.write_super_lockfs	= NULL,		/* ? */
+	//.unlockfs	= NULL,			/* ? */
+#endif /* NTFS_RW */
+	.put_super	= ntfs_put_super,	/* Syscall: umount. */
+	.statfs		= ntfs_statfs,		/* Syscall: statfs */
+	.remount_fs	= ntfs_remount,		/* Syscall: mount -o remount. */
 	.clear_inode	= ntfs_clear_big_inode,	/* VFS: Called when an inode is
 						   removed from memory. */
-	//.umount_begin	= NULL,		     /* Forced umount. */
-	.show_options	= ntfs_show_options, /* Show mount options in proc. */
+	//.umount_begin	= NULL,			/* Forced umount. */
+	.show_options	= ntfs_show_options,	/* Show mount options in
+						   proc. */
 };
 
 
@@ -1424,7 +1645,11 @@
 	vol->mft_ino = NULL;
 	vol->mftbmp_ino = NULL;
 	init_rwsem(&vol->mftbmp_lock);
+#ifdef NTFS_RW
 	vol->mftmirr_ino = NULL;
+	vol->mftmirr_size = 0;
+	vol->logfile_ino = NULL;
+#endif /* NTFS_RW */
 	vol->lcnbmp_ino = NULL;
 	init_rwsem(&vol->lcnbmp_lock);
 	vol->vol_ino = NULL;
@@ -1474,7 +1699,7 @@
 			ntfs_error(sb, "Not an NTFS volume.");
 		goto err_out_now;
 	}
-	
+
 	/*
 	 * Extract the data from the boot sector and setup the ntfs super block
 	 * using it.
@@ -1489,7 +1714,7 @@
 		goto err_out_now;
 	}
 
-	/* 
+	/*
 	 * TODO: When we start coping with sector sizes different from
 	 * NTFS_BLOCK_SIZE, we now probably need to set the blocksize of the
 	 * device (probably to NTFS_BLOCK_SIZE).
@@ -1500,7 +1725,7 @@
 
 	/*
 	 * Ntfs allows 63 bits for the file size, i.e. correct would be:
-	 * 	sb->s_maxbytes = ~0ULL >> 1;
+	 *	sb->s_maxbytes = ~0ULL >> 1;
 	 * But the kernel uses a long as the page cache page index which on
 	 * 32-bit architectures is only 32-bits. MAX_LFS_FILESIZE is kernel
 	 * defined to the maximum the page cache page index can cope with
@@ -1519,7 +1744,7 @@
 	 * Poison vol->mft_ino so we know whether iget() called into our
 	 * ntfs_read_inode_mount() method.
 	 */
-#define OGIN	((struct inode*)le32_to_cpu(0x4e49474f))	/* OGIN */
+#define OGIN	((struct inode*)n2p(le32_to_cpu(0x4e49474f)))	/* OGIN */
 	vol->mft_ino = OGIN;
 	sb->s_op = &ntfs_mount_sops;
 	tmp_ino = iget(vol->sb, FILE_MFT);
@@ -1601,8 +1826,10 @@
 	vol->root_ino = NULL;
 	iput(vol->lcnbmp_ino);
 	vol->lcnbmp_ino = NULL;
+#ifdef NTFS_RW
 	iput(vol->mftmirr_ino);
 	vol->mftmirr_ino = NULL;
+#endif /* NTFS_RW */
 	iput(vol->mftbmp_ino);
 	vol->mftbmp_ino = NULL;
 	vol->upcase_len = 0;
@@ -1757,7 +1984,7 @@
 	}
 
 	ntfs_inode_cache = kmem_cache_create(ntfs_inode_cache_name,
-			sizeof(ntfs_inode), 0, 
+			sizeof(ntfs_inode), 0,
 			SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, NULL, NULL);
 	if (!ntfs_inode_cache) {
 		printk(KERN_CRIT "NTFS: Failed to create %s!\n",
@@ -1766,7 +1993,7 @@
 	}
 
 	ntfs_big_inode_cache = kmem_cache_create(ntfs_big_inode_cache_name,
-			sizeof(big_ntfs_inode), 0, 
+			sizeof(big_ntfs_inode), 0,
 			SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
 			ntfs_big_inode_init_once, NULL);
 	if (!ntfs_big_inode_cache) {
diff -Nru a/fs/ntfs/time.c b/fs/ntfs/time.c
--- a/fs/ntfs/time.c	Thu Apr 29 23:19:49 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,82 +0,0 @@
-/*
- * time.c - NTFS time conversion functions. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001 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
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be 
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS 
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/sched.h>	/* For CURRENT_TIME. */
-#include <asm/div64.h>		/* For do_div(). */
-
-#include "ntfs.h"
-
-#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
-
-/**
- * utc2ntfs - convert Linux time to NTFS time
- * @time:		Linux time to convert to NTFS
- *
- * Convert the Linux time @time to its corresponding NTFS time and return that
- * in little endian format.
- *
- * Linux stores time in a long at present and measures it as the number of
- * 1-second intervals since 1st January 1970, 00:00:00 UTC.
- *
- * NTFS uses Microsoft's standard time format which is stored in a s64 and is
- * measured as the number of 100 nano-second intervals since 1st January 1601,
- * 00:00:00 UTC.
- */
-inline s64 utc2ntfs(const time_t time)
-{
-	/* Convert to 100ns intervals and then add the NTFS time offset. */
-	return cpu_to_sle64((s64)time * 10000000 + NTFS_TIME_OFFSET);
-}
-
-/**
- * get_current_ntfs_time - get the current time in little endian NTFS format
- *
- * Get the current time from the Linux kernel, convert it to its corresponding
- * NTFS time and return that in little endian format.
- */
-inline s64 get_current_ntfs_time(void)
-{
-	/* ignores leap second */
-	return utc2ntfs(get_seconds()) + xtime.tv_nsec/1000;
-}
-
-/**
- * ntfs2utc - convert NTFS time to Linux time
- * @time:		NTFS time (little endian) to convert to Linux
- *
- * Convert the little endian NTFS time @time to its corresponding Linux time
- * and return that in cpu format.
- *
- * Linux stores time in a long at present and measures it as the number of
- * 1-second intervals since 1st January 1970, 00:00:00 UTC.
- *
- * NTFS uses Microsoft's standard time format which is stored in a s64 and is
- * measured as the number of 100 nano-second intervals since 1st January 1601,
- * 00:00:00 UTC.
- */
-inline time_t ntfs2utc(const s64 time)
-{
-	/* Subtract the NTFS time offset, then convert to 1s intervals. */
-	s64 t = sle64_to_cpu(time) - NTFS_TIME_OFFSET;
-	do_div(t, 10000000);
-	return (time_t)t;
-}
-
diff -Nru a/fs/ntfs/time.h b/fs/ntfs/time.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/ntfs/time.h	Thu Apr 29 23:19:49 2004
@@ -0,0 +1,100 @@
+/*
+ * time.h - NTFS time conversion functions.  Part of the Linux-NTFS project.
+ *
+ * Copyright (c) 2001-2004 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
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program/include file is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (in the main directory of the Linux-NTFS
+ * distribution in the file COPYING); if not, write to the Free Software
+ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LINUX_NTFS_TIME_H
+#define _LINUX_NTFS_TIME_H
+
+#include <linux/time.h>		/* For current_kernel_time(). */
+#include <asm/div64.h>		/* For do_div(). */
+
+#include "endian.h"
+
+#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
+
+/**
+ * utc2ntfs - convert Linux UTC time to NTFS time
+ * @ts:		Linux UTC time to convert to NTFS time
+ *
+ * Convert the Linux UTC time @ts to its corresponding NTFS time and return
+ * that in little endian format.
+ *
+ * Linux stores time in a struct timespec consisting of a time_t (long at
+ * present) tv_sec and a long tv_nsec where tv_sec is the number of 1-second
+ * intervals since 1st January 1970, 00:00:00 UTC and tv_nsec is the number of
+ * 1-nano-second intervals since the value of tv_sec.
+ *
+ * NTFS uses Microsoft's standard time format which is stored in a s64 and is
+ * measured as the number of 100-nano-second intervals since 1st January 1601,
+ * 00:00:00 UTC.
+ */
+static inline s64 utc2ntfs(const struct timespec ts)
+{
+	/*
+	 * Convert the seconds to 100ns intervals, add the nano-seconds
+	 * converted to 100ns intervals, and then add the NTFS time offset.
+	 */
+	return cpu_to_sle64((s64)ts.tv_sec * 10000000 + ts.tv_nsec / 100 +
+			NTFS_TIME_OFFSET);
+}
+
+/**
+ * get_current_ntfs_time - get the current time in little endian NTFS format
+ *
+ * Get the current time from the Linux kernel, convert it to its corresponding
+ * NTFS time and return that in little endian format.
+ */
+static inline s64 get_current_ntfs_time(void)
+{
+	return utc2ntfs(current_kernel_time());
+}
+
+/**
+ * ntfs2utc - convert NTFS time to Linux time
+ * @time:	NTFS time (little endian) to convert to Linux UTC
+ *
+ * Convert the little endian NTFS time @time to its corresponding Linux UTC
+ * time and return that in cpu format.
+ *
+ * Linux stores time in a struct timespec consisting of a time_t (long at
+ * present) tv_sec and a long tv_nsec where tv_sec is the number of 1-second
+ * intervals since 1st January 1970, 00:00:00 UTC and tv_nsec is the number of
+ * 1-nano-second intervals since the value of tv_sec.
+ *
+ * NTFS uses Microsoft's standard time format which is stored in a s64 and is
+ * measured as the number of 100 nano-second intervals since 1st January 1601,
+ * 00:00:00 UTC.
+ */
+static inline struct timespec ntfs2utc(const s64 time)
+{
+	struct timespec ts;
+
+	/* Subtract the NTFS time offset. */
+	s64 t = sle64_to_cpu(time) - NTFS_TIME_OFFSET;
+	/*
+	 * Convert the time to 1-second intervals and the remainder to
+	 * 1-nano-second intervals.
+	 */
+	ts.tv_nsec = do_div(t, 10000000) * 100;
+	ts.tv_sec = t;
+	return ts;
+}
+
+#endif /* _LINUX_NTFS_TIME_H */
diff -Nru a/fs/ntfs/volume.h b/fs/ntfs/volume.h
--- a/fs/ntfs/volume.h	Thu Apr 29 23:19:49 2004
+++ b/fs/ntfs/volume.h	Thu Apr 29 23:19:49 2004
@@ -2,7 +2,7 @@
  * volume.h - Defines for volume structures in NTFS Linux kernel driver. Part
  *	      of the Linux-NTFS project.
  *
- * Copyright (c) 2001,2002 Anton Altaparmakov.
+ * Copyright (c) 2001-2004 Anton Altaparmakov.
  * Copyright (c) 2002 Richard Russon.
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -10,13 +10,13 @@
  * by the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * This program/include file is distributed in the hope that it will be 
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
+ * This program/include file is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS 
+ * along with this program (in the main directory of the Linux-NTFS
  * distribution in the file COPYING); if not, write to the Free Software
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
@@ -25,6 +25,7 @@
 #define _LINUX_NTFS_VOLUME_H
 
 #include "types.h"
+#include "layout.h"
 
 /*
  * The NTFS in memory super block structure.
@@ -44,7 +45,7 @@
 	LCN nr_blocks;			/* Number of NTFS_BLOCK_SIZE bytes
 					   sized blocks on the device. */
 	/* Configuration provided by user at mount time. */
-	unsigned long flags;		/* Miscellaneous flags, see above. */
+	unsigned long flags;		/* Miscellaneous flags, see below. */
 	uid_t uid;			/* uid that files will be mounted as. */
 	gid_t gid;			/* gid that files will be mounted as. */
 	mode_t fmask;			/* The mask for file permissions. */
@@ -82,14 +83,22 @@
 	unsigned long nr_mft_records;	/* Number of mft records == number of
 					   bits in mft bitmap. */
 
+#ifdef NTFS_RW
 	struct inode *mftmirr_ino;	/* The VFS inode of $MFTMirr. */
+	int mftmirr_size;		/* Size of mft mirror in mft records. */
+
+	struct inode *logfile_ino;	/* The VFS inode of $LogFile. */
+#endif /* NTFS_RW */
+
 	struct inode *lcnbmp_ino;	/* The VFS inode of $Bitmap. */
 	struct rw_semaphore lcnbmp_lock; /* Lock for serializing accesses to the
 					    cluster bitmap ($Bitmap/$DATA). */
+
 	struct inode *vol_ino;		/* The VFS inode of $Volume. */
-	unsigned long vol_flags;	/* Volume flags (VOLUME_*). */
+	VOLUME_FLAGS vol_flags;		/* Volume flags. */
 	u8 major_ver;			/* Ntfs major version of volume. */
 	u8 minor_ver;			/* Ntfs minor version of volume. */
+
 	struct inode *root_ino;		/* The VFS inode of the root
 					   directory. */
 	struct inode *secure_ino;	/* The VFS inode of $Secure (NTFS3.0+
@@ -133,4 +142,3 @@
 NVOL_FNS(CaseSensitive)
 
 #endif /* _LINUX_NTFS_VOLUME_H */
-