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:
Коммит
a1a051b187
|
@ -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:
|
||||||
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 \
|
||||||
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 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#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 @@ unm_done:
|
||||||
|
|
||||||
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 @@ err_out:
|
||||||
"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 = {
|
||||||
#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 = {
|
||||||
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
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* 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 @@ do_next_attr_loop:
|
||||||
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,7 +1695,9 @@ 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 = 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.compressed_size =
|
||||||
a->data.non_resident.allocated_size;
|
a->data.non_resident.allocated_size;
|
||||||
} else
|
} else
|
||||||
|
@ -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.
|
||||||
vol->cluster_size_bits);
|
non_resident.compression_unit +
|
||||||
ni->itype.compressed.block_size_bits =
|
vol->cluster_size_bits);
|
||||||
ffs(ni->itype.compressed.block_size) - 1;
|
ni->itype.compressed.block_size_bits =
|
||||||
ni->itype.compressed.block_clusters = 1U <<
|
ffs(ni->itype.compressed.block_size) -
|
||||||
a->data.non_resident.compression_unit;
|
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;
|
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 @@ undo_alloc:
|
||||||
"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 @@ undo_alloc:
|
||||||
"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);
|
||||||
/**
|
/**
|
||||||
* 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)
|
||||||
/**
|
/**
|
||||||
* 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)
|
||||||
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 @@ rl_not_mapped_enoent:
|
||||||
}
|
}
|
||||||
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 @@ rl_not_mapped_enoent:
|
||||||
"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 @@ rl_not_mapped_enoent:
|
||||||
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 @@ rl_not_mapped_enoent:
|
||||||
"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 @@ err_out:
|
||||||
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 @@ err_out:
|
||||||
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);
|
||||||
|
|
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.
|
* 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 @@
|
||||||
* 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)
|
||||||
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)
|
||||||
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 @@ skip_large_dir_stuff:
|
||||||
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 @@ skip_large_dir_stuff:
|
||||||
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 << (
|
compression_unit +
|
||||||
a->data.non_resident.
|
vol->cluster_size_bits);
|
||||||
compression_unit +
|
ni->itype.compressed.block_size_bits =
|
||||||
vol->cluster_size_bits);
|
ffs(ni->itype.
|
||||||
ni->itype.compressed.block_size_bits = ffs(
|
compressed.
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ err_out:
|
||||||
"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)
|
||||||
"$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 @@ done:
|
||||||
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 @@ out:
|
||||||
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)
|
||||||
* 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) {
|
||||||
mark_ntfs_record_dirty(ctx->ntfs_ino->page,
|
flush_dcache_mft_record_page(ctx->ntfs_ino);
|
||||||
ctx->ntfs_ino->page_ofs);
|
if (!NInoTestSetDirty(ctx->ntfs_ino))
|
||||||
|
mark_ntfs_record_dirty(ctx->ntfs_ino->page,
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 @@ err_out:
|
||||||
"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 @@
|
||||||
#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 <linux/fs.h>
|
|
||||||
#include <linux/seq_file.h>
|
|
||||||
#include <linux/list.h>
|
|
||||||
#include <asm/atomic.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 "layout.h"
|
||||||
#include "volume.h"
|
#include "volume.h"
|
||||||
|
@ -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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
/* 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)
|
||||||
"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 @@ err_out:
|
||||||
* 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 @@ err_out:
|
||||||
* 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)
|
||||||
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)
|
||||||
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,
|
||||||
* 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 @@ map_err_out:
|
||||||
/* 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 @@ map_err_out:
|
||||||
/* 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 @@ map_err_out:
|
||||||
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)
|
||||||
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 @@ err_out:
|
||||||
* 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,
|
||||||
}
|
}
|
||||||
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,
|
||||||
* 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,
|
||||||
* 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,
|
||||||
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 @@ mft_rec_already_initialized:
|
||||||
* 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)
|
||||||
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)
|
||||||
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 @@ rollback_error:
|
||||||
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 @@ rollback:
|
||||||
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 @@ rollback:
|
||||||
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);
|
||||||
* 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 @@
|
||||||
* 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,
|
||||||
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,
|
||||||
/* 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,
|
||||||
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);
|
||||||
|
|
||||||
/* 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,
|
||||||
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,
|
||||||
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 (IS_ERR(dst))
|
if (delta > 0) {
|
||||||
return dst;
|
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
|
* 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)
|
||||||
kmirr = page_address(mirr_page);
|
kmirr = page_address(mirr_page);
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
/* Make sure the record is ok. */
|
/* Do not check the record if it is not in use. */
|
||||||
if (ntfs_is_baad_recordp((le32*)kmft)) {
|
if (((MFT_RECORD*)kmft)->flags & MFT_RECORD_IN_USE) {
|
||||||
ntfs_error(sb, "Incomplete multi sector transfer "
|
/* Make sure the record is ok. */
|
||||||
"detected in mft record %i.", i);
|
if (ntfs_is_baad_recordp((le32*)kmft)) {
|
||||||
|
ntfs_error(sb, "Incomplete multi sector "
|
||||||
|
"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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ntfs_is_baad_recordp((le32*)kmirr)) {
|
/* Do not check the mirror record if it is not in use. */
|
||||||
ntfs_error(sb, "Incomplete multi sector transfer "
|
if (((MFT_RECORD*)kmirr)->flags & MFT_RECORD_IN_USE) {
|
||||||
"detected in mft mirror record %i.", i);
|
if (ntfs_is_baad_recordp((le32*)kmirr)) {
|
||||||
goto mm_unmap_out;
|
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. */
|
/* 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 @@ read_partial_upcase_page:
|
||||||
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 @@ read_partial_upcase_page:
|
||||||
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 @@ iput_upcase_failed:
|
||||||
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 @@ iput_attrdef_err_out:
|
||||||
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)
|
||||||
* 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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ unl_upcase_iput_tmp_ino_err_out_now:
|
||||||
* 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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* 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 @@
|
||||||
* 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,
|
||||||
* 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,
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Загрузка…
Ссылка в новой задаче