Commit a1a051b1 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs-2.6:
  NTFS: 2.1.27 - Various bug fixes and cleanups.
  NTFS: Semaphore to mutex conversion.
  NTFS: Handle the recently introduced -ENAMETOOLONG return value from
  NTFS: Add a missing call to flush_dcache_mft_record_page() in
  NTFS: Fix a bug in fs/ntfs/inode.c::ntfs_read_locked_index_inode() where we
  NTFS: Improve comments on file attribute flags in fs/ntfs/layout.h.
  NTFS: Limit name length in fs/ntfs/unistr.c::ntfs_nlstoucs() to maximum
  NTFS: Remove all the make_bad_inode() calls.  This should only be called
  NTFS: Add support for sparse files which have a compression unit of 0.
  NTFS: Fix comparison of $MFT and $MFTMirr to not bail out when there are
  NTFS: Use buffer_migrate_page() for the ->migratepage function of all ntfs
  NTFS: Fix a buggette in an "should be impossible" case handling where we
  NTFS: Fix an (innocent) off-by-one error in the runlist code.
  NTFS: Fix two compiler warnings on Alpha.  Thanks to Andrew Morton for
parents aca361c1 b425c8c5
...@@ -457,6 +457,11 @@ ChangeLog ...@@ -457,6 +457,11 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.1.27:
- Implement page migration support so the kernel can move memory used
by NTFS files and directories around for management purposes.
- Add support for writing to sparse files created with Windows XP SP2.
- Many minor improvements and bug fixes.
2.1.26: 2.1.26:
- Implement support for sector sizes above 512 bytes (up to the maximum - Implement support for sector sizes above 512 bytes (up to the maximum
supported by NTFS which is 4096 bytes). supported by NTFS which is 4096 bytes).
......
...@@ -16,8 +16,34 @@ ToDo/Notes: ...@@ -16,8 +16,34 @@ ToDo/Notes:
inode having been discarded already. Whether this can actually ever inode having been discarded already. Whether this can actually ever
happen is unclear however so it is worth waiting until someone hits happen is unclear however so it is worth waiting until someone hits
the problem. the problem.
- Enable the code for setting the NT4 compatibility flag when we start
making NTFS 1.2 specific modifications. 2.1.27 - Various bug fixes and cleanups.
- Fix two compiler warnings on Alpha. Thanks to Andrew Morton for
reporting them.
- Fix an (innocent) off-by-one error in the runlist code.
- Fix a buggette in an "should be impossible" case handling where we
continued the attribute lookup loop instead of aborting it.
- Use buffer_migrate_page() for the ->migratepage function of all ntfs
address space operations.
- Fix comparison of $MFT and $MFTMirr to not bail out when there are
unused, invalid mft records which are the same in both $MFT and
$MFTMirr.
- Add support for sparse files which have a compression unit of 0.
- Remove all the make_bad_inode() calls. This should only be called
from read inode and new inode code paths.
- Limit name length in fs/ntfs/unistr.c::ntfs_nlstoucs() to maximum
allowed by NTFS, i.e. 255 Unicode characters, not including the
terminating NULL (which is not stored on disk).
- Improve comments on file attribute flags in fs/ntfs/layout.h.
- Fix a bug in fs/ntfs/inode.c::ntfs_read_locked_index_inode() where we
forgot to update a temporary variable so loading index inodes which
have an index allocation attribute failed.
- Add a missing call to flush_dcache_mft_record_page() in
fs/ntfs/inode.c::ntfs_write_inode().
- Handle the recently introduced -ENAMETOOLONG return value from
fs/ntfs/unistr.c::ntfs_nlstoucs() in fs/ntfs/namei.c::ntfs_lookup().
- Semaphore to mutex conversion. (Ingo Molnar)
2.1.26 - Minor bug fixes and updates. 2.1.26 - Minor bug fixes and updates.
......
...@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ ...@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
unistr.o upcase.o unistr.o upcase.o
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.26\" EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.27\"
ifeq ($(CONFIG_NTFS_DEBUG),y) ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG EXTRA_CFLAGS += -DDEBUG
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/swap.h> #include <linux/swap.h>
...@@ -1277,18 +1278,18 @@ static int ntfs_write_mst_block(struct page *page, ...@@ -1277,18 +1278,18 @@ static int ntfs_write_mst_block(struct page *page,
tni = locked_nis[nr_locked_nis]; tni = locked_nis[nr_locked_nis];
/* Get the base inode. */ /* Get the base inode. */
down(&tni->extent_lock); mutex_lock(&tni->extent_lock);
if (tni->nr_extents >= 0) if (tni->nr_extents >= 0)
base_tni = tni; base_tni = tni;
else { else {
base_tni = tni->ext.base_ntfs_ino; base_tni = tni->ext.base_ntfs_ino;
BUG_ON(!base_tni); BUG_ON(!base_tni);
} }
up(&tni->extent_lock); mutex_unlock(&tni->extent_lock);
ntfs_debug("Unlocking %s inode 0x%lx.", ntfs_debug("Unlocking %s inode 0x%lx.",
tni == base_tni ? "base" : "extent", tni == base_tni ? "base" : "extent",
tni->mft_no); tni->mft_no);
up(&tni->mrec_lock); mutex_unlock(&tni->mrec_lock);
atomic_dec(&tni->count); atomic_dec(&tni->count);
iput(VFS_I(base_tni)); iput(VFS_I(base_tni));
} }
...@@ -1529,7 +1530,6 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -1529,7 +1530,6 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
"error %i.", err); "error %i.", err);
SetPageError(page); SetPageError(page);
NVolSetErrors(ni->vol); NVolSetErrors(ni->vol);
make_bad_inode(vi);
} }
unlock_page(page); unlock_page(page);
if (ctx) if (ctx)
...@@ -1551,6 +1551,9 @@ struct address_space_operations ntfs_aops = { ...@@ -1551,6 +1551,9 @@ struct address_space_operations ntfs_aops = {
#ifdef NTFS_RW #ifdef NTFS_RW
.writepage = ntfs_writepage, /* Write dirty page to disk. */ .writepage = ntfs_writepage, /* Write dirty page to disk. */
#endif /* NTFS_RW */ #endif /* NTFS_RW */
.migratepage = buffer_migrate_page, /* Move a page cache page from
one physical page to an
other. */
}; };
/** /**
...@@ -1567,6 +1570,9 @@ struct address_space_operations ntfs_mst_aops = { ...@@ -1567,6 +1570,9 @@ struct address_space_operations ntfs_mst_aops = {
without touching the buffers without touching the buffers
belonging to the page. */ belonging to the page. */
#endif /* NTFS_RW */ #endif /* NTFS_RW */
.migratepage = buffer_migrate_page, /* Move a page cache page from
one physical page to an
other. */
}; };
#ifdef NTFS_RW #ifdef NTFS_RW
......
/** /**
* attrib.c - NTFS attribute operations. Part of the Linux-NTFS project. * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project.
* *
* Copyright (c) 2001-2005 Anton Altaparmakov * Copyright (c) 2001-2006 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon * Copyright (c) 2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
...@@ -1048,7 +1048,7 @@ static int ntfs_external_attr_find(const ATTR_TYPE type, ...@@ -1048,7 +1048,7 @@ static int ntfs_external_attr_find(const ATTR_TYPE type,
le32_to_cpu(ctx->mrec->bytes_allocated)) le32_to_cpu(ctx->mrec->bytes_allocated))
break; break;
if (a->type == AT_END) if (a->type == AT_END)
continue; break;
if (!a->length) if (!a->length)
break; break;
if (al_entry->instance != a->instance) if (al_entry->instance != a->instance)
...@@ -1695,6 +1695,8 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size) ...@@ -1695,6 +1695,8 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size)
a->data.non_resident.initialized_size = a->data.non_resident.initialized_size =
cpu_to_sle64(attr_size); cpu_to_sle64(attr_size);
if (NInoSparse(ni) || NInoCompressed(ni)) { if (NInoSparse(ni) || NInoCompressed(ni)) {
a->data.non_resident.compression_unit = 0;
if (NInoCompressed(ni) || vol->major_ver < 3)
a->data.non_resident.compression_unit = 4; a->data.non_resident.compression_unit = 4;
a->data.non_resident.compressed_size = a->data.non_resident.compressed_size =
a->data.non_resident.allocated_size; a->data.non_resident.allocated_size;
...@@ -1714,13 +1716,20 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size) ...@@ -1714,13 +1716,20 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size)
ni->allocated_size = new_size; ni->allocated_size = new_size;
if (NInoSparse(ni) || NInoCompressed(ni)) { if (NInoSparse(ni) || NInoCompressed(ni)) {
ni->itype.compressed.size = ni->allocated_size; ni->itype.compressed.size = ni->allocated_size;
ni->itype.compressed.block_size = 1U << if (a->data.non_resident.compression_unit) {
(a->data.non_resident.compression_unit + ni->itype.compressed.block_size = 1U << (a->data.
non_resident.compression_unit +
vol->cluster_size_bits); vol->cluster_size_bits);
ni->itype.compressed.block_size_bits = ni->itype.compressed.block_size_bits =
ffs(ni->itype.compressed.block_size) - 1; ffs(ni->itype.compressed.block_size) -
1;
ni->itype.compressed.block_clusters = 1U << ni->itype.compressed.block_clusters = 1U <<
a->data.non_resident.compression_unit; a->data.non_resident.compression_unit;
} else {
ni->itype.compressed.block_size = 0;
ni->itype.compressed.block_size_bits = 0;
ni->itype.compressed.block_clusters = 0;
}
vi->i_blocks = ni->itype.compressed.size >> 9; vi->i_blocks = ni->itype.compressed.size >> 9;
} else } else
vi->i_blocks = ni->allocated_size >> 9; vi->i_blocks = ni->allocated_size >> 9;
...@@ -2429,16 +2438,12 @@ s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size, ...@@ -2429,16 +2438,12 @@ s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
"chkdsk to recover.", IS_ERR(m) ? "chkdsk to recover.", IS_ERR(m) ?
"restore attribute search context" : "restore attribute search context" :
"truncate attribute runlist"); "truncate attribute runlist");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol); NVolSetErrors(vol);
} else if (mp_rebuilt) { } else if (mp_rebuilt) {
if (ntfs_attr_record_resize(m, a, attr_len)) { if (ntfs_attr_record_resize(m, a, attr_len)) {
ntfs_error(vol->sb, "Failed to restore attribute " ntfs_error(vol->sb, "Failed to restore attribute "
"record in error code path. Run " "record in error code path. Run "
"chkdsk to recover."); "chkdsk to recover.");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol); NVolSetErrors(vol);
} else /* if (success) */ { } else /* if (success) */ {
if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu( if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(
...@@ -2451,8 +2456,6 @@ s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size, ...@@ -2451,8 +2456,6 @@ s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
"mapping pairs array in error " "mapping pairs array in error "
"code path. Run chkdsk to " "code path. Run chkdsk to "
"recover."); "recover.");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol); NVolSetErrors(vol);
} }
flush_dcache_mft_record_page(ctx->ntfs_ino); flush_dcache_mft_record_page(ctx->ntfs_ino);
......
...@@ -67,7 +67,7 @@ static DEFINE_SPINLOCK(ntfs_cb_lock); ...@@ -67,7 +67,7 @@ static DEFINE_SPINLOCK(ntfs_cb_lock);
/** /**
* allocate_compression_buffers - allocate the decompression buffers * allocate_compression_buffers - allocate the decompression buffers
* *
* Caller has to hold the ntfs_lock semaphore. * Caller has to hold the ntfs_lock mutex.
* *
* Return 0 on success or -ENOMEM if the allocations failed. * Return 0 on success or -ENOMEM if the allocations failed.
*/ */
...@@ -84,7 +84,7 @@ int allocate_compression_buffers(void) ...@@ -84,7 +84,7 @@ int allocate_compression_buffers(void)
/** /**
* free_compression_buffers - free the decompression buffers * free_compression_buffers - free the decompression buffers
* *
* Caller has to hold the ntfs_lock semaphore. * Caller has to hold the ntfs_lock mutex.
*/ */
void free_compression_buffers(void) void free_compression_buffers(void)
{ {
......
...@@ -1136,7 +1136,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1136,7 +1136,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (fpos == 1) { if (fpos == 1) {
ntfs_debug("Calling filldir for .. with len 2, fpos 0x1, " ntfs_debug("Calling filldir for .. with len 2, fpos 0x1, "
"inode 0x%lx, DT_DIR.", "inode 0x%lx, DT_DIR.",
parent_ino(filp->f_dentry)); (unsigned long)parent_ino(filp->f_dentry));
rc = filldir(dirent, "..", 2, fpos, rc = filldir(dirent, "..", 2, fpos,
parent_ino(filp->f_dentry), DT_DIR); parent_ino(filp->f_dentry), DT_DIR);
if (rc) if (rc)
......
...@@ -943,7 +943,8 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, ...@@ -943,7 +943,8 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
} }
ni->runlist.rl = rl; ni->runlist.rl = rl;
status.runlist_merged = 1; status.runlist_merged = 1;
ntfs_debug("Allocated cluster, lcn 0x%llx.", lcn); ntfs_debug("Allocated cluster, lcn 0x%llx.",
(unsigned long long)lcn);
/* Map and lock the mft record and get the attribute record. */ /* Map and lock the mft record and get the attribute record. */
if (!NInoAttr(ni)) if (!NInoAttr(ni))
base_ni = ni; base_ni = ni;
...@@ -1206,8 +1207,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, ...@@ -1206,8 +1207,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
"attribute runlist in error code " "attribute runlist in error code "
"path. Run chkdsk to recover the " "path. Run chkdsk to recover the "
"lost cluster."); "lost cluster.");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol); NVolSetErrors(vol);
} else /* if (success) */ { } else /* if (success) */ {
status.runlist_merged = 0; status.runlist_merged = 0;
...@@ -1238,8 +1237,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, ...@@ -1238,8 +1237,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
ntfs_error(vol->sb, "Failed to restore attribute " ntfs_error(vol->sb, "Failed to restore attribute "
"record in error code path. Run " "record in error code path. Run "
"chkdsk to recover."); "chkdsk to recover.");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol); NVolSetErrors(vol);
} else /* if (success) */ { } else /* if (success) */ {
if (ntfs_mapping_pairs_build(vol, (u8*)a + if (ntfs_mapping_pairs_build(vol, (u8*)a +
...@@ -1252,8 +1249,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, ...@@ -1252,8 +1249,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
"mapping pairs array in error " "mapping pairs array in error "
"code path. Run chkdsk to " "code path. Run chkdsk to "
"recover."); "recover.");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol); NVolSetErrors(vol);
} }
flush_dcache_mft_record_page(ctx->ntfs_ino); flush_dcache_mft_record_page(ctx->ntfs_ino);
...@@ -1622,11 +1617,8 @@ static inline int ntfs_commit_pages_after_non_resident_write( ...@@ -1622,11 +1617,8 @@ static inline int ntfs_commit_pages_after_non_resident_write(
unmap_mft_record(base_ni); unmap_mft_record(base_ni);
ntfs_error(vi->i_sb, "Failed to update initialized_size/i_size (error " ntfs_error(vi->i_sb, "Failed to update initialized_size/i_size (error "
"code %i).", err); "code %i).", err);
if (err != -ENOMEM) { if (err != -ENOMEM)
NVolSetErrors(ni->vol); NVolSetErrors(ni->vol);
make_bad_inode(VFS_I(base_ni));
make_bad_inode(vi);
}
return err; return err;
} }
...@@ -1801,8 +1793,6 @@ static int ntfs_commit_pages_after_write(struct page **pages, ...@@ -1801,8 +1793,6 @@ static int ntfs_commit_pages_after_write(struct page **pages,
ntfs_error(vi->i_sb, "Resident attribute commit write failed " ntfs_error(vi->i_sb, "Resident attribute commit write failed "
"with error %i.", err); "with error %i.", err);
NVolSetErrors(ni->vol); NVolSetErrors(ni->vol);
make_bad_inode(VFS_I(base_ni));
make_bad_inode(vi);
} }
if (ctx) if (ctx)
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
......
/** /**
* inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project. * inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project.
* *
* Copyright (c) 2001-2005 Anton Altaparmakov * Copyright (c) 2001-2006 Anton Altaparmakov
* *
* This program/include file is free software; you can redistribute it and/or * 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 * modify it under the terms of the GNU General Public License as published
...@@ -19,13 +19,19 @@ ...@@ -19,13 +19,19 @@
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/pagemap.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/smp_lock.h> #include <linux/fs.h>
#include <linux/quotaops.h> #include <linux/mm.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/mutex.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include "aops.h" #include "aops.h"
#include "attrib.h"
#include "bitmap.h"
#include "dir.h" #include "dir.h"
#include "debug.h" #include "debug.h"
#include "inode.h" #include "inode.h"
...@@ -382,7 +388,7 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni) ...@@ -382,7 +388,7 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
atomic_set(&ni->count, 1); atomic_set(&ni->count, 1);
ni->vol = NTFS_SB(sb); ni->vol = NTFS_SB(sb);
ntfs_init_runlist(&ni->runlist); ntfs_init_runlist(&ni->runlist);
init_MUTEX(&ni->mrec_lock); mutex_init(&ni->mrec_lock);
ni->page = NULL; ni->page = NULL;
ni->page_ofs = 0; ni->page_ofs = 0;
ni->attr_list_size = 0; ni->attr_list_size = 0;
...@@ -394,7 +400,7 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni) ...@@ -394,7 +400,7 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
ni->itype.index.collation_rule = 0; ni->itype.index.collation_rule = 0;
ni->itype.index.block_size_bits = 0; ni->itype.index.block_size_bits = 0;
ni->itype.index.vcn_size_bits = 0; ni->itype.index.vcn_size_bits = 0;
init_MUTEX(&ni->extent_lock); mutex_init(&ni->extent_lock);
ni->nr_extents = 0; ni->nr_extents = 0;
ni->ext.base_ntfs_ino = NULL; ni->ext.base_ntfs_ino = NULL;
} }
...@@ -1064,10 +1070,10 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -1064,10 +1070,10 @@ static int ntfs_read_locked_inode(struct inode *vi)
if (a->non_resident) { if (a->non_resident) {
NInoSetNonResident(ni); NInoSetNonResident(ni);
if (NInoCompressed(ni) || NInoSparse(ni)) { if (NInoCompressed(ni) || NInoSparse(ni)) {
if (a->data.non_resident.compression_unit != if (NInoCompressed(ni) && a->data.non_resident.
4) { compression_unit != 4) {
ntfs_error(vi->i_sb, "Found " ntfs_error(vi->i_sb, "Found "
"nonstandard " "non-standard "
"compression unit (%u " "compression unit (%u "
"instead of 4). " "instead of 4). "
"Cannot handle this.", "Cannot handle this.",
...@@ -1076,16 +1082,26 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -1076,16 +1082,26 @@ static int ntfs_read_locked_inode(struct inode *vi)
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto unm_err_out; goto unm_err_out;
} }
ni->itype.compressed.block_clusters = 1U << if (a->data.non_resident.compression_unit) {
a->data.non_resident. ni->itype.compressed.block_size = 1U <<
compression_unit; (a->data.non_resident.
ni->itype.compressed.block_size = 1U << (
a->data.non_resident.
compression_unit + compression_unit +
vol->cluster_size_bits); vol->cluster_size_bits);
ni->itype.compressed.block_size_bits = ffs( ni->itype.compressed.block_size_bits =
ni->itype.compressed. ffs(ni->itype.
compressed.
block_size) - 1; block_size) - 1;
ni->itype.compressed.block_clusters =
1U << a->data.
non_resident.
compression_unit;
} else {
ni->itype.compressed.block_size = 0;
ni->itype.compressed.block_size_bits =
0;
ni->itype.compressed.block_clusters =
0;
}
ni->itype.compressed.size = sle64_to_cpu( ni->itype.compressed.size = sle64_to_cpu(
a->data.non_resident. a->data.non_resident.
compressed_size); compressed_size);
...@@ -1338,8 +1354,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1338,8 +1354,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
goto unm_err_out; goto unm_err_out;
} }
if (NInoCompressed(ni) || NInoSparse(ni)) { if (NInoCompressed(ni) || NInoSparse(ni)) {
if (a->data.non_resident.compression_unit != 4) { if (NInoCompressed(ni) && a->data.non_resident.
ntfs_error(vi->i_sb, "Found nonstandard " compression_unit != 4) {
ntfs_error(vi->i_sb, "Found non-standard "
"compression unit (%u instead " "compression unit (%u instead "
"of 4). Cannot handle this.", "of 4). Cannot handle this.",
a->data.non_resident. a->data.non_resident.
...@@ -1347,13 +1364,22 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1347,13 +1364,22 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto unm_err_out; goto unm_err_out;
} }
ni->itype.compressed.block_clusters = 1U << if (a->data.non_resident.compression_unit) {
a->data.non_resident.compression_unit; ni->itype.compressed.block_size = 1U <<
ni->itype.compressed.block_size = 1U << ( (a->data.non_resident.
a->data.non_resident.compression_unit + compression_unit +
vol->cluster_size_bits); vol->cluster_size_bits);
ni->itype.compressed.block_size_bits = ffs( ni->itype.compressed.block_size_bits =
ni->itype.compressed.block_size) - 1; ffs(ni->itype.compressed.
block_size) - 1;
ni->itype.compressed.block_clusters = 1U <<
a->data.non_resident.
compression_unit;
} else {
ni->itype.compressed.block_size = 0;
ni->itype.compressed.block_size_bits = 0;
ni->itype.compressed.block_clusters = 0;
}
ni->itype.compressed.size = sle64_to_cpu( ni->itype.compressed.size = sle64_to_cpu(
a->data.non_resident.compressed_size); a->data.non_resident.compressed_size);
} }
...@@ -1406,7 +1432,6 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1406,7 +1432,6 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"Run chkdsk.", err, vi->i_ino, ni->type, ni->name_len, "Run chkdsk.", err, vi->i_ino, ni->type, ni->name_len,
base_vi->i_ino); base_vi->i_ino);
make_bad_inode(vi); make_bad_inode(vi);
make_bad_inode(base_vi);
if (err != -ENOMEM) if (err != -ENOMEM)
NVolSetErrors(vol); NVolSetErrors(vol);
return err; return err;
...@@ -1591,6 +1616,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) ...@@ -1591,6 +1616,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
"$INDEX_ALLOCATION attribute."); "$INDEX_ALLOCATION attribute.");
goto unm_err_out; goto unm_err_out;
} }
a = ctx->attr;
if (!a->non_resident) { if (!a->non_resident) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
"resident."); "resident.");
...@@ -2823,11 +2849,8 @@ int ntfs_truncate(struct inode *vi) ...@@ -2823,11 +2849,8 @@ int ntfs_truncate(struct inode *vi)
old_bad_out: old_bad_out:
old_size = -1; old_size = -1;
bad_out: bad_out:
if (err != -ENOMEM && err != -EOPNOTSUPP) { if (err != -ENOMEM && err != -EOPNOTSUPP)
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol); NVolSetErrors(vol);
}
if (err != -EOPNOTSUPP) if (err != -EOPNOTSUPP)
NInoSetTruncateFailed(ni); NInoSetTruncateFailed(ni);
else if (old_size >= 0) else if (old_size >= 0)
...@@ -2842,11 +2865,8 @@ int ntfs_truncate(struct inode *vi) ...@@ -2842,11 +2865,8 @@ int ntfs_truncate(struct inode *vi)
ntfs_debug("Failed. Returning error code %i.", err); ntfs_debug("Failed. Returning error code %i.", err);
return err; return err;
conv_err_out: conv_err_out:
if (err != -ENOMEM && err != -EOPNOTSUPP) { if (err != -ENOMEM && err != -EOPNOTSUPP)
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol); NVolSetErrors(vol);
}
if (err != -EOPNOTSUPP) if (err != -EOPNOTSUPP)
NInoSetTruncateFailed(ni); NInoSetTruncateFailed(ni);
else else
...@@ -3044,15 +3064,18 @@ int ntfs_write_inode(struct inode *vi, int sync) ...@@ -3044,15 +3064,18 @@ int ntfs_write_inode(struct inode *vi, int sync)
* record will be cleaned and written out to disk below, i.e. before * record will be cleaned and written out to disk below, i.e. before
* this function returns. * this function returns.
*/ */
if (modified && !NInoTestSetDirty(ctx->ntfs_ino)) if (modified) {
flush_dcache_mft_record_page(ctx->ntfs_ino);
if (!NInoTestSetDirty(ctx->ntfs_ino))
mark_ntfs_record_dirty(ctx->ntfs_ino->page, mark_ntfs_record_dirty(ctx->ntfs_ino->page,
ctx->ntfs_ino->page_ofs); ctx->ntfs_ino->page_ofs);
}
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
/* Now the access times are updated, write the base mft record. */ /* Now the access times are updated, write the base mft record. */
if (NInoDirty(ni)) if (NInoDirty(ni))
err = write_mft_record(ni, m, sync); err = write_mft_record(ni, m, sync);
/* Write all attached extent mft records. */ /* Write all attached extent mft records. */
down(&ni->extent_lock); mutex_lock(&ni->extent_lock);
if (ni->nr_extents > 0) { if (ni->nr_extents > 0) {
ntfs_inode **extent_nis = ni->ext.extent_ntfs_inos; ntfs_inode **extent_nis = ni->ext.extent_ntfs_inos;
int i; int i;
...@@ -3079,7 +3102,7 @@ int ntfs_write_inode(struct inode *vi, int sync) ...@@ -3079,7 +3102,7 @@ int ntfs_write_inode(struct inode *vi, int sync)
} }
} }
} }
up(&ni->extent_lock); mutex_unlock(&ni->extent_lock);
unmap_mft_record(ni); unmap_mft_record(ni);
if (unlikely(err)) if (unlikely(err))
goto err_out; goto err_out;
...@@ -3094,9 +3117,7 @@ int ntfs_write_inode(struct inode *vi, int sync) ...@@ -3094,9 +3117,7 @@ int ntfs_write_inode(struct inode *vi, int sync)
"retries later."); "retries later.");
mark_inode_dirty(vi); mark_inode_dirty(vi);
} else { } else {
ntfs_error(vi->i_sb, "Failed (error code %i): Marking inode " ntfs_error(vi->i_sb, "Failed (error %i): Run chkdsk.", -err);
"as bad. You should run chkdsk.", -err);
make_bad_inode(vi);
NVolSetErrors(ni->vol); NVolSetErrors(ni->vol);
} }
return err; return err;
......
...@@ -24,12 +24,13 @@ ...@@ -24,12 +24,13 @@
#ifndef _LINUX_NTFS_INODE_H #ifndef _LINUX_NTFS_INODE_H
#define _LINUX_NTFS_INODE_H #define _LINUX_NTFS_INODE_H
#include <linux/mm.h> #include <asm/atomic.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/list.h> #include <linux/list.h>
#include <asm/atomic.h> #include <linux/mm.h>
#include <asm/semaphore.h> #include <linux/mutex.h>
#include <linux/seq_file.h>
#include "layout.h" #include "layout.h"
#include "volume.h" #include "volume.h"
...@@ -81,7 +82,7 @@ struct _ntfs_inode { ...@@ -81,7 +82,7 @@ struct _ntfs_inode {
* The following fields are only valid for real inodes and extent * The following fields are only valid for real inodes and extent
* inodes. * inodes.
*/ */
struct semaphore mrec_lock; /* Lock for serializing access to the struct mutex mrec_lock; /* Lock for serializing access to the
mft record belonging to this inode. */ mft record belonging to this inode. */
struct page *page; /* The page containing the mft record of the struct page *page; /* The page containing the mft record of the
inode. This should only be touched by the inode. This should only be touched by the
...@@ -119,7 +120,7 @@ struct _ntfs_inode { ...@@ -119,7 +120,7 @@ struct _ntfs_inode {
u8 block_clusters; /* Number of clusters per cb. */ u8 block_clusters; /* Number of clusters per cb. */
} compressed; } compressed;
} itype; } itype;
struct semaphore extent_lock; /* Lock for accessing/modifying the struct mutex extent_lock; /* Lock for accessing/modifying the
below . */ below . */
s32 nr_extents; /* For a base mft record, the number of attached extent s32 nr_extents; /* For a base mft record, the number of attached extent
inodes (0 if none), for extent records and for fake inodes (0 if none), for extent records and for fake
......
...@@ -769,7 +769,7 @@ typedef struct { ...@@ -769,7 +769,7 @@ typedef struct {
compressed. (This effectively limits the compressed. (This effectively limits the
compression unit size to be a power of two compression unit size to be a power of two
clusters.) WinNT4 only uses a value of 4. clusters.) WinNT4 only uses a value of 4.
Sparse files also have this set to 4. */ Sparse files have this set to 0 on XPSP2. */
/* 35*/ u8 reserved[5]; /* Align to 8-byte boundary. */ /* 35*/ u8 reserved[5]; /* Align to 8-byte boundary. */
/* The sizes below are only used when lowest_vcn is zero, as otherwise it would /* The sizes below are only used when lowest_vcn is zero, as otherwise it would
be difficult to keep them up-to-date.*/ be difficult to keep them up-to-date.*/
...@@ -801,13 +801,16 @@ typedef struct { ...@@ -801,13 +801,16 @@ typedef struct {
typedef ATTR_RECORD ATTR_REC; typedef ATTR_RECORD ATTR_REC;
/* /*
* File attribute flags (32-bit). * File attribute flags (32-bit) appearing in the file_attributes fields of the
* STANDARD_INFORMATION attribute of MFT_RECORDs and the FILENAME_ATTR
* attributes of MFT_RECORDs and directory index entries.
*
* All of the below flags appear in the directory index entries but only some
* appear in the STANDARD_INFORMATION attribute whilst only some others appear
* in the FILENAME_ATTR attribute of MFT_RECORDs. Unless otherwise stated the
* flags appear in all of the above.
*/ */
enum { enum {
/*
* The following flags are only present in the STANDARD_INFORMATION
* attribute (in the field file_attributes).
*/
FILE_ATTR_READONLY = const_cpu_to_le32(0x00000001), FILE_ATTR_READONLY = const_cpu_to_le32(0x00000001),
FILE_ATTR_HIDDEN = const_cpu_to_le32(0x00000002), FILE_ATTR_HIDDEN = const_cpu_to_le32(0x00000002),
FILE_ATTR_SYSTEM = const_cpu_to_le32(0x00000004), FILE_ATTR_SYSTEM = const_cpu_to_le32(0x00000004),
...@@ -839,18 +842,14 @@ enum { ...@@ -839,18 +842,14 @@ enum {
F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask
is used to to obtain all flags that are valid for setting. */ is used to to obtain all flags that are valid for setting. */
/* /*
* The following flag is only present in the FILE_NAME attribute (in * The flag FILE_ATTR_DUP_FILENAME_INDEX_PRESENT is present in all
* the field file_attributes). * FILENAME_ATTR attributes but not in the STANDARD_INFORMATION
* attribute of an mft record.
*/ */
FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = const_cpu_to_le32(0x10000000), FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = const_cpu_to_le32(0x10000000),
/* Note, this is a copy of the corresponding bit from the mft record, /* Note, this is a copy of the corresponding bit from the mft record,
telling us whether this is a directory or not, i.e. whether it has telling us whether this is a directory or not, i.e. whether it has
an index root attribute or not. */ an index root attribute or not. */
/*
* The following flag is present both in the STANDARD_INFORMATION
* attribute and in the FILE_NAME attribute (in the field
* file_attributes).
*/
FILE_ATTR_DUP_VIEW_INDEX_PRESENT = const_cpu_to_le32(0x20000000), FILE_ATTR_DUP_VIEW_INDEX_PRESENT = const_cpu_to_le32(0x20000000),
/* Note, this is a copy of the corresponding bit from the mft record, /* Note, this is a copy of the corresponding bit from the mft record,
telling us whether this file has a view index present (eg. object id telling us whether this file has a view index present (eg. object id
...@@ -891,7 +890,7 @@ typedef struct { ...@@ -891,7 +890,7 @@ typedef struct {
Windows this is only updated when Windows this is only updated when
accessed if some time delta has accessed if some time delta has
passed since the last update. Also, passed since the last update. Also,
last access times updates can be last access time updates can be
disabled altogether for speed. */ disabled altogether for speed. */
/* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */ /* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
/* 36*/ union { /* 36*/ union {
...@@ -1076,16 +1075,21 @@ typedef struct { ...@@ -1076,16 +1075,21 @@ typedef struct {
/* 20*/ sle64 last_access_time; /* Time this mft record was last /* 20*/ sle64 last_access_time; /* Time this mft record was last
accessed. */ accessed. */
/* 28*/ sle64 allocated_size; /* Byte size of on-disk allocated space /* 28*/ sle64 allocated_size; /* Byte size of on-disk allocated space
for the data attribute. So for for the unnamed data attribute. So
normal $DATA, this is the for normal $DATA, this is the
allocated_size from the unnamed allocated_size from the unnamed
$DATA attribute and for compressed $DATA attribute and for compressed
and/or sparse $DATA, this is the and/or sparse $DATA, this is the
compressed_size from the unnamed compressed_size from the unnamed
$DATA attribute. NOTE: This is a $DATA attribute. For a directory or
multiple of the cluster size. */ other inode without an unnamed $DATA
/* 30*/ sle64 data_size; /* Byte size of actual data in data attribute, this is always 0. NOTE:
attribute. */ This is a multiple of the cluster
size. */
/* 30*/ sle64 data_size; /* Byte size of actual data in unnamed
data attribute. For a directory or
other inode without an unnamed $DATA
attribute, this is always 0. */
/* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */ /* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
/* 3c*/ union { /* 3c*/ union {
/* 3c*/ struct { /* 3c*/ struct {
......
...@@ -93,6 +93,7 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni) ...@@ -93,6 +93,7 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
"Run chkdsk.", ni->mft_no); "Run chkdsk.", ni->mft_no);
ntfs_unmap_page(page); ntfs_unmap_page(page);
page = ERR_PTR(-EIO); page = ERR_PTR(-EIO);
NVolSetErrors(vol);
} }
err_out: err_out:
ni->page = NULL; ni->page = NULL;
...@@ -104,8 +105,8 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni) ...@@ -104,8 +105,8 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
* map_mft_record - map, pin and lock an mft record * map_mft_record - map, pin and lock an mft record
* @ni: ntfs inode whose MFT record to map * @ni: ntfs inode whose MFT record to map
* *
* First, take the mrec_lock semaphore. We might now be sleeping, while waiting * First, take the mrec_lock mutex. We might now be sleeping, while waiting
* for the semaphore if it was already locked by someone else. * for the mutex if it was already locked by someone else.
* *
* The page of the record is mapped using map_mft_record_page() before being * The page of the record is mapped using map_mft_record_page() before being
* returned to the caller. * returned to the caller.
...@@ -135,9 +136,9 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni) ...@@ -135,9 +136,9 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
* So that code will end up having to own the mrec_lock of all mft * So that code will end up having to own the mrec_lock of all mft
* records/inodes present in the page before I/O can proceed. In that case we * records/inodes present in the page before I/O can proceed. In that case we
* wouldn't need to bother with PG_locked and PG_uptodate as nobody will be * wouldn't need to bother with PG_locked and PG_uptodate as nobody will be
* accessing anything without owning the mrec_lock semaphore. But we do need * accessing anything without owning the mrec_lock mutex. But we do need to
* to use them because of the read_cache_page() invocation and the code becomes * use them because of the read_cache_page() invocation and the code becomes so
* so much simpler this way that it is well worth it. * much simpler this way that it is well worth it.
* *
* The mft record is now ours and we return a pointer to it. You need to check * The mft record is now ours and we return a pointer to it. You need to check
* the returned pointer with IS_ERR() and if that is true, PTR_ERR() will return * the returned pointer with IS_ERR() and if that is true, PTR_ERR() will return
...@@ -160,13 +161,13 @@ MFT_RECORD *map_mft_record(ntfs_inode *ni) ...@@ -160,13 +161,13 @@ MFT_RECORD *map_mft_record(ntfs_inode *ni)
atomic_inc(&ni->count); atomic_inc(&ni->count);
/* Serialize access to this mft record. */ /* Serialize access to this mft record. */
down(&ni->mrec_lock); mutex_lock(&ni->mrec_lock);
m = map_mft_record_page(ni); m = map_mft_record_page(ni);
if (likely(!IS_ERR(m))) if (likely(!IS_ERR(m)))
return m; return m;
up(&ni->mrec_lock); mutex_unlock(&ni->mrec_lock);
atomic_dec(&ni->count); atomic_dec(&ni->count);
ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m)); ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
return m; return m;
...@@ -217,7 +218,7 @@ void unmap_mft_record(ntfs_inode *ni) ...@@ -217,7 +218,7 @@ void unmap_mft_record(ntfs_inode *ni)
ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no); ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);
unmap_mft_record_page(ni); unmap_mft_record_page(ni);
up(&ni->mrec_lock); mutex_unlock(&ni->mrec_lock);
atomic_dec(&ni->count); atomic_dec(&ni->count);
/* /*
* If pure ntfs_inode, i.e. no vfs inode attached, we leave it to * If pure ntfs_inode, i.e. no vfs inode attached, we leave it to
...@@ -261,7 +262,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -261,7 +262,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
* in which case just return it. If not found, add it to the base * in which case just return it. If not found, add it to the base
* inode before returning it. * inode before returning it.
*/ */
down(&base_ni->extent_lock); mutex_lock(&base_ni->extent_lock);
if (base_ni->nr_extents > 0) { if (base_ni->nr_extents > 0) {
extent_nis = base_ni->ext.extent_ntfs_inos; extent_nis = base_ni->ext.extent_ntfs_inos;
for (i = 0; i < base_ni->nr_extents; i++) { for (i = 0; i < base_ni->nr_extents; i++) {
...@@ -274,7 +275,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -274,7 +275,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
} }
} }
if (likely(ni != NULL)) { if (likely(ni != NULL)) {
up(&base_ni->extent_lock); mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count); atomic_dec(&base_ni->count);
/* We found the record; just have to map and return it. */ /* We found the record; just have to map and return it. */
m = map_mft_record(ni); m = map_mft_record(ni);
...@@ -301,7 +302,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -301,7 +302,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
/* Record wasn't there. Get a new ntfs inode and initialize it. */ /* Record wasn't there. Get a new ntfs inode and initialize it. */
ni = ntfs_new_extent_inode(base_ni->vol->sb, mft_no); ni = ntfs_new_extent_inode(base_ni->vol->sb, mft_no);
if (unlikely(!ni)) { if (unlikely(!ni)) {
up(&base_ni->extent_lock); mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count); atomic_dec(&base_ni->count);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
...@@ -312,7 +313,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -312,7 +313,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
/* Now map the record. */ /* Now map the record. */
m = map_mft_record(ni); m = map_mft_record(ni);
if (IS_ERR(m)) { if (IS_ERR(m)) {
up(&base_ni->extent_lock); mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count); atomic_dec(&base_ni->count);
ntfs_clear_extent_inode(ni); ntfs_clear_extent_inode(ni);
goto map_err_out; goto map_err_out;
...@@ -347,14 +348,14 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -347,14 +348,14 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
base_ni->ext.extent_ntfs_inos = tmp; base_ni->ext.extent_ntfs_inos = tmp;
} }
base_ni->ext.extent_ntfs_inos[base_ni->nr_extents++] = ni; base_ni->ext.extent_ntfs_inos[base_ni->nr_extents++] = ni;
up(&base_ni->extent_lock); mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count); atomic_dec(&base_ni->count);
ntfs_debug("Done 2."); ntfs_debug("Done 2.");
*ntfs_ino = ni; *ntfs_ino = ni;
return m; return m;
unm_err_out: unm_err_out:
unmap_mft_record(ni); unmap_mft_record(ni);
up(&base_ni->extent_lock); mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count); atomic_dec(&base_ni->count);
/* /*
* If the extent inode was not attached to the base inode we need to * If the extent inode was not attached to the base inode we need to
...@@ -399,12 +400,12 @@ void __mark_mft_record_dirty(ntfs_inode *ni) ...@@ -399,12 +400,12 @@ void __mark_mft_record_dirty(ntfs_inode *ni)
BUG_ON(NInoAttr(ni)); BUG_ON(NInoAttr(ni));
mark_ntfs_record_dirty(ni->page, ni->page_ofs); mark_ntfs_record_dirty(ni->page, ni->page_ofs);
/* Determine the base vfs inode and mark it dirty, too. */ /* Determine the base vfs inode and mark it dirty, too. */
down(&ni->extent_lock); mutex_lock(&ni->extent_lock);
if (likely(ni->nr_extents >= 0)) if (likely(ni->nr_extents >= 0))
base_ni = ni; base_ni = ni;
else else
base_ni = ni->ext.base_ntfs_ino; base_ni = ni->ext.base_ntfs_ino;
up(&ni->extent_lock); mutex_unlock(&ni->extent_lock);
__mark_inode_dirty(VFS_I(base_ni), I_DIRTY_SYNC | I_DIRTY_DATASYNC); __mark_inode_dirty(VFS_I(base_ni), I_DIRTY_SYNC | I_DIRTY_DATASYNC);
} }
...@@ -650,10 +651,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no, ...@@ -650,10 +651,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
* fs/ntfs/aops.c::mark_ntfs_record_dirty(). * fs/ntfs/aops.c::mark_ntfs_record_dirty().
* *
* On success, clean the mft record and return 0. On error, leave the mft * On success, clean the mft record and return 0. On error, leave the mft
* record dirty and return -errno. The caller should call make_bad_inode() on * record dirty and return -errno.
* the base inode to ensure no more access happens to this inode. We do not do
* it here as the caller may want to finish writing other extent mft records
* first to minimize on-disk metadata inconsistencies.
* *
* NOTE: We always perform synchronous i/o and ignore the @sync parameter. * NOTE: We always perform synchronous i/o and ignore the @sync parameter.
* However, if the mft record has a counterpart in the mft mirror and @sync is * However, if the mft record has a counterpart in the mft mirror and @sync is
...@@ -983,7 +981,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no, ...@@ -983,7 +981,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
} }
ntfs_debug("Inode 0x%lx is not dirty.", mft_no); ntfs_debug("Inode 0x%lx is not dirty.", mft_no);
/* The inode is not dirty, try to take the mft record lock. */ /* The inode is not dirty, try to take the mft record lock. */
if (unlikely(down_trylock(&ni->mrec_lock))) { if (unlikely(!mutex_trylock(&ni->mrec_lock))) {
ntfs_debug("Mft record 0x%lx is already locked, do " ntfs_debug("Mft record 0x%lx is already locked, do "
"not write it.", mft_no); "not write it.", mft_no);
atomic_dec(&ni->count); atomic_dec(&ni->count);
...@@ -1043,13 +1041,13 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no, ...@@ -1043,13 +1041,13 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
* corresponding to this extent mft record attached. * corresponding to this extent mft record attached.
*/ */
ni = NTFS_I(vi); ni = NTFS_I(vi);
down(&ni->extent_lock); mutex_lock(&ni->extent_lock);
if (ni->nr_extents <= 0) { if (ni->nr_extents <= 0) {
/* /*
* The base inode has no attached extent inodes, write this * The base inode has no attached extent inodes, write this
* extent mft record. * extent mft record.
*/ */
up(&ni->extent_lock); mutex_unlock(&ni->extent_lock);
iput(vi); iput(vi);
ntfs_debug("Base inode 0x%lx has no attached extent inodes, " ntfs_debug("Base inode 0x%lx has no attached extent inodes, "
"write the extent record.", na.mft_no); "write the extent record.", na.mft_no);
...@@ -1072,7 +1070,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no, ...@@ -1072,7 +1070,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
* extent mft record. * extent mft record.
*/ */
if (!eni) { if (!eni) {
up(&ni->extent_lock); mutex_unlock(&ni->extent_lock);
iput(vi); iput(vi);
ntfs_debug("Extent inode 0x%lx is not attached to its base " ntfs_debug("Extent inode 0x%lx is not attached to its base "
"inode 0x%lx, write the extent record.", "inode 0x%lx, write the extent record.",
...@@ -1083,12 +1081,12 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no, ...@@ -1083,12 +1081,12 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
mft_no, na.mft_no); mft_no, na.mft_no);
/* Take a reference to the extent ntfs inode. */ /* Take a reference to the extent ntfs inode. */
atomic_inc(&eni->count); atomic_inc(&eni->count);
up(&ni->extent_lock); mutex_unlock(&ni->extent_lock);
/* /*
* Found the extent inode coresponding to this extent mft record. * Found the extent inode coresponding to this extent mft record.
* Try to take the mft record lock. * Try to take the mft record lock.
*/ */
if (unlikely(down_trylock(&eni->mrec_lock))) { if (unlikely(!mutex_trylock(&eni->mrec_lock))) {
atomic_dec(&eni->count); atomic_dec(&eni->count);
iput(vi); iput(vi);
ntfs_debug("Extent mft record 0x%lx is already locked, do " ntfs_debug("Extent mft record 0x%lx is already locked, do "
...@@ -2711,7 +2709,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, const int mode, ...@@ -2711,7 +2709,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, const int mode,
* have its page mapped and it is very easy to do. * have its page mapped and it is very easy to do.
*/ */
atomic_inc(&ni->count); atomic_inc(&ni->count);
down(&ni->mrec_lock); mutex_lock(&ni->mrec_lock);
ni->page = page; ni->page = page;
ni->page_ofs = ofs; ni->page_ofs = ofs;
/* /*
...@@ -2798,22 +2796,22 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m) ...@@ -2798,22 +2796,22 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
BUG_ON(NInoAttr(ni)); BUG_ON(NInoAttr(ni));
BUG_ON(ni->nr_extents != -1); BUG_ON(ni->nr_extents != -1);
down(&ni->extent_lock); mutex_lock(&ni->extent_lock);
base_ni = ni->ext.base_ntfs_ino; base_ni = ni->ext.base_ntfs_ino;
up(&ni->extent_lock); mutex_unlock(&ni->extent_lock);
BUG_ON(base_ni->nr_extents <= 0); BUG_ON(base_ni->nr_extents <= 0);
ntfs_debug("Entering for extent inode 0x%lx, base inode 0x%lx.\n", ntfs_debug("Entering for extent inode 0x%lx, base inode 0x%lx.\n",
mft_no, base_ni->mft_no); mft_no, base_ni->mft_no);
down(&base_ni->extent_lock); mutex_lock(&base_ni->extent_lock);
/* Make sure we are holding the only reference to the extent inode. */ /* Make sure we are holding the only reference to the extent inode. */
if (atomic_read(&ni->count) > 2) { if (atomic_read(&ni->count) > 2) {
ntfs_error(vol->sb, "Tried to free busy extent inode 0x%lx, " ntfs_error(vol->sb, "Tried to free busy extent inode 0x%lx, "
"not freeing.", base_ni->mft_no); "not freeing.", base_ni->mft_no);
up(&base_ni->extent_lock); mutex_unlock(&base_ni->extent_lock);
return -EBUSY; return -EBUSY;
} }
...@@ -2831,7 +2829,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m) ...@@ -2831,7 +2829,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
break; break;
} }
up(&base_ni->extent_lock); mutex_unlock(&base_ni->extent_lock);
if (unlikely(err)) { if (unlikely(err)) {
ntfs_error(vol->sb, "Extent inode 0x%lx is not attached to " ntfs_error(vol->sb, "Extent inode 0x%lx is not attached to "
...@@ -2890,7 +2888,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m) ...@@ -2890,7 +2888,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
return 0; return 0;
rollback: rollback:
/* Rollback what we did... */ /* Rollback what we did... */
down(&base_ni->extent_lock); mutex_lock(&base_ni->extent_lock);
extent_nis = base_ni->ext.extent_ntfs_inos; extent_nis = base_ni->ext.extent_ntfs_inos;
if (!(base_ni->nr_extents & 3)) { if (!(base_ni->nr_extents & 3)) {
int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode*); int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode*);
...@@ -2899,7 +2897,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m) ...@@ -2899,7 +2897,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
if (unlikely(!extent_nis)) { if (unlikely(!extent_nis)) {
ntfs_error(vol->sb, "Failed to allocate internal " ntfs_error(vol->sb, "Failed to allocate internal "
"buffer during rollback.%s", es); "buffer during rollback.%s", es);
up(&base_ni->extent_lock); mutex_unlock(&base_ni->extent_lock);
NVolSetErrors(vol); NVolSetErrors(vol);
goto rollback_error; goto rollback_error;
} }
...@@ -2914,7 +2912,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m) ...@@ -2914,7 +2912,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
m->flags |= MFT_RECORD_IN_USE; m->flags |= MFT_RECORD_IN_USE;
m->sequence_number = old_seq_no; m->sequence_number = old_seq_no;
extent_nis[base_ni->nr_extents++] = ni; extent_nis[base_ni->nr_extents++] = ni;
up(&base_ni->extent_lock); mutex_unlock(&base_ni->extent_lock);
mark_mft_record_dirty(ni); mark_mft_record_dirty(ni);
return err; return err;
} }
......
...@@ -97,10 +97,7 @@ extern int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync); ...@@ -97,10 +97,7 @@ extern int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync);
* uptodate. * uptodate.
* *
* On success, clean the mft record and return 0. On error, leave the mft * On success, clean the mft record and return 0. On error, leave the mft
* record dirty and return -errno. The caller should call make_bad_inode() on * record dirty and return -errno.
* the base inode to ensure no more access happens to this inode. We do not do
* it here as the caller may want to finish writing other extent mft records
* first to minimize on-disk metadata inconsistencies.
*/ */
static inline int write_mft_record(ntfs_inode *ni, MFT_RECORD *m, int sync) static inline int write_mft_record(ntfs_inode *ni, MFT_RECORD *m, int sync)
{ {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS * namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS
* project. * project.
* *
* Copyright (c) 2001-2004 Anton Altaparmakov * Copyright (c) 2001-2006 Anton Altaparmakov
* *
* This program/include file is free software; you can redistribute it and/or * 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 * modify it under the terms of the GNU General Public License as published
...@@ -115,7 +115,9 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, ...@@ -115,7 +115,9 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len, uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len,
&uname); &uname);
if (uname_len < 0) { if (uname_len < 0) {
ntfs_error(vol->sb, "Failed to convert name to Unicode."); if (uname_len != -ENAMETOOLONG)
ntfs_error(vol->sb, "Failed to convert name to "
"Unicode.");
return ERR_PTR(uname_len); return ERR_PTR(uname_len);
} }
mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len, mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len,
...@@ -157,7 +159,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, ...@@ -157,7 +159,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
/* Return the error code. */ /* Return the error code. */
return (struct dentry *)dent_inode; return (struct dentry *)dent_inode;
} }
/* It is guaranteed that name is no longer allocated at this point. */ /* It is guaranteed that @name is no longer allocated at this point. */
if (MREF_ERR(mref) == -ENOENT) { if (MREF_ERR(mref) == -ENOENT) {
ntfs_debug("Entry was not found, adding negative dentry."); ntfs_debug("Entry was not found, adding negative dentry.");
/* The dcache will handle negative entries. */ /* The dcache will handle negative entries. */
...@@ -168,7 +170,6 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, ...@@ -168,7 +170,6 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error " ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error "
"code %i.", -MREF_ERR(mref)); "code %i.", -MREF_ERR(mref));
return ERR_PTR(MREF_ERR(mref)); return ERR_PTR(MREF_ERR(mref));
// TODO: Consider moving this lot to a separate function! (AIA) // TODO: Consider moving this lot to a separate function! (AIA)
handle_name: handle_name:
{ {
......
...@@ -91,7 +91,7 @@ extern void free_compression_buffers(void); ...@@ -91,7 +91,7 @@ extern void free_compression_buffers(void);
/* From fs/ntfs/super.c */ /* From fs/ntfs/super.c */
#define default_upcase_len 0x10000 #define default_upcase_len 0x10000
extern struct semaphore ntfs_lock; extern struct mutex ntfs_lock;
typedef struct { typedef struct {
int val; int val;
......
...@@ -381,6 +381,7 @@ static inline runlist_element *ntfs_rl_insert(runlist_element *dst, ...@@ -381,6 +381,7 @@ static inline runlist_element *ntfs_rl_insert(runlist_element *dst,
static inline runlist_element *ntfs_rl_replace(runlist_element *dst, static inline runlist_element *ntfs_rl_replace(runlist_element *dst,
int dsize, runlist_element *src, int ssize, int loc) int dsize, runlist_element *src, int ssize, int loc)
{ {
signed delta;
BOOL left = FALSE; /* Left end of @src needs merging. */ BOOL left = FALSE; /* Left end of @src needs merging. */
BOOL right = FALSE; /* Right end of @src needs merging. */ BOOL right = FALSE; /* Right end of @src needs merging. */
int tail; /* Start of tail of @dst. */ int tail; /* Start of tail of @dst. */
...@@ -396,11 +397,14 @@ static inline runlist_element *ntfs_rl_replace(runlist_element *dst, ...@@ -396,11 +397,14 @@ static inline runlist_element *ntfs_rl_replace(runlist_element *dst,
left = ntfs_are_rl_mergeable(dst + loc - 1, src); left = ntfs_are_rl_mergeable(dst + loc - 1, src);
/* /*
* Allocate some space. We will need less if the left, right, or both * Allocate some space. We will need less if the left, right, or both
* ends get merged. * ends get merged. The -1 accounts for the run being replaced.
*/ */
dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left - right); delta = ssize - 1 - left - right;
if (delta > 0) {
dst = ntfs_rl_realloc(dst, dsize, dsize + delta);
if (IS_ERR(dst)) if (IS_ERR(dst))
return dst; return dst;
}
/* /*
* We are guaranteed to succeed from here so can start modifying the * We are guaranteed to succeed from here so can start modifying the
* original runlists. * original runlists.
......
...@@ -1099,26 +1099,38 @@ static BOOL check_mft_mirror(ntfs_volume *vol) ...@@ -1099,26 +1099,38 @@ static BOOL check_mft_mirror(ntfs_volume *vol)
kmirr = page_address(mirr_page); kmirr = page_address(mirr_page);
++index; ++index;
} }
/* Do not check the record if it is not in use. */
if (((MFT_RECORD*)kmft)->flags & MFT_RECORD_IN_USE) {
/* Make sure the record is ok. */ /* Make sure the record is ok. */
if (ntfs_is_baad_recordp((le32*)kmft)) { if (ntfs_is_baad_recordp((le32*)kmft)) {
ntfs_error(sb, "Incomplete multi sector transfer " ntfs_error(sb, "Incomplete multi sector "
"detected in mft record %i.", i); "transfer detected in mft "
"record %i.", i);
mm_unmap_out: mm_unmap_out:
ntfs_unmap_page(mirr_page); ntfs_unmap_page(mirr_page);
mft_unmap_out: mft_unmap_out:
ntfs_unmap_page(mft_page); ntfs_unmap_page(mft_page);
return FALSE; return FALSE;
} }
}
/* Do not check the mirror record if it is not in use. */
if (((MFT_RECORD*)kmirr)->flags & MFT_RECORD_IN_USE) {
if (ntfs_is_baad_recordp((le32*)kmirr)) { if (ntfs_is_baad_recordp((le32*)kmirr)) {
ntfs_error(sb, "Incomplete multi sector transfer " ntfs_error(sb, "Incomplete multi sector "
"detected in mft mirror record %i.", i); "transfer detected in mft "
"mirror record %i.", i);
goto mm_unmap_out; goto mm_unmap_out;
} }
}
/* Get the amount of data in the current record. */ /* Get the amount of data in the current record. */
bytes = le32_to_cpu(((MFT_RECORD*)kmft)->bytes_in_use); bytes = le32_to_cpu(((MFT_RECORD*)kmft)->bytes_in_use);
if (!bytes || bytes > vol->mft_record_size) { if (bytes < sizeof(MFT_RECORD_OLD) ||
bytes > vol->mft_record_size ||
ntfs_is_baad_recordp((le32*)kmft)) {
bytes = le32_to_cpu(((MFT_RECORD*)kmirr)->bytes_in_use); bytes = le32_to_cpu(((MFT_RECORD*)kmirr)->bytes_in_use);
if (!bytes || bytes > vol->mft_record_size) if (bytes < sizeof(MFT_RECORD_OLD) ||
bytes > vol->mft_record_size ||
ntfs_is_baad_recordp((le32*)kmirr))
bytes = vol->mft_record_size; bytes = vol->mft_record_size;
} }
/* Compare the two records. */ /* Compare the two records. */
...@@ -1665,11 +1677,11 @@ static BOOL load_and_init_upcase(ntfs_volume *vol) ...@@ -1665,11 +1677,11 @@ static BOOL load_and_init_upcase(ntfs_volume *vol)
ntfs_debug("Read %llu bytes from $UpCase (expected %zu bytes).", ntfs_debug("Read %llu bytes from $UpCase (expected %zu bytes).",
i_size, 64 * 1024 * sizeof(ntfschar)); i_size, 64 * 1024 * sizeof(ntfschar));
iput(ino); iput(ino);
down(&ntfs_lock); mutex_lock(&ntfs_lock);
if (!default_upcase) { if (!default_upcase) {
ntfs_debug("Using volume specified $UpCase since default is " ntfs_debug("Using volume specified $UpCase since default is "
"not present."); "not present.");
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
return TRUE; return TRUE;
} }
max = default_upcase_len; max = default_upcase_len;
...@@ -1683,12 +1695,12 @@ static BOOL load_and_init_upcase(ntfs_volume *vol) ...@@ -1683,12 +1695,12 @@ static BOOL load_and_init_upcase(ntfs_volume *vol)
vol->upcase = default_upcase; vol->upcase = default_upcase;
vol->upcase_len = max; vol->upcase_len = max;
ntfs_nr_upcase_users++; ntfs_nr_upcase_users++;
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
ntfs_debug("Volume specified $UpCase matches default. Using " ntfs_debug("Volume specified $UpCase matches default. Using "
"default."); "default.");
return TRUE; return TRUE;
} }
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
ntfs_debug("Using volume specified $UpCase since it does not match " ntfs_debug("Using volume specified $UpCase since it does not match "
"the default."); "the default.");
return TRUE; return TRUE;
...@@ -1697,17 +1709,17 @@ static BOOL load_and_init_upcase(ntfs_volume *vol) ...@@ -1697,17 +1709,17 @@ static BOOL load_and_init_upcase(ntfs_volume *vol)
ntfs_free(vol->upcase); ntfs_free(vol->upcase);
vol->upcase = NULL; vol->upcase = NULL;
upcase_failed: upcase_failed:
down(&ntfs_lock); mutex_lock(&ntfs_lock);
if (default_upcase) { if (default_upcase) {
vol->upcase = default_upcase; vol->upcase = default_upcase;
vol->upcase_len = default_upcase_len; vol->upcase_len = default_upcase_len;
ntfs_nr_upcase_users++; ntfs_nr_upcase_users++;
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
ntfs_error(sb, "Failed to load $UpCase from the volume. Using " ntfs_error(sb, "Failed to load $UpCase from the volume. Using "
"default."); "default.");
return TRUE; return TRUE;
} }
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
ntfs_error(sb, "Failed to initialize upcase table."); ntfs_error(sb, "Failed to initialize upcase table.");
return FALSE; return FALSE;
} }
...@@ -2183,12 +2195,12 @@ static BOOL load_system_files(ntfs_volume *vol) ...@@ -2183,12 +2195,12 @@ static BOOL load_system_files(ntfs_volume *vol)
iput_upcase_err_out: iput_upcase_err_out:
#endif /* NTFS_RW */ #endif /* NTFS_RW */
vol->upcase_len = 0; vol->upcase_len = 0;
down(&ntfs_lock); mutex_lock(&ntfs_lock);
if (vol->upcase == default_upcase) { if (vol->upcase == default_upcase) {
ntfs_nr_upcase_users--; ntfs_nr_upcase_users--;
vol->upcase = NULL; vol->upcase = NULL;
} }
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
if (vol->upcase) { if (vol->upcase) {
ntfs_free(vol->upcase); ntfs_free(vol->upcase);
vol->upcase = NULL; vol->upcase = NULL;
...@@ -2393,7 +2405,7 @@ static void ntfs_put_super(struct super_block *sb) ...@@ -2393,7 +2405,7 @@ static void ntfs_put_super(struct super_block *sb)
* Destroy the global default upcase table if necessary. Also decrease * Destroy the global default upcase table if necessary. Also decrease
* the number of upcase users if we are a user. * the number of upcase users if we are a user.
*/ */
down(&ntfs_lock); mutex_lock(&ntfs_lock);
if (vol->upcase == default_upcase) { if (vol->upcase == default_upcase) {
ntfs_nr_upcase_users--; ntfs_nr_upcase_users--;
vol->upcase = NULL; vol->upcase = NULL;
...@@ -2404,7 +2416,7 @@ static void ntfs_put_super(struct super_block *sb) ...@@ -2404,7 +2416,7 @@ static void ntfs_put_super(struct super_block *sb)
} }
if (vol->cluster_size <= 4096 && !--ntfs_nr_compression_users) if (vol->cluster_size <= 4096 && !--ntfs_nr_compression_users)
free_compression_buffers(); free_compression_buffers();
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
if (vol->upcase) { if (vol->upcase) {
ntfs_free(vol->upcase); ntfs_free(vol->upcase);
vol->upcase = NULL; vol->upcase = NULL;
...@@ -2878,7 +2890,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -2878,7 +2890,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
ntfs_error(sb, "Failed to load essential metadata."); ntfs_error(sb, "Failed to load essential metadata.");
goto iput_tmp_ino_err_out_now; goto iput_tmp_ino_err_out_now;
} }
down(&ntfs_lock); mutex_lock(&ntfs_lock);
/* /*
* The current mount is a compression user if the cluster size is * The current mount is a compression user if the cluster size is
* less than or equal 4kiB. * less than or equal 4kiB.
...@@ -2889,7 +2901,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -2889,7 +2901,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
ntfs_error(NULL, "Failed to allocate buffers " ntfs_error(NULL, "Failed to allocate buffers "
"for compression engine."); "for compression engine.");
ntfs_nr_compression_users--; ntfs_nr_compression_users--;
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
goto iput_tmp_ino_err_out_now; goto iput_tmp_ino_err_out_now;
} }
} }
...@@ -2901,7 +2913,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -2901,7 +2913,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
if (!default_upcase) if (!default_upcase)
default_upcase = generate_default_upcase(); default_upcase = generate_default_upcase();
ntfs_nr_upcase_users++; ntfs_nr_upcase_users++;
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
/* /*
* From now on, ignore @silent parameter. If we fail below this line, * From now on, ignore @silent parameter. If we fail below this line,
* it will be due to a corrupt fs or a system error, so we report it. * it will be due to a corrupt fs or a system error, so we report it.
...@@ -2919,12 +2931,12 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -2919,12 +2931,12 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
atomic_inc(&vol->root_ino->i_count); atomic_inc(&vol->root_ino->i_count);
ntfs_debug("Exiting, status successful."); ntfs_debug("Exiting, status successful.");
/* Release the default upcase if it has no users. */ /* Release the default upcase if it has no users. */
down(&ntfs_lock); mutex_lock(&ntfs_lock);
if (!--ntfs_nr_upcase_users && default_upcase) { if (!--ntfs_nr_upcase_users && default_upcase) {
ntfs_free(default_upcase); ntfs_free(default_upcase);
default_upcase = NULL; default_upcase = NULL;
} }
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
sb->s_export_op = &ntfs_export_ops; sb->s_export_op = &ntfs_export_ops;
lock_kernel(); lock_kernel();
return 0; return 0;
...@@ -2992,12 +3004,12 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -2992,12 +3004,12 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
vol->attrdef = NULL; vol->attrdef = NULL;
} }
vol->upcase_len = 0; vol->upcase_len = 0;
down(&ntfs_lock); mutex_lock(&ntfs_lock);
if (vol->upcase == default_upcase) { if (vol->upcase == default_upcase) {
ntfs_nr_upcase_users--; ntfs_nr_upcase_users--;
vol->upcase = NULL; vol->upcase = NULL;
} }
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
if (vol->upcase) { if (vol->upcase) {
ntfs_free(vol->upcase); ntfs_free(vol->upcase);
vol->upcase = NULL; vol->upcase = NULL;
...@@ -3012,14 +3024,14 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -3012,14 +3024,14 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
* Decrease the number of upcase users and destroy the global default * Decrease the number of upcase users and destroy the global default
* upcase table if necessary. * upcase table if necessary.
*/ */
down(&ntfs_lock); mutex_lock(&ntfs_lock);
if (!--ntfs_nr_upcase_users && default_upcase) { if (!--ntfs_nr_upcase_users && default_upcase) {
ntfs_free(default_upcase); ntfs_free(default_upcase);
default_upcase = NULL; default_upcase = NULL;
} }
if (vol->cluster_size <= 4096 && !--ntfs_nr_compression_users) if (vol->cluster_size <= 4096 && !--ntfs_nr_compression_users)
free_compression_buffers(); free_compression_buffers();
up(&ntfs_lock); mutex_unlock(&ntfs_lock);
iput_tmp_ino_err_out_now: iput_tmp_ino_err_out_now:
iput(tmp_ino); iput(tmp_ino);
if (vol->mft_ino && vol->mft_ino != tmp_ino) if (vol->mft_ino && vol->mft_ino != tmp_ino)
...@@ -3078,8 +3090,8 @@ static void ntfs_big_inode_init_once(void *foo, struct kmem_cache *cachep, ...@@ -3078,8 +3090,8 @@ static void ntfs_big_inode_init_once(void *foo, struct kmem_cache *cachep,
struct kmem_cache *ntfs_attr_ctx_cache; struct kmem_cache *ntfs_attr_ctx_cache;
struct kmem_cache *ntfs_index_ctx_cache; struct kmem_cache *ntfs_index_ctx_cache;
/* Driver wide semaphore. */ /* Driver wide mutex. */
DECLARE_MUTEX(ntfs_lock); DEFINE_MUTEX(ntfs_lock);
static struct super_block *ntfs_get_sb(struct file_system_type *fs_type, static struct super_block *ntfs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data) int flags, const char *dev_name, void *data)
...@@ -3234,7 +3246,7 @@ static void __exit exit_ntfs_fs(void) ...@@ -3234,7 +3246,7 @@ static void __exit exit_ntfs_fs(void)
} }
MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>"); MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>");
MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2005 Anton Altaparmakov"); MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2006 Anton Altaparmakov");
MODULE_VERSION(NTFS_VERSION); MODULE_VERSION(NTFS_VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#ifdef DEBUG #ifdef DEBUG
......
/* /*
* unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project. * unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project.
* *
* Copyright (c) 2001-2005 Anton Altaparmakov * Copyright (c) 2001-2006 Anton Altaparmakov
* *
* This program/include file is free software; you can redistribute it and/or * 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 * modify it under the terms of the GNU General Public License as published
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/slab.h>
#include "types.h" #include "types.h"
#include "debug.h" #include "debug.h"
#include "ntfs.h" #include "ntfs.h"
...@@ -242,7 +244,7 @@ int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1, ...@@ -242,7 +244,7 @@ int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1,
* map dictates, into a little endian, 2-byte Unicode string. * map dictates, into a little endian, 2-byte Unicode string.
* *
* This function allocates the string and the caller is responsible for * This function allocates the string and the caller is responsible for
* calling kmem_cache_free(ntfs_name_cache, @outs); when finished with it. * calling kmem_cache_free(ntfs_name_cache, *@outs); when finished with it.
* *
* On success the function returns the number of Unicode characters written to * On success the function returns the number of Unicode characters written to
* the output string *@outs (>= 0), not counting the terminating Unicode NULL * the output string *@outs (>= 0), not counting the terminating Unicode NULL
...@@ -262,37 +264,48 @@ int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins, ...@@ -262,37 +264,48 @@ int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
wchar_t wc; wchar_t wc;
int i, o, wc_len; int i, o, wc_len;
/* We don't trust outside sources. */ /* We do not trust outside sources. */
if (ins) { if (likely(ins)) {
ucs = kmem_cache_alloc(ntfs_name_cache, SLAB_NOFS); ucs = kmem_cache_alloc(ntfs_name_cache, SLAB_NOFS);
if (ucs) { if (likely(ucs)) {
for (i = o = 0; i < ins_len; i += wc_len) { for (i = o = 0; i < ins_len; i += wc_len) {
wc_len = nls->char2uni(ins + i, ins_len - i, wc_len = nls->char2uni(ins + i, ins_len - i,
&wc); &wc);
if (wc_len >= 0) { if (likely(wc_len >= 0 &&
if (wc) { o < NTFS_MAX_NAME_LEN)) {
if (likely(wc)) {
ucs[o++] = cpu_to_le16(wc); ucs[o++] = cpu_to_le16(wc);
continue; continue;
} /* else (!wc) */ } /* else if (!wc) */
break; break;
} /* else (wc_len < 0) */ } /* else if (wc_len < 0 ||
goto conversion_err; o >= NTFS_MAX_NAME_LEN) */
goto name_err;
} }
ucs[o] = 0; ucs[o] = 0;
*outs = ucs; *outs = ucs;
return o; return o;
} /* else (!ucs) */ } /* else if (!ucs) */
ntfs_error(vol->sb, "Failed to allocate name from " ntfs_error(vol->sb, "Failed to allocate buffer for converted "
"ntfs_name_cache!"); "name from ntfs_name_cache.");
return -ENOMEM; return -ENOMEM;
} /* else (!ins) */ } /* else if (!ins) */
ntfs_error(NULL, "Received NULL pointer."); ntfs_error(vol->sb, "Received NULL pointer.");
return -EINVAL; return -EINVAL;
conversion_err: name_err:
ntfs_error(vol->sb, "Name using character set %s contains characters "
"that cannot be converted to Unicode.", nls->charset);
kmem_cache_free(ntfs_name_cache, ucs); kmem_cache_free(ntfs_name_cache, ucs);
return -EILSEQ; if (wc_len < 0) {
ntfs_error(vol->sb, "Name using character set %s contains "
"characters that cannot be converted to "
"Unicode.", nls->charset);
i = -EILSEQ;
} else /* if (o >= NTFS_MAX_NAME_LEN) */ {
ntfs_error(vol->sb, "Name is too long (maximum length for a "
"name on NTFS is %d Unicode characters.",
NTFS_MAX_NAME_LEN);
i = -ENAMETOOLONG;
}
return i;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment