Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
b425c8c5
Commit
b425c8c5
authored
Mar 23, 2006
by
Anton Altaparmakov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git://imp.csi.cam.ac.uk/home/src/ntfs-2.6-devel/
parents
a05ba456
92fe7b9e
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
291 additions
and
211 deletions
+291
-211
Documentation/filesystems/ntfs.txt
Documentation/filesystems/ntfs.txt
+5
-0
fs/ntfs/ChangeLog
fs/ntfs/ChangeLog
+28
-2
fs/ntfs/Makefile
fs/ntfs/Makefile
+1
-1
fs/ntfs/aops.c
fs/ntfs/aops.c
+10
-4
fs/ntfs/attrib.c
fs/ntfs/attrib.c
+19
-16
fs/ntfs/compress.c
fs/ntfs/compress.c
+2
-2
fs/ntfs/file.c
fs/ntfs/file.c
+1
-12
fs/ntfs/inode.c
fs/ntfs/inode.c
+66
-45
fs/ntfs/inode.h
fs/ntfs/inode.h
+7
-6
fs/ntfs/layout.h
fs/ntfs/layout.h
+24
-20
fs/ntfs/mft.c
fs/ntfs/mft.c
+33
-35
fs/ntfs/mft.h
fs/ntfs/mft.h
+1
-4
fs/ntfs/namei.c
fs/ntfs/namei.c
+5
-4
fs/ntfs/ntfs.h
fs/ntfs/ntfs.h
+1
-1
fs/ntfs/runlist.c
fs/ntfs/runlist.c
+8
-4
fs/ntfs/super.c
fs/ntfs/super.c
+48
-36
fs/ntfs/unistr.c
fs/ntfs/unistr.c
+32
-19
No files found.
Documentation/filesystems/ntfs.txt
View file @
b425c8c5
...
...
@@ -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).
...
...
fs/ntfs/ChangeLog
View file @
b425c8c5
...
...
@@ -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.
...
...
fs/ntfs/Makefile
View file @
b425c8c5
...
...
@@ -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.2
6
\"
EXTRA_CFLAGS
=
-DNTFS_VERSION
=
\"
2.1.2
7
\"
ifeq
($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS
+=
-DDEBUG
...
...
fs/ntfs/aops.c
View file @
b425c8c5
...
...
@@ -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 @@ static int ntfs_write_mst_block(struct page *page,
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 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
"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
...
...
fs/ntfs/attrib.c
View file @
b425c8c5
/**
* attrib.c - NTFS attribute operations. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-200
5
Anton Altaparmakov
* Copyright (c) 2001-200
6
Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
...
...
@@ -1048,7 +1048,7 @@ static int ntfs_external_attr_find(const ATTR_TYPE type,
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 @@ s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
"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 @@ s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
"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
);
...
...
fs/ntfs/compress.c
View file @
b425c8c5
...
...
@@ -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
)
{
...
...
fs/ntfs/file.c
View file @
b425c8c5
...
...
@@ -1207,8 +1207,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
"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
;
...
...
@@ -1239,8 +1237,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
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
+
...
...
@@ -1253,8 +1249,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
"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
);
...
...
@@ -1623,11 +1617,8 @@ static inline int ntfs_commit_pages_after_non_resident_write(
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
;
}
...
...
@@ -1802,8 +1793,6 @@ static int ntfs_commit_pages_after_write(struct page **pages,
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
);
...
...
fs/ntfs/inode.c
View file @
b425c8c5
/**
* inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-200
5
Anton Altaparmakov
* Copyright (c) 2001-200
6
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 @@ static int ntfs_read_locked_inode(struct inode *vi)
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 @@ static int ntfs_read_locked_inode(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
);
...
...
@@ -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 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"Run chkdsk."
,
err
,
vi
->
i_ino
,
ni
->
type
,
ni
->
name_len
,
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 @@ int ntfs_truncate(struct inode *vi)
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 @@ int ntfs_truncate(struct inode *vi)
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 @@ int ntfs_write_inode(struct inode *vi, int sync)
"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
;
...
...
fs/ntfs/inode.h
View file @
b425c8c5
...
...
@@ -24,12 +24,13 @@
#ifndef _LINUX_NTFS_INODE_H
#define _LINUX_NTFS_INODE_H
#include <linux/mm.h>
#include <asm/atomic.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <asm/atomic.h>
#include <asm/semaphore.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
...
...
fs/ntfs/layout.h
View file @
b425c8c5
...
...
@@ -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 time
s
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
{
...
...
fs/ntfs/mft.c
View file @
b425c8c5
...
...
@@ -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 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
* 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 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
* So that code will end up having to own the mrec_lock of all mft
* 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 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
/* Record wasn't there. Get a new ntfs inode and initialize it. */
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 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
/* 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 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
base_ni
->
ext
.
extent_ntfs_inos
=
tmp
;
}
base_ni
->
ext
.
extent_ntfs_inos
[
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 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
* 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 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, const int mode,
* 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 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
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 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
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 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
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
;
}
...
...
fs/ntfs/mft.h
View file @
b425c8c5
...
...
@@ -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
)
{
...
...
fs/ntfs/namei.c
View file @
b425c8c5
...
...
@@ -2,7 +2,7 @@
* namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS
* project.
*
* Copyright (c) 2001-200
4
Anton Altaparmakov
* Copyright (c) 2001-200
6
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:
{
...
...
fs/ntfs/ntfs.h
View file @
b425c8c5
...
...
@@ -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
;
...
...
fs/ntfs/runlist.c
View file @
b425c8c5
...
...
@@ -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.
...
...
fs/ntfs/super.c
View file @
b425c8c5
...
...
@@ -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 @@ static BOOL load_and_init_upcase(ntfs_volume *vol)
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 @@ static BOOL load_and_init_upcase(ntfs_volume *vol)
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 @@ static BOOL load_and_init_upcase(ntfs_volume *vol)
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 @@ static BOOL load_system_files(ntfs_volume *vol)
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 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
* Decrease the number of upcase users and destroy the global default
* 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
. */
DE
CLAR
E_MUTEX
(
ntfs_lock
);
/* Driver wide
mutex
. */
DE
FIN
E_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-200
5
Anton Altaparmakov"
);
MODULE_DESCRIPTION
(
"NTFS 1.2/3.x driver - Copyright (c) 2001-200
6
Anton Altaparmakov"
);
MODULE_VERSION
(
NTFS_VERSION
);
MODULE_LICENSE
(
"GPL"
);
#ifdef DEBUG
...
...
fs/ntfs/unistr.c
View file @
b425c8c5
/*
* unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-200
5
Anton Altaparmakov
* Copyright (c) 2001-200
6
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 do
n'
t trust outside sources. */
if
(
ins
)
{
/* We do
no
t 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
"
"n
tfs_name_cache!
"
);
}
/* else
if
(!ucs) */
ntfs_error
(
vol
->
sb
,
"Failed to allocate
buffer for converted
"
"n
ame 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
;
}
/**
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment