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
0907f58e
Commit
0907f58e
authored
Aug 06, 2002
by
Anton Altaparmakov
Browse files
Options
Browse Files
Download
Plain Diff
Merge cantab.net:/usr/src/bklinux-2.5 into cantab.net:/usr/src/tng
parents
c4265b8b
8e27b910
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
294 additions
and
285 deletions
+294
-285
Documentation/filesystems/ntfs.txt
Documentation/filesystems/ntfs.txt
+8
-0
fs/ntfs/ChangeLog
fs/ntfs/ChangeLog
+14
-0
fs/ntfs/Makefile
fs/ntfs/Makefile
+1
-1
fs/ntfs/aops.c
fs/ntfs/aops.c
+5
-5
fs/ntfs/attrib.c
fs/ntfs/attrib.c
+4
-4
fs/ntfs/compress.c
fs/ntfs/compress.c
+21
-2
fs/ntfs/dir.c
fs/ntfs/dir.c
+109
-93
fs/ntfs/inode.c
fs/ntfs/inode.c
+30
-17
fs/ntfs/inode.h
fs/ntfs/inode.h
+1
-2
fs/ntfs/malloc.h
fs/ntfs/malloc.h
+2
-15
fs/ntfs/mft.c
fs/ntfs/mft.c
+72
-123
fs/ntfs/mft.h
fs/ntfs/mft.h
+3
-3
fs/ntfs/namei.c
fs/ntfs/namei.c
+21
-17
fs/ntfs/super.c
fs/ntfs/super.c
+3
-3
No files found.
Documentation/filesystems/ntfs.txt
View file @
0907f58e
...
...
@@ -247,6 +247,14 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.0.23:
- Massive internal locking changes to mft record locking. Fixes
various race conditions and deadlocks.
- Fix ntfs over loopback for compressed files by adding an
optimization barrier. (gcc was screwing up otherwise ?)
Thanks go to Christoph Hellwig for pointing these two out:
- Remove now unused function fs/ntfs/malloc.h::vmalloc_nofs().
- Fix ntfs_free() for ia64 and parisc.
2.0.22:
- Small internal cleanups.
2.0.21:
...
...
fs/ntfs/ChangeLog
View file @
0907f58e
...
...
@@ -2,6 +2,20 @@ ToDo:
- Find and fix bugs.
- Enable NFS exporting of NTFS.
2.0.23 - Major bug fixes (races, deadlocks, non-i386 architectures).
- Massive internal locking changes to mft record locking. Fixes lock
recursion and replaces the mrec_lock read/write semaphore with a
mutex. Also removes the now superfluous mft_count. This fixes several
race conditions and deadlocks, especially in the future write code.
- Fix ntfs over loopback for compressed files by adding an
optimization barrier. (gcc was screwing up otherwise ?)
- Miscellaneous cleanups all over the code and a fix or two in error
handling code paths.
Thanks go to Christoph Hellwig for pointing out the following two:
- Remove now unused function fs/ntfs/malloc.h::vmalloc_nofs().
- Fix ntfs_free() for ia64 and parisc by checking for VMALLOC_END, too.
2.0.22 - Cleanups, mainly to ntfs_readdir(), and use C99 initializers.
- Change fs/ntfs/dir.c::ntfs_reddir() to only read/write ->f_pos once
...
...
fs/ntfs/Makefile
View file @
0907f58e
...
...
@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
ntfs-objs
:=
aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o
\
mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
EXTRA_CFLAGS
=
-DNTFS_VERSION
=
\"
2.0.2
2
\"
EXTRA_CFLAGS
=
-DNTFS_VERSION
=
\"
2.0.2
3
\"
ifeq
($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS
+=
-DDEBUG
...
...
fs/ntfs/aops.c
View file @
0907f58e
...
...
@@ -106,8 +106,6 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
if
(
!
NInoMstProtected
(
ni
))
{
if
(
likely
(
page_uptodate
&&
!
PageError
(
page
)))
SetPageUptodate
(
page
);
unlock_page
(
page
);
return
;
}
else
{
char
*
addr
;
unsigned
int
i
,
recs
,
nr_err
;
...
...
@@ -332,6 +330,8 @@ static int ntfs_read_block(struct page *page)
* for it to be read in before we can do the copy.
*
* Return 0 on success and -errno on error.
*
* WARNING: Do not make this function static! It is used by mft.c!
*/
int
ntfs_readpage
(
struct
file
*
file
,
struct
page
*
page
)
{
...
...
@@ -372,8 +372,8 @@ int ntfs_readpage(struct file *file, struct page *page)
else
base_ni
=
ni
->
_INE
(
base_ntfs_ino
);
/* Map, pin and lock the mft record
for reading
. */
mrec
=
map_mft_record
(
READ
,
base_ni
);
/* Map, pin and lock the mft record. */
mrec
=
map_mft_record
(
base_ni
);
if
(
unlikely
(
IS_ERR
(
mrec
)))
{
err
=
PTR_ERR
(
mrec
);
goto
err_out
;
...
...
@@ -416,7 +416,7 @@ int ntfs_readpage(struct file *file, struct page *page)
put_unm_err_out:
put_attr_search_ctx
(
ctx
);
unm_err_out:
unmap_mft_record
(
READ
,
base_ni
);
unmap_mft_record
(
base_ni
);
err_out:
unlock_page
(
page
);
return
err
;
...
...
fs/ntfs/attrib.c
View file @
0907f58e
...
...
@@ -948,7 +948,7 @@ int map_run_list(ntfs_inode *ni, VCN vcn)
else
base_ni
=
ni
->
_INE
(
base_ntfs_ino
);
mrec
=
map_mft_record
(
READ
,
base_ni
);
mrec
=
map_mft_record
(
base_ni
);
if
(
IS_ERR
(
mrec
))
return
PTR_ERR
(
mrec
);
ctx
=
get_attr_search_ctx
(
base_ni
,
mrec
);
...
...
@@ -979,7 +979,7 @@ int map_run_list(ntfs_inode *ni, VCN vcn)
put_attr_search_ctx
(
ctx
);
err_out:
unmap_mft_record
(
READ
,
base_ni
);
unmap_mft_record
(
base_ni
);
return
err
;
}
...
...
@@ -1671,7 +1671,7 @@ void reinit_attr_search_ctx(attr_search_context *ctx)
return
;
}
/* Attribute list. */
if
(
ctx
->
ntfs_ino
!=
ctx
->
base_ntfs_ino
)
unmap_mft_record
(
READ
,
ctx
->
ntfs_ino
);
unmap_mft_record
(
ctx
->
ntfs_ino
);
init_attr_search_ctx
(
ctx
,
ctx
->
base_ntfs_ino
,
ctx
->
base_mrec
);
return
;
}
...
...
@@ -1704,7 +1704,7 @@ attr_search_context *get_attr_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec)
void
put_attr_search_ctx
(
attr_search_context
*
ctx
)
{
if
(
ctx
->
base_ntfs_ino
&&
ctx
->
ntfs_ino
!=
ctx
->
base_ntfs_ino
)
unmap_mft_record
(
READ
,
ctx
->
ntfs_ino
);
unmap_mft_record
(
ctx
->
ntfs_ino
);
kmem_cache_free
(
ntfs_attr_ctx_cache
,
ctx
);
return
;
}
...
...
fs/ntfs/compress.c
View file @
0907f58e
...
...
@@ -608,8 +608,27 @@ int ntfs_read_compressed_block(struct page *page)
if
(
buffer_uptodate
(
tbh
))
continue
;
wait_on_buffer
(
tbh
);
if
(
unlikely
(
!
buffer_uptodate
(
tbh
)))
goto
read_err
;
/*
* We need an optimization barrier here, otherwise we start
* hitting the below fixup code when accessing a loopback
* mounted ntfs partition. This indicates either there is a
* race condition in the loop driver or, more likely, gcc
* overoptimises the code without the barrier and it doesn't
* do the Right Thing(TM).
*/
barrier
();
if
(
unlikely
(
!
buffer_uptodate
(
tbh
)))
{
ntfs_warning
(
vol
->
sb
,
"Buffer is unlocked but not "
"uptodate! Unplugging the disk queue "
"and rescheduling."
);
get_bh
(
tbh
);
blk_run_queues
();
schedule
();
put_bh
(
tbh
);
if
(
unlikely
(
!
buffer_uptodate
(
tbh
)))
goto
read_err
;
ntfs_warning
(
vol
->
sb
,
"Buffer is now uptodate. Good."
);
}
}
/*
...
...
fs/ntfs/dir.c
View file @
0907f58e
...
...
@@ -76,7 +76,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
u8
*
index_end
;
u64
mref
;
attr_search_context
*
ctx
;
int
err
=
0
,
rc
;
int
err
,
rc
;
VCN
vcn
,
old_vcn
;
struct
address_space
*
ia_mapping
;
struct
page
*
page
;
...
...
@@ -84,23 +84,24 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ntfs_name
*
name
=
NULL
;
/* Get hold of the mft record for the directory. */
m
=
map_mft_record
(
READ
,
dir_ni
);
if
(
IS_ERR
(
m
))
goto
map_err_out
;
m
=
map_mft_record
(
dir_ni
);
if
(
unlikely
(
IS_ERR
(
m
)))
{
ntfs_error
(
sb
,
"map_mft_record() failed with error code %ld."
,
-
PTR_ERR
(
m
));
return
ERR_MREF
(
PTR_ERR
(
m
));
}
ctx
=
get_attr_search_ctx
(
dir_ni
,
m
);
if
(
!
ctx
)
{
if
(
unlikely
(
!
ctx
)
)
{
err
=
-
ENOMEM
;
goto
unm_
err_out
;
goto
err_out
;
}
/* Find the index root attribute in the mft record. */
if
(
!
lookup_attr
(
AT_INDEX_ROOT
,
I30
,
4
,
CASE_SENSITIVE
,
0
,
NULL
,
0
,
ctx
))
{
ntfs_error
(
sb
,
"Index root attribute missing in directory "
"inode 0x%lx."
,
dir_ni
->
mft_no
);
err
=
-
EIO
;
goto
put_unm_
err_out
;
goto
err_out
;
}
/* Get to the index root value (it's been verified in read_inode). */
ir
=
(
INDEX_ROOT
*
)((
u8
*
)
ctx
->
attr
+
...
...
@@ -154,7 +155,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
GFP_NOFS
);
if
(
!
name
)
{
err
=
-
ENOMEM
;
goto
put_unm_
err_out
;
goto
err_out
;
}
}
name
->
mref
=
le64_to_cpu
(
...
...
@@ -169,7 +170,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
}
mref
=
le64_to_cpu
(
ie
->
_IIF
(
indexed_file
));
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
READ
,
dir_ni
);
unmap_mft_record
(
dir_ni
);
return
mref
;
}
/*
...
...
@@ -208,7 +209,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
name
=
kmalloc
(
name_size
,
GFP_NOFS
);
if
(
!
name
)
{
err
=
-
ENOMEM
;
goto
put_unm_
err_out
;
goto
err_out
;
}
name
->
mref
=
le64_to_cpu
(
ie
->
_IIF
(
indexed_file
));
name
->
type
=
type
;
...
...
@@ -267,12 +268,12 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if
(
!
(
ie
->
_IEH
(
flags
)
&
INDEX_ENTRY_NODE
))
{
if
(
name
)
{
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
READ
,
dir_ni
);
unmap_mft_record
(
dir_ni
);
return
name
->
mref
;
}
ntfs_debug
(
"Entry not found."
);
err
=
-
ENOENT
;
goto
put_unm_
err_out
;
goto
err_out
;
}
/* Child node present, descend into it. */
/* Consistency check: Verify that an index allocation exists. */
if
(
!
NInoIndexAllocPresent
(
dir_ni
))
{
...
...
@@ -280,11 +281,19 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"requires one. Directory inode 0x%lx is "
"corrupt or driver bug."
,
dir_ni
->
mft_no
);
err
=
-
EIO
;
goto
put_unm_
err_out
;
goto
err_out
;
}
/* Get the starting vcn of the index_block holding the child node. */
vcn
=
sle64_to_cpup
((
u8
*
)
ie
+
le16_to_cpu
(
ie
->
_IEH
(
length
))
-
8
);
ia_mapping
=
VFS_I
(
dir_ni
)
->
i_mapping
;
/*
* We are done with the index root and the mft record. Release them,
* otherwise we deadlock with ntfs_map_page().
*/
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
dir_ni
);
m
=
NULL
;
ctx
=
NULL
;
descend_into_child_node:
/*
* Convert vcn to index into the index allocation attribute in units
...
...
@@ -296,7 +305,8 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if
(
IS_ERR
(
page
))
{
ntfs_error
(
sb
,
"Failed to map directory index page, error %ld."
,
-
PTR_ERR
(
page
));
goto
put_unm_err_out
;
err
=
PTR_ERR
(
page
);
goto
err_out
;
}
kaddr
=
(
u8
*
)
page_address
(
page
);
fast_descend_into_child_node:
...
...
@@ -308,7 +318,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ntfs_error
(
sb
,
"Out of bounds check failed. Corrupt directory "
"inode 0x%lx or driver bug."
,
dir_ni
->
mft_no
);
err
=
-
EIO
;
goto
unm_
unm_
err_out
;
goto
unm_err_out
;
}
if
(
sle64_to_cpu
(
ia
->
index_block_vcn
)
!=
vcn
)
{
ntfs_error
(
sb
,
"Actual VCN (0x%Lx) of index buffer is "
...
...
@@ -318,7 +328,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
(
long
long
)
sle64_to_cpu
(
ia
->
index_block_vcn
),
(
long
long
)
vcn
,
dir_ni
->
mft_no
);
err
=
-
EIO
;
goto
unm_
unm_
err_out
;
goto
unm_err_out
;
}
if
(
le32_to_cpu
(
ia
->
index
.
allocated_size
)
+
0x18
!=
dir_ni
->
_IDM
(
index_block_size
))
{
...
...
@@ -330,7 +340,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
le32_to_cpu
(
ia
->
index
.
allocated_size
)
+
0x18
,
dir_ni
->
_IDM
(
index_block_size
));
err
=
-
EIO
;
goto
unm_
unm_
err_out
;
goto
unm_err_out
;
}
index_end
=
(
u8
*
)
ia
+
dir_ni
->
_IDM
(
index_block_size
);
if
(
index_end
>
kaddr
+
PAGE_CACHE_SIZE
)
{
...
...
@@ -339,7 +349,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"Cannot access! This is probably a bug in the "
"driver."
,
(
long
long
)
vcn
,
dir_ni
->
mft_no
);
err
=
-
EIO
;
goto
unm_
unm_
err_out
;
goto
unm_err_out
;
}
index_end
=
(
u8
*
)
&
ia
->
index
+
le32_to_cpu
(
ia
->
index
.
index_length
);
if
(
index_end
>
(
u8
*
)
ia
+
dir_ni
->
_IDM
(
index_block_size
))
{
...
...
@@ -347,7 +357,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"inode 0x%lx exceeds maximum size."
,
(
long
long
)
vcn
,
dir_ni
->
mft_no
);
err
=
-
EIO
;
goto
unm_
unm_
err_out
;
goto
unm_err_out
;
}
/* The first index entry. */
ie
=
(
INDEX_ENTRY
*
)((
u8
*
)
&
ia
->
index
+
...
...
@@ -367,7 +377,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"directory inode 0x%lx."
,
dir_ni
->
mft_no
);
err
=
-
EIO
;
goto
unm_
unm_
err_out
;
goto
unm_err_out
;
}
/*
* The last entry cannot contain a name. It can however contain
...
...
@@ -403,7 +413,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
GFP_NOFS
);
if
(
!
name
)
{
err
=
-
ENOMEM
;
goto
unm_
unm_
err_out
;
goto
unm_err_out
;
}
}
name
->
mref
=
le64_to_cpu
(
...
...
@@ -418,8 +428,6 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
}
mref
=
le64_to_cpu
(
ie
->
_IIF
(
indexed_file
));
ntfs_unmap_page
(
page
);
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
READ
,
dir_ni
);
return
mref
;
}
/*
...
...
@@ -459,7 +467,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
name
=
kmalloc
(
name_size
,
GFP_NOFS
);
if
(
!
name
)
{
err
=
-
ENOMEM
;
goto
put_
unm_err_out
;
goto
unm_err_out
;
}
name
->
mref
=
le64_to_cpu
(
ie
->
_IIF
(
indexed_file
));
name
->
type
=
type
;
...
...
@@ -519,7 +527,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"a leaf node in directory inode 0x%lx."
,
dir_ni
->
mft_no
);
err
=
-
EIO
;
goto
unm_
unm_
err_out
;
goto
unm_err_out
;
}
/* Child node present, descend into it. */
old_vcn
=
vcn
;
...
...
@@ -539,7 +547,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ntfs_error
(
sb
,
"Negative child node vcn in directory inode "
"0x%lx."
,
dir_ni
->
mft_no
);
err
=
-
EIO
;
goto
unm_
unm_
err_out
;
goto
unm_err_out
;
}
/*
* No child node present, return -ENOENT, unless we have got a matching
...
...
@@ -548,31 +556,26 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
*/
if
(
name
)
{
ntfs_unmap_page
(
page
);
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
READ
,
dir_ni
);
return
name
->
mref
;
}
ntfs_debug
(
"Entry not found."
);
err
=
-
ENOENT
;
unm_unm_err_out:
ntfs_unmap_page
(
page
);
put_unm_err_out:
put_attr_search_ctx
(
ctx
);
unm_err_out:
unmap_mft_record
(
READ
,
dir_ni
);
ntfs_unmap_page
(
page
);
err_out:
if
(
ctx
)
put_attr_search_ctx
(
ctx
);
if
(
m
)
unmap_mft_record
(
dir_ni
);
if
(
name
)
{
kfree
(
name
);
*
res
=
NULL
;
}
return
ERR_MREF
(
err
);
map_err_out:
ntfs_error
(
sb
,
"map_mft_record(READ) failed with error code %ld."
,
-
PTR_ERR
(
m
));
return
ERR_MREF
(
PTR_ERR
(
m
));
dir_err_out:
ntfs_error
(
sb
,
"Corrupt directory. Aborting lookup."
);
err
=
-
EIO
;
goto
put_unm_
err_out
;
goto
err_out
;
}
#if 0
...
...
@@ -614,7 +617,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
u8 *index_end;
u64 mref;
attr_search_context *ctx;
int err
= 0
, rc;
int err, rc;
IGNORE_CASE_BOOL ic;
VCN vcn, old_vcn;
struct address_space *ia_mapping;
...
...
@@ -622,23 +625,24 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
u8 *kaddr;
/* Get hold of the mft record for the directory. */
m = map_mft_record(READ, dir_ni);
if (IS_ERR(m))
goto map_err_out;
m = map_mft_record(dir_ni);
if (IS_ERR(m)) {
ntfs_error(sb, "map_mft_record() failed with error code %ld.",
-PTR_ERR(m));
return ERR_MREF(PTR_ERR(m));
}
ctx = get_attr_search_ctx(dir_ni, m);
if (!ctx) {
err = -ENOMEM;
goto
unm_
err_out;
goto err_out;
}
/* Find the index root attribute in the mft record. */
if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
ctx)) {
ntfs_error(sb, "Index root attribute missing in directory "
"inode 0x%lx.", dir_ni->mft_no);
err = -EIO;
goto
put_unm_
err_out;
goto err_out;
}
/* Get to the index root value (it's been verified in read_inode). */
ir = (INDEX_ROOT*)((u8*)ctx->attr +
...
...
@@ -689,7 +693,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
found_it:
mref = le64_to_cpu(ie->_IIF(indexed_file));
put_attr_search_ctx(ctx);
unmap_mft_record(
READ,
dir_ni);
unmap_mft_record(dir_ni);
return mref;
}
/*
...
...
@@ -737,7 +741,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if (!(ie->_IEH(flags) & INDEX_ENTRY_NODE)) {
/* No child node, return -ENOENT. */
err = -ENOENT;
goto
put_unm_
err_out;
goto err_out;
} /* Child node present, descend into it. */
/* Consistency check: Verify that an index allocation exists. */
if (!NInoIndexAllocPresent(dir_ni)) {
...
...
@@ -745,11 +749,19 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"requires one. Directory inode 0x%lx is "
"corrupt or driver bug.", dir_ni->mft_no);
err = -EIO;
goto
put_unm_
err_out;
goto err_out;
}
/* Get the starting vcn of the index_block holding the child node. */
vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->_IEH(length)) - 8);
ia_mapping = VFS_I(dir_ni)->i_mapping;
/*
* We are done with the index root and the mft record. Release them,
* otherwise we deadlock with ntfs_map_page().
*/
put_attr_search_ctx(ctx);
unmap_mft_record(dir_ni);
m = NULL;
ctx = NULL;
descend_into_child_node:
/*
* Convert vcn to index into the index allocation attribute in units
...
...
@@ -761,7 +773,8 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
if (IS_ERR(page)) {
ntfs_error(sb, "Failed to map directory index page, error %ld.",
-PTR_ERR(page));
goto put_unm_err_out;
err = PTR_ERR(page);
goto err_out;
}
kaddr = (u8*)page_address(page);
fast_descend_into_child_node:
...
...
@@ -773,7 +786,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
"inode 0x%lx or driver bug.", dir_ni->mft_no);
err = -EIO;
goto unm_
unm_
err_out;
goto unm_err_out;
}
if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
...
...
@@ -783,7 +796,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
(long long)sle64_to_cpu(ia->index_block_vcn),
(long long)vcn, dir_ni->mft_no);
err = -EIO;
goto unm_
unm_
err_out;
goto unm_err_out;
}
if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
dir_ni->_IDM(index_block_size)) {
...
...
@@ -795,7 +808,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
le32_to_cpu(ia->index.allocated_size) + 0x18,
dir_ni->_IDM(index_block_size));
err = -EIO;
goto unm_
unm_
err_out;
goto unm_err_out;
}
index_end = (u8*)ia + dir_ni->_IDM(index_block_size);
if (index_end > kaddr + PAGE_CACHE_SIZE) {
...
...
@@ -804,7 +817,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"Cannot access! This is probably a bug in the "
"driver.", (long long)vcn, dir_ni->mft_no);
err = -EIO;
goto unm_
unm_
err_out;
goto unm_err_out;
}
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) {
...
...
@@ -812,7 +825,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"inode 0x%lx exceeds maximum size.",
(long long)vcn, dir_ni->mft_no);
err = -EIO;
goto unm_
unm_
err_out;
goto unm_err_out;
}
/* The first index entry. */
ie = (INDEX_ENTRY*)((u8*)&ia->index +
...
...
@@ -832,7 +845,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"directory inode 0x%lx.",
dir_ni->mft_no);
err = -EIO;
goto unm_
unm_
err_out;
goto unm_err_out;
}
/*
* The last entry cannot contain a name. It can however contain
...
...
@@ -865,8 +878,6 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
found_it2:
mref = le64_to_cpu(ie->_IIF(indexed_file));
ntfs_unmap_page(page);
put_attr_search_ctx(ctx);
unmap_mft_record(READ, dir_ni);
return mref;
}
/*
...
...
@@ -917,7 +928,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"a leaf node in directory inode 0x%lx.",
dir_ni->mft_no);
err = -EIO;
goto unm_
unm_
err_out;
goto unm_err_out;
}
/* Child node present, descend into it. */
old_vcn = vcn;
...
...
@@ -937,26 +948,23 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ntfs_error(sb, "Negative child node vcn in directory inode "
"0x%lx.", dir_ni->mft_no);
err = -EIO;
goto unm_
unm_
err_out;
goto unm_err_out;
}
/* No child node, return -ENOENT. */
ntfs_debug("Entry not found.");
err = -ENOENT;
unm_unm_err_out:
ntfs_unmap_page(page);
put_unm_err_out:
put_attr_search_ctx(ctx);
unm_err_out:
unmap_mft_record(READ, dir_ni);
ntfs_unmap_page(page);
err_out:
if (ctx)
put_attr_search_ctx(ctx);
if (m)
unmap_mft_record(dir_ni);
return ERR_MREF(err);
map_err_out:
ntfs_error(sb, "map_mft_record(READ) failed with error code %ld.",
-PTR_ERR(m));
return ERR_MREF(PTR_ERR(m));
dir_err_out:
ntfs_error(sb, "Corrupt directory. Aborting lookup.");
err = -EIO;
goto
put_unm_
err_out;
goto err_out;
}
#endif
...
...
@@ -1095,22 +1103,8 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto
done
;
fpos
++
;
}
/* Get hold of the mft record for the directory. */
m
=
map_mft_record
(
READ
,
ndir
);
if
(
unlikely
(
IS_ERR
(
m
)))
{
err
=
PTR_ERR
(
m
);
m
=
NULL
;
ctx
=
NULL
;
goto
err_out
;
}
ctx
=
get_attr_search_ctx
(
ndir
,
m
);
if
(
unlikely
(
!
ctx
))
{
err
=
-
ENOMEM
;
goto
err_out
;
}
m
=
NULL
;
ctx
=
NULL
;
/*
* Allocate a buffer to store the current name being processed
* converted to format determined by current NLS.
...
...
@@ -1124,6 +1118,18 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* Are we jumping straight into the index allocation attribute? */
if
(
fpos
>=
vol
->
mft_record_size
)
goto
skip_index_root
;
/* Get hold of the mft record for the directory. */
m
=
map_mft_record
(
ndir
);
if
(
unlikely
(
IS_ERR
(
m
)))
{
err
=
PTR_ERR
(
m
);
m
=
NULL
;
goto
err_out
;
}
ctx
=
get_attr_search_ctx
(
ndir
,
m
);
if
(
unlikely
(
!
ctx
))
{
err
=
-
ENOMEM
;
goto
err_out
;
}
/* Get the offset into the index root attribute. */
ir_pos
=
(
s64
)
fpos
;
/* Find the index root attribute in the mft record. */
...
...
@@ -1162,9 +1168,21 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* Submit the name to the filldir callback. */
rc
=
ntfs_filldir
(
vol
,
&
fpos
,
ndir
,
INDEX_TYPE_ROOT
,
ir
,
ie
,
name
,
dirent
,
filldir
);
if
(
rc
)
if
(
rc
)
{
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
ndir
);
goto
abort
;
}
}
/*
* We are done with the index root and the mft record for that matter.
* We need to release it, otherwise we deadlock on ntfs_attr_iget()
* and/or ntfs_read_page().
*/
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
ndir
);
m
=
NULL
;
ctx
=
NULL
;
/* If there is no index allocation attribute we are finished. */
if
(
!
NInoIndexAllocPresent
(
ndir
))
goto
EOD
;
...
...
@@ -1197,7 +1215,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
/* Get the starting bit position in the current bitmap page. */
cur_bmp_pos
=
bmp_pos
&
((
PAGE_CACHE_SIZE
*
8
)
-
1
);
bmp_pos
&=
~
((
PAGE_CACHE_SIZE
*
8
)
-
1
);
bmp_pos
&=
~
(
u64
)(
(
PAGE_CACHE_SIZE
*
8
)
-
1
);
get_next_bmp_page:
ntfs_debug
(
"Reading bitmap with page index 0x%Lx, bit ofs 0x%Lx"
,
(
long
long
)
bmp_pos
>>
(
3
+
PAGE_CACHE_SHIFT
),
...
...
@@ -1343,8 +1361,6 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* We are finished, set fpos to EOD. */
fpos
=
vdir
->
i_size
+
vol
->
mft_record_size
;
abort:
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
READ
,
ndir
);
kfree
(
name
);
done:
#ifdef DEBUG
...
...
@@ -1366,7 +1382,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if
(
ctx
)
put_attr_search_ctx
(
ctx
);
if
(
m
)
unmap_mft_record
(
READ
,
ndir
);
unmap_mft_record
(
ndir
);
if
(
!
err
)
err
=
-
EIO
;
ntfs_debug
(
"Failed. Returning error code %i."
,
-
err
);
...
...
fs/ntfs/inode.c
View file @
0907f58e
...
...
@@ -278,7 +278,7 @@ void ntfs_destroy_big_inode(struct inode *inode)
ntfs_inode
*
ni
=
NTFS_I
(
inode
);
ntfs_debug
(
"Entering."
);
BUG_ON
(
atomic_read
(
&
ni
->
mft_count
)
||
!
atomic_dec_and_test
(
&
ni
->
count
));
BUG_ON
(
ni
->
page
||
!
atomic_dec_and_test
(
&
ni
->
count
));
kmem_cache_free
(
ntfs_big_inode_cache
,
NTFS_I
(
inode
));
}
...
...
@@ -299,7 +299,7 @@ static inline ntfs_inode *ntfs_alloc_extent_inode(void)
void
ntfs_destroy_extent_inode
(
ntfs_inode
*
ni
)
{
ntfs_debug
(
"Entering."
);
BUG_ON
(
atomic_read
(
&
ni
->
mft_count
)
||
!
atomic_dec_and_test
(
&
ni
->
count
));
BUG_ON
(
ni
->
page
||
!
atomic_dec_and_test
(
&
ni
->
count
));
kmem_cache_free
(
ntfs_inode_cache
,
ni
);
}
...
...
@@ -323,8 +323,7 @@ static void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
atomic_set
(
&
ni
->
count
,
1
);
ni
->
vol
=
NTFS_SB
(
sb
);
init_run_list
(
&
ni
->
run_list
);
init_rwsem
(
&
ni
->
mrec_lock
);
atomic_set
(
&
ni
->
mft_count
,
0
);
init_MUTEX
(
&
ni
->
mrec_lock
);
ni
->
page
=
NULL
;
ni
->
page_ofs
=
0
;
ni
->
attr_list_size
=
0
;
...
...
@@ -504,7 +503,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
ntfs_init_big_inode
(
vi
);
ni
=
NTFS_I
(
vi
);
m
=
map_mft_record
(
READ
,
ni
);
m
=
map_mft_record
(
ni
);
if
(
IS_ERR
(
m
))
{
err
=
PTR_ERR
(
m
);
goto
err_out
;
...
...
@@ -790,6 +789,11 @@ static int ntfs_read_locked_inode(struct inode *vi)
/* No index allocation. */
vi
->
i_size
=
ni
->
initialized_size
=
ni
->
allocated_size
=
0
;
/* We are done with the mft record, so we release it. */
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
ni
);
m
=
NULL
;
ctx
=
NULL
;
goto
skip_large_dir_stuff
;
}
/* LARGE_INDEX: Index allocation present. Setup state. */
NInoSetIndexAllocPresent
(
ni
);
...
...
@@ -834,7 +838,14 @@ static int ntfs_read_locked_inode(struct inode *vi)
ctx
->
attr
->
_ANR
(
initialized_size
));
ni
->
allocated_size
=
sle64_to_cpu
(
ctx
->
attr
->
_ANR
(
allocated_size
));
/*
* We are done with the mft record, so we release it. Otherwise
*
*/
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
ni
);
m
=
NULL
;
ctx
=
NULL
;
/* Get the index bitmap attribute inode. */
bvi
=
ntfs_attr_iget
(
vi
,
AT_BITMAP
,
I30
,
4
);
if
(
unlikely
(
IS_ERR
(
bvi
)))
{
...
...
@@ -858,7 +869,6 @@ static int ntfs_read_locked_inode(struct inode *vi)
bvi
->
i_size
<<
3
,
vi
->
i_size
);
goto
unm_err_out
;
}
skip_large_dir_stuff:
/* Everyone gets read and scan permissions. */
vi
->
i_mode
|=
S_IRUGO
|
S_IXUGO
;
...
...
@@ -998,6 +1008,11 @@ static int ntfs_read_locked_inode(struct inode *vi)
le32_to_cpu
(
ctx
->
attr
->
_ARA
(
value_length
));
}
no_data_attr_special_case:
/* We are done with the mft record, so we release it. */
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
ni
);
m
=
NULL
;
ctx
=
NULL
;
/* Everyone gets all permissions. */
vi
->
i_mode
|=
S_IRWXUGO
;
/* If read-only, noone gets write permissions. */
...
...
@@ -1026,9 +1041,6 @@ static int ntfs_read_locked_inode(struct inode *vi)
else
vi
->
i_blocks
=
ni
->
_ICF
(
compressed_size
)
>>
9
;
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
READ
,
ni
);
ntfs_debug
(
"Done."
);
return
0
;
...
...
@@ -1037,7 +1049,8 @@ static int ntfs_read_locked_inode(struct inode *vi)
err
=
-
EIO
;
if
(
ctx
)
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
READ
,
ni
);
if
(
m
)
unmap_mft_record
(
ni
);
err_out:
ntfs_error
(
vi
->
i_sb
,
"Failed with error code %i. Marking inode 0x%lx "
"as bad."
,
-
err
,
vi
->
i_ino
);
...
...
@@ -1091,7 +1104,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
/* Set inode type to zero but preserve permissions. */
vi
->
i_mode
=
base_vi
->
i_mode
&
~
S_IFMT
;
m
=
map_mft_record
(
READ
,
base_ni
);
m
=
map_mft_record
(
base_ni
);
if
(
IS_ERR
(
m
))
{
err
=
PTR_ERR
(
m
);
goto
err_out
;
...
...
@@ -1265,7 +1278,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
ni
->
nr_extents
=
-
1
;
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
READ
,
base_ni
);
unmap_mft_record
(
base_ni
);
ntfs_debug
(
"Done."
);
return
0
;
...
...
@@ -1275,7 +1288,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
err
=
-
EIO
;
if
(
ctx
)
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
READ
,
base_ni
);
unmap_mft_record
(
base_ni
);
err_out:
ntfs_error
(
vi
->
i_sb
,
"Failed with error code %i while reading "
"attribute inode (mft_no 0x%lx, type 0x%x, name_len "
...
...
@@ -1398,7 +1411,7 @@ void ntfs_read_inode_mount(struct inode *vi)
/* Need this to sanity check attribute list references to $MFT. */
ni
->
seq_no
=
le16_to_cpu
(
m
->
sequence_number
);
/* Provides readpage() and sync_page() for map_mft_record(
READ
). */
/* Provides readpage() and sync_page() for map_mft_record(). */
vi
->
i_mapping
->
a_ops
=
&
ntfs_mft_aops
;
ctx
=
get_attr_search_ctx
(
ni
,
m
);
...
...
@@ -1795,8 +1808,8 @@ void __ntfs_clear_inode(ntfs_inode *ni)
}
}
/* Synchronize with ntfs_commit_inode(). */
down
_write
(
&
ni
->
mrec_lock
);
up
_write
(
&
ni
->
mrec_lock
);
down
(
&
ni
->
mrec_lock
);
up
(
&
ni
->
mrec_lock
);
if
(
NInoDirty
(
ni
))
{
ntfs_error
(
ni
->
vol
->
sb
,
"Failed to commit dirty inode "
"asynchronously."
);
...
...
fs/ntfs/inode.h
View file @
0907f58e
...
...
@@ -72,9 +72,8 @@ struct _ntfs_inode {
* The following fields are only valid for real inodes and extent
* inodes.
*/
struct
rw_semaphore
mrec_lock
;
/* Lock for serializing access to the
struct
semaphore
mrec_lock
;
/* Lock for serializing access to the
mft record belonging to this inode. */
atomic_t
mft_count
;
/* Mapping reference count for book keeping. */
struct
page
*
page
;
/* The page containing the mft record of the
inode. This should only be touched by the
(un)map_mft_record*() functions. */
...
...
fs/ntfs/malloc.h
View file @
0907f58e
...
...
@@ -25,20 +25,6 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
/**
* vmalloc_nofs - allocate any pages but don't allow calls into fs layer
* @size: number of bytes to allocate
*
* Allocate any pages but don't allow calls into fs layer. Return allocated
* memory or NULL if insufficient memory.
*/
static
inline
void
*
vmalloc_nofs
(
unsigned
long
size
)
{
if
(
likely
(
size
>>
PAGE_SHIFT
<
num_physpages
))
return
__vmalloc
(
size
,
GFP_NOFS
|
__GFP_HIGHMEM
,
PAGE_KERNEL
);
return
NULL
;
}
/**
* ntfs_malloc_nofs - allocate memory in multiples of pages
* @size number of bytes to allocate
...
...
@@ -66,7 +52,8 @@ static inline void *ntfs_malloc_nofs(unsigned long size)
static
inline
void
ntfs_free
(
void
*
addr
)
{
if
(
likely
((
unsigned
long
)
addr
<
VMALLOC_START
))
{
if
(
likely
(((
unsigned
long
)
addr
<
VMALLOC_START
)
||
((
unsigned
long
)
addr
>=
VMALLOC_END
)))
{
return
kfree
(
addr
);
/* return free_page((unsigned long)addr); */
}
...
...
fs/ntfs/mft.c
View file @
0907f58e
...
...
@@ -2,7 +2,7 @@
* mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project.
*
* Copyright (c) 2001,2002 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
* modify it under the terms of the GNU General Public License as published
...
...
@@ -85,13 +85,15 @@ int format_mft_record(ntfs_inode *ni, MFT_RECORD *mft_rec)
if
(
mft_rec
)
m
=
mft_rec
;
else
{
m
=
map_mft_record
(
WRITE
,
ni
);
m
=
map_mft_record
(
ni
);
if
(
IS_ERR
(
m
))
return
PTR_ERR
(
m
);
}
__format_mft_record
(
m
,
ni
->
vol
->
mft_record_size
,
ni
->
mft_no
);
if
(
!
mft_rec
)
unmap_mft_record
(
WRITE
,
ni
);
if
(
!
mft_rec
)
{
// FIXME: Need to set the mft record dirty!
unmap_mft_record
(
ni
);
}
return
0
;
}
...
...
@@ -132,7 +134,7 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
struct
page
*
page
;
unsigned
long
index
,
ofs
,
end_index
;
BUG_ON
(
atomic_read
(
&
ni
->
mft_count
)
||
ni
->
page
);
BUG_ON
(
ni
->
page
);
/*
* The index into the page cache and the offset within the page cache
* page of the wanted mft record. FIXME: We need to check for
...
...
@@ -146,70 +148,36 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
end_index
=
mft_vi
->
i_size
>>
PAGE_CACHE_SHIFT
;
/* If the wanted index is out of bounds the mft record doesn't exist. */
if
(
index
>=
end_index
)
{
if
(
unlikely
(
index
>=
end_index
)
)
{
if
(
index
>
end_index
||
(
mft_vi
->
i_size
&
~
PAGE_CACHE_MASK
)
<
ofs
+
vol
->
mft_record_size
)
{
page
=
ERR_PTR
(
-
ENOENT
);
goto
up_
err_out
;
goto
err_out
;
}
}
/* Read, map, and pin the page. */
page
=
ntfs_map_page
(
mft_vi
->
i_mapping
,
index
);
if
(
!
IS_ERR
(
page
))
{
/* Pin the mft record mapping in the ntfs_inode. */
atomic_inc
(
&
ni
->
mft_count
);
/* Setup the references in the ntfs_inode. */
if
(
likely
(
!
IS_ERR
(
page
)))
{
ni
->
page
=
page
;
ni
->
page_ofs
=
ofs
;
return
page_address
(
page
)
+
ofs
;
}
up_err_out:
/* Just in case... */
err_out:
ni
->
page
=
NULL
;
ni
->
page_ofs
=
0
;
ntfs_error
(
vol
->
sb
,
"Failed with error code %lu."
,
-
PTR_ERR
(
page
));
return
(
void
*
)
page
;
}
/**
* unmap_mft_record_page - unmap the page in which a specific mft record resides
* @ni: ntfs inode whose mft record page to unmap
*
* This unmaps the page in which the mft record of the ntfs inode @ni is
* situated and returns. This is a NOOP if highmem is not configured.
*
* The unmap happens via ntfs_unmap_page() which in turn decrements the use
* count on the page thus releasing it from the pinned state.
*
* We do not actually unmap the page from memory of course, as that will be
* done by the page cache code itself when memory pressure increases or
* whatever.
*/
static
inline
void
unmap_mft_record_page
(
ntfs_inode
*
ni
)
{
BUG_ON
(
atomic_read
(
&
ni
->
mft_count
)
||
!
ni
->
page
);
// TODO: If dirty, blah...
ntfs_unmap_page
(
ni
->
page
);
ni
->
page
=
NULL
;
ni
->
page_ofs
=
0
;
return
;
}
/**
* map_mft_record - map, pin and lock an mft record
* @rw: map for read (rw = READ) or write (rw = WRITE)
* @ni: ntfs inode whose MFT record to map
*
* First, take the mrec_lock semaphore for reading or writing, depending on
* the value or @rw. We might now be sleeping, while waiting for the semaphore
* if it was already locked by someone else.
* First, take the mrec_lock semaphore. We might now be sleeping, while waiting
* for the semaphore if it was already locked by someone else.
*
* Then increment the map reference count and return the mft. If this is the
* first invocation, the page of the record is first mapped using
* map_mft_record_page().
* The page of the record is first mapped using map_mft_record_page() before
* being returned to the caller.
*
* This in turn uses ntfs_map_page() to get the page containing the wanted mft
* record (it in turn calls read_cache_page() which reads it in from disk if
...
...
@@ -234,11 +202,11 @@ static inline void unmap_mft_record_page(ntfs_inode *ni)
* locking problem then is them locking the page while we are accessing it.
*
* 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.
Grr. In that
*
case we wouldn't need 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() invokation and
*
the code becomes
so much simpler this way that it is well worth it.
* 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() invokation 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
...
...
@@ -251,89 +219,75 @@ static inline void unmap_mft_record_page(ntfs_inode *ni)
* A: No, the inode ones mean we want to change the mft record, not we want to
* write it out.
*/
MFT_RECORD
*
map_mft_record
(
const
int
rw
,
ntfs_inode
*
ni
)
MFT_RECORD
*
map_mft_record
(
ntfs_inode
*
ni
)
{
MFT_RECORD
*
m
;
ntfs_debug
(
"Entering for mft_no 0x%lx, mapping for %s."
,
ni
->
mft_no
,
rw
==
READ
?
"READ"
:
"WRITE"
);
ntfs_debug
(
"Entering for mft_no 0x%lx."
,
ni
->
mft_no
);
/* Make sure the ntfs inode doesn't go away. */
atomic_inc
(
&
ni
->
count
);
/* Serialize access to this mft record. */
if
(
rw
==
READ
)
down_read
(
&
ni
->
mrec_lock
);
else
down_write
(
&
ni
->
mrec_lock
);
/* If already mapped, bump reference count and return the mft record. */
if
(
atomic_read
(
&
ni
->
mft_count
))
{
BUG_ON
(
!
ni
->
page
);
atomic_inc
(
&
ni
->
mft_count
);
return
page_address
(
ni
->
page
)
+
ni
->
page_ofs
;
}
down
(
&
ni
->
mrec_lock
);
/* Wasn't mapped. Map it now and return it if all was ok. */
m
=
map_mft_record_page
(
ni
);
if
(
!
IS_ERR
(
m
))
if
(
likely
(
!
IS_ERR
(
m
)
))
return
m
;
/* Mapping failed. Release the mft record lock. */
if
(
rw
==
READ
)
up_read
(
&
ni
->
mrec_lock
);
else
up_write
(
&
ni
->
mrec_lock
);
ntfs_error
(
ni
->
vol
->
sb
,
"Failed with error code %lu."
,
-
PTR_ERR
(
m
));
/* Release the ntfs inode and return the error code. */
up
(
&
ni
->
mrec_lock
);
atomic_dec
(
&
ni
->
count
);
ntfs_error
(
ni
->
vol
->
sb
,
"Failed with error code %lu."
,
-
PTR_ERR
(
m
));
return
m
;
}
/**
* unmap_mft_record - release a mapped mft record
* @rw: unmap from read (@rw = READ) or write (@rw = WRITE)
* @ni: ntfs inode whose MFT record to unmap
*
* First, decrement the mapping count and when it reaches zero unmap the mft
* record.
* unmap_mft_record_page - unmap the page in which a specific mft record resides
* @ni: ntfs inode whose mft record page to unmap
*
* Second, release the mrec_lock semaphore.
* This unmaps the page in which the mft record of the ntfs inode @ni is
* situated and returns. This is a NOOP if highmem is not configured.
*
* The mft record is now released for others to get hold of.
* The unmap happens via ntfs_unmap_page() which in turn decrements the use
* count on the page thus releasing it from the pinned state.
*
* Finally, release the ntfs inode by decreasing the ntfs inode reference count.
* We do not actually unmap the page from memory of course, as that will be
* done by the page cache code itself when memory pressure increases or
* whatever.
*/
static
inline
void
unmap_mft_record_page
(
ntfs_inode
*
ni
)
{
BUG_ON
(
!
ni
->
page
);
// TODO: If dirty, blah...
ntfs_unmap_page
(
ni
->
page
);
ni
->
page
=
NULL
;
ni
->
page_ofs
=
0
;
return
;
}
/**
* unmap_mft_record - release a mapped mft record
* @ni: ntfs inode whose MFT record to unmap
*
* NOTE: If caller had the mft record mapped for write and has modified it, it
* is imperative to set the mft record dirty BEFORE calling unmap_mft_record().
* We release the page mapping and the mrec_lock mutex which unmaps the mft
* record and releases it for others to get hold of. We also release the ntfs
* inode by decrementing the ntfs inode reference count.
*
* NOTE:
This has to be done both for 'normal' mft records, and for extent
mft
* record
s
.
* NOTE:
If caller has modified the mft record, it is imperative to set the
mft
* record
dirty BEFORE calling unmap_mft_record()
.
*/
void
unmap_mft_record
(
const
int
rw
,
ntfs_inode
*
ni
)
void
unmap_mft_record
(
ntfs_inode
*
ni
)
{
struct
page
*
page
=
ni
->
page
;
BUG_ON
(
!
atomic_read
(
&
ni
->
mft_count
)
||
!
page
);
ntfs_debug
(
"Entering for mft_no 0x%lx, unmapping from %s."
,
ni
->
mft_no
,
rw
==
READ
?
"READ"
:
"WRITE"
);
BUG_ON
(
!
page
);
/* Only release the actual page mapping if this is the last one. */
if
(
atomic_dec_and_test
(
&
ni
->
mft_count
))
unmap_mft_record_page
(
ni
);
ntfs_debug
(
"Entering for mft_no 0x%lx."
,
ni
->
mft_no
);
/* Release the semaphore. */
if
(
rw
==
READ
)
up_read
(
&
ni
->
mrec_lock
);
else
up_write
(
&
ni
->
mrec_lock
);
/* Release the ntfs inode. */
unmap_mft_record_page
(
ni
);
up
(
&
ni
->
mrec_lock
);
atomic_dec
(
&
ni
->
count
);
/*
* If pure ntfs_inode, i.e. no vfs inode attached, we leave it to
* ntfs_clear_extent_inode() in the extent inode case, and to the
...
...
@@ -355,11 +309,6 @@ void unmap_mft_record(const int rw, ntfs_inode *ni)
*
* On successful return, @ntfs_ino contains a pointer to the ntfs_inode
* structure of the mapped extent inode.
*
* Note, we always map for READ. We consider this lock as irrelevant because
* the base inode will be write locked in all cases when we want to write to
* an extent inode which already gurantees that there is no-one else accessing
* the extent inode.
*/
MFT_RECORD
*
map_extent_mft_record
(
ntfs_inode
*
base_ni
,
MFT_REF
mref
,
ntfs_inode
**
ntfs_ino
)
...
...
@@ -393,21 +342,21 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
break
;
}
}
if
(
ni
)
{
if
(
likely
(
ni
!=
NULL
)
)
{
up
(
&
base_ni
->
extent_lock
);
atomic_dec
(
&
base_ni
->
count
);
/* We found the record; just have to map and return it. */
m
=
map_mft_record
(
READ
,
ni
);
/*
Map mft record increments
this on success. */
m
=
map_mft_record
(
ni
);
/*
map_mft_record() has incremented
this on success. */
atomic_dec
(
&
ni
->
count
);
if
(
!
IS_ERR
(
m
))
{
if
(
likely
(
!
IS_ERR
(
m
)
))
{
/* Verify the sequence number. */
if
(
l
e16_to_cpu
(
m
->
sequence_number
)
==
seq_no
)
{
if
(
l
ikely
(
le16_to_cpu
(
m
->
sequence_number
)
==
seq_no
)
)
{
ntfs_debug
(
"Done 1."
);
*
ntfs_ino
=
ni
;
return
m
;
}
unmap_mft_record
(
READ
,
ni
);
unmap_mft_record
(
ni
);
ntfs_error
(
base_ni
->
vol
->
sb
,
"Found stale extent mft "
"reference! Corrupt file system. "
"Run chkdsk."
);
...
...
@@ -420,7 +369,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
(
!
ni
)
{
if
(
unlikely
(
!
ni
)
)
{
up
(
&
base_ni
->
extent_lock
);
atomic_dec
(
&
base_ni
->
count
);
return
ERR_PTR
(
-
ENOMEM
);
...
...
@@ -430,15 +379,15 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
ni
->
nr_extents
=
-
1
;
ni
->
_INE
(
base_ntfs_ino
)
=
base_ni
;
/* Now map the record. */
m
=
map_mft_record
(
READ
,
ni
);
if
(
IS_ERR
(
m
))
{
m
=
map_mft_record
(
ni
);
if
(
unlikely
(
IS_ERR
(
m
)
))
{
up
(
&
base_ni
->
extent_lock
);
atomic_dec
(
&
base_ni
->
count
);
ntfs_clear_extent_inode
(
ni
);
goto
map_err_out
;
}
/* Verify the sequence number. */
if
(
le16_to_cpu
(
m
->
sequence_number
)
!=
seq_no
)
{
if
(
unlikely
(
le16_to_cpu
(
m
->
sequence_number
)
!=
seq_no
)
)
{
ntfs_error
(
base_ni
->
vol
->
sb
,
"Found stale extent mft "
"reference! Corrupt file system. Run chkdsk."
);
destroy_ni
=
TRUE
;
...
...
@@ -451,7 +400,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
int
new_size
=
(
base_ni
->
nr_extents
+
4
)
*
sizeof
(
ntfs_inode
*
);
tmp
=
(
ntfs_inode
**
)
kmalloc
(
new_size
,
GFP_NOFS
);
if
(
!
tmp
)
{
if
(
unlikely
(
!
tmp
)
)
{
ntfs_error
(
base_ni
->
vol
->
sb
,
"Failed to allocate "
"internal buffer."
);
destroy_ni
=
TRUE
;
...
...
@@ -472,7 +421,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
*
ntfs_ino
=
ni
;
return
m
;
unm_err_out:
unmap_mft_record
(
READ
,
ni
);
unmap_mft_record
(
ni
);
up
(
&
base_ni
->
extent_lock
);
atomic_dec
(
&
base_ni
->
count
);
/*
...
...
fs/ntfs/mft.h
View file @
0907f58e
...
...
@@ -31,15 +31,15 @@ extern int format_mft_record(ntfs_inode *ni, MFT_RECORD *m);
//extern int format_mft_record2(struct super_block *vfs_sb,
// const unsigned long inum, MFT_RECORD *m);
extern
MFT_RECORD
*
map_mft_record
(
const
int
rw
,
ntfs_inode
*
ni
);
extern
void
unmap_mft_record
(
const
int
rw
,
ntfs_inode
*
ni
);
extern
MFT_RECORD
*
map_mft_record
(
ntfs_inode
*
ni
);
extern
void
unmap_mft_record
(
ntfs_inode
*
ni
);
extern
MFT_RECORD
*
map_extent_mft_record
(
ntfs_inode
*
base_ni
,
MFT_REF
mref
,
ntfs_inode
**
ntfs_ino
);
static
inline
void
unmap_extent_mft_record
(
ntfs_inode
*
ni
)
{
unmap_mft_record
(
READ
,
ni
);
unmap_mft_record
(
ni
);
return
;
}
...
...
fs/ntfs/namei.c
View file @
0907f58e
...
...
@@ -162,6 +162,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
handle_name:
{
struct
dentry
*
real_dent
;
MFT_RECORD
*
m
;
attr_search_context
*
ctx
;
ntfs_inode
*
ni
=
NTFS_I
(
dent_inode
);
int
err
;
...
...
@@ -175,22 +176,23 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
name
->
len
*
3
+
1
);
kfree
(
name
);
}
else
/* if (name->type == FILE_NAME_DOS) */
{
/* Case 3. */
MFT_RECORD
*
m
;
FILE_NAME_ATTR
*
fn
;
kfree
(
name
);
/* Find the WIN32 name corresponding to the matched DOS name. */
ni
=
NTFS_I
(
dent_inode
);
m
=
map_mft_record
(
READ
,
ni
);
m
=
map_mft_record
(
ni
);
if
(
IS_ERR
(
m
))
{
err
=
PTR_ERR
(
m
);
goto
name_err_out
;
m
=
NULL
;
ctx
=
NULL
;
goto
err_out
;
}
ctx
=
get_attr_search_ctx
(
ni
,
m
);
if
(
!
ctx
)
{
err
=
-
ENOMEM
;
goto
unm_
err_out
;
goto
err_out
;
}
do
{
ATTR_RECORD
*
a
;
...
...
@@ -202,21 +204,21 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
"namespace counterpart to DOS "
"file name. Run chkdsk."
);
err
=
-
EIO
;
goto
put_unm_
err_out
;
goto
err_out
;
}
/* Consistency checks. */
a
=
ctx
->
attr
;
if
(
a
->
non_resident
||
a
->
flags
)
goto
eio_
put_unm_
err_out
;
goto
eio_err_out
;
val_len
=
le32_to_cpu
(
a
->
_ARA
(
value_length
));
if
(
le16_to_cpu
(
a
->
_ARA
(
value_offset
))
+
val_len
>
le32_to_cpu
(
a
->
length
))
goto
eio_
put_unm_
err_out
;
goto
eio_err_out
;
fn
=
(
FILE_NAME_ATTR
*
)((
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
_ARA
(
value_offset
)));
if
((
u32
)(
fn
->
file_name_length
*
sizeof
(
uchar_t
)
+
sizeof
(
FILE_NAME_ATTR
))
>
val_len
)
goto
eio_
put_unm_
err_out
;
goto
eio_err_out
;
}
while
(
fn
->
file_name_type
!=
FILE_NAME_WIN32
);
/* Convert the found WIN32 name to current NLS code page. */
...
...
@@ -226,13 +228,15 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
fn
->
file_name_length
*
3
+
1
);
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
READ
,
ni
);
unmap_mft_record
(
ni
);
}
m
=
NULL
;
ctx
=
NULL
;
/* Check if a conversion error occured. */
if
((
signed
)
nls_name
.
len
<
0
)
{
err
=
(
signed
)
nls_name
.
len
;
goto
name_
err_out
;
goto
err_out
;
}
nls_name
.
hash
=
full_name_hash
(
nls_name
.
name
,
nls_name
.
len
);
...
...
@@ -248,7 +252,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
kfree
(
nls_name
.
name
);
if
(
!
real_dent
)
{
err
=
-
ENOMEM
;
goto
name_
err_out
;
goto
err_out
;
}
d_add
(
real_dent
,
dent_inode
);
return
real_dent
;
...
...
@@ -269,14 +273,14 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
d_instantiate
(
real_dent
,
dent_inode
);
return
real_dent
;
eio_
put_unm_
err_out:
eio_err_out:
ntfs_error
(
vol
->
sb
,
"Illegal file name attribute. Run chkdsk."
);
err
=
-
EIO
;
put_unm_
err_out:
put_attr_search_ctx
(
ctx
);
unm_err_out:
unmap_mft_record
(
READ
,
ni
);
name_err_out:
err_out:
if
(
ctx
)
put_attr_search_ctx
(
ctx
);
if
(
m
)
unmap_mft_record
(
ni
);
iput
(
dent_inode
);
return
ERR_PTR
(
err
);
}
...
...
fs/ntfs/super.c
View file @
0907f58e
...
...
@@ -852,7 +852,7 @@ static BOOL load_system_files(ntfs_volume *vol)
ntfs_error
(
sb
,
"Failed to load $Volume."
);
goto
iput_lcnbmp_err_out
;
}
m
=
map_mft_record
(
READ
,
NTFS_I
(
vol
->
vol_ino
));
m
=
map_mft_record
(
NTFS_I
(
vol
->
vol_ino
));
if
(
IS_ERR
(
m
))
{
iput_volume_failed:
iput
(
vol
->
vol_ino
);
...
...
@@ -867,7 +867,7 @@ static BOOL load_system_files(ntfs_volume *vol)
err_put_vol:
put_attr_search_ctx
(
ctx
);
get_ctx_vol_failed:
unmap_mft_record
(
READ
,
NTFS_I
(
vol
->
vol_ino
));
unmap_mft_record
(
NTFS_I
(
vol
->
vol_ino
));
goto
iput_volume_failed
;
}
vi
=
(
VOLUME_INFORMATION
*
)((
char
*
)
ctx
->
attr
+
...
...
@@ -882,7 +882,7 @@ static BOOL load_system_files(ntfs_volume *vol)
vol
->
major_ver
=
vi
->
major_ver
;
vol
->
minor_ver
=
vi
->
minor_ver
;
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
READ
,
NTFS_I
(
vol
->
vol_ino
));
unmap_mft_record
(
NTFS_I
(
vol
->
vol_ino
));
printk
(
KERN_INFO
"NTFS volume version %i.%i.
\n
"
,
vol
->
major_ver
,
vol
->
minor_ver
);
/*
...
...
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