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