bk://linux-ntfs.bkbits.net/ntfs-2.6-devel aia21@cantab.net|ChangeSet|20040807094822|32144 aia21 # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/08/07 14:39:35-07:00 akpm@bix.(none) # Merge bk://linux-ntfs.bkbits.net/ntfs-2.6-devel # into bix.(none):/usr/src/bk-ntfs # # fs/ntfs/super.c # 2004/08/07 14:39:32-07:00 akpm@bix.(none) +0 -0 # Auto merged # # fs/ntfs/dir.c # 2004/08/07 14:39:32-07:00 akpm@bix.(none) +0 -0 # Auto merged # # fs/ntfs/compress.c # 2004/08/07 14:39:32-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/08/07 10:48:22+01:00 aia21@cantab.net # Merge cantab.net:/home/src/ntfs-2.6 # into cantab.net:/home/src/ntfs-2.6-devel # # fs/ntfs/super.c # 2004/08/07 10:48:18+01:00 aia21@cantab.net +0 -0 # Auto merged # # fs/ntfs/compress.c # 2004/08/07 10:48:18+01:00 aia21@cantab.net +0 -0 # Auto merged # # ChangeSet # 2004/08/07 10:29:14+01:00 aia21@cantab.net # Merge cantab.net:/home/src/bklinux-2.6 # into cantab.net:/home/src/ntfs-2.6 # # fs/ntfs/super.c # 2004/08/07 10:29:10+01:00 aia21@cantab.net +0 -0 # Auto merged # # fs/ntfs/dir.c # 2004/08/07 10:29:10+01:00 aia21@cantab.net +0 -0 # Auto merged # # ChangeSet # 2004/07/30 08:57:21+01:00 aia21@cantab.net # NTFS: Fix compilation with gcc-2.95 in attrib.c::ntfs_find_vcn(). (Adrian Bunk) # # Signed-off-by: Anton Altaparmakov # Signed-off-by: Adrian Bunk # # fs/ntfs/attrib.c # 2004/07/30 08:55:04+01:00 aia21@cantab.net +5 -9 # Fix compilation with gcc-2.95. (Adrian Bunk) # # ChangeSet # 2004/07/26 23:13:47-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-ntfs # # fs/ntfs/super.c # 2004/07/26 23:13:44-07:00 akpm@bix.(none) +0 -0 # Auto merged # # fs/ntfs/dir.c # 2004/07/26 23:13:43-07:00 akpm@bix.(none) +0 -0 # Auto merged # # fs/ntfs/compress.c # 2004/07/26 23:13:43-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/07/22 10:56:09+01:00 aia21@cantab.net # NTFS: Add fs/ntfs/attrib.[hc]::ntfs_find_vcn(). # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/attrib.h # 2004/07/22 10:56:03+01:00 aia21@cantab.net +3 -0 # Add ntfs_find_vcn(). # # fs/ntfs/attrib.c # 2004/07/22 10:56:03+01:00 aia21@cantab.net +101 -0 # Add ntfs_find_vcn(). # # fs/ntfs/ChangeLog # 2004/07/22 10:56:03+01:00 aia21@cantab.net +20 -17 # Update # # ChangeSet # 2004/07/22 10:49:50+01:00 aia21@cantab.net # NTFS: Move a NULL check to before the first use of the pointer. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/bitmap.c # 2004/07/22 10:49:44+01:00 aia21@cantab.net +1 -1 # Move a NULL check to before the first use of the pointer. # # ChangeSet # 2004/07/22 10:47:22+01:00 aia21@cantab.net # NTFS: Complete "run list" to "runlist" renaming. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/types.h # 2004/07/22 10:47:15+01:00 aia21@cantab.net +1 -1 # Complete run list to runlist renaming. # # fs/ntfs/super.c # 2004/07/22 10:47:15+01:00 aia21@cantab.net +3 -3 # Complete run list to runlist renaming. # # fs/ntfs/layout.h # 2004/07/22 10:47:15+01:00 aia21@cantab.net +7 -7 # Complete run list to runlist renaming. # # fs/ntfs/inode.h # 2004/07/22 10:47:15+01:00 aia21@cantab.net +2 -2 # Complete run list to runlist renaming. # # fs/ntfs/inode.c # 2004/07/22 10:47:15+01:00 aia21@cantab.net +4 -4 # Complete run list to runlist renaming. # # fs/ntfs/debug.c # 2004/07/22 10:47:15+01:00 aia21@cantab.net +4 -4 # Complete run list to runlist renaming. # # fs/ntfs/compress.c # 2004/07/22 10:47:14+01:00 aia21@cantab.net +2 -2 # Complete run list to runlist renaming. # # fs/ntfs/attrib.c # 2004/07/22 10:47:14+01:00 aia21@cantab.net +145 -145 # Complete run list to runlist renaming. # # fs/ntfs/aops.c # 2004/07/22 10:47:14+01:00 aia21@cantab.net +6 -6 # Complete run list to runlist renaming. # # ChangeSet # 2004/07/21 14:34:22+01:00 aia21@cantab.net # NTFS: Rename vcn_to_lcn() to ntfs_vcn_to_lcn(). # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/debug.c # 2004/07/21 14:34:16+01:00 aia21@cantab.net +2 -3 # Rename vcn_to_lcn() to ntfs_vcn_to_lcn(). # # fs/ntfs/compress.c # 2004/07/21 14:34:16+01:00 aia21@cantab.net +3 -3 # Rename vcn_to_lcn() to ntfs_vcn_to_lcn(). # # fs/ntfs/attrib.h # 2004/07/21 14:34:16+01:00 aia21@cantab.net +1 -2 # Rename vcn_to_lcn() to ntfs_vcn_to_lcn(). # # fs/ntfs/attrib.c # 2004/07/21 14:34:15+01:00 aia21@cantab.net +11 -6 # Rename vcn_to_lcn() to ntfs_vcn_to_lcn(). # # fs/ntfs/aops.c # 2004/07/21 14:34:15+01:00 aia21@cantab.net +10 -10 # Rename vcn_to_lcn() to ntfs_vcn_to_lcn(). # # ChangeSet # 2004/07/21 13:12:11+01:00 aia21@cantab.net # NTFS: Rename map_runlist() to ntfs_map_runlist(). # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/compress.c # 2004/07/21 13:12:05+01:00 aia21@cantab.net +3 -3 # Rename map_runlist() to ntfs_map_runlist(). # # fs/ntfs/attrib.h # 2004/07/21 13:12:04+01:00 aia21@cantab.net +1 -1 # Rename map_runlist() to ntfs_map_runlist(). # # fs/ntfs/attrib.c # 2004/07/21 13:12:04+01:00 aia21@cantab.net +2 -2 # Rename map_runlist() to ntfs_map_runlist(). # # fs/ntfs/aops.c # 2004/07/21 13:12:04+01:00 aia21@cantab.net +3 -3 # Rename map_runlist() to ntfs_map_runlist(). # # ChangeSet # 2004/07/21 12:46:07+01:00 aia21@cantab.net # NTFS: Rename run_list to runlist everywhere to bring in line with libntfs. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/types.h # 2004/07/21 12:46:00+01:00 aia21@cantab.net +5 -5 # Rename run_list to runlist everywhere to bring in line with libntfs. # # fs/ntfs/super.c # 2004/07/21 12:45:59+01:00 aia21@cantab.net +5 -5 # Rename run_list to runlist everywhere to bring in line with libntfs. # # fs/ntfs/inode.h # 2004/07/21 12:45:59+01:00 aia21@cantab.net +4 -4 # Rename run_list to runlist everywhere to bring in line with libntfs. # # fs/ntfs/inode.c # 2004/07/21 12:45:59+01:00 aia21@cantab.net +12 -12 # Rename run_list to runlist everywhere to bring in line with libntfs. # # fs/ntfs/debug.h # 2004/07/21 12:45:59+01:00 aia21@cantab.net +1 -1 # Rename run_list to runlist everywhere to bring in line with libntfs. # # fs/ntfs/debug.c # 2004/07/21 12:45:59+01:00 aia21@cantab.net +1 -1 # Rename run_list to runlist everywhere to bring in line with libntfs. # # fs/ntfs/compress.c # 2004/07/21 12:45:59+01:00 aia21@cantab.net +9 -9 # Rename run_list to runlist everywhere to bring in line with libntfs. # # fs/ntfs/attrib.h # 2004/07/21 12:45:58+01:00 aia21@cantab.net +6 -6 # Rename run_list to runlist everywhere to bring in line with libntfs. # # fs/ntfs/attrib.c # 2004/07/21 12:45:58+01:00 aia21@cantab.net +55 -58 # Rename run_list to runlist everywhere to bring in line with libntfs. # # fs/ntfs/aops.c # 2004/07/21 12:45:58+01:00 aia21@cantab.net +20 -20 # Rename run_list to runlist everywhere to bring in line with libntfs. # # ChangeSet # 2004/07/21 08:56:45+01:00 aia21@cantab.net # NTFS: Wrap the new bitmap.[hc] code in #ifdef NTFS_RW / #endif. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/bitmap.h # 2004/07/21 08:56:38+01:00 aia21@cantab.net +4 -0 # Wrap code in #ifdef NTFS_RW / #endif. # # fs/ntfs/bitmap.c # 2004/07/21 08:56:38+01:00 aia21@cantab.net +4 -0 # Wrap code in #ifdef NTFS_RW / #endif. # # ChangeSet # 2004/07/21 08:49:04+01:00 aia21@cantab.net # NTFS: Implement bitmap modification code (fs/ntfs/bitmap.[hc]). This # includes functions to set/clear a single bit or a run of bits. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/bitmap.h # 2004/07/21 08:46:57+01:00 aia21@cantab.net +21 -2 # Implement bitmap modification code including rollback on error ability. This # includes functions to set/clear a single bit or a run of bits. # # fs/ntfs/Makefile # 2004/07/21 08:46:56+01:00 aia21@cantab.net +2 -2 # Add bitmap.c to build. # # fs/ntfs/ChangeLog # 2004/07/21 08:46:56+01:00 aia21@cantab.net +5 -5 # Update # # fs/ntfs/bitmap.c # 2004/07/20 22:33:02+01:00 aia21@cantab.net +183 -0 # Implement bitmap modification code including rollback on error ability. # # fs/ntfs/bitmap.c # 2004/07/20 22:33:02+01:00 aia21@cantab.net +0 -0 # BitKeeper file /home/src/ntfs-2.6-devel/fs/ntfs/bitmap.c # # fs/ntfs/bitmap.h # 2004/07/20 21:38:32+01:00 aia21@cantab.net +95 -0 # # fs/ntfs/bitmap.h # 2004/07/20 21:38:32+01:00 aia21@cantab.net +0 -0 # BitKeeper file /home/src/ntfs-2.6-devel/fs/ntfs/bitmap.h # # ChangeSet # 2004/07/14 10:52:07+01:00 aia21@cantab.net # NTFS: 2.1.16 - Implement access time updates in fs/ntfs/inode.c::ntfs_write_inode. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/super.c # 2004/07/14 10:52:00+01:00 aia21@cantab.net +3 -32 # Remove enforcement of no atime updates and corresponding "not implemented" # warnings as atime updates are now implemented. # # fs/ntfs/inode.c # 2004/07/14 10:52:00+01:00 aia21@cantab.net +48 -26 # Implement access time updates in ntfs_write_inode(). # # fs/ntfs/Makefile # 2004/07/14 10:52:00+01:00 aia21@cantab.net +1 -1 # Update for 2.1.16 release. # # fs/ntfs/ChangeLog # 2004/07/14 10:52:00+01:00 aia21@cantab.net +7 -1 # Update for 2.1.16 release. # # Documentation/filesystems/ntfs.txt # 2004/07/14 10:52:00+01:00 aia21@cantab.net +6 -0 # Update for 2.1.16 release. # # ChangeSet # 2004/07/08 13:07:12+01:00 aia21@cantab.net # NTFS: Implement fsync, fdatasync, and msync both for files (fs/ntfs/file.c) # and directories (fs/ntfs/dir.c). # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/file.c # 2004/07/08 13:07:05+01:00 aia21@cantab.net +55 -3 # Implement fsync, fdatasync, and msync for files. # # fs/ntfs/dir.c # 2004/07/08 13:07:05+01:00 aia21@cantab.net +60 -1 # Implement fsync, fdatasync, and msync for directories. # # fs/ntfs/ChangeLog # 2004/07/08 13:07:05+01:00 aia21@cantab.net +2 -0 # Update # # ChangeSet # 2004/07/08 12:13:35+01:00 aia21@cantab.net # NTFS: Change ntfs_write_inode to return 0 on success and -errno on error # and create a wrapper ntfs_write_inode_vfs that does not have a # return value and use the wrapper for the VFS super_operations # write_inode function. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/super.c # 2004/07/08 12:13:29+01:00 aia21@cantab.net +1 -1 # Change ntfs_write_inode to return 0 on success and -errno on error and # create a wrapper ntfs_write_inode_vfs that does not have a return value # and use the wrapper for the VFS super_operations write_inode function. # # fs/ntfs/inode.h # 2004/07/08 12:13:29+01:00 aia21@cantab.net +2 -1 # Change ntfs_write_inode to return 0 on success and -errno on error and # create a wrapper ntfs_write_inode_vfs that does not have a return value # and use the wrapper for the VFS super_operations write_inode function. # # fs/ntfs/inode.c # 2004/07/08 12:13:28+01:00 aia21@cantab.net +30 -4 # Change ntfs_write_inode to return 0 on success and -errno on error and # create a wrapper ntfs_write_inode_vfs that does not have a return value # and use the wrapper for the VFS super_operations write_inode function. # # ChangeSet # 2004/07/07 16:10:11+01:00 aia21@cantab.net # NTFS: Add support for readv/writev and aio_read/aio_write. # # Signed-off-by: Anton Altaparmakov # # fs/ntfs/file.c # 2004/07/07 16:10:04+01:00 aia21@cantab.net +35 -12 # Add support for readv/writev and aio_read/aio_write. # # fs/ntfs/Makefile # 2004/07/07 16:10:04+01:00 aia21@cantab.net +1 -1 # Bump version to 2.1.16-WIP. # # fs/ntfs/ChangeLog # 2004/07/07 16:10:04+01:00 aia21@cantab.net +6 -0 # Update # diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt --- a/Documentation/filesystems/ntfs.txt 2004-08-09 21:46:58 -07:00 +++ b/Documentation/filesystems/ntfs.txt 2004-08-09 21:46:58 -07:00 @@ -273,6 +273,12 @@ Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. +2.1.16: + - Implement access time updates (including mtime and ctime). + - Implement fsync(2), fdatasync(2), and msync(2) system calls. + - Enable the readv(2) and writev(2) system calls. + - Enable access via the asynchronous io (aio) API by adding support for + the aio_read(3) and aio_write(3) functions. 2.1.15: - Invalidate quotas when (re)mounting read-write. NOTE: This now only leave user space journalling on the side. (See diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog --- a/fs/ntfs/ChangeLog 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/ChangeLog 2004-08-09 21:46:58 -07:00 @@ -1,11 +1,6 @@ ToDo/Notes: - Find and fix bugs. - Checkpoint or disable the user space journal ($UsnJrnl). - - Implement sops->dirty_inode() to implement {a,m,c}time updates and - such things. This should probably just flag the ntfs inode such that - sops->write_inode(), i.e. ntfs_write_inode(), will copy the times - when it is invoked rather than having to update the mft record - every time. - In between ntfs_prepare/commit_write, need exclusion between simultaneous file extensions. Need perhaps an NInoResizeUnderway() flag which we can set in ntfs_prepare_write() and clear again in @@ -26,6 +21,28 @@ - Enable the code for setting the NT4 compatibility flag when we start making NTFS 1.2 specific modifications. +2.1.17 - WIP. + + - Implement bitmap modification code (fs/ntfs/bitmap.[hc]). This + includes functions to set/clear a single bit or a run of bits. + - Add fs/ntfs/attrib.[hc]::ntfs_find_vcn() which returns the locked + runlist element containing a particular vcn. It also takes care of + mapping any needed runlist fragments. + +2.1.16 - Implement access time updates, file sync, async io, and read/writev. + + - Add support for readv/writev and aio_read/aio_write (fs/ntfs/file.c). + This is done by setting the appropriate file operations pointers to + the generic helper functions provided by mm/filemap.c. + - Implement fsync, fdatasync, and msync both for files (fs/ntfs/file.c) + and directories (fs/ntfs/dir.c). + - Add support for {a,m,c}time updates to inode.c::ntfs_write_inode(). + Note, except for the root directory and any other system files opened + by the user, the system files will not have their access times + updated as they are only accessed at the inode level an hence the + file level functions which cause the times to be updated are never + invoked. + 2.1.15 - Invalidate quotas when (re)mounting read-write. - Add new element itype.index.collation_rule to the ntfs inode @@ -434,7 +451,7 @@ cannot set any write related options when the driver is compiled read-only. - Optimize block resolution in fs/ntfs/aops.c::ntfs_read_block() to - cache the current run list element. This should improve performance + cache the current runlist element. This should improve performance when reading very large and/or very fragmented data. 2.0.16 - Convert access to $MFT/$BITMAP to attribute inode API. @@ -482,9 +499,9 @@ - Change fs/ntfs/super.c::ntfs_statfs() to not rely on BKL by moving the locking out of super.c::get_nr_free_mft_records() and taking and dropping the mftbmp_lock rw_semaphore in ntfs_statfs() itself. - - Bring attribute run list merging code (fs/ntfs/attrib.c) in sync with + - Bring attribute runlist merging code (fs/ntfs/attrib.c) in sync with current userspace ntfs library code. This means that if a merge - fails the original run lists are always left unmodified instead of + fails the original runlists are always left unmodified instead of being silently corrupted. - Misc typo fixes. @@ -676,7 +693,7 @@ appropriately. - Update to 2.5.9 kernel (preserving backwards compatibility) by replacing all occurences of page->buffers with page_buffers(page). - - Fix minor bugs in run list merging, also minor cleanup. + - Fix minor bugs in runlist merging, also minor cleanup. - Updates to bootsector layout and mft mirror contents descriptions. - Small bug fix in error detection in unistr.c and some cleanups. - Grow name buffer allocations in unistr.c in aligned mutlipled of 64 @@ -699,12 +716,12 @@ initialized_size vs data_size (i.e. i_size). Done are mft.c::ntfs_mft_readpage(), aops.c::end_buffer_read_index_async(), and attrib.c::load_attribute_list(). - - Lock the run list in attrib.c::load_attribute_list() while using it. + - Lock the runlist in attrib.c::load_attribute_list() while using it. - Fix memory leak in ntfs_file_read_compressed_block() and generally clean up compress.c a little, removing some uncommented/unused debug code. - Tidy up dir.c a little bit. - - Don't bother getting the run list in inode.c::ntfs_read_inode(). + - Don't bother getting the runlist in inode.c::ntfs_read_inode(). - Merge mft.c::ntfs_mft_readpage() and aops.c::ntfs_index_readpage() creating aops.c::ntfs_mst_readpage(), improving the handling of holes and overflow in the process and implementing the correct @@ -734,7 +751,7 @@ - Apply kludge in ntfs_read_inode(), setting i_nlink to 1 for directories. Without this the "find" utility gets very upset which is fair enough as Linux/Unix do not support directory hard links. - - Further run list merging work. (Richard Russon) + - Further runlist merging work. (Richard Russon) - Backwards compatibility for gcc-2.95. (Richard Russon) - Update to kernel 2.5.5-pre1 and rediff the now tiny patch. - Convert to new file system declaration using ->ntfs_get_sb() and @@ -789,7 +806,7 @@ which is then referenced but not copied. - Rename run_list structure to run_list_element and create a new run_list structure containing a pointer to a run_list_element - structure and a read/write semaphore. Adapt all users of run lists + structure and a read/write semaphore. Adapt all users of runlists to new scheme and take and release the lock as needed. This fixes a nasty race as the run_list changes even when inodes are locked for reading and even when the inode isn't locked at all, so we really @@ -820,7 +837,7 @@ - Cleanup mft.c and it's debug/error output in particular. Fix a minor bug in mapping of extent inodes. Update all the comments to fit all the recent code changes. - - Modify vcn_to_lcn() to cope with entirely unmapped run lists. + - Modify vcn_to_lcn() to cope with entirely unmapped runlists. - Cleanups in compress.c, mostly comments and folding help. - Implement attrib.c::map_run_list() as a generic helper. - Make compress.c::ntfs_file_read_compressed_block() use map_run_list() @@ -846,11 +863,11 @@ pass in the upcase table and its length. These can be gotten from ctx->ntfs_ino->vol->upcase{_len}. Update all callers. - Cleanups in attrib.c. - - Implement merging of run lists, attrib.c::merge_run_lists() and its + - Implement merging of runlists, attrib.c::merge_run_lists() and its helpers. (Richard Russon) - - Attribute lists part 2, attribute extents and multi part run lists: + - Attribute lists part 2, attribute extents and multi part runlists: enable proper support for LCN_RL_NOT_MAPPED and automatic mapping of - further run list parts via attrib.c::map_run_list(). + further runlist parts via attrib.c::map_run_list(). - Tiny endianness bug fix in decompress_mapping_pairs(). tng-0.0.6 - Encrypted directories, bug fixes, cleanups, debugging enhancements. @@ -882,7 +899,7 @@ support dollar signs in the names of variables/constants. Attribute types now start with AT_ instead of $ and $I30 is now just I30. - Cleanup ntfs_lookup() and add consistency check of sequence numbers. - - Load complete run list for $MFT/$BITMAP during mount and cleanup + - Load complete runlist for $MFT/$BITMAP during mount and cleanup access functions. This means we now cope with $MFT/$BITMAP being spread accross several mft records. - Disable modification of mft_zone_multiplier on remount. We can always @@ -915,11 +932,11 @@ parameter list. Pass either READ or WRITE to this, each has the obvious meaning. - General cleanups to allow for easier folding in vi. - - attrib.c::decompress_mapping_pairs() now accepts the old run list + - attrib.c::decompress_mapping_pairs() now accepts the old runlist argument, and invokes attrib.c::merge_run_lists() to merge the old - and the new run lists. + and the new runlists. - Removed attrib.c::find_first_attr(). - - Implemented loading of attribute list and complete run list for $MFT. + - Implemented loading of attribute list and complete runlist for $MFT. This means we now cope with $MFT being spread across several mft records. - Adapt to 2.5.2-pre9 and the changed create_empty_buffers() syntax. @@ -957,7 +974,7 @@ tng-0.0.3 - Cleanups, enhancements, bug fixes. - Work on attrib.c::decompress_mapping_pairs() to detect base extents - and setup the run list appropriately using knowledge provided by the + and setup the runlist appropriately using knowledge provided by the sizes in the base attribute record. - Balance the get_/put_attr_search_ctx() calls so we don't leak memory any more. diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile --- a/fs/ntfs/Makefile 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/Makefile 2004-08-09 21:46:58 -07:00 @@ -6,7 +6,7 @@ index.o inode.o mft.o mst.o namei.o super.o sysctl.o unistr.o \ upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.15\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.17-WIP\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG @@ -15,5 +15,5 @@ ifeq ($(CONFIG_NTFS_RW),y) EXTRA_CFLAGS += -DNTFS_RW -ntfs-objs += logfile.o quota.o +ntfs-objs += bitmap.o logfile.o quota.o endif diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c --- a/fs/ntfs/aops.c 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/aops.c 2004-08-09 21:46:58 -07:00 @@ -170,7 +170,7 @@ LCN lcn; ntfs_inode *ni; ntfs_volume *vol; - run_list_element *rl; + runlist_element *rl; struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE]; sector_t iblock, lblock, zblock; unsigned int blocksize, vcn_ofs; @@ -196,8 +196,8 @@ zblock = (ni->initialized_size + blocksize - 1) >> blocksize_bits; #ifdef DEBUG - if (unlikely(!ni->run_list.rl && !ni->mft_no && !NInoAttr(ni))) - panic("NTFS: $MFT/$DATA run list has been unmapped! This is a " + if (unlikely(!ni->runlist.rl && !ni->mft_no && !NInoAttr(ni))) + panic("NTFS: $MFT/$DATA runlist has been unmapped! This is a " "very serious bug! Cannot continue..."); #endif @@ -225,14 +225,14 @@ vol->cluster_size_mask; if (!rl) { lock_retry_remap: - down_read(&ni->run_list.lock); - rl = ni->run_list.rl; + down_read(&ni->runlist.lock); + rl = ni->runlist.rl; } if (likely(rl != NULL)) { /* Seek to element containing target vcn. */ while (rl->length && rl[1].vcn <= vcn) rl++; - lcn = vcn_to_lcn(rl, vcn); + lcn = ntfs_vcn_to_lcn(rl, vcn); } else lcn = (LCN)LCN_RL_NOT_MAPPED; /* Successful remap. */ @@ -252,29 +252,29 @@ /* It is a hole, need to zero it. */ if (lcn == LCN_HOLE) goto handle_hole; - /* If first try and run list unmapped, map and retry. */ + /* If first try and runlist unmapped, map and retry. */ if (!is_retry && lcn == LCN_RL_NOT_MAPPED) { is_retry = TRUE; /* - * Attempt to map run list, dropping lock for + * Attempt to map runlist, dropping lock for * the duration. */ - up_read(&ni->run_list.lock); - if (!map_run_list(ni, vcn)) + up_read(&ni->runlist.lock); + if (!ntfs_map_runlist(ni, vcn)) goto lock_retry_remap; rl = NULL; } /* Hard error, zero out region. */ SetPageError(page); - ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%llx) failed " - "with error code 0x%llx%s.", + ntfs_error(vol->sb, "ntfs_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. } /* - * Either iblock was outside lblock limits or vcn_to_lcn() + * Either iblock was outside lblock limits or ntfs_vcn_to_lcn() * returned error. Just zero that portion of the page and set * the buffer uptodate. */ @@ -291,7 +291,7 @@ /* Release the lock if we took it. */ if (rl) - up_read(&ni->run_list.lock); + up_read(&ni->runlist.lock); /* Check we have at least one buffer ready for i/o. */ if (nr) { @@ -473,7 +473,7 @@ struct inode *vi; ntfs_inode *ni; ntfs_volume *vol; - run_list_element *rl; + runlist_element *rl; struct buffer_head *bh, *head; unsigned int blocksize, vcn_ofs; int err; @@ -631,14 +631,14 @@ vol->cluster_size_mask; if (!rl) { lock_retry_remap: - down_read(&ni->run_list.lock); - rl = ni->run_list.rl; + down_read(&ni->runlist.lock); + rl = ni->runlist.rl; } if (likely(rl != NULL)) { /* Seek to element containing target vcn. */ while (rl->length && rl[1].vcn <= vcn) rl++; - lcn = vcn_to_lcn(rl, vcn); + lcn = ntfs_vcn_to_lcn(rl, vcn); } else lcn = (LCN)LCN_RL_NOT_MAPPED; /* Successful remap. */ @@ -659,22 +659,22 @@ err = -EOPNOTSUPP; break; } - /* If first try and run list unmapped, map and retry. */ + /* If first try and runlist unmapped, map and retry. */ if (!is_retry && lcn == LCN_RL_NOT_MAPPED) { is_retry = TRUE; /* - * Attempt to map run list, dropping lock for + * Attempt to map runlist, dropping lock for * the duration. */ - up_read(&ni->run_list.lock); - err = map_run_list(ni, vcn); + up_read(&ni->runlist.lock); + err = ntfs_map_runlist(ni, vcn); if (likely(!err)) goto lock_retry_remap; rl = NULL; } /* Failed to map the buffer, even after retrying. */ bh->b_blocknr = -1UL; - ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%llx) failed " + ntfs_error(vol->sb, "ntfs_vcn_to_lcn(vcn = 0x%llx) failed " "with error code 0x%llx%s.", (unsigned long long)vcn, (unsigned long long)-lcn, @@ -687,7 +687,7 @@ /* Release the lock if we took it. */ if (rl) - up_read(&ni->run_list.lock); + up_read(&ni->runlist.lock); /* For the error case, need to reset bh to the beginning. */ bh = head; @@ -1240,7 +1240,7 @@ struct inode *vi; ntfs_inode *ni; ntfs_volume *vol; - run_list_element *rl; + runlist_element *rl; struct buffer_head *bh, *head, *wait[2], **wait_bh = wait; unsigned int vcn_ofs, block_start, block_end, blocksize; int err; @@ -1397,14 +1397,14 @@ is_retry = FALSE; if (!rl) { lock_retry_remap: - down_read(&ni->run_list.lock); - rl = ni->run_list.rl; + down_read(&ni->runlist.lock); + rl = ni->runlist.rl; } if (likely(rl != NULL)) { /* Seek to element containing target vcn. */ while (rl->length && rl[1].vcn <= vcn) rl++; - lcn = vcn_to_lcn(rl, vcn); + lcn = ntfs_vcn_to_lcn(rl, vcn); } else lcn = (LCN)LCN_RL_NOT_MAPPED; if (unlikely(lcn < 0)) { @@ -1439,11 +1439,11 @@ lcn == LCN_RL_NOT_MAPPED) { is_retry = TRUE; /* - * Attempt to map run list, dropping + * Attempt to map runlist, dropping * lock for the duration. */ - up_read(&ni->run_list.lock); - err = map_run_list(ni, vcn); + up_read(&ni->runlist.lock); + err = ntfs_map_runlist(ni, vcn); if (likely(!err)) goto lock_retry_remap; rl = NULL; @@ -1453,9 +1453,9 @@ * retrying. */ bh->b_blocknr = -1UL; - ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%llx) " - "failed with error code " - "0x%llx%s.", + ntfs_error(vol->sb, "ntfs_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 " @@ -1530,7 +1530,7 @@ /* Release the lock if we took it. */ if (rl) { - up_read(&ni->run_list.lock); + up_read(&ni->runlist.lock); rl = NULL; } @@ -1576,7 +1576,7 @@ if (is_retry) flush_dcache_page(page); if (rl) - up_read(&ni->run_list.lock); + up_read(&ni->runlist.lock); return err; } diff -Nru a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c --- a/fs/ntfs/attrib.c 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/attrib.c 2004-08-09 21:46:59 -07:00 @@ -27,11 +27,11 @@ /* Temporary helper functions -- might become macros */ /** - * ntfs_rl_mm - run_list memmove + * ntfs_rl_mm - runlist memmove * - * It is up to the caller to serialize access to the run list @base. + * It is up to the caller to serialize access to the runlist @base. */ -static inline void ntfs_rl_mm(run_list_element *base, int dst, int src, +static inline void ntfs_rl_mm(runlist_element *base, int dst, int src, int size) { if (likely((dst != src) && (size > 0))) @@ -39,42 +39,42 @@ } /** - * ntfs_rl_mc - run_list memory copy + * ntfs_rl_mc - runlist memory copy * - * It is up to the caller to serialize access to the run lists @dstbase and + * It is up to the caller to serialize access to the runlists @dstbase and * @srcbase. */ -static inline void ntfs_rl_mc(run_list_element *dstbase, int dst, - run_list_element *srcbase, int src, int size) +static inline void ntfs_rl_mc(runlist_element *dstbase, int dst, + runlist_element *srcbase, int src, int size) { if (likely(size > 0)) memcpy(dstbase + dst, srcbase + src, size * sizeof(*dstbase)); } /** - * ntfs_rl_realloc - Reallocate memory for run_lists - * @rl: original run list - * @old_size: number of run list elements in the original run list @rl - * @new_size: number of run list elements we need space for + * ntfs_rl_realloc - Reallocate memory for runlists + * @rl: original runlist + * @old_size: number of runlist elements in the original runlist @rl + * @new_size: number of runlist elements we need space for * - * As the run_lists grow, more memory will be required. To prevent the + * As the runlists grow, more memory will be required. To prevent the * kernel having to allocate and reallocate large numbers of small bits of * memory, this function returns and entire page of memory. * - * It is up to the caller to serialize access to the run list @rl. + * It is up to the caller to serialize access to the runlist @rl. * * N.B. If the new allocation doesn't require a different number of pages in * memory, the function will return the original pointer. * * On success, return a pointer to the newly allocated, or recycled, memory. * On error, return -errno. The following error codes are defined: - * -ENOMEM - Not enough memory to allocate run list array. + * -ENOMEM - Not enough memory to allocate runlist array. * -EINVAL - Invalid parameters were passed in. */ -static inline run_list_element *ntfs_rl_realloc(run_list_element *rl, +static inline runlist_element *ntfs_rl_realloc(runlist_element *rl, int old_size, int new_size) { - run_list_element *new_rl; + runlist_element *new_rl; old_size = PAGE_ALIGN(old_size * sizeof(*rl)); new_size = PAGE_ALIGN(new_size * sizeof(*rl)); @@ -95,20 +95,20 @@ } /** - * ntfs_are_rl_mergeable - test if two run lists can be joined together - * @dst: original run list - * @src: new run list to test for mergeability with @dst + * ntfs_are_rl_mergeable - test if two runlists can be joined together + * @dst: original runlist + * @src: new runlist to test for mergeability with @dst * - * Test if two run lists can be joined together. For this, their VCNs and LCNs + * Test if two runlists can be joined together. For this, their VCNs and LCNs * must be adjacent. * - * It is up to the caller to serialize access to the run lists @dst and @src. + * It is up to the caller to serialize access to the runlists @dst and @src. * - * Return: TRUE Success, the run lists can be merged. - * FALSE Failure, the run lists cannot be merged. + * Return: TRUE Success, the runlists can be merged. + * FALSE Failure, the runlists cannot be merged. */ -static inline BOOL ntfs_are_rl_mergeable(run_list_element *dst, - run_list_element *src) +static inline BOOL ntfs_are_rl_mergeable(runlist_element *dst, + runlist_element *src) { BUG_ON(!dst); BUG_ON(!src); @@ -124,37 +124,37 @@ } /** - * __ntfs_rl_merge - merge two run lists without testing if they can be merged - * @dst: original, destination run list - * @src: new run list to merge with @dst - * - * Merge the two run lists, writing into the destination run list @dst. The - * caller must make sure the run lists can be merged or this will corrupt the - * destination run list. + * __ntfs_rl_merge - merge two runlists without testing if they can be merged + * @dst: original, destination runlist + * @src: new runlist to merge with @dst + * + * Merge the two runlists, writing into the destination runlist @dst. The + * caller must make sure the runlists can be merged or this will corrupt the + * destination runlist. * - * It is up to the caller to serialize access to the run lists @dst and @src. + * It is up to the caller to serialize access to the runlists @dst and @src. */ -static inline void __ntfs_rl_merge(run_list_element *dst, run_list_element *src) +static inline void __ntfs_rl_merge(runlist_element *dst, runlist_element *src) { dst->length += src->length; } /** - * ntfs_rl_merge - test if two run lists can be joined together and merge them - * @dst: original, destination run list - * @src: new run list to merge with @dst + * ntfs_rl_merge - test if two runlists can be joined together and merge them + * @dst: original, destination runlist + * @src: new runlist to merge with @dst * - * Test if two run lists can be joined together. For this, their VCNs and LCNs + * Test if two runlists can be joined together. For this, their VCNs and LCNs * must be adjacent. If they can be merged, perform the merge, writing into - * the destination run list @dst. + * the destination runlist @dst. * - * It is up to the caller to serialize access to the run lists @dst and @src. + * It is up to the caller to serialize access to the runlists @dst and @src. * - * Return: TRUE Success, the run lists have been merged. - * FALSE Failure, the run lists cannot be merged and have not been + * Return: TRUE Success, the runlists have been merged. + * FALSE Failure, the runlists cannot be merged and have not been * modified. */ -static inline BOOL ntfs_rl_merge(run_list_element *dst, run_list_element *src) +static inline BOOL ntfs_rl_merge(runlist_element *dst, runlist_element *src) { BOOL merge = ntfs_are_rl_mergeable(dst, src); @@ -164,31 +164,31 @@ } /** - * ntfs_rl_append - append a run list after a given element - * @dst: original run list to be worked on + * ntfs_rl_append - append a runlist after a given element + * @dst: original runlist to be worked on * @dsize: number of elements in @dst (including end marker) - * @src: run list to be inserted into @dst + * @src: runlist to be inserted into @dst * @ssize: number of elements in @src (excluding end marker) - * @loc: append the new run list @src after this element in @dst + * @loc: append the new runlist @src after this element in @dst * - * Append the run list @src after element @loc in @dst. Merge the right end of - * the new run list, if necessary. Adjust the size of the hole before the - * appended run list. + * Append the runlist @src after element @loc in @dst. Merge the right end of + * the new runlist, if necessary. Adjust the size of the hole before the + * appended runlist. * - * It is up to the caller to serialize access to the run lists @dst and @src. + * It is up to the caller to serialize access to the runlists @dst and @src. * - * On success, return a pointer to the new, combined, run list. Note, both - * run lists @dst and @src are deallocated before returning so you cannot use - * the pointers for anything any more. (Strictly speaking the returned run list + * On success, return a pointer to the new, combined, runlist. Note, both + * runlists @dst and @src are deallocated before returning so you cannot use + * the pointers for anything any more. (Strictly speaking the returned runlist * may be the same as @dst but this is irrelevant.) * - * On error, return -errno. Both run lists are left unmodified. The following + * On error, return -errno. Both runlists are left unmodified. The following * error codes are defined: - * -ENOMEM - Not enough memory to allocate run list array. + * -ENOMEM - Not enough memory to allocate runlist array. * -EINVAL - Invalid parameters were passed in. */ -static inline run_list_element *ntfs_rl_append(run_list_element *dst, - int dsize, run_list_element *src, int ssize, int loc) +static inline runlist_element *ntfs_rl_append(runlist_element *dst, + int dsize, runlist_element *src, int ssize, int loc) { BOOL right; int magic; @@ -205,7 +205,7 @@ return dst; /* * We are guaranteed to succeed from here so can start modifying the - * original run lists. + * original runlists. */ /* First, merge the right hand end, if necessary. */ @@ -229,31 +229,31 @@ } /** - * ntfs_rl_insert - insert a run list into another - * @dst: original run list to be worked on + * ntfs_rl_insert - insert a runlist into another + * @dst: original runlist to be worked on * @dsize: number of elements in @dst (including end marker) - * @src: new run list to be inserted + * @src: new runlist to be inserted * @ssize: number of elements in @src (excluding end marker) - * @loc: insert the new run list @src before this element in @dst + * @loc: insert the new runlist @src before this element in @dst * - * Insert the run list @src before element @loc in the run list @dst. Merge the - * left end of the new run list, if necessary. Adjust the size of the hole - * after the inserted run list. + * Insert the runlist @src before element @loc in the runlist @dst. Merge the + * left end of the new runlist, if necessary. Adjust the size of the hole + * after the inserted runlist. * - * It is up to the caller to serialize access to the run lists @dst and @src. + * It is up to the caller to serialize access to the runlists @dst and @src. * - * On success, return a pointer to the new, combined, run list. Note, both - * run lists @dst and @src are deallocated before returning so you cannot use - * the pointers for anything any more. (Strictly speaking the returned run list + * On success, return a pointer to the new, combined, runlist. Note, both + * runlists @dst and @src are deallocated before returning so you cannot use + * the pointers for anything any more. (Strictly speaking the returned runlist * may be the same as @dst but this is irrelevant.) * - * On error, return -errno. Both run lists are left unmodified. The following + * On error, return -errno. Both runlists are left unmodified. The following * error codes are defined: - * -ENOMEM - Not enough memory to allocate run list array. + * -ENOMEM - Not enough memory to allocate runlist array. * -EINVAL - Invalid parameters were passed in. */ -static inline run_list_element *ntfs_rl_insert(run_list_element *dst, - int dsize, run_list_element *src, int ssize, int loc) +static inline runlist_element *ntfs_rl_insert(runlist_element *dst, + int dsize, runlist_element *src, int ssize, int loc) { BOOL left = FALSE; BOOL disc = FALSE; /* Discontinuity */ @@ -290,7 +290,7 @@ return dst; /* * We are guaranteed to succeed from here so can start modifying the - * original run list. + * original runlist. */ if (left) @@ -336,30 +336,30 @@ } /** - * ntfs_rl_replace - overwrite a run_list element with another run list - * @dst: original run list to be worked on + * ntfs_rl_replace - overwrite a runlist element with another runlist + * @dst: original runlist to be worked on * @dsize: number of elements in @dst (including end marker) - * @src: new run list to be inserted + * @src: new runlist to be inserted * @ssize: number of elements in @src (excluding end marker) - * @loc: index in run list @dst to overwrite with @src + * @loc: index in runlist @dst to overwrite with @src * - * Replace the run list element @dst at @loc with @src. Merge the left and - * right ends of the inserted run list, if necessary. + * Replace the runlist element @dst at @loc with @src. Merge the left and + * right ends of the inserted runlist, if necessary. * - * It is up to the caller to serialize access to the run lists @dst and @src. + * It is up to the caller to serialize access to the runlists @dst and @src. * - * On success, return a pointer to the new, combined, run list. Note, both - * run lists @dst and @src are deallocated before returning so you cannot use - * the pointers for anything any more. (Strictly speaking the returned run list + * On success, return a pointer to the new, combined, runlist. Note, both + * runlists @dst and @src are deallocated before returning so you cannot use + * the pointers for anything any more. (Strictly speaking the returned runlist * may be the same as @dst but this is irrelevant.) * - * On error, return -errno. Both run lists are left unmodified. The following + * On error, return -errno. Both runlists are left unmodified. The following * error codes are defined: - * -ENOMEM - Not enough memory to allocate run list array. + * -ENOMEM - Not enough memory to allocate runlist array. * -EINVAL - Invalid parameters were passed in. */ -static inline run_list_element *ntfs_rl_replace(run_list_element *dst, - int dsize, run_list_element *src, int ssize, int loc) +static inline runlist_element *ntfs_rl_replace(runlist_element *dst, + int dsize, runlist_element *src, int ssize, int loc) { BOOL left = FALSE; BOOL right; @@ -380,7 +380,7 @@ return dst; /* * We are guaranteed to succeed from here so can start modifying the - * original run lists. + * original runlists. */ if (right) __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); @@ -401,31 +401,31 @@ } /** - * ntfs_rl_split - insert a run list into the centre of a hole - * @dst: original run list to be worked on + * ntfs_rl_split - insert a runlist into the centre of a hole + * @dst: original runlist to be worked on * @dsize: number of elements in @dst (including end marker) - * @src: new run list to be inserted + * @src: new runlist to be inserted * @ssize: number of elements in @src (excluding end marker) - * @loc: index in run list @dst at which to split and insert @src + * @loc: index in runlist @dst at which to split and insert @src * - * Split the run list @dst at @loc into two and insert @new in between the two - * fragments. No merging of run lists is necessary. Adjust the size of the + * Split the runlist @dst at @loc into two and insert @new in between the two + * fragments. No merging of runlists is necessary. Adjust the size of the * holes either side. * - * It is up to the caller to serialize access to the run lists @dst and @src. + * It is up to the caller to serialize access to the runlists @dst and @src. * - * On success, return a pointer to the new, combined, run list. Note, both - * run lists @dst and @src are deallocated before returning so you cannot use - * the pointers for anything any more. (Strictly speaking the returned run list + * On success, return a pointer to the new, combined, runlist. Note, both + * runlists @dst and @src are deallocated before returning so you cannot use + * the pointers for anything any more. (Strictly speaking the returned runlist * may be the same as @dst but this is irrelevant.) * - * On error, return -errno. Both run lists are left unmodified. The following + * On error, return -errno. Both runlists are left unmodified. The following * error codes are defined: - * -ENOMEM - Not enough memory to allocate run list array. + * -ENOMEM - Not enough memory to allocate runlist array. * -EINVAL - Invalid parameters were passed in. */ -static inline run_list_element *ntfs_rl_split(run_list_element *dst, int dsize, - run_list_element *src, int ssize, int loc) +static inline runlist_element *ntfs_rl_split(runlist_element *dst, int dsize, + runlist_element *src, int ssize, int loc) { BUG_ON(!dst); BUG_ON(!src); @@ -436,7 +436,7 @@ return dst; /* * We are guaranteed to succeed from here so can start modifying the - * original run lists. + * original runlists. */ /* Move the tail of @dst out of the way, then copy in @src. */ @@ -452,17 +452,17 @@ } /** - * ntfs_merge_run_lists - merge two run_lists into one - * @drl: original run list to be worked on - * @srl: new run list to be merged into @drl + * ntfs_merge_runlists - merge two runlists into one + * @drl: original runlist to be worked on + * @srl: new runlist to be merged into @drl * - * First we sanity check the two run lists @srl and @drl to make sure that they - * are sensible and can be merged. The run list @srl must be either after the - * run list @drl or completely within a hole (or unmapped region) in @drl. + * First we sanity check the two runlists @srl and @drl to make sure that they + * are sensible and can be merged. The runlist @srl must be either after the + * runlist @drl or completely within a hole (or unmapped region) in @drl. * - * It is up to the caller to serialize access to the run lists @drl and @srl. + * It is up to the caller to serialize access to the runlists @drl and @srl. * - * Merging of run lists is necessary in two cases: + * Merging of runlists is necessary in two cases: * 1. When attribute lists are used and a further extent is being mapped. * 2. When new clusters are allocated to fill a hole or extend a file. * @@ -471,22 +471,22 @@ * - split the hole in two and be inserted between the two fragments, * - be appended at the end of a hole, or it can * - replace the whole hole. - * It can also be appended to the end of the run list, which is just a variant + * It can also be appended to the end of the runlist, which is just a variant * of the insert case. * - * On success, return a pointer to the new, combined, run list. Note, both - * run lists @drl and @srl are deallocated before returning so you cannot use - * the pointers for anything any more. (Strictly speaking the returned run list + * On success, return a pointer to the new, combined, runlist. Note, both + * runlists @drl and @srl are deallocated before returning so you cannot use + * the pointers for anything any more. (Strictly speaking the returned runlist * may be the same as @dst but this is irrelevant.) * - * On error, return -errno. Both run lists are left unmodified. The following + * On error, return -errno. Both runlists are left unmodified. The following * error codes are defined: - * -ENOMEM - Not enough memory to allocate run list array. + * -ENOMEM - Not enough memory to allocate runlist array. * -EINVAL - Invalid parameters were passed in. - * -ERANGE - The run lists overlap and cannot be merged. + * -ERANGE - The runlists overlap and cannot be merged. */ -run_list_element *ntfs_merge_run_lists(run_list_element *drl, - run_list_element *srl) +runlist_element *ntfs_merge_runlists(runlist_element *drl, + runlist_element *srl) { int di, si; /* Current index into @[ds]rl. */ int sstart; /* First index with lcn > LCN_RL_NOT_MAPPED. */ @@ -513,15 +513,15 @@ /* Check for the case where the first mapping is being done now. */ if (unlikely(!drl)) { drl = srl; - /* Complete the source run list if necessary. */ + /* Complete the source runlist if necessary. */ if (unlikely(drl[0].vcn)) { - /* Scan to the end of the source run list. */ + /* Scan to the end of the source runlist. */ for (dend = 0; likely(drl[dend].length); dend++) ; drl = ntfs_rl_realloc(drl, dend, dend + 1); if (IS_ERR(drl)) return drl; - /* Insert start element at the front of the run list. */ + /* Insert start element at the front of the runlist. */ ntfs_rl_mm(drl, 1, 0, dend); drl[0].vcn = 0; drl[0].lcn = LCN_RL_NOT_MAPPED; @@ -532,11 +532,11 @@ si = di = 0; - /* Skip any unmapped start element(s) in the source run_list. */ + /* Skip any unmapped start element(s) in the source runlist. */ while (srl[si].length && srl[si].lcn < (LCN)LCN_HOLE) si++; - /* Can't have an entirely unmapped source run list. */ + /* Can't have an entirely unmapped source runlist. */ BUG_ON(!srl[si].length); /* Record the starting points. */ @@ -560,7 +560,7 @@ return ERR_PTR(-ERANGE); } - /* Scan to the end of both run lists in order to know their sizes. */ + /* Scan to the end of both runlists in order to know their sizes. */ for (send = si; srl[send].length; send++) ; for (dend = di; drl[dend].length; dend++) @@ -631,7 +631,7 @@ goto finished; } /* - * We need to create an unmapped run list element in + * We need to create an unmapped runlist element in * @drl or extend an existing one before adding the * ENOENT terminator. */ @@ -640,7 +640,7 @@ slots = 1; } if (drl[ds].lcn != (LCN)LCN_RL_NOT_MAPPED) { - /* Add an unmapped run list element. */ + /* Add an unmapped runlist element. */ if (!slots) { /* FIXME/TODO: We need to have the * extra memory already! (AIA) */ @@ -677,7 +677,7 @@ finished: /* The merge was completed successfully. */ - ntfs_debug("Merged run list:"); + ntfs_debug("Merged runlist:"); ntfs_debug_dump_runlist(drl); return drl; @@ -688,45 +688,45 @@ } /** - * decompress_mapping_pairs - convert mapping pairs array to run list + * decompress_mapping_pairs - convert mapping pairs array to runlist * @vol: ntfs volume on which the attribute resides * @attr: attribute record whose mapping pairs array to decompress - * @old_rl: optional run list in which to insert @attr's run list + * @old_rl: optional runlist in which to insert @attr's runlist * - * It is up to the caller to serialize access to the run list @old_rl. + * It is up to the caller to serialize access to the runlist @old_rl. * - * Decompress the attribute @attr's mapping pairs array into a run list. On - * success, return the decompressed run list. + * Decompress the attribute @attr's mapping pairs array into a runlist. On + * success, return the decompressed runlist. * - * If @old_rl is not NULL, decompressed run list is inserted into the - * appropriate place in @old_rl and the resultant, combined run list is + * If @old_rl is not NULL, decompressed runlist is inserted into the + * appropriate place in @old_rl and the resultant, combined runlist is * returned. The original @old_rl is deallocated. * * On error, return -errno. @old_rl is left unmodified in that case. * * The following error codes are defined: - * -ENOMEM - Not enough memory to allocate run list array. - * -EIO - Corrupt run list. + * -ENOMEM - Not enough memory to allocate runlist array. + * -EIO - Corrupt runlist. * -EINVAL - Invalid parameters were passed in. - * -ERANGE - The two run lists overlap. + * -ERANGE - The two runlists overlap. * * FIXME: For now we take the conceptionally simplest approach of creating the - * new run list disregarding the already existing one and then splicing the + * new runlist disregarding the already existing one and then splicing the * two into one, if that is possible (we check for overlap and discard the new - * run list if overlap present before returning ERR_PTR(-ERANGE)). + * runlist if overlap present before returning ERR_PTR(-ERANGE)). */ -run_list_element *decompress_mapping_pairs(const ntfs_volume *vol, - const ATTR_RECORD *attr, run_list_element *old_rl) +runlist_element *decompress_mapping_pairs(const ntfs_volume *vol, + const ATTR_RECORD *attr, runlist_element *old_rl) { VCN vcn; /* Current vcn. */ LCN lcn; /* Current lcn. */ s64 deltaxcn; /* Change in [vl]cn. */ - run_list_element *rl; /* The output run list. */ + runlist_element *rl; /* The output runlist. */ u8 *buf; /* Current position in mapping pairs array. */ u8 *attr_end; /* End of attribute. */ - int rlsize; /* Size of run list buffer. */ - u16 rlpos; /* Current run list position in units of - run_list_elements. */ + int rlsize; /* Size of runlist buffer. */ + u16 rlpos; /* Current runlist position in units of + runlist_elements. */ u8 b; /* Current byte offset in buf. */ #ifdef DEBUG @@ -748,9 +748,9 @@ ntfs_error(vol->sb, "Corrupt attribute."); return ERR_PTR(-EIO); } - /* Current position in run list array. */ + /* Current position in runlist array. */ rlpos = 0; - /* Allocate first page and set current run list size to one page. */ + /* Allocate first page and set current runlist size to one page. */ rl = ntfs_malloc_nofs(rlsize = PAGE_SIZE); if (unlikely(!rl)) return ERR_PTR(-ENOMEM); @@ -768,7 +768,7 @@ * operates on whole pages only. */ if (((rlpos + 3) * sizeof(*old_rl)) > rlsize) { - run_list_element *rl2; + runlist_element *rl2; rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE); if (unlikely(!rl2)) { @@ -780,7 +780,7 @@ rl = rl2; rlsize += PAGE_SIZE; } - /* Enter the current vcn into the current run_list element. */ + /* Enter the current vcn into the current runlist element. */ rl[rlpos].vcn = vcn; /* * Get the change in vcn, i.e. the run length in clusters. @@ -810,7 +810,7 @@ goto err_out; } /* - * Enter the current run length into the current run list + * Enter the current run length into the current runlist * element. */ rl[rlpos].length = deltaxcn; @@ -854,10 +854,10 @@ "mapping pairs array."); goto err_out; } - /* Enter the current lcn into the run_list element. */ + /* Enter the current lcn into the runlist element. */ rl[rlpos].lcn = lcn; } - /* Get to the next run_list element. */ + /* Get to the next runlist element. */ rlpos++; /* Increment the buffer position to the next mapping pair. */ buf += (*buf & 0xf) + ((*buf >> 4) & 0xf) + 1; @@ -866,7 +866,7 @@ goto io_error; /* * If there is a highest_vcn specified, it must be equal to the final - * vcn in the run list - 1, or something has gone badly wrong. + * vcn in the runlist - 1, or something has gone badly wrong. */ deltaxcn = sle64_to_cpu(attr->data.non_resident.highest_vcn); if (unlikely(deltaxcn && vcn - 1 != deltaxcn)) { @@ -875,7 +875,7 @@ "non-resident attribute."); goto err_out; } - /* Setup not mapped run list element if this is the base extent. */ + /* Setup not mapped runlist element if this is the base extent. */ if (!attr->data.non_resident.lowest_vcn) { VCN max_cluster; @@ -885,7 +885,7 @@ vol->cluster_size_bits; /* * If there is a difference between the highest_vcn and the - * highest cluster, the run list is either corrupt or, more + * highest cluster, the runlist is either corrupt or, more * likely, there are more extents following this one. */ if (deltaxcn < --max_cluster) { @@ -908,21 +908,21 @@ } else /* Not the base extent. There may be more extents to follow. */ rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED; - /* Setup terminating run_list element. */ + /* Setup terminating runlist element. */ rl[rlpos].vcn = vcn; rl[rlpos].length = (s64)0; - /* If no existing run list was specified, we are done. */ + /* If no existing runlist was specified, we are done. */ if (!old_rl) { ntfs_debug("Mapping pairs array successfully decompressed:"); ntfs_debug_dump_runlist(rl); return rl; } - /* Now combine the new and old run lists checking for overlaps. */ - old_rl = ntfs_merge_run_lists(old_rl, rl); + /* Now combine the new and old runlists checking for overlaps. */ + old_rl = ntfs_merge_runlists(old_rl, rl); if (likely(!IS_ERR(old_rl))) return old_rl; ntfs_free(rl); - ntfs_error(vol->sb, "Failed to merge run lists."); + ntfs_error(vol->sb, "Failed to merge runlists."); return old_rl; io_error: ntfs_error(vol->sb, "Corrupt attribute."); @@ -932,22 +932,25 @@ } /** - * 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 - * @vcn: map run list part containing this vcn + * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode + * @ni: ntfs inode for which to map (part of) a runlist + * @vcn: map runlist part containing this vcn * - * Map the part of a run list containing the @vcn of an the ntfs inode @ni. + * Map the part of a runlist containing the @vcn of the ntfs inode @ni. * * Return 0 on success and -errno on error. + * + * Locking: - The runlist must be unlocked on entry and is unlocked on return. + * - This function takes the lock for writing and modifies the runlist. */ -int map_run_list(ntfs_inode *ni, VCN vcn) +int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) { ntfs_inode *base_ni; attr_search_context *ctx; MFT_RECORD *mrec; int err = 0; - ntfs_debug("Mapping run list part containing vcn 0x%llx.", + ntfs_debug("Mapping runlist part containing vcn 0x%llx.", (unsigned long long)vcn); if (!NInoAttr(ni)) @@ -970,19 +973,19 @@ goto err_out; } - down_write(&ni->run_list.lock); + down_write(&ni->runlist.lock); /* Make sure someone else didn't do the work while we were sleeping. */ - if (likely(vcn_to_lcn(ni->run_list.rl, vcn) <= LCN_RL_NOT_MAPPED)) { - run_list_element *rl; + if (likely(ntfs_vcn_to_lcn(ni->runlist.rl, vcn) <= LCN_RL_NOT_MAPPED)) { + runlist_element *rl; rl = decompress_mapping_pairs(ni->vol, ctx->attr, - ni->run_list.rl); + ni->runlist.rl); if (unlikely(IS_ERR(rl))) err = PTR_ERR(rl); else - ni->run_list.rl = rl; + ni->runlist.rl = rl; } - up_write(&ni->run_list.lock); + up_write(&ni->runlist.lock); put_attr_search_ctx(ctx); err_out: @@ -991,36 +994,35 @@ } /** - * vcn_to_lcn - convert a vcn into a lcn given a run list - * @rl: run list to use for conversion + * ntfs_vcn_to_lcn - convert a vcn into a lcn given a runlist + * @rl: runlist to use for conversion * @vcn: vcn to convert * * Convert the virtual cluster number @vcn of an attribute into a logical - * cluster number (lcn) of a device using the run list @rl to map vcns to their + * cluster number (lcn) of a device using the runlist @rl to map vcns to their * corresponding lcns. * - * It is up to the caller to serialize access to the run list @rl. + * It is up to the caller to serialize access to the runlist @rl. * * Since lcns must be >= 0, we use negative return values with special meaning: * * Return value Meaning / Description * ================================================== * -1 = LCN_HOLE Hole / not allocated on disk. - * -2 = LCN_RL_NOT_MAPPED This is part of the run list which has not been - * inserted into the run list yet. + * -2 = LCN_RL_NOT_MAPPED This is part of the runlist which has not been + * inserted into the runlist yet. * -3 = LCN_ENOENT There is no such vcn in the attribute. - * -4 = LCN_EINVAL Input parameter error (if debug enabled). + * + * Locking: - The caller must have locked the runlist (for reading or writing). + * - This function does not touch the lock. */ -LCN vcn_to_lcn(const run_list_element *rl, const VCN vcn) +LCN ntfs_vcn_to_lcn(const runlist_element *rl, const VCN vcn) { int i; -#ifdef DEBUG - if (vcn < (VCN)0) - return (LCN)LCN_EINVAL; -#endif + BUG_ON(vcn < 0); /* - * If rl is NULL, assume that we have found an unmapped run list. The + * If rl is NULL, assume that we have found an unmapped runlist. The * caller can then attempt to map it and fail appropriately if * necessary. */ @@ -1049,6 +1051,103 @@ } /** + * ntfs_find_vcn - find a vcn in the runlist described by an ntfs inode + * @ni: ntfs inode describing the runlist to search + * @vcn: vcn to find + * @need_write: if false, lock for reading and if true, lock for writing + * + * Find the virtual cluster number @vcn in the runlist described by the ntfs + * inode @ni and return the address of the runlist element containing the @vcn. + * The runlist is left locked and the caller has to unlock it. If @need_write + * is true, the runlist is locked for writing and if @need_write is false, the + * runlist is locked for reading. In the error case, the runlist is not left + * locked. + * + * Note you need to distinguish between the lcn of the returned runlist element + * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on + * read and allocate clusters on write. + * + * Return the runlist element containing the @vcn on success and + * ERR_PTR(-errno) on error. You need to test the return value with IS_ERR() + * to decide if the return is success or failure and PTR_ERR() to get to the + * error code if IS_ERR() is true. + * + * The possible error return codes are: + * -ENOENT - No such vcn in the runlist, i.e. @vcn is out of bounds. + * -ENOMEM - Not enough memory to map runlist. + * -EIO - Critical error (runlist/file is corrupt, i/o error, etc). + * + * Locking: - The runlist must be unlocked on entry. + * - On failing return, the runlist is unlocked. + * - On successful return, the runlist is locked. If @need_write us + * true, it is locked for writing. Otherwise is is locked for + * reading. + */ +runlist_element *ntfs_find_vcn(ntfs_inode *ni, const VCN vcn, + const BOOL need_write) +{ + runlist_element *rl; + int err = 0; + BOOL is_retry = FALSE; + + ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, lock for %sing.", + ni->mft_no, (unsigned long long)vcn, + !need_write ? "read" : "writ"); + BUG_ON(!ni); + BUG_ON(!NInoNonResident(ni)); + BUG_ON(vcn < 0); +lock_retry_remap: + if (!need_write) + down_read(&ni->runlist.lock); + else + down_write(&ni->runlist.lock); + rl = ni->runlist.rl; + if (likely(rl && vcn >= rl[0].vcn)) { + while (likely(rl->length)) { + if (likely(vcn < rl[1].vcn)) { + if (likely(rl->lcn >= (LCN)LCN_HOLE)) { + ntfs_debug("Done."); + return rl; + } + break; + } + rl++; + } + if (likely(rl->lcn != (LCN)LCN_RL_NOT_MAPPED)) { + if (likely(rl->lcn == (LCN)LCN_ENOENT)) + err = -ENOENT; + else + err = -EIO; + } + } + if (!need_write) + up_read(&ni->runlist.lock); + else + up_write(&ni->runlist.lock); + if (!err && !is_retry) { + /* + * The @vcn is in an unmapped region, map the runlist and + * retry. + */ + err = ntfs_map_runlist(ni, vcn); + if (likely(!err)) { + is_retry = TRUE; + goto lock_retry_remap; + } + /* + * -EINVAL and -ENOENT coming from a failed mapping attempt are + * equivalent to i/o errors for us as they should not happen in + * our code paths. + */ + if (err == -EINVAL || err == -ENOENT) + err = -EIO; + } else if (!err) + err = -EIO; + ntfs_error(ni->vol->sb, "Failed with error code %i.", err); + return ERR_PTR(err); +} + +/** * find_attr - find (next) attribute in mft record * @type: attribute type to find * @name: attribute name to find (optional, i.e. NULL means don't care) @@ -1214,12 +1313,12 @@ /** * load_attribute_list - load an attribute list into memory * @vol: ntfs volume from which to read - * @run_list: run list of the attribute list + * @runlist: runlist of the attribute list * @al_start: destination buffer * @size: size of the destination buffer in bytes * @initialized_size: initialized size of the attribute list * - * Walk the run list @run_list and load all clusters from it copying them into + * Walk the runlist @runlist and load all clusters from it copying them into * the linear buffer @al. The maximum number of bytes copied to @al is @size * bytes. Note, @size does not need to be a multiple of the cluster size. If * @initialized_size is less than @size, the region in @al between @@ -1227,13 +1326,13 @@ * * Return 0 on success or -errno on error. */ -int load_attribute_list(ntfs_volume *vol, run_list *run_list, u8 *al_start, +int load_attribute_list(ntfs_volume *vol, runlist *runlist, u8 *al_start, const s64 size, const s64 initialized_size) { LCN lcn; u8 *al = al_start; u8 *al_end = al + initialized_size; - run_list_element *rl; + runlist_element *rl; struct buffer_head *bh; struct super_block *sb; unsigned long block_size; @@ -1242,7 +1341,7 @@ unsigned char block_size_bits; ntfs_debug("Entering."); - if (!vol || !run_list || !al || size <= 0 || initialized_size < 0 || + if (!vol || !runlist || !al || size <= 0 || initialized_size < 0 || initialized_size > size) return -EINVAL; if (!initialized_size) { @@ -1252,17 +1351,17 @@ sb = vol->sb; block_size = sb->s_blocksize; block_size_bits = sb->s_blocksize_bits; - down_read(&run_list->lock); - rl = run_list->rl; - /* Read all clusters specified by the run list one run at a time. */ + down_read(&runlist->lock); + rl = runlist->rl; + /* Read all clusters specified by the runlist one run at a time. */ while (rl->length) { - lcn = vcn_to_lcn(rl, rl->vcn); + lcn = ntfs_vcn_to_lcn(rl, rl->vcn); 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 " + ntfs_error(sb, "ntfs_vcn_to_lcn() failed. Cannot read " "attribute list."); goto err_out; } @@ -1292,7 +1391,7 @@ memset(al_start + initialized_size, 0, size - initialized_size); } done: - up_read(&run_list->lock); + up_read(&runlist->lock); return err; do_final: if (al < al_end) { diff -Nru a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h --- a/fs/ntfs/attrib.h 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/attrib.h 2004-08-09 21:46:58 -07:00 @@ -30,7 +30,7 @@ #include "types.h" #include "layout.h" -static inline void init_run_list(run_list *rl) +static inline void init_runlist(runlist *rl) { rl->rl = NULL; init_rwsem(&rl->lock); @@ -40,7 +40,6 @@ LCN_HOLE = -1, /* Keep this as highest value or die! */ LCN_RL_NOT_MAPPED = -2, LCN_ENOENT = -3, - LCN_EINVAL = -4, } LCN_SPECIAL_VALUES; /** @@ -72,12 +71,15 @@ ATTR_RECORD *base_attr; } attr_search_context; -extern run_list_element *decompress_mapping_pairs(const ntfs_volume *vol, - const ATTR_RECORD *attr, run_list_element *old_rl); +extern runlist_element *decompress_mapping_pairs(const ntfs_volume *vol, + const ATTR_RECORD *attr, runlist_element *old_rl); -extern int map_run_list(ntfs_inode *ni, VCN vcn); +extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn); -extern LCN vcn_to_lcn(const run_list_element *rl, const VCN vcn); +extern LCN ntfs_vcn_to_lcn(const runlist_element *rl, const VCN vcn); + +extern runlist_element *ntfs_find_vcn(ntfs_inode *ni, const VCN vcn, + const BOOL need_write); extern BOOL find_attr(const ATTR_TYPES type, const ntfschar *name, const u32 name_len, const IGNORE_CASE_BOOL ic, const u8 *val, @@ -88,7 +90,7 @@ const VCN lowest_vcn, const u8 *val, const u32 val_len, attr_search_context *ctx); -extern int load_attribute_list(ntfs_volume *vol, run_list *rl, u8 *al_start, +extern int load_attribute_list(ntfs_volume *vol, runlist *rl, u8 *al_start, const s64 size, const s64 initialized_size); static inline s64 attribute_value_length(const ATTR_RECORD *a) diff -Nru a/fs/ntfs/bitmap.c b/fs/ntfs/bitmap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/fs/ntfs/bitmap.c 2004-08-09 21:46:59 -07:00 @@ -0,0 +1,187 @@ +/* + * bitmap.c - NTFS kernel bitmap handling. Part of the Linux-NTFS project. + * + * Copyright (c) 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 + */ + +#ifdef NTFS_RW + +#include + +#include "bitmap.h" +#include "debug.h" +#include "ntfs.h" + +/** + * __ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value + * @vi: vfs inode describing the bitmap + * @start_bit: first bit to set + * @count: number of bits to set + * @value: value to set the bits to (i.e. 0 or 1) + * @is_rollback: if TRUE this is a rollback operation + * + * Set @count bits starting at bit @start_bit in the bitmap described by the + * vfs inode @vi to @value, where @value is either 0 or 1. + * + * @is_rollback should always be FALSE, it is for internal use to rollback + * errors. You probably want to use ntfs_bitmap_set_bits_in_run() instead. + * + * Return 0 on success and -errno on error. + */ +int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit, + const s64 count, const u8 value, const BOOL is_rollback) +{ + s64 cnt = count; + pgoff_t index, end_index; + struct address_space *mapping; + struct page *page; + u8 *kaddr; + int pos, len; + u8 bit; + + BUG_ON(!vi); + ntfs_debug("Entering for i_ino 0x%lx, start_bit 0x%llx, count 0x%llx, " + "value %u.", vi->i_ino, (unsigned long long)start_bit, + (unsigned long long)cnt, (unsigned int)value); + BUG_ON(start_bit < 0); + BUG_ON(cnt < 0); + BUG_ON(value > 1); + /* + * Calculate the indices for the pages containing the first and last + * bits, i.e. @start_bit and @start_bit + @cnt - 1, respectively. + */ + index = start_bit >> (3 + PAGE_CACHE_SHIFT); + end_index = (start_bit + cnt - 1) >> (3 + PAGE_CACHE_SHIFT); + + /* Get the page containing the first bit (@start_bit). */ + mapping = vi->i_mapping; + page = ntfs_map_page(mapping, index); + if (IS_ERR(page)) { + if (!is_rollback) + ntfs_error(vi->i_sb, "Failed to map first page (error " + "%li), aborting.", PTR_ERR(page)); + return PTR_ERR(page); + } + kaddr = page_address(page); + + /* Set @pos to the position of the byte containing @start_bit. */ + pos = (start_bit >> 3) & ~PAGE_CACHE_MASK; + + /* Calculate the position of @start_bit in the first byte. */ + bit = start_bit & 7; + + /* If the first byte is partial, modify the appropriate bits in it. */ + if (bit) { + u8 *byte = kaddr + pos; + while ((bit & 7) && cnt--) { + if (value) + *byte |= 1 << bit++; + else + *byte &= ~(1 << bit++); + } + /* If we are done, unmap the page and return success. */ + if (!cnt) + goto done; + + /* Update @pos to the new position. */ + pos++; + } + /* + * Depending on @value, modify all remaining whole bytes in the page up + * to @cnt. + */ + len = min_t(s64, cnt >> 3, PAGE_CACHE_SIZE - pos); + memset(kaddr + pos, value ? 0xff : 0, len); + cnt -= len << 3; + + /* Update @len to point to the first not-done byte in the page. */ + if (cnt < 8) + len += pos; + + /* If we are not in the last page, deal with all subsequent pages. */ + while (end_index > index) { + BUG_ON(cnt <= 0); + + /* Update @index and get the next page. */ + flush_dcache_page(page); + set_page_dirty(page); + ntfs_unmap_page(page); + page = ntfs_map_page(mapping, ++index); + if (IS_ERR(page)) + goto rollback; + kaddr = page_address(page); + /* + * Depending on @value, modify all remaining whole bytes in the + * page up to @cnt. + */ + len = min_t(s64, cnt >> 3, PAGE_CACHE_SIZE); + memset(kaddr, value ? 0xff : 0, len); + cnt -= len << 3; + } + /* + * The currently mapped page is the last one. If the last byte is + * partial, modify the appropriate bits in it. Note, @len is the + * position of the last byte inside the page. + */ + if (cnt) { + u8 *byte; + + BUG_ON(cnt > 7); + + bit = cnt; + byte = kaddr + len; + while (bit--) { + if (value) + *byte |= 1 << bit; + else + *byte &= ~(1 << bit); + } + } +done: + /* We are done. Unmap the page and return success. */ + flush_dcache_page(page); + set_page_dirty(page); + ntfs_unmap_page(page); + ntfs_debug("Done."); + return 0; +rollback: + /* + * Current state: + * - no pages are mapped + * - @count - @cnt is the number of bits that have been modified + */ + if (is_rollback) + return PTR_ERR(page); + pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt, + value ? 0 : 1, TRUE); + if (!pos) { + /* Rollback was successful. */ + ntfs_error(vi->i_sb, "Failed to map subsequent page (error " + "%li), aborting.", PTR_ERR(page)); + } else { + /* Rollback failed. */ + ntfs_error(vi->i_sb, "Failed to map subsequent page (error " + "%li) and rollback failed (error %i). " + "Aborting and leaving inconsistent metadata. " + "Unmount and run chkdsk.", PTR_ERR(page), pos); + NVolSetErrors(NTFS_SB(vi->i_sb)); + } + return PTR_ERR(page); +} + +#endif /* NTFS_RW */ diff -Nru a/fs/ntfs/bitmap.h b/fs/ntfs/bitmap.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/fs/ntfs/bitmap.h 2004-08-09 21:46:59 -07:00 @@ -0,0 +1,118 @@ +/* + * bitmap.h - Defines for NTFS kernel bitmap handling. Part of the Linux-NTFS + * project. + * + * Copyright (c) 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_BITMAP_H +#define _LINUX_NTFS_BITMAP_H + +#ifdef NTFS_RW + +#include + +#include "types.h" + +extern int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit, + const s64 count, const u8 value, const BOOL is_rollback); + +/** + * ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value + * @vi: vfs inode describing the bitmap + * @start_bit: first bit to set + * @count: number of bits to set + * @value: value to set the bits to (i.e. 0 or 1) + * + * Set @count bits starting at bit @start_bit in the bitmap described by the + * vfs inode @vi to @value, where @value is either 0 or 1. + * + * Return 0 on success and -errno on error. + */ +static inline int ntfs_bitmap_set_bits_in_run(struct inode *vi, + const s64 start_bit, const s64 count, const u8 value) +{ + return __ntfs_bitmap_set_bits_in_run(vi, start_bit, count, value, + FALSE); +} + +/** + * ntfs_bitmap_set_run - set a run of bits in a bitmap + * @vi: vfs inode describing the bitmap + * @start_bit: first bit to set + * @count: number of bits to set + * + * Set @count bits starting at bit @start_bit in the bitmap described by the + * vfs inode @vi. + * + * Return 0 on success and -errno on error. + */ +static inline int ntfs_bitmap_set_run(struct inode *vi, const s64 start_bit, + const s64 count) +{ + return ntfs_bitmap_set_bits_in_run(vi, start_bit, count, 1); +} + +/** + * ntfs_bitmap_clear_run - clear a run of bits in a bitmap + * @vi: vfs inode describing the bitmap + * @start_bit: first bit to clear + * @count: number of bits to clear + * + * Clear @count bits starting at bit @start_bit in the bitmap described by the + * vfs inode @vi. + * + * Return 0 on success and -errno on error. + */ +static inline int ntfs_bitmap_clear_run(struct inode *vi, const s64 start_bit, + const s64 count) +{ + return ntfs_bitmap_set_bits_in_run(vi, start_bit, count, 0); +} + +/** + * ntfs_bitmap_set_bit - set a bit in a bitmap + * @vi: vfs inode describing the bitmap + * @bit: bit to set + * + * Set bit @bit in the bitmap described by the vfs inode @vi. + * + * Return 0 on success and -errno on error. + */ +static inline int ntfs_bitmap_set_bit(struct inode *vi, const s64 bit) +{ + return ntfs_bitmap_set_run(vi, bit, 1); +} + +/** + * ntfs_bitmap_clear_bit - clear a bit in a bitmap + * @vi: vfs inode describing the bitmap + * @bit: bit to clear + * + * Clear bit @bit in the bitmap described by the vfs inode @vi. + * + * Return 0 on success and -errno on error. + */ +static inline int ntfs_bitmap_clear_bit(struct inode *vi, const s64 bit) +{ + return ntfs_bitmap_clear_run(vi, bit, 1); +} + +#endif /* NTFS_RW */ + +#endif /* defined _LINUX_NTFS_BITMAP_H */ diff -Nru a/fs/ntfs/compress.c b/fs/ntfs/compress.c --- a/fs/ntfs/compress.c 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/compress.c 2004-08-09 21:46:58 -07:00 @@ -478,7 +478,7 @@ ntfs_inode *ni = NTFS_I(mapping->host); ntfs_volume *vol = ni->vol; struct super_block *sb = vol->sb; - run_list_element *rl; + runlist_element *rl; unsigned long block_size = sb->s_blocksize; unsigned char block_size_bits = sb->s_blocksize_bits; u8 *cb, *cb_pos, *cb_end; @@ -575,7 +575,7 @@ } /* - * We have the run list, and all the destination pages we need to fill. + * We have the runlist, and all the destination pages we need to fill. * Now read the first compression block. */ cur_page = 0; @@ -593,14 +593,14 @@ if (!rl) { lock_retry_remap: - down_read(&ni->run_list.lock); - rl = ni->run_list.rl; + down_read(&ni->runlist.lock); + rl = ni->runlist.rl; } if (likely(rl != NULL)) { /* Seek to element containing target vcn. */ while (rl->length && rl[1].vcn <= vcn) rl++; - lcn = vcn_to_lcn(rl, vcn); + lcn = ntfs_vcn_to_lcn(rl, vcn); } else lcn = (LCN)LCN_RL_NOT_MAPPED; ntfs_debug("Reading vcn = 0x%llx, lcn = 0x%llx.", @@ -617,11 +617,11 @@ goto rl_err; is_retry = TRUE; /* - * Attempt to map run list, dropping lock for the + * Attempt to map runlist, dropping lock for the * duration. */ - up_read(&ni->run_list.lock); - if (!map_run_list(ni, vcn)) + up_read(&ni->runlist.lock); + if (!ntfs_map_runlist(ni, vcn)) goto lock_retry_remap; goto map_rl_err; } @@ -638,7 +638,7 @@ /* Release the lock if we took it. */ if (rl) - up_read(&ni->run_list.lock); + up_read(&ni->runlist.lock); /* Setup and initiate io on all buffer heads. */ for (i = 0; i < nr_bhs; i++) { @@ -920,18 +920,18 @@ goto err_out; map_rl_err: - ntfs_error(vol->sb, "map_run_list() failed. Cannot read compression " - "block."); + ntfs_error(vol->sb, "ntfs_map_runlist() failed. Cannot read " + "compression block."); goto err_out; rl_err: - up_read(&ni->run_list.lock); - ntfs_error(vol->sb, "vcn_to_lcn() failed. Cannot read compression " - "block."); + up_read(&ni->runlist.lock); + ntfs_error(vol->sb, "ntfs_vcn_to_lcn() failed. Cannot read " + "compression block."); goto err_out; getblk_err: - up_read(&ni->run_list.lock); + up_read(&ni->runlist.lock); ntfs_error(vol->sb, "getblk() failed. Cannot read compression block."); err_out: diff -Nru a/fs/ntfs/debug.c b/fs/ntfs/debug.c --- a/fs/ntfs/debug.c 2004-08-09 21:46:59 -07:00 +++ b/fs/ntfs/debug.c 2004-08-09 21:46:59 -07:00 @@ -132,17 +132,16 @@ spin_unlock(&err_buf_lock); } -/* Dump a run list. Caller has to provide synchronisation for @rl. */ -void ntfs_debug_dump_runlist(const run_list_element *rl) +/* Dump a runlist. Caller has to provide synchronisation for @rl. */ +void ntfs_debug_dump_runlist(const runlist_element *rl) { int i; const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED", - "LCN_ENOENT ", "LCN_EINVAL ", - "LCN_unknown " }; + "LCN_ENOENT ", "LCN_unknown " }; if (!debug_msgs) return; - printk(KERN_DEBUG "NTFS-fs DEBUG: Dumping run list (values " + printk(KERN_DEBUG "NTFS-fs DEBUG: Dumping runlist (values " "in hex):\n"); if (!rl) { printk(KERN_DEBUG "Run list not present.\n"); @@ -155,17 +154,17 @@ if (lcn < (LCN)0) { int index = -lcn - 1; - if (index > -LCN_EINVAL - 1) + if (index > -LCN_ENOENT - 1) index = 4; printk(KERN_DEBUG "%-16Lx %s %-16Lx%s\n", (rl + i)->vcn, lcn_str[index], (rl + i)->length, (rl + i)->length ? - "" : " (run list end)"); + "" : " (runlist end)"); } else printk(KERN_DEBUG "%-16Lx %-16Lx %-16Lx%s\n", (rl + i)->vcn, (rl + i)->lcn, (rl + i)->length, (rl + i)->length ? - "" : " (run list end)"); + "" : " (runlist end)"); if (!(rl + i)->length) break; } diff -Nru a/fs/ntfs/debug.h b/fs/ntfs/debug.h --- a/fs/ntfs/debug.h 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/debug.h 2004-08-09 21:46:58 -07:00 @@ -51,7 +51,7 @@ #define ntfs_debug(f, a...) \ __ntfs_debug(__FILE__, __LINE__, __FUNCTION__, f, ##a) -extern void ntfs_debug_dump_runlist(const run_list_element *rl); +extern void ntfs_debug_dump_runlist(const runlist_element *rl); #else /* !DEBUG */ diff -Nru a/fs/ntfs/dir.c b/fs/ntfs/dir.c --- a/fs/ntfs/dir.c 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/dir.c 2004-08-09 21:46:58 -07:00 @@ -1495,10 +1495,69 @@ return 0; } +#ifdef NTFS_RW + +/** + * ntfs_dir_fsync - sync a directory to disk + * @filp: directory to be synced + * @dentry: dentry describing the directory to sync + * @datasync: if non-zero only flush user data and not metadata + * + * Data integrity sync of a directory to disk. Used for fsync, fdatasync, and + * msync system calls. This function is based on file.c::ntfs_file_fsync(). + * + * Write the mft record and all associated extent mft records as well as the + * $INDEX_ALLOCATION and $BITMAP attributes and then sync the block device. + * + * If @datasync is true, we do not wait on the inode(s) to be written out + * but we always wait on the page cache pages to be written out. + * + * Note: In the past @filp could be NULL so we ignore it as we don't need it + * anyway. + * + * Locking: Caller must hold i_sem on the inode. + * + * TODO: We should probably also write all attribute/index inodes associated + * with this inode but since we have no simple way of getting to them we ignore + * this problem for now. We do write the $BITMAP attribute if it is present + * which is the important one for a directory so things are not too bad. + */ +static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry, + int datasync) +{ + struct inode *vi = dentry->d_inode; + ntfs_inode *ni = NTFS_I(vi); + int err, ret; + + ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); + BUG_ON(!S_ISDIR(vi->i_mode)); + if (NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino) + write_inode_now(ni->itype.index.bmp_ino, !datasync); + ret = ntfs_write_inode(vi, 1); + write_inode_now(vi, !datasync); + err = sync_blockdev(vi->i_sb->s_bdev); + if (unlikely(err && !ret)) + ret = err; + if (likely(!ret)) + ntfs_debug("Done."); + else + ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " + "%u.", datasync ? "data" : "", vi->i_ino, -ret); + return ret; +} + +#endif /* NTFS_RW */ + struct file_operations ntfs_dir_ops = { .llseek = generic_file_llseek, /* Seek inside directory. */ .read = generic_read_dir, /* Return -EISDIR. */ .readdir = ntfs_readdir, /* Read directory contents. */ +#ifdef NTFS_RW + .fsync = ntfs_dir_fsync, /* Sync a directory to disk. */ + /*.aio_fsync = ,*/ /* Sync all outstanding async + i/o operations on a kiocb. */ +#endif /* NTFS_RW */ + /*.ioctl = ,*/ /* Perform function on the + mounted filesystem. */ .open = ntfs_dir_open, /* Open directory. */ }; - diff -Nru a/fs/ntfs/file.c b/fs/ntfs/file.c --- a/fs/ntfs/file.c 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/file.c 2004-08-09 21:46:58 -07:00 @@ -48,26 +48,101 @@ return generic_file_open(vi, filp); } +#ifdef NTFS_RW + +/** + * ntfs_file_fsync - sync a file to disk + * @filp: file to be synced + * @dentry: dentry describing the file to sync + * @datasync: if non-zero only flush user data and not metadata + * + * Data integrity sync of a file to disk. Used for fsync, fdatasync, and msync + * system calls. This function is inspired by fs/buffer.c::file_fsync(). + * + * If @datasync is false, write the mft record and all associated extent mft + * records as well as the $DATA attribute and then sync the block device. + * + * If @datasync is true and the attribute is non-resident, we skip the writing + * of the mft record and all associated extent mft records (this might still + * happen due to the write_inode_now() call). + * + * Also, if @datasync is true, we do not wait on the inode to be written out + * but we always wait on the page cache pages to be written out. + * + * Note: In the past @filp could be NULL so we ignore it as we don't need it + * anyway. + * + * Locking: Caller must hold i_sem on the inode. + * + * TODO: We should probably also write all attribute/index inodes associated + * with this inode but since we have no simple way of getting to them we ignore + * this problem for now. + */ +static int ntfs_file_fsync(struct file *filp, struct dentry *dentry, + int datasync) +{ + struct inode *vi = dentry->d_inode; + int err, ret = 0; + + ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); + BUG_ON(S_ISDIR(vi->i_mode)); + if (!datasync || !NInoNonResident(NTFS_I(vi))) + ret = ntfs_write_inode(vi, 1); + write_inode_now(vi, !datasync); + err = sync_blockdev(vi->i_sb->s_bdev); + if (unlikely(err && !ret)) + ret = err; + if (likely(!ret)) + ntfs_debug("Done."); + else + ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " + "%u.", datasync ? "data" : "", vi->i_ino, -ret); + return ret; +} + +#endif /* NTFS_RW */ + struct file_operations ntfs_file_ops = { - .llseek = generic_file_llseek, /* Seek inside file. */ - .read = generic_file_read, /* Read from file. */ + .llseek = generic_file_llseek, /* Seek inside file. */ + .read = generic_file_read, /* Read from file. */ + .aio_read = generic_file_aio_read, /* Async read from file. */ + .readv = generic_file_readv, /* Read from file. */ #ifdef NTFS_RW - .write = generic_file_write, /* Write to a file. */ -#endif - .mmap = generic_file_mmap, /* Mmap file. */ - .sendfile = generic_file_sendfile,/* Zero-copy data send with the - data source being on the - ntfs partition. We don't - need to care about the data - destination. */ - .open = ntfs_file_open, /* Open file. */ + .write = generic_file_write, /* Write to file. */ + .aio_write = generic_file_aio_write, /* Async write to file. */ + .writev = generic_file_writev, /* Write to file. */ + /*.release = ,*/ /* Last file is closed. See + fs/ext2/file.c:: + ext2_release_file() for + how to use this to discard + preallocated space for + write opened files. */ + .fsync = ntfs_file_fsync, /* Sync a file to disk. */ + /*.aio_fsync = ,*/ /* Sync all outstanding async + i/o operations on a + kiocb. */ +#endif /* NTFS_RW */ + /*.ioctl = ,*/ /* Perform function on the + mounted filesystem. */ + .mmap = generic_file_mmap, /* Mmap file. */ + .open = ntfs_file_open, /* Open file. */ + .sendfile = generic_file_sendfile, /* Zero-copy data send with + the data source being on + the ntfs partition. We + do not need to care about + the data destination. */ + /*.sendpage = ,*/ /* Zero-copy data send with + the data destination being + on the ntfs partition. We + do not need to care about + the data source. */ }; struct inode_operations ntfs_file_inode_ops = { #ifdef NTFS_RW .truncate = ntfs_truncate, .setattr = ntfs_setattr, -#endif +#endif /* NTFS_RW */ }; struct file_operations ntfs_empty_file_ops = {}; diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c --- a/fs/ntfs/inode.c 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/inode.c 2004-08-09 21:46:58 -07:00 @@ -372,13 +372,13 @@ ni->seq_no = 0; atomic_set(&ni->count, 1); ni->vol = NTFS_SB(sb); - init_run_list(&ni->run_list); + init_runlist(&ni->runlist); init_MUTEX(&ni->mrec_lock); ni->page = NULL; ni->page_ofs = 0; ni->attr_list_size = 0; ni->attr_list = NULL; - init_run_list(&ni->attr_list_rl); + init_runlist(&ni->attr_list_rl); ni->itype.index.bmp_ino = NULL; ni->itype.index.block_size = 0; ni->itype.index.vcn_size = 0; @@ -622,7 +622,7 @@ si = (STANDARD_INFORMATION*)((char*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset)); - /* Transfer information from the standard information into vfs_ino. */ + /* Transfer information from the standard information into vi. */ /* * Note: The i_?times do not quite map perfectly onto the NTFS times, * but they are close enough, and in the end it doesn't really matter @@ -680,7 +680,7 @@ goto unm_err_out; } /* - * Setup the run list. No need for locking as we have + * Setup the runlist. No need for locking as we have * exclusive access to the inode at this time. */ ni->attr_list_rl.rl = decompress_mapping_pairs(vol, @@ -1628,7 +1628,7 @@ * We solve these problems by starting with the $DATA attribute before anything * else and iterating using lookup_attr($DATA) over all extents. As each extent * is found, we decompress_mapping_pairs() including the implied - * merge_run_lists(). Each step of the iteration necessarily provides + * merge_runlists(). Each step of the iteration necessarily provides * sufficient information for the next step to complete. * * This should work but there are two possible pit falls (see inline comments @@ -1757,7 +1757,7 @@ "You should run chkdsk."); goto put_err_out; } - /* Setup the run list. */ + /* Setup the runlist. */ ni->attr_list_rl.rl = decompress_mapping_pairs(vol, ctx->attr, NULL); if (IS_ERR(ni->attr_list_rl.rl)) { @@ -1861,7 +1861,7 @@ attr = NULL; next_vcn = last_vcn = highest_vcn = 0; while (lookup_attr(AT_DATA, NULL, 0, 0, next_vcn, NULL, 0, ctx)) { - run_list_element *nrl; + runlist_element *nrl; /* Cache the current attribute. */ attr = ctx->attr; @@ -1885,18 +1885,18 @@ } /* * Decompress the mapping pairs array of this extent and merge - * the result into the existing run list. No need for locking + * the result into the existing runlist. No need for locking * as we have exclusive access to the inode at this time and we * are a mount in progress task, too. */ - nrl = decompress_mapping_pairs(vol, attr, ni->run_list.rl); + nrl = decompress_mapping_pairs(vol, attr, ni->runlist.rl); if (IS_ERR(nrl)) { ntfs_error(sb, "decompress_mapping_pairs() failed with " "error code %ld. $MFT is corrupt.", PTR_ERR(nrl)); goto put_err_out; } - ni->run_list.rl = nrl; + ni->runlist.rl = nrl; /* Are we in the first extent? */ if (!next_vcn) { @@ -1932,7 +1932,7 @@ } vol->nr_mft_records = ll; /* - * We have got the first extent of the run_list for + * We have got the first extent of the runlist for * $MFT which means it is now relatively safe to call * the normal ntfs_read_inode() function. * Complete reading the inode, this will actually @@ -2001,7 +2001,7 @@ goto put_err_out; } if (highest_vcn && highest_vcn != last_vcn - 1) { - ntfs_error(sb, "Failed to load the complete run list " + ntfs_error(sb, "Failed to load the complete runlist " "for $MFT/$DATA. Driver bug or " "corrupt $MFT. Run chkdsk."); ntfs_debug("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx", @@ -2073,12 +2073,12 @@ void __ntfs_clear_inode(ntfs_inode *ni) { /* Free all alocated memory. */ - down_write(&ni->run_list.lock); - if (ni->run_list.rl) { - ntfs_free(ni->run_list.rl); - ni->run_list.rl = NULL; + down_write(&ni->runlist.lock); + if (ni->runlist.rl) { + ntfs_free(ni->runlist.rl); + ni->runlist.rl = NULL; } - up_write(&ni->run_list.lock); + up_write(&ni->runlist.lock); if (ni->attr_list) { ntfs_free(ni->attr_list); @@ -2314,25 +2314,30 @@ * marking the page (and in this case mft record) dirty but we do not implement * this yet as write_mft_record() largely ignores the @sync parameter and * always performs synchronous writes. + * + * Return 0 on success and -errno on error. */ -void ntfs_write_inode(struct inode *vi, int sync) +int ntfs_write_inode(struct inode *vi, int sync) { + s64 nt; ntfs_inode *ni = NTFS_I(vi); -#if 0 attr_search_context *ctx; -#endif MFT_RECORD *m; + STANDARD_INFORMATION *si; int err = 0; + BOOL modified = FALSE; ntfs_debug("Entering for %sinode 0x%lx.", NInoAttr(ni) ? "attr " : "", vi->i_ino); /* * Dirty attribute inodes are written via their real inodes so just - * clean them here. TODO: Take care of access time updates. + * clean them here. Access time updates are taken care off when the + * real inode is written. */ if (NInoAttr(ni)) { NInoClearDirty(ni); - return; + ntfs_debug("Done."); + return 0; } /* Map, pin, and lock the mft record belonging to the inode. */ m = map_mft_record(ni); @@ -2340,8 +2345,7 @@ err = PTR_ERR(m); goto err_out; } -#if 0 - /* Obtain the standard information attribute. */ + /* Update the access times in the standard information attribute. */ ctx = get_attr_search_ctx(ni, m); if (unlikely(!ctx)) { err = -ENOMEM; @@ -2353,28 +2357,50 @@ err = -ENOENT; goto unm_err_out; } - // TODO: Update the access times in the standard information attribute - // which is now in ctx->attr. - // - Probably want to have use sops->dirty_inode() to set a flag that - // we need to update the times here rather than having to blindly do - // it every time. Or even don't do it here at all and do it in - // sops->dirty_inode() instead. Problem with this would be that - // sops->dirty_inode() must be atomic under certain circumstances - // and mapping mft records and such like is not atomic. - // - For atime updates also need to check whether they are enabled in - // the superblock flags. - ntfs_warning(vi->i_sb, "Access time updates not implement yet."); + si = (STANDARD_INFORMATION*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->data.resident.value_offset)); + /* Update the access times if they have changed. */ + nt = utc2ntfs(vi->i_mtime); + if (si->last_data_change_time != nt) { + ntfs_debug("Updating mtime for inode 0x%lx: old = 0x%llx, " + "new = 0x%llx", vi->i_ino, + sle64_to_cpu(si->last_data_change_time), + sle64_to_cpu(nt)); + si->last_data_change_time = nt; + modified = TRUE; + } + nt = utc2ntfs(vi->i_ctime); + if (si->last_mft_change_time != nt) { + ntfs_debug("Updating ctime for inode 0x%lx: old = 0x%llx, " + "new = 0x%llx", vi->i_ino, + sle64_to_cpu(si->last_mft_change_time), + sle64_to_cpu(nt)); + si->last_mft_change_time = nt; + modified = TRUE; + } + nt = utc2ntfs(vi->i_atime); + if (si->last_access_time != nt) { + ntfs_debug("Updating atime for inode 0x%lx: old = 0x%llx, " + "new = 0x%llx", vi->i_ino, + sle64_to_cpu(si->last_access_time), + sle64_to_cpu(nt)); + si->last_access_time = nt; + modified = TRUE; + } /* - * We just modified the mft record containing the standard information - * attribute. So need to mark the mft record dirty, too, but we do it - * manually so that mark_inode_dirty() is not called again. - * TODO: Only do this if there was a change in any of the times! + * If we just modified the standard information attribute we need to + * mark the mft record it is in dirty. We do this manually so that + * mark_inode_dirty() is not called which would redirty the inode and + * hence result in an infinite loop of trying to write the inode. + * There is no need to mark the base inode nor the base mft record + * dirty, since we are going to write this mft record below in any case + * and the base mft record may actually not have been modified so it + * might not need to be written out. */ - if (!NInoTestSetDirty(ctx->ntfs_ino)) + if (modified && !NInoTestSetDirty(ctx->ntfs_ino)) __set_page_dirty_nobuffers(ctx->ntfs_ino->page); put_attr_search_ctx(ctx); -#endif - /* Write this base mft record. */ + /* 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. */ @@ -2410,11 +2436,9 @@ if (unlikely(err)) goto err_out; ntfs_debug("Done."); - return; -#if 0 + return 0; unm_err_out: unmap_mft_record(ni); -#endif err_out: if (err == -ENOMEM) { ntfs_warning(vi->i_sb, "Not enough memory to write inode. " @@ -2426,7 +2450,31 @@ "as bad. You should run chkdsk.", -err); make_bad_inode(vi); } - return; + return err; +} + +/** + * ntfs_write_inode_vfs - write out a dirty inode + * @vi: inode to write out + * @sync: if true, write out synchronously + * + * Write out a dirty inode to disk including any extent inodes if present. + * + * If @sync is true, commit the inode to disk and wait for io completion. This + * is done using write_mft_record(). + * + * If @sync is false, just schedule the write to happen but do not wait for i/o + * completion. In 2.6 kernels, scheduling usually happens just by virtue of + * marking the page (and in this case mft record) dirty but we do not implement + * this yet as write_mft_record() largely ignores the @sync parameter and + * always performs synchronous writes. + * + * This functions does not have a return value which is the required behaviour + * for the VFS super_operations ->dirty_inode function. + */ +void ntfs_write_inode_vfs(struct inode *vi, int sync) +{ + ntfs_write_inode(vi, sync); } #endif /* NTFS_RW */ diff -Nru a/fs/ntfs/inode.h b/fs/ntfs/inode.h --- a/fs/ntfs/inode.h 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/inode.h 2004-08-09 21:46:58 -07:00 @@ -56,18 +56,18 @@ ATTR_TYPES type; /* Attribute type of this fake inode. */ ntfschar *name; /* Attribute name of this fake inode. */ u32 name_len; /* Attribute name length of this fake inode. */ - run_list run_list; /* If state has the NI_NonResident bit set, - the run list of the unnamed data attribute + runlist runlist; /* If state has the NI_NonResident bit set, + the runlist of the unnamed data attribute (if a file) or of the index allocation attribute (directory) or of the attribute described by the fake inode (if NInoAttr()). - If run_list.rl is NULL, the run list has not + If runlist.rl is NULL, the runlist has not been read in yet or has been unmapped. If NI_NonResident is clear, the attribute is resident (file and fake inode) or there is no $I30 index allocation attribute (small directory). In the latter case - run_list.rl is always NULL.*/ + runlist.rl is always NULL.*/ /* * The following fields are only valid for real inodes and extent * inodes. @@ -88,7 +88,7 @@ */ u32 attr_list_size; /* Length of attribute list value in bytes. */ u8 *attr_list; /* Attribute list value itself. */ - run_list attr_list_rl; /* Run list for the attribute list value. */ + runlist attr_list_rl; /* Run list for the attribute list value. */ union { struct { /* It is a directory, $MFT, or an index inode. */ struct inode *bmp_ino; /* Attribute inode for the @@ -285,7 +285,8 @@ extern int ntfs_setattr(struct dentry *dentry, struct iattr *attr); -extern void ntfs_write_inode(struct inode *vi, int sync); +extern int ntfs_write_inode(struct inode *vi, int sync); +extern void ntfs_write_inode_vfs(struct inode *vi, int sync); static inline void ntfs_commit_inode(struct inode *vi) { diff -Nru a/fs/ntfs/layout.h b/fs/ntfs/layout.h --- a/fs/ntfs/layout.h 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/layout.h 2004-08-09 21:46:58 -07:00 @@ -545,7 +545,7 @@ * can be stored: * * 1) The data in the block is all zero (a sparse block): - * This is stored as a sparse block in the run list, i.e. the run list + * This is stored as a sparse block in the runlist, i.e. the runlist * entry has length = X and lcn = -1. The mapping pairs array actually * uses a delta_lcn value length of 0, i.e. delta_lcn is not present at * all, which is then interpreted by the driver as lcn = -1. @@ -558,7 +558,7 @@ * in clusters. I.e. if compression has a small effect so that the * compressed data still occupies X clusters, then the uncompressed data * is stored in the block. - * This case is recognised by the fact that the run list entry has + * This case is recognised by the fact that the runlist entry has * length = X and lcn >= 0. The mapping pairs array stores this as * normal with a run length of X and some specific delta_lcn, i.e. * delta_lcn has to be present. @@ -567,7 +567,7 @@ * The common case. This case is recognised by the fact that the run * list entry has length L < X and lcn >= 0. The mapping pairs array * stores this as normal with a run length of X and some specific - * delta_lcn, i.e. delta_lcn has to be present. This run list entry is + * delta_lcn, i.e. delta_lcn has to be present. This runlist entry is * immediately followed by a sparse entry with length = X - L and * lcn = -1. The latter entry is to make up the vcn counting to the * full compression block size X. @@ -575,15 +575,15 @@ * In fact, life is more complicated because adjacent entries of the same type * can be coalesced. This means that one has to keep track of the number of * clusters handled and work on a basis of X clusters at a time being one - * block. An example: if length L > X this means that this particular run list + * block. An example: if length L > X this means that this particular runlist * entry contains a block of length X and part of one or more blocks of length * L - X. Another example: if length L < X, this does not necessarily mean that * the block is compressed as it might be that the lcn changes inside the block - * and hence the following run list entry describes the continuation of the + * and hence the following runlist entry describes the continuation of the * potentially compressed block. The block would be compressed if the - * following run list entry describes at least X - L sparse clusters, thus + * following runlist entry describes at least X - L sparse clusters, thus * making up the compression block length as described in point 3 above. (Of - * course, there can be several run list entries with small lengths so that the + * course, there can be several runlist entries with small lengths so that the * sparse entry does not follow the first data containing entry with * length < X.) * diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c --- a/fs/ntfs/super.c 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/super.c 2004-08-09 21:46:58 -07:00 @@ -409,7 +409,7 @@ #ifndef NTFS_RW /* For read-only compiled driver, enforce all read-only flags. */ *flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; -#else /* ! NTFS_RW */ +#else /* NTFS_RW */ /* * For the read-write compiled driver, if we are remounting read-write, * make sure there are no volume errors and that no unsupported volume @@ -479,28 +479,7 @@ "flags. Run chkdsk."); } } - // TODO: For now we enforce no atime and dir atime updates as they are - // not implemented. - if ((sb->s_flags & MS_NOATIME) && !(*flags & MS_NOATIME)) - ntfs_warning(sb, "Atime updates are not implemented yet. " - "Leaving them disabled."); - else if ((sb->s_flags & MS_NODIRATIME) && !(*flags & MS_NODIRATIME)) - ntfs_warning(sb, "Directory atime updates are not implemented " - "yet. Leaving them disabled."); - *flags |= MS_NOATIME | MS_NODIRATIME; -#endif /* ! NTFS_RW */ - - // FIXME/TODO: If left like this we will have problems with rw->ro and - // ro->rw, as well as with sync->async and vice versa remounts. - // Note: The VFS already checks that there are no pending deletes and - // no open files for writing. So we only need to worry about dirty - // inode pages and dirty system files (which include dirty inodes). - // Either handle by flushing the whole volume NOW or by having the - // write routines work on MS_RDONLY fs and guarantee we don't mark - // anything as dirty if MS_RDONLY is set. That way the dirty data - // would get flushed but no new dirty data would appear. This is - // probably best but we need to be careful not to mark anything dirty - // or the MS_RDONLY will be leaking writes. +#endif /* NTFS_RW */ // TODO: Deal with *flags. @@ -934,7 +913,7 @@ ntfs_inode *mirr_ni; struct page *mft_page, *mirr_page; u8 *kmft, *kmirr; - run_list_element *rl, rl2[2]; + runlist_element *rl, rl2[2]; int mrecs_per_page, i; ntfs_debug("Entering."); @@ -1007,7 +986,7 @@ ntfs_unmap_page(mft_page); ntfs_unmap_page(mirr_page); - /* Construct the mft mirror run list by hand. */ + /* Construct the mft mirror runlist by hand. */ rl2[0].vcn = 0; rl2[0].lcn = vol->mftmirr_lcn; rl2[0].length = (vol->mftmirr_size * vol->mft_record_size + @@ -1017,23 +996,23 @@ 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. + * mapped the full runlist 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. */ + down_read(&mirr_ni->runlist.lock); + rl = mirr_ni->runlist.rl; + /* Compare the two runlists. 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); + up_read(&mirr_ni->runlist.lock); return FALSE; } } while (rl2[i++].length); - up_read(&mirr_ni->run_list.lock); + up_read(&mirr_ni->runlist.lock); ntfs_debug("Done."); return TRUE; } @@ -2050,7 +2029,7 @@ #ifdef NTFS_RW //.dirty_inode = NULL, /* VFS: Called from // __mark_inode_dirty(). */ - .write_inode = ntfs_write_inode, /* VFS: Write dirty inode to + .write_inode = ntfs_write_inode_vfs, /* VFS: Write dirty inode to disk. */ //.drop_inode = NULL, /* VFS: Called just after the // inode reference count has @@ -2139,15 +2118,7 @@ ntfs_debug("Entering."); #ifndef NTFS_RW sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; -#else - if (!(sb->s_flags & MS_NOATIME)) - ntfs_warning(sb, "Atime updates are not implemented yet. " - "Disabling them."); - else if (!(sb->s_flags & MS_NODIRATIME)) - ntfs_warning(sb, "Directory atime updates are not implemented " - "yet. Disabling them."); - sb->s_flags |= MS_NOATIME | MS_NODIRATIME; -#endif +#endif /* ! NTFS_RW */ /* Allocate a new ntfs_volume and place it in sb->s_fs_info. */ sb->s_fs_info = kmalloc(sizeof(ntfs_volume), GFP_NOFS); vol = NTFS_SB(sb); diff -Nru a/fs/ntfs/types.h b/fs/ntfs/types.h --- a/fs/ntfs/types.h 2004-08-09 21:46:58 -07:00 +++ b/fs/ntfs/types.h 2004-08-09 21:46:58 -07:00 @@ -42,7 +42,7 @@ typedef s64 LSN; /** - * run_list_element - in memory vcn to lcn mapping array element + * runlist_element - in memory vcn to lcn mapping array element * @vcn: starting vcn of the current array element * @lcn: starting lcn of the current array element * @length: length in clusters of the current array element @@ -56,18 +56,18 @@ VCN vcn; /* vcn = Starting virtual cluster number. */ LCN lcn; /* lcn = Starting logical cluster number. */ s64 length; /* Run length in clusters. */ -} run_list_element; +} runlist_element; /** - * run_list - in memory vcn to lcn mapping array including a read/write lock - * @rl: pointer to an array of run list elements + * runlist - in memory vcn to lcn mapping array including a read/write lock + * @rl: pointer to an array of runlist elements * @lock: read/write spinlock for serializing access to @rl * */ typedef struct { - run_list_element *rl; + runlist_element *rl; struct rw_semaphore lock; -} run_list; +} runlist; typedef enum { FALSE = 0,