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
nexedi
linux
Commits
af81e654
Commit
af81e654
authored
Nov 10, 2004
by
Anton Altaparmakov
Browse files
Options
Browse Files
Download
Plain Diff
Merge
ssh://linux-ntfs@bkbits.net/ntfs-2.6-devel
into cantab.net:/home/src/ntfs-2.6-devel
parents
aae109de
d586a8d9
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
68 additions
and
76 deletions
+68
-76
Documentation/filesystems/ntfs.txt
Documentation/filesystems/ntfs.txt
+3
-0
fs/ntfs/ChangeLog
fs/ntfs/ChangeLog
+4
-1
fs/ntfs/Makefile
fs/ntfs/Makefile
+1
-1
fs/ntfs/aops.c
fs/ntfs/aops.c
+60
-74
No files found.
Documentation/filesystems/ntfs.txt
View file @
af81e654
...
@@ -432,6 +432,9 @@ ChangeLog
...
@@ -432,6 +432,9 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.1.22:
- Improve handling of ntfs volumes with errors.
- Fix various bugs and race conditions.
2.1.21:
2.1.21:
- Fix several race conditions and various other bugs.
- Fix several race conditions and various other bugs.
- Many internal cleanups, code reorganization, optimizations, and mft
- Many internal cleanups, code reorganization, optimizations, and mft
...
...
fs/ntfs/ChangeLog
View file @
af81e654
...
@@ -25,7 +25,7 @@ ToDo/Notes:
...
@@ -25,7 +25,7 @@ ToDo/Notes:
- Enable the code for setting the NT4 compatibility flag when we start
- Enable the code for setting the NT4 compatibility flag when we start
making NTFS 1.2 specific modifications.
making NTFS 1.2 specific modifications.
2.1.22
-WIP
2.1.22
- Many bug and race fixes and error handling improvements.
- Improve error handling in fs/ntfs/inode.c::ntfs_truncate().
- Improve error handling in fs/ntfs/inode.c::ntfs_truncate().
- Change fs/ntfs/inode.c::ntfs_truncate() to return an error code
- Change fs/ntfs/inode.c::ntfs_truncate() to return an error code
...
@@ -85,6 +85,9 @@ ToDo/Notes:
...
@@ -85,6 +85,9 @@ ToDo/Notes:
complete runlist for the mft mirror is always mapped into memory.
complete runlist for the mft mirror is always mapped into memory.
- Add creation of buffers to fs/ntfs/mft.c::ntfs_sync_mft_mirror().
- Add creation of buffers to fs/ntfs/mft.c::ntfs_sync_mft_mirror().
- Improve error handling in fs/ntfs/aops.c::ntfs_{read,write}_block().
- Improve error handling in fs/ntfs/aops.c::ntfs_{read,write}_block().
- Cleanup fs/ntfs/aops.c::ntfs_{read,write}page() since we know that a
resident attribute will be smaller than a page which makes the code
simpler. Also make the code more tolerant to concurrent ->truncate.
2.1.21 - Fix some races and bugs, rewrite mft write code, add mft allocator.
2.1.21 - Fix some races and bugs, rewrite mft write code, add mft allocator.
...
...
fs/ntfs/Makefile
View file @
af81e654
...
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
...
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o
\
index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o
\
unistr.o upcase.o
unistr.o upcase.o
EXTRA_CFLAGS
=
-DNTFS_VERSION
=
\"
2.1.22
-WIP
\"
EXTRA_CFLAGS
=
-DNTFS_VERSION
=
\"
2.1.22
\"
ifeq
($(CONFIG_NTFS_DEBUG),y)
ifeq
($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS
+=
-DDEBUG
EXTRA_CFLAGS
+=
-DDEBUG
...
...
fs/ntfs/aops.c
View file @
af81e654
...
@@ -341,7 +341,7 @@ static int ntfs_read_block(struct page *page)
...
@@ -341,7 +341,7 @@ static int ntfs_read_block(struct page *page)
*/
*/
static
int
ntfs_readpage
(
struct
file
*
file
,
struct
page
*
page
)
static
int
ntfs_readpage
(
struct
file
*
file
,
struct
page
*
page
)
{
{
s64
attr_pos
;
loff_t
i_size
;
ntfs_inode
*
ni
,
*
base_ni
;
ntfs_inode
*
ni
,
*
base_ni
;
u8
*
kaddr
;
u8
*
kaddr
;
ntfs_attr_search_ctx
*
ctx
;
ntfs_attr_search_ctx
*
ctx
;
...
@@ -350,7 +350,6 @@ static int ntfs_readpage(struct file *file, struct page *page)
...
@@ -350,7 +350,6 @@ static int ntfs_readpage(struct file *file, struct page *page)
int
err
=
0
;
int
err
=
0
;
BUG_ON
(
!
PageLocked
(
page
));
BUG_ON
(
!
PageLocked
(
page
));
/*
/*
* This can potentially happen because we clear PageUptodate() during
* This can potentially happen because we clear PageUptodate() during
* ntfs_writepage() of MstProtected() attributes.
* ntfs_writepage() of MstProtected() attributes.
...
@@ -359,7 +358,6 @@ static int ntfs_readpage(struct file *file, struct page *page)
...
@@ -359,7 +358,6 @@ static int ntfs_readpage(struct file *file, struct page *page)
unlock_page
(
page
);
unlock_page
(
page
);
return
0
;
return
0
;
}
}
ni
=
NTFS_I
(
page
->
mapping
->
host
);
ni
=
NTFS_I
(
page
->
mapping
->
host
);
/* NInoNonResident() == NInoIndexAllocPresent() */
/* NInoNonResident() == NInoIndexAllocPresent() */
...
@@ -381,12 +379,23 @@ static int ntfs_readpage(struct file *file, struct page *page)
...
@@ -381,12 +379,23 @@ static int ntfs_readpage(struct file *file, struct page *page)
/* Normal data stream. */
/* Normal data stream. */
return
ntfs_read_block
(
page
);
return
ntfs_read_block
(
page
);
}
}
/* Attribute is resident, implying it is not compressed or encrypted. */
/*
* Attribute is resident, implying it is not compressed or encrypted.
* This also means the attribute is smaller than an mft record and
* hence smaller than a page, so can simply zero out any pages with
* index above 0. We can also do this if the file size is 0.
*/
if
(
unlikely
(
page
->
index
>
0
||
!
i_size_read
(
VFS_I
(
ni
))))
{
kaddr
=
kmap_atomic
(
page
,
KM_USER0
);
memset
(
kaddr
,
0
,
PAGE_CACHE_SIZE
);
flush_dcache_page
(
page
);
kunmap_atomic
(
kaddr
,
KM_USER0
);
goto
done
;
}
if
(
!
NInoAttr
(
ni
))
if
(
!
NInoAttr
(
ni
))
base_ni
=
ni
;
base_ni
=
ni
;
else
else
base_ni
=
ni
->
ext
.
base_ntfs_ino
;
base_ni
=
ni
->
ext
.
base_ntfs_ino
;
/* Map, pin, and lock the mft record. */
/* Map, pin, and lock the mft record. */
mrec
=
map_mft_record
(
base_ni
);
mrec
=
map_mft_record
(
base_ni
);
if
(
IS_ERR
(
mrec
))
{
if
(
IS_ERR
(
mrec
))
{
...
@@ -402,35 +411,25 @@ static int ntfs_readpage(struct file *file, struct page *page)
...
@@ -402,35 +411,25 @@ static int ntfs_readpage(struct file *file, struct page *page)
CASE_SENSITIVE
,
0
,
NULL
,
0
,
ctx
);
CASE_SENSITIVE
,
0
,
NULL
,
0
,
ctx
);
if
(
unlikely
(
err
))
if
(
unlikely
(
err
))
goto
put_unm_err_out
;
goto
put_unm_err_out
;
/* Starting position of the page within the attribute value. */
attr_pos
=
page
->
index
<<
PAGE_CACHE_SHIFT
;
/* The total length of the attribute value. */
attr_len
=
le32_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_length
);
attr_len
=
le32_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_length
);
i_size
=
i_size_read
(
VFS_I
(
ni
));
if
(
unlikely
(
attr_len
>
i_size
))
attr_len
=
i_size
;
kaddr
=
kmap_atomic
(
page
,
KM_USER0
);
kaddr
=
kmap_atomic
(
page
,
KM_USER0
);
/* Copy over in bounds data, zeroing the remainder of the page. */
if
(
attr_pos
<
attr_len
)
{
u32
bytes
=
attr_len
-
attr_pos
;
if
(
bytes
>
PAGE_CACHE_SIZE
)
bytes
=
PAGE_CACHE_SIZE
;
else
if
(
bytes
<
PAGE_CACHE_SIZE
)
memset
(
kaddr
+
bytes
,
0
,
PAGE_CACHE_SIZE
-
bytes
);
/* Copy the data to the page. */
/* Copy the data to the page. */
memcpy
(
kaddr
,
attr_pos
+
(
char
*
)
ctx
->
attr
+
memcpy
(
kaddr
,
(
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
le16_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_offset
),
ctx
->
attr
->
data
.
resident
.
value_offset
),
bytes
);
attr_len
);
}
else
/* Zero the remainder of the page. */
memset
(
kaddr
,
0
,
PAGE_CACHE_SIZE
);
memset
(
kaddr
+
attr_len
,
0
,
PAGE_CACHE_SIZE
-
attr_len
);
flush_dcache_page
(
page
);
flush_dcache_page
(
page
);
kunmap_atomic
(
kaddr
,
KM_USER0
);
kunmap_atomic
(
kaddr
,
KM_USER0
);
SetPageUptodate
(
page
);
put_unm_err_out:
put_unm_err_out:
ntfs_attr_put_search_ctx
(
ctx
);
ntfs_attr_put_search_ctx
(
ctx
);
unm_err_out:
unm_err_out:
unmap_mft_record
(
base_ni
);
unmap_mft_record
(
base_ni
);
done:
SetPageUptodate
(
page
);
err_out:
err_out:
unlock_page
(
page
);
unlock_page
(
page
);
return
err
;
return
err
;
...
@@ -1223,21 +1222,22 @@ static int ntfs_write_mst_block(struct page *page,
...
@@ -1223,21 +1222,22 @@ static int ntfs_write_mst_block(struct page *page,
*/
*/
static
int
ntfs_writepage
(
struct
page
*
page
,
struct
writeback_control
*
wbc
)
static
int
ntfs_writepage
(
struct
page
*
page
,
struct
writeback_control
*
wbc
)
{
{
s64
attr_pos
;
loff_t
i_size
;
struct
inode
*
vi
;
struct
inode
*
vi
;
ntfs_inode
*
ni
,
*
base_ni
;
ntfs_inode
*
ni
,
*
base_ni
;
char
*
kaddr
;
char
*
kaddr
;
ntfs_attr_search_ctx
*
ctx
;
ntfs_attr_search_ctx
*
ctx
;
MFT_RECORD
*
m
;
MFT_RECORD
*
m
;
u32
attr_len
,
bytes
;
u32
attr_len
;
int
err
;
int
err
;
BUG_ON
(
!
PageLocked
(
page
));
BUG_ON
(
!
PageLocked
(
page
));
vi
=
page
->
mapping
->
host
;
vi
=
page
->
mapping
->
host
;
i_size
=
i_size_read
(
vi
);
/* Is the page fully outside i_size? (truncate in progress) */
/* Is the page fully outside i_size? (truncate in progress) */
if
(
unlikely
(
page
->
index
>=
(
vi
->
i_size
+
PAGE_CACHE_SIZE
-
1
)
>>
if
(
unlikely
(
page
->
index
>=
(
i_size
+
PAGE_CACHE_SIZE
-
1
)
>>
PAGE_CACHE_SHIFT
))
{
PAGE_CACHE_SHIFT
))
{
/*
/*
* The page may have dirty, unmapped buffers. Make them
* The page may have dirty, unmapped buffers. Make them
...
@@ -1248,7 +1248,6 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
...
@@ -1248,7 +1248,6 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
ntfs_debug
(
"Write outside i_size - truncated?"
);
ntfs_debug
(
"Write outside i_size - truncated?"
);
return
0
;
return
0
;
}
}
ni
=
NTFS_I
(
vi
);
ni
=
NTFS_I
(
vi
);
/* NInoNonResident() == NInoIndexAllocPresent() */
/* NInoNonResident() == NInoIndexAllocPresent() */
...
@@ -1284,9 +1283,9 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
...
@@ -1284,9 +1283,9 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
}
}
}
}
/* We have to zero every time due to mmap-at-end-of-file. */
/* We have to zero every time due to mmap-at-end-of-file. */
if
(
page
->
index
>=
(
vi
->
i_size
>>
PAGE_CACHE_SHIFT
))
{
if
(
page
->
index
>=
(
i_size
>>
PAGE_CACHE_SHIFT
))
{
/* The page straddles i_size. */
/* The page straddles i_size. */
unsigned
int
ofs
=
vi
->
i_size
&
~
PAGE_CACHE_MASK
;
unsigned
int
ofs
=
i_size
&
~
PAGE_CACHE_MASK
;
kaddr
=
kmap_atomic
(
page
,
KM_USER0
);
kaddr
=
kmap_atomic
(
page
,
KM_USER0
);
memset
(
kaddr
+
ofs
,
0
,
PAGE_CACHE_SIZE
-
ofs
);
memset
(
kaddr
+
ofs
,
0
,
PAGE_CACHE_SIZE
-
ofs
);
flush_dcache_page
(
page
);
flush_dcache_page
(
page
);
...
@@ -1300,16 +1299,25 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
...
@@ -1300,16 +1299,25 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
}
}
/*
/*
* Attribute is resident, implying it is not compressed, encrypted,
* Attribute is resident, implying it is not compressed, encrypted,
* sparse, or mst protected.
* sparse, or mst protected. This also means the attribute is smaller
* than an mft record and hence smaller than a page, so can simply
* return error on any pages with index above 0.
*/
*/
BUG_ON
(
page_has_buffers
(
page
));
BUG_ON
(
page_has_buffers
(
page
));
BUG_ON
(
!
PageUptodate
(
page
));
BUG_ON
(
!
PageUptodate
(
page
));
if
(
unlikely
(
page
->
index
>
0
))
{
ntfs_error
(
vi
->
i_sb
,
"BUG()! page->index (0x%lx) > 0. "
"Aborting write."
,
page
->
index
);
BUG_ON
(
PageWriteback
(
page
));
set_page_writeback
(
page
);
unlock_page
(
page
);
end_page_writeback
(
page
);
return
-
EIO
;
}
if
(
!
NInoAttr
(
ni
))
if
(
!
NInoAttr
(
ni
))
base_ni
=
ni
;
base_ni
=
ni
;
else
else
base_ni
=
ni
->
ext
.
base_ntfs_ino
;
base_ni
=
ni
->
ext
.
base_ntfs_ino
;
/* Map, pin, and lock the mft record. */
/* Map, pin, and lock the mft record. */
m
=
map_mft_record
(
base_ni
);
m
=
map_mft_record
(
base_ni
);
if
(
IS_ERR
(
m
))
{
if
(
IS_ERR
(
m
))
{
...
@@ -1327,32 +1335,6 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
...
@@ -1327,32 +1335,6 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
CASE_SENSITIVE
,
0
,
NULL
,
0
,
ctx
);
CASE_SENSITIVE
,
0
,
NULL
,
0
,
ctx
);
if
(
unlikely
(
err
))
if
(
unlikely
(
err
))
goto
err_out
;
goto
err_out
;
/* Starting position of the page within the attribute value. */
attr_pos
=
page
->
index
<<
PAGE_CACHE_SHIFT
;
/* The total length of the attribute value. */
attr_len
=
le32_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_length
);
if
(
unlikely
(
vi
->
i_size
!=
attr_len
))
{
ntfs_error
(
vi
->
i_sb
,
"BUG()! i_size (0x%llx) doesn't match "
"attr_len (0x%x). Aborting write."
,
vi
->
i_size
,
attr_len
);
err
=
-
EIO
;
goto
err_out
;
}
if
(
unlikely
(
attr_pos
>=
attr_len
))
{
ntfs_error
(
vi
->
i_sb
,
"BUG()! attr_pos (0x%llx) > attr_len "
"(0x%x). Aborting write."
,
(
unsigned
long
long
)
attr_pos
,
attr_len
);
err
=
-
EIO
;
goto
err_out
;
}
bytes
=
attr_len
-
attr_pos
;
if
(
unlikely
(
bytes
>
PAGE_CACHE_SIZE
))
bytes
=
PAGE_CACHE_SIZE
;
/*
/*
* Keep the VM happy. This must be done otherwise the radix-tree tag
* Keep the VM happy. This must be done otherwise the radix-tree tag
* PAGECACHE_TAG_DIRTY remains set even though the page is clean.
* PAGECACHE_TAG_DIRTY remains set even though the page is clean.
...
@@ -1384,26 +1366,30 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
...
@@ -1384,26 +1366,30 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
* TODO: ntfs_truncate(), others?
* TODO: ntfs_truncate(), others?
*/
*/
attr_len
=
le32_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_length
);
i_size
=
i_size_read
(
VFS_I
(
ni
));
kaddr
=
kmap_atomic
(
page
,
KM_USER0
);
kaddr
=
kmap_atomic
(
page
,
KM_USER0
);
if
(
unlikely
(
attr_len
>
i_size
))
{
/* Zero out of bounds area in the mft record. */
memset
((
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_offset
)
+
i_size
,
0
,
attr_len
-
i_size
);
attr_len
=
i_size
;
}
/* Copy the data from the page to the mft record. */
/* Copy the data from the page to the mft record. */
memcpy
((
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
memcpy
((
u8
*
)
ctx
->
attr
+
ctx
->
attr
->
data
.
resident
.
value_offset
)
+
attr_pos
,
le16_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_offset
)
,
kaddr
,
bytes
);
kaddr
,
attr_len
);
flush_dcache_mft_record_page
(
ctx
->
ntfs_ino
);
flush_dcache_mft_record_page
(
ctx
->
ntfs_ino
);
#if 0
/* Zero out of bounds area in the page cache page. */
/* Zero out of bounds area. */
memset
(
kaddr
+
attr_len
,
0
,
PAGE_CACHE_SIZE
-
attr_len
);
if (likely(bytes < PAGE_CACHE_SIZE)) {
memset(kaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
flush_dcache_page
(
page
);
flush_dcache_page
(
page
);
}
#endif
kunmap_atomic
(
kaddr
,
KM_USER0
);
kunmap_atomic
(
kaddr
,
KM_USER0
);
end_page_writeback
(
page
);
end_page_writeback
(
page
);
/* Mark the mft record dirty, so it gets written back. */
/* Mark the mft record dirty, so it gets written back. */
mark_mft_record_dirty
(
ctx
->
ntfs_ino
);
mark_mft_record_dirty
(
ctx
->
ntfs_ino
);
ntfs_attr_put_search_ctx
(
ctx
);
ntfs_attr_put_search_ctx
(
ctx
);
unmap_mft_record
(
base_ni
);
unmap_mft_record
(
base_ni
);
return
0
;
return
0
;
...
@@ -1413,13 +1399,13 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
...
@@ -1413,13 +1399,13 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
"page so we try again later."
);
"page so we try again later."
);
/*
/*
* Put the page back on mapping->dirty_pages, but leave its
* Put the page back on mapping->dirty_pages, but leave its
* buffer
's
dirty state as-is.
* buffer
s'
dirty state as-is.
*/
*/
redirty_page_for_writepage
(
wbc
,
page
);
redirty_page_for_writepage
(
wbc
,
page
);
err
=
0
;
err
=
0
;
}
else
{
}
else
{
ntfs_error
(
vi
->
i_sb
,
"Resident attribute write failed with "
ntfs_error
(
vi
->
i_sb
,
"Resident attribute write failed with "
"error %i.
Setting page error flag."
,
-
err
);
"error %i.
Setting page error flag."
,
err
);
SetPageError
(
page
);
SetPageError
(
page
);
}
}
unlock_page
(
page
);
unlock_page
(
page
);
...
...
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