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
20fed049
Commit
20fed049
authored
Nov 19, 2002
by
David Woodhouse
Browse files
Options
Browse Files
Download
Plain Diff
Merge [acm]time nanosecond support from 2.5.48.
parents
65b5db50
f662cf7a
Changes
23
Show whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
1949 additions
and
1354 deletions
+1949
-1354
fs/Kconfig
fs/Kconfig
+15
-2
fs/jffs2/TODO
fs/jffs2/TODO
+4
-8
fs/jffs2/background.c
fs/jffs2/background.c
+37
-40
fs/jffs2/build.c
fs/jffs2/build.c
+48
-98
fs/jffs2/dir.c
fs/jffs2/dir.c
+56
-49
fs/jffs2/erase.c
fs/jffs2/erase.c
+146
-131
fs/jffs2/file.c
fs/jffs2/file.c
+92
-76
fs/jffs2/fs.c
fs/jffs2/fs.c
+27
-34
fs/jffs2/gc.c
fs/jffs2/gc.c
+186
-111
fs/jffs2/nodelist.c
fs/jffs2/nodelist.c
+251
-32
fs/jffs2/nodelist.h
fs/jffs2/nodelist.h
+65
-18
fs/jffs2/nodemgmt.c
fs/jffs2/nodemgmt.c
+136
-63
fs/jffs2/os-linux.h
fs/jffs2/os-linux.h
+10
-2
fs/jffs2/read.c
fs/jffs2/read.c
+50
-38
fs/jffs2/readinode.c
fs/jffs2/readinode.c
+223
-131
fs/jffs2/scan.c
fs/jffs2/scan.c
+337
-361
fs/jffs2/super.c
fs/jffs2/super.c
+1
-1
fs/jffs2/wbuf.c
fs/jffs2/wbuf.c
+93
-48
fs/jffs2/write.c
fs/jffs2/write.c
+93
-72
fs/jffs2/writev.c
fs/jffs2/writev.c
+2
-2
include/linux/jffs2.h
include/linux/jffs2.h
+69
-34
include/linux/jffs2_fs_i.h
include/linux/jffs2_fs_i.h
+3
-2
include/linux/jffs2_fs_sb.h
include/linux/jffs2_fs_sb.h
+5
-1
No files found.
fs/Kconfig
View file @
20fed049
...
...
@@ -531,8 +531,8 @@ config JFFS2_FS
levelling, compression and support for hard links. You cannot use
this on normal block devices, only on 'MTD' devices.
Further information
should be made available soon at
<http://sources.redhat.com/jffs2/>.
Further information
on the design and implementation of JFFS2 is
available at
<http://sources.redhat.com/jffs2/>.
config JFFS2_FS_DEBUG
int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)"
...
...
@@ -554,6 +554,19 @@ config JFFS2_FS_DEBUG
config JFFS2_FS_NAND
bool "JFFS2 support for NAND flash (EXPERIMENTAL)"
depends on JFFS2_FS && EXPERIMENTAL
default n
---help---
This enables the experimental support for NAND flash in JFFS2. NAND
is a newer type of flash chip design than the traditional NOR flash,
with higher density but a handful of characteristics which make it
more interesting for the file system to use. Support for NAND flash
is not yet complete and may corrupt data. For further information,
including a link to the mailing list where details of the remaining
work to be completed for NAND flash support can be found, see the
JFFS2 web site at <http://sources.redhat.com/jffs2>.
Say 'N' unless you have NAND flash and you are willing to test and
develop JFFS2 support for it.
config CRAMFS
tristate "Compressed ROM file system support"
...
...
fs/jffs2/TODO
View file @
20fed049
$Id: TODO,v 1.
9 2002/07/11 10:39:04
dwmw2 Exp $
$Id: TODO,v 1.
10 2002/09/09 16:31:21
dwmw2 Exp $
- disable compression in commit_write()?
- fine-tune the allocation / GC thresholds
...
...
@@ -23,22 +23,18 @@ $Id: TODO,v 1.9 2002/07/11 10:39:04 dwmw2 Exp $
- Optimisations:
- Stop GC from decompressing and immediately recompressing nodes which could
just be copied intact.
just be copied intact.
(We now keep track of REF_PRISTINE flag. Easy now.)
- Furthermore, in the case where it could be copied intact we don't even need
to call iget() for it -- if we use (raw_node_raw->flash_offset & 2) as a flag
to show a node can be copied intact and it's _not_ in icache, we could just do
it, fix up the next_in_ino list and move on. We would need a way to find out
_whether_ it's in icache though -- if it's in icache we also need to do the
fragment lists, etc. P'raps a flag or pointer in the jffs2_inode_cache could
help.
help.
(We have half of this now.)
- Stop keeping name in-core with struct jffs2_full_dirent. If we keep the hash in
the full dirent, we only need to go to the flash in lookup() when we think we've
got a match, and in readdir().
- Doubly-linked next_in_ino list to allow us to free obsoleted raw_node_refs immediately?
- Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into
jffs2_mark_node_obsolete(). Can all callers work it out?
- Don't check data CRC on node scan during mount. We don't really need to know
yet. This means we can't build up node fragment lists, and hence can't
build accurate clean/dirty information. But we don't _need_ that for reading,
only for writing. And in fact we don't even need it for writing until we
start to need GC.
- Remove size from jffs2_raw_node_frag.
fs/jffs2/background.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: background.c,v 1.
29 2002/06/07 10:04:28
dwmw2 Exp $
* $Id: background.c,v 1.
33 2002/11/12 09:44:30
dwmw2 Exp $
*
*/
...
...
@@ -83,6 +83,7 @@ static int jffs2_garbage_collect_thread(void *_c)
struct
jffs2_sb_info
*
c
=
_c
;
daemonize
();
c
->
gc_task
=
current
;
up
(
&
c
->
gc_thread_start
);
...
...
@@ -91,10 +92,10 @@ static int jffs2_garbage_collect_thread(void *_c)
set_user_nice
(
current
,
10
);
for
(;;)
{
spin_lock_irq
(
&
current
->
sig
->
sig
lock
);
spin_lock_irq
(
&
current
_sig_
lock
);
siginitsetinv
(
&
current
->
blocked
,
sigmask
(
SIGHUP
)
|
sigmask
(
SIGKILL
)
|
sigmask
(
SIGSTOP
)
|
sigmask
(
SIGCONT
));
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sig
->
sig
lock
);
spin_unlock_irq
(
&
current
_sig_
lock
);
if
(
!
thread_should_wake
(
c
))
{
set_current_state
(
TASK_INTERRUPTIBLE
);
...
...
@@ -112,11 +113,11 @@ static int jffs2_garbage_collect_thread(void *_c)
*/
while
(
signal_pending
(
current
))
{
siginfo_t
info
;
unsigned
long
signr
=
0
;
unsigned
long
signr
;
spin_lock_irq
(
&
current
->
sig
->
sig
lock
);
spin_lock_irq
(
&
current_sig_
lock
);
signr
=
dequeue_signal
(
&
current
->
blocked
,
&
info
);
spin_unlock_irq
(
&
current
->
sig
->
sig
lock
);
spin_unlock_irq
(
&
current_sig_
lock
);
switch
(
signr
)
{
case
SIGSTOP
:
...
...
@@ -137,14 +138,13 @@ static int jffs2_garbage_collect_thread(void *_c)
break
;
default:
D1
(
printk
(
KERN_DEBUG
"jffs2_garbage_collect_thread(): signal %ld received
\n
"
,
signr
));
}
}
/* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
spin_lock_irq
(
&
current
->
sig
->
sig
lock
);
spin_lock_irq
(
&
current
_sig_
lock
);
siginitsetinv
(
&
current
->
blocked
,
sigmask
(
SIGKILL
)
|
sigmask
(
SIGSTOP
)
|
sigmask
(
SIGCONT
));
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sig
->
sig
lock
);
spin_unlock_irq
(
&
current
_sig_
lock
);
D1
(
printk
(
KERN_DEBUG
"jffs2_garbage_collect_thread(): pass
\n
"
));
jffs2_garbage_collect_pass
(
c
);
...
...
@@ -153,23 +153,20 @@ static int jffs2_garbage_collect_thread(void *_c)
static
int
thread_should_wake
(
struct
jffs2_sb_info
*
c
)
{
uint32_t
gcnodeofs
=
0
;
int
ret
;
int
ret
=
0
;
/* Don't count any progress we've already made through the gcblock
as dirty space, for the purposes of this calculation */
if
(
c
->
gcblock
&&
c
->
gcblock
->
gc_node
)
gcnodeofs
=
c
->
gcblock
->
gc_node
->
flash_offset
&
~
3
&
(
c
->
sector_size
-
1
);
if
(
c
->
unchecked_size
)
{
D1
(
printk
(
KERN_DEBUG
"thread_should_wake(): unchecked_size %d, checked_ino #%d
\n
"
,
c
->
unchecked_size
,
c
->
checked_ino
));
return
1
;
}
if
(
c
->
nr_free_blocks
+
c
->
nr_erasing_blocks
<
JFFS2_RESERVED_BLOCKS_GCTRIGGER
&&
(
c
->
dirty_size
-
gcnodeofs
)
>
c
->
sector_size
)
(
c
->
dirty_size
>
c
->
sector_size
))
ret
=
1
;
else
ret
=
0
;
D1
(
printk
(
KERN_DEBUG
"thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x (mod 0x%x): %s
\n
"
,
c
->
nr_free_blocks
,
c
->
nr_erasing_blocks
,
c
->
dirty_size
,
c
->
dirty_size
-
gcnodeofs
,
ret
?
"yes"
:
"no"
));
D1
(
printk
(
KERN_DEBUG
"thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s
\n
"
,
c
->
nr_free_blocks
,
c
->
nr_erasing_blocks
,
c
->
dirty_size
,
ret
?
"yes"
:
"no"
));
return
ret
;
}
fs/jffs2/build.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: build.c,v 1.
35 2002/05/20 14:56:37
dwmw2 Exp $
* $Id: build.c,v 1.
42 2002/09/09 16:29:08
dwmw2 Exp $
*
*/
...
...
@@ -43,8 +43,9 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
return
ret
;
D1
(
printk
(
KERN_DEBUG
"Scanned flash completely
\n
"
));
/* Now build the data map for each inode, marking obsoleted nodes
as such, and also increase nlink of any children. */
D1
(
jffs2_dump_block_lists
(
c
));
/* Now scan the directory tree, increasing nlink according to every dirent found. */
for_each_inode
(
i
,
c
,
ic
)
{
D1
(
printk
(
KERN_DEBUG
"Pass 1: ino #%u
\n
"
,
ic
->
ino
));
ret
=
jffs2_build_inode_pass1
(
c
,
ic
);
...
...
@@ -52,8 +53,10 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
D1
(
printk
(
KERN_WARNING
"Eep. jffs2_build_inode_pass1 for ino %d returned %d
\n
"
,
ic
->
ino
,
ret
));
return
ret
;
}
cond_resched
();
}
D1
(
printk
(
KERN_DEBUG
"Pass 1 complete
\n
"
));
D1
(
jffs2_dump_block_lists
(
c
));
/* Next, scan for inodes with nlink == 0 and remove them. If
they were directories, then decrement the nlink of their
...
...
@@ -68,6 +71,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
if
(
ic
->
nlink
)
continue
;
/* XXX: Can get high latency here. Move the cond_resched() from the end of the loop? */
ret
=
jffs2_build_remove_unlinked_inode
(
c
,
ic
);
if
(
ret
)
break
;
...
...
@@ -75,30 +80,29 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
and furthermore that it had children and their nlink has now
gone to zero too. So we have to restart the scan. */
}
D1
(
jffs2_dump_block_lists
(
c
));
cond_resched
();
}
while
(
ret
==
-
EAGAIN
);
D1
(
printk
(
KERN_DEBUG
"Pass 2 complete
\n
"
));
/* Finally, we can scan again and free the dirent nodes and scan_info structs */
for_each_inode
(
i
,
c
,
ic
)
{
struct
jffs2_scan_info
*
scan
=
ic
->
scan
;
struct
jffs2_full_dirent
*
fd
;
D1
(
printk
(
KERN_DEBUG
"Pass 3: ino #%u, ic %p, nodes %p
\n
"
,
ic
->
ino
,
ic
,
ic
->
nodes
));
if
(
!
scan
)
{
if
(
ic
->
nlink
)
{
D1
(
printk
(
KERN_WARNING
"Why no scan struct for ino #%u which has nlink %d?
\n
"
,
ic
->
ino
,
ic
->
nlink
));
}
continue
;
}
ic
->
scan
=
NULL
;
while
(
scan
->
dents
)
{
fd
=
scan
->
dents
;
scan
->
dents
=
fd
->
next
;
while
(
ic
->
scan_dents
)
{
fd
=
ic
->
scan_dents
;
ic
->
scan_dents
=
fd
->
next
;
jffs2_free_full_dirent
(
fd
);
}
kfree
(
scan
);
ic
->
scan_dents
=
NULL
;
cond_resched
();
}
D1
(
printk
(
KERN_DEBUG
"Pass 3 complete
\n
"
));
D1
(
jffs2_dump_block_lists
(
c
));
/* Rotate the lists by some number to ensure wear levelling */
jffs2_rotate_lists
(
c
);
...
...
@@ -108,83 +112,21 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
int
jffs2_build_inode_pass1
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_inode_cache
*
ic
)
{
struct
jffs2_tmp_dnode_info
*
tn
;
struct
jffs2_full_dirent
*
fd
;
struct
jffs2_node_frag
*
fraglist
=
NULL
;
struct
jffs2_tmp_dnode_info
*
metadata
=
NULL
;
D1
(
printk
(
KERN_DEBUG
"jffs2_build_inode building inode #%u
\n
"
,
ic
->
ino
));
if
(
ic
->
ino
>
c
->
highest_ino
)
c
->
highest_ino
=
ic
->
ino
;
if
(
!
ic
->
scan
->
tmpnodes
&&
ic
->
ino
!=
1
)
{
D1
(
printk
(
KERN_DEBUG
"jffs2_build_inode: ino #%u has no data nodes!
\n
"
,
ic
->
ino
));
}
/* Build the list to make sure any obsolete nodes are marked as such */
while
(
ic
->
scan
->
tmpnodes
)
{
tn
=
ic
->
scan
->
tmpnodes
;
ic
->
scan
->
tmpnodes
=
tn
->
next
;
if
(
metadata
&&
tn
->
version
>
metadata
->
version
)
{
D1
(
printk
(
KERN_DEBUG
"jffs2_build_inode_pass1 ignoring old metadata at 0x%08x
\n
"
,
metadata
->
fn
->
raw
->
flash_offset
&~
3
));
jffs2_mark_node_obsolete
(
c
,
metadata
->
fn
->
raw
);
jffs2_free_full_dnode
(
metadata
->
fn
);
jffs2_free_tmp_dnode_info
(
metadata
);
metadata
=
NULL
;
}
if
(
tn
->
fn
->
size
)
{
jffs2_add_full_dnode_to_fraglist
(
c
,
&
fraglist
,
tn
->
fn
);
jffs2_free_tmp_dnode_info
(
tn
);
}
else
{
if
(
!
metadata
)
{
metadata
=
tn
;
}
else
{
/* This will only happen if it has the _same_ version
number as the existing metadata node. */
D1
(
printk
(
KERN_DEBUG
"jffs2_build_inode_pass1 ignoring new metadata at 0x%08x
\n
"
,
tn
->
fn
->
raw
->
flash_offset
&~
3
));
jffs2_mark_node_obsolete
(
c
,
tn
->
fn
->
raw
);
jffs2_free_full_dnode
(
tn
->
fn
);
jffs2_free_tmp_dnode_info
(
tn
);
}
}
}
if
(
ic
->
scan
->
version
)
{
/* It's a regular file, so truncate it to the last known
i_size, if necessary */
D1
(
printk
(
KERN_DEBUG
"jffs2_build_inode_pass1 truncating fraglist to 0x%08x
\n
"
,
ic
->
scan
->
isize
));
jffs2_truncate_fraglist
(
c
,
&
fraglist
,
ic
->
scan
->
isize
);
}
/* OK. Now clear up */
if
(
metadata
)
{
jffs2_free_full_dnode
(
metadata
->
fn
);
jffs2_free_tmp_dnode_info
(
metadata
);
}
metadata
=
NULL
;
while
(
fraglist
)
{
struct
jffs2_node_frag
*
frag
;
frag
=
fraglist
;
fraglist
=
fraglist
->
next
;
if
(
frag
->
node
&&
!
(
--
frag
->
node
->
frags
))
{
jffs2_free_full_dnode
(
frag
->
node
);
}
jffs2_free_node_frag
(
frag
);
}
/* Now for each child, increase nlink */
for
(
fd
=
ic
->
scan
->
dents
;
fd
;
fd
=
fd
->
next
)
{
/* For each child, increase nlink */
for
(
fd
=
ic
->
scan_dents
;
fd
;
fd
=
fd
->
next
)
{
struct
jffs2_inode_cache
*
child_ic
;
if
(
!
fd
->
ino
)
continue
;
/* XXX: Can get high latency here with huge directories */
child_ic
=
jffs2_get_ino_cache
(
c
,
fd
->
ino
);
if
(
!
child_ic
)
{
printk
(
KERN_NOTICE
"Eep. Child
\"
%s
\"
(ino #%u) of dir ino #%u doesn't exist!
\n
"
,
...
...
@@ -212,26 +154,33 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
struct
jffs2_full_dirent
*
fd
;
int
ret
=
0
;
if
(
!
ic
->
scan
)
{
D1
(
printk
(
KERN_DEBUG
"ino #%u was already removed
\n
"
,
ic
->
ino
));
return
0
;
}
D1
(
printk
(
KERN_DEBUG
"JFFS2: Removing ino #%u with nlink == zero.
\n
"
,
ic
->
ino
));
for
(
raw
=
ic
->
nodes
;
raw
!=
(
void
*
)
ic
;
raw
=
raw
->
next_in_ino
)
{
D1
(
printk
(
KERN_DEBUG
"obsoleting node at 0x%08x
\n
"
,
r
aw
->
flash_offset
&~
3
));
D1
(
printk
(
KERN_DEBUG
"obsoleting node at 0x%08x
\n
"
,
r
ef_offset
(
raw
)
));
jffs2_mark_node_obsolete
(
c
,
raw
);
}
if
(
ic
->
scan
->
dents
)
{
printk
(
KERN_NOTICE
"Inode #%u was a directory with children - removing those too...
\n
"
,
ic
->
ino
);
if
(
ic
->
scan_dents
)
{
int
whinged
=
0
;
D1
(
printk
(
KERN_DEBUG
"Inode #%u was a directory which may have children...
\n
"
,
ic
->
ino
));
while
(
ic
->
scan
->
dents
)
{
while
(
ic
->
scan
_
dents
)
{
struct
jffs2_inode_cache
*
child_ic
;
fd
=
ic
->
scan
->
dents
;
ic
->
scan
->
dents
=
fd
->
next
;
fd
=
ic
->
scan_dents
;
ic
->
scan_dents
=
fd
->
next
;
if
(
!
fd
->
ino
)
{
/* It's a deletion dirent. Ignore it */
D1
(
printk
(
KERN_DEBUG
"Child
\"
%s
\"
is a deletion dirent, skipping...
\n
"
,
fd
->
name
));
jffs2_free_full_dirent
(
fd
);
continue
;
}
if
(
!
whinged
)
{
whinged
=
1
;
printk
(
KERN_NOTICE
"Inode #%u was a directory with children - removing those too...
\n
"
,
ic
->
ino
);
}
D1
(
printk
(
KERN_DEBUG
"Removing child
\"
%s
\"
, ino #%u
\n
"
,
fd
->
name
,
fd
->
ino
));
...
...
@@ -239,6 +188,7 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
child_ic
=
jffs2_get_ino_cache
(
c
,
fd
->
ino
);
if
(
!
child_ic
)
{
printk
(
KERN_NOTICE
"Cannot remove child
\"
%s
\"
, ino #%u, because it doesn't exist
\n
"
,
fd
->
name
,
fd
->
ino
);
jffs2_free_full_dirent
(
fd
);
continue
;
}
jffs2_free_full_dirent
(
fd
);
...
...
@@ -246,8 +196,6 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
}
ret
=
-
EAGAIN
;
}
kfree
(
ic
->
scan
);
ic
->
scan
=
NULL
;
/*
We don't delete the inocache from the hash list and free it yet.
...
...
@@ -271,6 +219,8 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
c
->
blocks
[
i
].
offset
=
i
*
c
->
sector_size
;
c
->
blocks
[
i
].
free_size
=
c
->
sector_size
;
c
->
blocks
[
i
].
dirty_size
=
0
;
c
->
blocks
[
i
].
wasted_size
=
0
;
c
->
blocks
[
i
].
unchecked_size
=
0
;
c
->
blocks
[
i
].
used_size
=
0
;
c
->
blocks
[
i
].
first_node
=
NULL
;
c
->
blocks
[
i
].
last_node
=
NULL
;
...
...
fs/jffs2/dir.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: dir.c,v 1.7
1 2002/07/23 17:00:45
dwmw2 Exp $
* $Id: dir.c,v 1.7
3 2002/08/26 15:00:51
dwmw2 Exp $
*
*/
...
...
@@ -211,7 +211,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode)
return
ret
;
}
dir_i
->
i_mtime
.
tv_sec
=
dir_i
->
i_ctime
.
tv_sec
=
ri
->
ctime
;
dir_i
->
i_mtime
.
tv_sec
=
dir_i
->
i_ctime
.
tv_sec
=
je32_to_cpu
(
ri
->
ctime
)
;
dir_i
->
i_mtime
.
tv_nsec
=
dir_i
->
i_ctime
.
tv_nsec
=
0
;
jffs2_free_raw_inode
(
ri
);
...
...
@@ -234,6 +234,7 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
ret
=
jffs2_do_unlink
(
c
,
dir_f
,
dentry
->
d_name
.
name
,
dentry
->
d_name
.
len
,
dead_f
);
if
(
dead_f
->
inocache
)
dentry
->
d_inode
->
i_nlink
=
dead_f
->
inocache
->
nlink
;
return
ret
;
}
...
...
@@ -248,6 +249,10 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
int
ret
;
uint8_t
type
;
/* Don't let people make hard links to bad inodes. */
if
(
!
f
->
inocache
)
return
-
EIO
;
if
(
S_ISDIR
(
old_dentry
->
d_inode
->
i_mode
))
return
-
EPERM
;
...
...
@@ -318,13 +323,14 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
f
=
JFFS2_INODE_INFO
(
inode
);
inode
->
i_size
=
ri
->
isize
=
ri
->
dsize
=
ri
->
csize
=
strlen
(
target
);
ri
->
totlen
=
sizeof
(
*
ri
)
+
ri
->
dsize
;
ri
->
hdr_crc
=
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
inode
->
i_size
=
strlen
(
target
);
ri
->
isize
=
ri
->
dsize
=
ri
->
csize
=
cpu_to_je32
(
inode
->
i_size
);
ri
->
totlen
=
cpu_to_je32
(
sizeof
(
*
ri
)
+
inode
->
i_size
);
ri
->
hdr_crc
=
cpu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
));
ri
->
compr
=
JFFS2_COMPR_NONE
;
ri
->
data_crc
=
c
rc32
(
0
,
target
,
strlen
(
target
));
ri
->
node_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
ri
->
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
target
,
strlen
(
target
)
));
ri
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
)
);
fn
=
jffs2_write_dnode
(
c
,
f
,
ri
,
target
,
strlen
(
target
),
phys_ofs
,
&
writtenlen
);
...
...
@@ -370,19 +376,19 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
dir_f
=
JFFS2_INODE_INFO
(
dir_i
);
down
(
&
dir_f
->
sem
);
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
dir_i
->
i_ino
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
ino
=
inode
->
i_ino
;
rd
->
mctime
=
get_seconds
(
);
rd
->
pino
=
cpu_to_je32
(
dir_i
->
i_ino
)
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
cpu_to_je32
(
inode
->
i_ino
)
;
rd
->
mctime
=
cpu_to_je32
(
get_seconds
()
);
rd
->
nsize
=
namelen
;
rd
->
type
=
DT_LNK
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
name_crc
=
c
rc32
(
0
,
dentry
->
d_name
.
name
,
namelen
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
pu_to_je32
(
crc32
(
0
,
dentry
->
d_name
.
name
,
namelen
)
);
fd
=
jffs2_write_dirent
(
c
,
dir_f
,
rd
,
dentry
->
d_name
.
name
,
namelen
,
phys_ofs
,
&
writtenlen
);
...
...
@@ -396,7 +402,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
return
PTR_ERR
(
fd
);
}
dir_i
->
i_mtime
.
tv_sec
=
dir_i
->
i_ctime
.
tv_sec
=
rd
->
mctime
;
dir_i
->
i_mtime
.
tv_sec
=
dir_i
->
i_ctime
.
tv_sec
=
je32_to_cpu
(
rd
->
mctime
)
;
dir_i
->
i_mtime
.
tv_nsec
=
dir_i
->
i_ctime
.
tv_nsec
=
0
;
jffs2_free_raw_dirent
(
rd
);
...
...
@@ -461,8 +467,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
f
=
JFFS2_INODE_INFO
(
inode
);
ri
->
data_crc
=
0
;
ri
->
node_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
ri
->
data_crc
=
cpu_to_je32
(
0
)
;
ri
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
)
);
fn
=
jffs2_write_dnode
(
c
,
f
,
ri
,
NULL
,
0
,
phys_ofs
,
&
writtenlen
);
...
...
@@ -508,19 +514,19 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
dir_f
=
JFFS2_INODE_INFO
(
dir_i
);
down
(
&
dir_f
->
sem
);
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
dir_i
->
i_ino
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
ino
=
inode
->
i_ino
;
rd
->
mctime
=
get_seconds
(
);
rd
->
pino
=
cpu_to_je32
(
dir_i
->
i_ino
)
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
cpu_to_je32
(
inode
->
i_ino
)
;
rd
->
mctime
=
cpu_to_je32
(
get_seconds
()
);
rd
->
nsize
=
namelen
;
rd
->
type
=
DT_DIR
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
name_crc
=
c
rc32
(
0
,
dentry
->
d_name
.
name
,
namelen
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
pu_to_je32
(
crc32
(
0
,
dentry
->
d_name
.
name
,
namelen
)
);
fd
=
jffs2_write_dirent
(
c
,
dir_f
,
rd
,
dentry
->
d_name
.
name
,
namelen
,
phys_ofs
,
&
writtenlen
);
...
...
@@ -534,7 +540,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
return
PTR_ERR
(
fd
);
}
dir_i
->
i_mtime
.
tv_sec
=
dir_i
->
i_ctime
.
tv_sec
=
rd
->
mctime
;
dir_i
->
i_mtime
.
tv_sec
=
dir_i
->
i_ctime
.
tv_sec
=
je32_to_cpu
(
rd
->
mctime
)
;
dir_i
->
i_mtime
.
tv_nsec
=
dir_i
->
i_ctime
.
tv_nsec
=
0
;
dir_i
->
i_nlink
++
;
...
...
@@ -617,13 +623,13 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
f
=
JFFS2_INODE_INFO
(
inode
);
ri
->
dsize
=
ri
->
csize
=
devlen
;
ri
->
totlen
=
sizeof
(
*
ri
)
+
ri
->
csize
;
ri
->
hdr_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
->
dsize
=
ri
->
csize
=
cpu_to_je32
(
devlen
)
;
ri
->
totlen
=
cpu_to_je32
(
sizeof
(
*
ri
)
+
devlen
)
;
ri
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
->
compr
=
JFFS2_COMPR_NONE
;
ri
->
data_crc
=
c
rc32
(
0
,
&
dev
,
devlen
);
ri
->
node_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
ri
->
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
dev
,
devlen
)
);
ri
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
)
);
fn
=
jffs2_write_dnode
(
c
,
f
,
ri
,
(
char
*
)
&
dev
,
devlen
,
phys_ofs
,
&
writtenlen
);
...
...
@@ -669,22 +675,22 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
dir_f
=
JFFS2_INODE_INFO
(
dir_i
);
down
(
&
dir_f
->
sem
);
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
dir_i
->
i_ino
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
ino
=
inode
->
i_ino
;
rd
->
mctime
=
get_seconds
(
);
rd
->
pino
=
cpu_to_je32
(
dir_i
->
i_ino
)
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
cpu_to_je32
(
inode
->
i_ino
)
;
rd
->
mctime
=
cpu_to_je32
(
get_seconds
()
);
rd
->
nsize
=
namelen
;
/* XXX: This is ugly. */
rd
->
type
=
(
mode
&
S_IFMT
)
>>
12
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
name_crc
=
c
rc32
(
0
,
dentry
->
d_name
.
name
,
namelen
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
pu_to_je32
(
crc32
(
0
,
dentry
->
d_name
.
name
,
namelen
)
);
fd
=
jffs2_write_dirent
(
c
,
dir_f
,
rd
,
dentry
->
d_name
.
name
,
namelen
,
phys_ofs
,
&
writtenlen
);
...
...
@@ -698,7 +704,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
return
PTR_ERR
(
fd
);
}
dir_i
->
i_mtime
.
tv_sec
=
dir_i
->
i_ctime
.
tv_sec
=
rd
->
mctime
;
dir_i
->
i_mtime
.
tv_sec
=
dir_i
->
i_ctime
.
tv_sec
=
je32_to_cpu
(
rd
->
mctime
)
;
dir_i
->
i_mtime
.
tv_nsec
=
dir_i
->
i_ctime
.
tv_nsec
=
0
;
jffs2_free_raw_dirent
(
rd
);
...
...
@@ -790,6 +796,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
struct
jffs2_inode_info
*
f
=
JFFS2_INODE_INFO
(
old_dentry
->
d_inode
);
down
(
&
f
->
sem
);
old_dentry
->
d_inode
->
i_nlink
++
;
if
(
f
->
inocache
)
f
->
inocache
->
nlink
++
;
up
(
&
f
->
sem
);
...
...
fs/jffs2/erase.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: erase.c,v 1.
39 2002/07/23 17:00:45
dwmw2 Exp $
* $Id: erase.c,v 1.
45 2002/10/09 08:27:08
dwmw2 Exp $
*
*/
...
...
@@ -27,6 +27,7 @@ struct erase_priv_struct {
static
void
jffs2_erase_callback
(
struct
erase_info
*
);
static
void
jffs2_erase_succeeded
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
);
static
void
jffs2_free_all_node_refs
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
);
static
void
jffs2_mark_erased_block
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
);
void
jffs2_erase_block
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
)
{
...
...
@@ -81,12 +82,18 @@ void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
else
printk
(
KERN_WARNING
"Erase at 0x%08x failed immediately: errno %d
\n
"
,
jeb
->
offset
,
ret
);
/* Note: This is almost identical to jffs2_erase_failed() except
for the fact that we used spin_lock_bh() not spin_lock(). If
we could use spin_lock_bh() from a BH, we could merge them.
Or if we abandon the idea that MTD drivers may call the erase
callback from a BH, I suppose :)
*/
spin_lock_bh
(
&
c
->
erase_completion_lock
);
c
->
erasing_size
-=
c
->
sector_size
;
c
->
bad_size
+=
c
->
sector_size
;
list_del
(
&
jeb
->
list
);
list_add
(
&
jeb
->
list
,
&
c
->
bad_list
);
c
->
nr_erasing_blocks
--
;
c
->
bad_size
+=
c
->
sector_size
;
c
->
erasing_size
-=
c
->
sector_size
;
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
wake_up
(
&
c
->
erase_wait
);
}
...
...
@@ -98,12 +105,19 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
down
(
&
c
->
erase_free_sem
);
spin_lock_bh
(
&
c
->
erase_completion_lock
);
while
(
!
list_empty
(
&
c
->
erase_pending_list
))
{
jeb
=
list_entry
(
c
->
erase_pending_list
.
next
,
struct
jffs2_eraseblock
,
list
);
while
(
!
list_empty
(
&
c
->
erase_complete_list
)
||
!
list_empty
(
&
c
->
erase_pending_list
))
{
D1
(
printk
(
KERN_DEBUG
"Starting erase of pending block 0x%08x
\n
"
,
jeb
->
offset
));
if
(
!
list_empty
(
&
c
->
erase_complete_list
))
{
jeb
=
list_entry
(
c
->
erase_complete_list
.
next
,
struct
jffs2_eraseblock
,
list
);
list_del
(
&
jeb
->
list
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
jffs2_mark_erased_block
(
c
,
jeb
);
}
else
if
(
!
list_empty
(
&
c
->
erase_pending_list
))
{
jeb
=
list_entry
(
c
->
erase_pending_list
.
next
,
struct
jffs2_eraseblock
,
list
);
D1
(
printk
(
KERN_DEBUG
"Starting erase of pending block 0x%08x
\n
"
,
jeb
->
offset
));
list_del
(
&
jeb
->
list
);
c
->
erasing_size
+=
c
->
sector_size
;
c
->
free_size
-=
jeb
->
free_size
;
...
...
@@ -116,18 +130,21 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
jffs2_erase_block
(
c
,
jeb
);
}
else
{
BUG
();
}
/* Be nice */
cond_resched
();
spin_lock_bh
(
&
c
->
erase_completion_lock
);
}
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
D1
(
printk
(
KERN_DEBUG
"jffs2_erase_pending_blocks completed
\n
"
));
up
(
&
c
->
erase_free_sem
);
}
static
void
jffs2_erase_succeeded
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
)
{
D1
(
printk
(
KERN_DEBUG
"Erase completed successfully at 0x%08x
\n
"
,
jeb
->
offset
));
...
...
@@ -135,6 +152,8 @@ static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblo
list_del
(
&
jeb
->
list
);
list_add_tail
(
&
jeb
->
list
,
&
c
->
erase_complete_list
);
spin_unlock
(
&
c
->
erase_completion_lock
);
/* Ensure that kupdated calls us again to mark them clean */
jffs2_erase_pending_trigger
(
c
);
}
...
...
@@ -160,8 +179,6 @@ static void jffs2_erase_callback(struct erase_info *instr)
}
else
{
jffs2_erase_succeeded
(
priv
->
c
,
priv
->
jeb
);
}
/* Make sure someone picks up the block off the erase_complete list */
OFNI_BS_2SFFJ
(
priv
->
c
)
->
s_dirt
=
1
;
kfree
(
instr
);
}
...
...
@@ -220,7 +237,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
this
=
ic
->
nodes
;
while
(
this
)
{
printk
(
"0x%08x(%d)->"
,
this
->
flash_offset
&
~
3
,
this
->
flash_offset
&
3
);
printk
(
"0x%08x(%d)->"
,
ref_offset
(
this
),
ref_flags
(
this
)
);
if
(
++
i
==
5
)
{
printk
(
"
\n
"
KERN_DEBUG
);
i
=
0
;
...
...
@@ -260,26 +277,22 @@ void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
OFNI_BS_2SFFJ
(
c
)
->
s_dirt
=
1
;
}
void
jffs2_mark_erased_blocks
(
struct
jffs2_sb_info
*
c
)
static
void
jffs2_mark_erased_block
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
)
{
struct
jffs2_eraseblock
*
jeb
;
struct
jffs2_raw_node_ref
*
marker_ref
=
NULL
;
unsigned
char
*
ebuf
;
size_t
retlen
;
int
ret
;
spin_lock_bh
(
&
c
->
erase_completion_lock
);
while
(
!
list_empty
(
&
c
->
erase_complete_list
))
{
jeb
=
list_entry
(
c
->
erase_complete_list
.
next
,
struct
jffs2_eraseblock
,
list
);
list_del
(
&
jeb
->
list
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
if
(
!
jffs2_cleanmarker_oob
(
c
))
{
marker_ref
=
jffs2_alloc_raw_node_ref
();
if
(
!
marker_ref
)
{
printk
(
KERN_WARNING
"Failed to allocate raw node ref for clean marker
\n
"
);
/* C
ome back later */
/* Stick it back on the list from whence it came and c
ome back later */
jffs2_erase_pending_trigger
(
c
);
spin_lock_bh
(
&
c
->
erase_completion_lock
);
list_add
(
&
jeb
->
list
,
&
c
->
erase_complete_list
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
return
;
}
}
...
...
@@ -344,37 +357,39 @@ void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
jeb
->
free_size
=
c
->
sector_size
;
jeb
->
used_size
=
0
;
jeb
->
dirty_size
=
0
;
jeb
->
wasted_size
=
0
;
}
else
{
struct
jffs2_unknown_node
marker
=
{
.
magic
=
JFFS2_MAGIC_BITMASK
,
.
nodetype
=
JFFS2_NODETYPE_CLEANMARKER
,
.
totlen
=
c
->
cleanmarker_size
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
,
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_CLEANMARKER
)
,
.
totlen
=
cpu_to_je32
(
c
->
cleanmarker_size
)
};
marker
.
hdr_crc
=
crc32
(
0
,
&
marker
,
marker
.
totlen
-
4
);
marker
.
hdr_crc
=
cpu_to_je32
(
crc32
(
0
,
&
marker
,
je32_to_cpu
(
marker
.
totlen
)
-
4
)
);
ret
=
jffs2_flash_write
(
c
,
jeb
->
offset
,
marker
.
totlen
,
&
retlen
,
(
char
*
)
&
marker
);
ret
=
jffs2_flash_write
(
c
,
jeb
->
offset
,
je32_to_cpu
(
marker
.
totlen
)
,
&
retlen
,
(
char
*
)
&
marker
);
if
(
ret
)
{
printk
(
KERN_WARNING
"Write clean marker to block at 0x%08x failed: %d
\n
"
,
jeb
->
offset
,
ret
);
goto
bad2
;
}
if
(
retlen
!=
marker
.
totlen
)
{
if
(
retlen
!=
je32_to_cpu
(
marker
.
totlen
)
)
{
printk
(
KERN_WARNING
"Short write to newly-erased block at 0x%08x: Wanted %d, got %d
\n
"
,
jeb
->
offset
,
marker
.
totlen
,
retlen
);
jeb
->
offset
,
je32_to_cpu
(
marker
.
totlen
)
,
retlen
);
goto
bad2
;
}
marker_ref
->
next_in_ino
=
NULL
;
marker_ref
->
next_phys
=
NULL
;
marker_ref
->
flash_offset
=
jeb
->
offset
;
marker_ref
->
totlen
=
PAD
(
marker
.
totlen
);
marker_ref
->
flash_offset
=
jeb
->
offset
|
REF_NORMAL
;
marker_ref
->
totlen
=
PAD
(
je32_to_cpu
(
marker
.
totlen
)
);
jeb
->
first_node
=
jeb
->
last_node
=
marker_ref
;
jeb
->
free_size
=
c
->
sector_size
-
marker_ref
->
totlen
;
jeb
->
used_size
=
marker_ref
->
totlen
;
jeb
->
dirty_size
=
0
;
jeb
->
wasted_size
=
0
;
}
spin_lock_bh
(
&
c
->
erase_completion_lock
);
...
...
@@ -383,12 +398,12 @@ void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
c
->
used_size
+=
jeb
->
used_size
;
ACCT_SANITY_CHECK
(
c
,
jeb
);
ACCT_PARANOIA_CHECK
(
jeb
);
D1
(
ACCT_PARANOIA_CHECK
(
jeb
)
);
list_add_tail
(
&
jeb
->
list
,
&
c
->
free_list
);
c
->
nr_erasing_blocks
--
;
c
->
nr_free_blocks
++
;
wake_up
(
&
c
->
erase_wait
);
}
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
wake_up
(
&
c
->
erase_wait
);
}
fs/jffs2/file.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: file.c,v 1.
76 2002/07/29 08:25:35
dwmw2 Exp $
* $Id: file.c,v 1.
81 2002/11/12 09:46:22
dwmw2 Exp $
*
*/
...
...
@@ -139,41 +139,43 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
down
(
&
f
->
sem
);
ivalid
=
iattr
->
ia_valid
;
ri
->
magic
=
JFFS2_MAGIC_BITMASK
;
ri
->
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
->
totlen
=
sizeof
(
*
ri
)
+
mdatalen
;
ri
->
hdr_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
->
totlen
=
cpu_to_je32
(
sizeof
(
*
ri
)
+
mdatalen
)
;
ri
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
->
ino
=
inode
->
i_ino
;
ri
->
version
=
++
f
->
highest_version
;
ri
->
ino
=
cpu_to_je32
(
inode
->
i_ino
)
;
ri
->
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
->
mode
=
(
ivalid
&
ATTR_MODE
)
?
iattr
->
ia_mode
:
inode
->
i_mode
;
ri
->
uid
=
(
ivalid
&
ATTR_UID
)
?
iattr
->
ia_uid
:
inode
->
i_uid
;
ri
->
gid
=
(
ivalid
&
ATTR_GID
)
?
iattr
->
ia_gid
:
inode
->
i_gid
;
ri
->
uid
=
cpu_to_je16
((
ivalid
&
ATTR_UID
)
?
iattr
->
ia_uid
:
inode
->
i_uid
);
ri
->
gid
=
cpu_to_je16
((
ivalid
&
ATTR_GID
)
?
iattr
->
ia_gid
:
inode
->
i_gid
);
if
(
ivalid
&
ATTR_MODE
&&
ri
->
mode
&
S_ISGID
&&
!
in_group_p
(
ri
->
gid
)
&&
!
capable
(
CAP_FSETID
))
ri
->
mode
&=
~
S_ISGID
;
if
(
ivalid
&
ATTR_MODE
)
if
(
iattr
->
ia_mode
&
S_ISGID
&&
!
in_group_p
(
je16_to_cpu
(
ri
->
gid
))
&&
!
capable
(
CAP_FSETID
))
ri
->
mode
=
cpu_to_je32
(
iattr
->
ia_mode
&
~
S_ISGID
);
else
ri
->
mode
=
cpu_to_je32
(
iattr
->
ia_mode
);
else
ri
->
mode
=
cpu_to_je32
(
inode
->
i_mode
);
ri
->
isize
=
(
ivalid
&
ATTR_SIZE
)
?
iattr
->
ia_size
:
inode
->
i_size
;
ri
->
atime
=
(
ivalid
&
ATTR_ATIME
)
?
iattr
->
ia_atime
.
tv_sec
:
inode
->
i_atime
.
tv_sec
;
ri
->
mtime
=
(
ivalid
&
ATTR_MTIME
)
?
iattr
->
ia_mtime
.
tv_sec
:
inode
->
i_mtime
.
tv_sec
;
ri
->
ctime
=
(
ivalid
&
ATTR_CTIME
)
?
iattr
->
ia_ctime
.
tv_sec
:
inode
->
i_ctime
.
tv_sec
;
ri
->
offset
=
0
;
ri
->
csize
=
ri
->
dsize
=
mdatalen
;
ri
->
isize
=
cpu_to_je32
((
ivalid
&
ATTR_SIZE
)
?
iattr
->
ia_size
:
inode
->
i_size
);
ri
->
atime
=
cpu_to_je32
((
ivalid
&
ATTR_ATIME
)
?
iattr
->
ia_atime
.
tv_sec
:
inode
->
i_atime
.
tv_sec
);
ri
->
mtime
=
cpu_to_je32
((
ivalid
&
ATTR_MTIME
)
?
iattr
->
ia_mtime
.
tv_sec
:
inode
->
i_mtime
.
tv_sec
);
ri
->
ctime
=
cpu_to_je32
((
ivalid
&
ATTR_CTIME
)
?
iattr
->
ia_ctime
.
tv_sec
:
inode
->
i_ctime
.
tv_sec
);
ri
->
compr
=
JFFS2_COMPR_NONE
;
if
(
i
node
->
i_size
<
ri
->
i
size
)
{
if
(
i
valid
&
ATTR_SIZE
&&
inode
->
i_size
<
iattr
->
ia_
size
)
{
/* It's an extension. Make it a hole node */
ri
->
compr
=
JFFS2_COMPR_ZERO
;
ri
->
dsize
=
ri
->
isize
-
inode
->
i_size
;
ri
->
offset
=
inode
->
i_size
;
ri
->
dsize
=
cpu_to_je32
(
iattr
->
ia_size
-
inode
->
i_size
)
;
ri
->
offset
=
cpu_to_je32
(
inode
->
i_size
)
;
}
ri
->
node_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
ri
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
)
);
if
(
mdatalen
)
ri
->
data_crc
=
c
rc32
(
0
,
mdata
,
mdatalen
);
ri
->
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
mdata
,
mdatalen
)
);
else
ri
->
data_crc
=
0
;
ri
->
data_crc
=
cpu_to_je32
(
0
)
;
new_metadata
=
jffs2_write_dnode
(
c
,
f
,
ri
,
mdata
,
mdatalen
,
phys_ofs
,
NULL
);
if
(
S_ISLNK
(
inode
->
i_mode
))
...
...
@@ -186,27 +188,27 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
return
PTR_ERR
(
new_metadata
);
}
/* It worked. Update the inode */
inode
->
i_atime
.
tv_sec
=
ri
->
atime
;
inode
->
i_ctime
.
tv_sec
=
ri
->
ctime
;
inode
->
i_mtime
.
tv_sec
=
ri
->
mtime
;
inode
->
i_atime
=
je32_to_cpu
(
ri
->
atime
.
tv_sec
)
;
inode
->
i_ctime
=
je32_to_cpu
(
ri
->
ctime
.
tv_sec
)
;
inode
->
i_mtime
=
je32_to_cpu
(
ri
->
mtime
.
tv_sec
)
;
inode
->
i_atime
.
tv_nsec
=
inode
->
i_ctime
.
tv_nsec
=
inode
->
i_mtime
.
tv_nsec
=
0
;
inode
->
i_mode
=
ri
->
mode
;
inode
->
i_uid
=
ri
->
uid
;
inode
->
i_gid
=
ri
->
gid
;
inode
->
i_mode
=
je32_to_cpu
(
ri
->
mode
)
;
inode
->
i_uid
=
je16_to_cpu
(
ri
->
uid
)
;
inode
->
i_gid
=
je16_to_cpu
(
ri
->
gid
)
;
old_metadata
=
f
->
metadata
;
if
(
i
node
->
i_size
>
ri
->
i
size
)
{
vmtruncate
(
inode
,
ri
->
i
size
);
jffs2_truncate_fraglist
(
c
,
&
f
->
frag
list
,
ri
->
i
size
);
if
(
i
valid
&
ATTR_SIZE
&&
inode
->
i_size
>
iattr
->
ia_
size
)
{
vmtruncate
(
inode
,
iattr
->
ia_
size
);
jffs2_truncate_fraglist
(
c
,
&
f
->
frag
tree
,
iattr
->
ia_
size
);
}
if
(
i
node
->
i_size
<
ri
->
i
size
)
{
if
(
i
valid
&
ATTR_SIZE
&&
inode
->
i_size
<
iattr
->
ia_
size
)
{
jffs2_add_full_dnode_to_inode
(
c
,
f
,
new_metadata
);
inode
->
i_size
=
ri
->
i
size
;
inode
->
i_size
=
iattr
->
ia_
size
;
f
->
metadata
=
NULL
;
}
else
{
f
->
metadata
=
new_metadata
;
...
...
@@ -281,7 +283,6 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
uint32_t
pageofs
=
pg
->
index
<<
PAGE_CACHE_SHIFT
;
int
ret
=
0
;
down
(
&
f
->
sem
);
D1
(
printk
(
KERN_DEBUG
"jffs2_prepare_write()
\n
"
));
if
(
pageofs
>
inode
->
i_size
)
{
...
...
@@ -295,30 +296,30 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
(
unsigned
int
)
inode
->
i_size
,
pageofs
));
ret
=
jffs2_reserve_space
(
c
,
sizeof
(
ri
),
&
phys_ofs
,
&
alloc_len
,
ALLOC_NORMAL
);
if
(
ret
)
{
up
(
&
f
->
sem
);
if
(
ret
)
return
ret
;
}
down
(
&
f
->
sem
);
memset
(
&
ri
,
0
,
sizeof
(
ri
));
ri
.
magic
=
JFFS2_MAGIC_BITMASK
;
ri
.
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
.
totlen
=
sizeof
(
ri
);
ri
.
hdr_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
.
ino
=
f
->
inocache
->
ino
;
ri
.
version
=
++
f
->
highest_version
;
ri
.
mode
=
inode
->
i_mode
;
ri
.
uid
=
inode
->
i_uid
;
ri
.
gid
=
inode
->
i_gid
;
ri
.
isize
=
max
((
uint32_t
)
inode
->
i_size
,
pageofs
);
ri
.
atime
=
ri
.
ctime
=
ri
.
mtime
=
get_seconds
(
);
ri
.
offset
=
inode
->
i_size
;
ri
.
dsize
=
pageofs
-
inode
->
i_size
;
ri
.
csize
=
0
;
ri
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
.
totlen
=
cpu_to_je32
(
sizeof
(
ri
)
);
ri
.
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
.
ino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
ri
.
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
.
mode
=
cpu_to_je32
(
inode
->
i_mode
)
;
ri
.
uid
=
cpu_to_je16
(
inode
->
i_uid
)
;
ri
.
gid
=
cpu_to_je16
(
inode
->
i_gid
)
;
ri
.
isize
=
cpu_to_je32
(
max
((
uint32_t
)
inode
->
i_size
,
pageofs
)
);
ri
.
atime
=
ri
.
ctime
=
ri
.
mtime
=
cpu_to_je32
(
get_seconds
()
);
ri
.
offset
=
cpu_to_je32
(
inode
->
i_size
)
;
ri
.
dsize
=
cpu_to_je32
(
pageofs
-
inode
->
i_size
)
;
ri
.
csize
=
cpu_to_je32
(
0
)
;
ri
.
compr
=
JFFS2_COMPR_ZERO
;
ri
.
node_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
);
ri
.
data_crc
=
0
;
ri
.
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
)
);
ri
.
data_crc
=
cpu_to_je32
(
0
)
;
fn
=
jffs2_write_dnode
(
c
,
f
,
&
ri
,
NULL
,
0
,
phys_ofs
,
NULL
);
...
...
@@ -344,14 +345,16 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
}
jffs2_complete_reservation
(
c
);
inode
->
i_size
=
pageofs
;
up
(
&
f
->
sem
);
}
/* Read in the page if it wasn't already present */
if
(
!
PageUptodate
(
pg
)
&&
(
start
||
end
<
PAGE_SIZE
))
/* Read in the page if it wasn't already present, unless it's a whole page */
if
(
!
PageUptodate
(
pg
)
&&
(
start
||
end
<
PAGE_CACHE_SIZE
))
{
down
(
&
f
->
sem
);
ret
=
jffs2_do_readpage_nolock
(
inode
,
pg
);
D1
(
printk
(
KERN_DEBUG
"end prepare_write()
\n
"
));
up
(
&
f
->
sem
);
}
D1
(
printk
(
KERN_DEBUG
"end prepare_write(). pg->flags %lx
\n
"
,
pg
->
flags
));
return
ret
;
}
...
...
@@ -367,8 +370,16 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
int
ret
=
0
;
uint32_t
writtenlen
=
0
;
D1
(
printk
(
KERN_DEBUG
"jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d
\n
"
,
inode
->
i_ino
,
pg
->
index
<<
PAGE_CACHE_SHIFT
,
start
,
end
));
D1
(
printk
(
KERN_DEBUG
"jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx
\n
"
,
inode
->
i_ino
,
pg
->
index
<<
PAGE_CACHE_SHIFT
,
start
,
end
,
pg
->
flags
));
if
(
!
start
&&
end
==
PAGE_CACHE_SIZE
)
{
/* We need to avoid deadlock with page_cache_read() in
jffs2_garbage_collect_pass(). So we have to mark the
page up to date, to prevent page_cache_read() from
trying to re-lock it. */
SetPageUptodate
(
pg
);
}
ri
=
jffs2_alloc_raw_inode
();
...
...
@@ -378,16 +389,21 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
}
/* Set the fields that the generic jffs2_write_inode_range() code can't find */
ri
->
ino
=
inode
->
i_ino
;
ri
->
mode
=
inode
->
i_mode
;
ri
->
uid
=
inode
->
i_uid
;
ri
->
gid
=
inode
->
i_gid
;
ri
->
isize
=
(
uint32_t
)
inode
->
i_size
;
ri
->
atime
=
ri
->
ctime
=
ri
->
mtime
=
get_seconds
();
ri
->
ino
=
cpu_to_je32
(
inode
->
i_ino
);
ri
->
mode
=
cpu_to_je32
(
inode
->
i_mode
);
ri
->
uid
=
cpu_to_je16
(
inode
->
i_uid
);
ri
->
gid
=
cpu_to_je16
(
inode
->
i_gid
);
ri
->
isize
=
cpu_to_je32
((
uint32_t
)
inode
->
i_size
);
ri
->
atime
=
ri
->
ctime
=
ri
->
mtime
=
cpu_to_je32
(
get_seconds
());
/* In 2.4, it was already kmapped by generic_file_write(). Doesn't
hurt to do it again. The alternative is ifdefs, which are ugly. */
kmap
(
pg
);
ret
=
jffs2_write_inode_range
(
c
,
f
,
ri
,
page_address
(
pg
)
+
start
,
(
pg
->
index
<<
PAGE_CACHE_SHIFT
)
+
start
,
end
-
start
,
&
writtenlen
);
(
pg
->
index
<<
PAGE_CACHE_SHIFT
)
+
start
,
end
-
start
,
&
writtenlen
);
kunmap
(
pg
);
if
(
ret
)
{
...
...
@@ -400,7 +416,7 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
inode
->
i_size
=
(
pg
->
index
<<
PAGE_CACHE_SHIFT
)
+
start
+
writtenlen
;
inode
->
i_blocks
=
(
inode
->
i_size
+
511
)
>>
9
;
inode
->
i_ctime
.
tv_sec
=
inode
->
i_mtime
.
tv_sec
=
ri
->
ctime
;
inode
->
i_ctime
.
tv_sec
=
inode
->
i_mtime
.
tv_sec
=
je32_to_cpu
(
ri
->
ctime
)
;
inode
->
i_ctime
.
tv_nsec
=
inode
->
i_mtime
.
tv_nsec
=
0
;
}
}
...
...
fs/jffs2/fs.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: fs.c,v 1.1
3 2002/07/02 22:48:24
dwmw2 Exp $
* $Id: fs.c,v 1.1
9 2002/11/12 09:53:40
dwmw2 Exp $
*
*/
...
...
@@ -86,13 +86,13 @@ void jffs2_read_inode (struct inode *inode)
up
(
&
f
->
sem
);
return
;
}
inode
->
i_mode
=
latest_node
.
mode
;
inode
->
i_uid
=
latest_node
.
uid
;
inode
->
i_gid
=
latest_node
.
gid
;
inode
->
i_size
=
latest_node
.
isize
;
inode
->
i_atime
.
tv_sec
=
latest_node
.
atime
;
inode
->
i_mtime
.
tv_sec
=
latest_node
.
mtime
;
inode
->
i_ctime
.
tv_sec
=
latest_node
.
ctime
;
inode
->
i_mode
=
je32_to_cpu
(
latest_node
.
mode
)
;
inode
->
i_uid
=
je16_to_cpu
(
latest_node
.
uid
)
;
inode
->
i_gid
=
je16_to_cpu
(
latest_node
.
gid
)
;
inode
->
i_size
=
je32_to_cpu
(
latest_node
.
isize
)
;
inode
->
i_atime
=
je32_to_cpu
(
latest_node
.
atime
)
;
inode
->
i_mtime
=
je32_to_cpu
(
latest_node
.
mtime
)
;
inode
->
i_ctime
=
je32_to_cpu
(
latest_node
.
ctime
)
;
inode
->
i_atime
.
tv_nsec
=
inode
->
i_mtime
.
tv_nsec
=
inode
->
i_ctime
.
tv_nsec
=
0
;
...
...
@@ -192,19 +192,9 @@ void jffs2_write_super (struct super_block *sb)
if
(
sb
->
s_flags
&
MS_RDONLY
)
return
;
D1
(
printk
(
KERN_DEBUG
"jffs2_write_super()
: flush_wbuf before gc-trigger
\n
"
));
D1
(
printk
(
KERN_DEBUG
"jffs2_write_super()
\n
"
));
jffs2_garbage_collect_trigger
(
c
);
jffs2_erase_pending_blocks
(
c
);
jffs2_mark_erased_blocks
(
c
);
/* Eep. If we lock this here, we deadlock with jffs2_reserve_space() when
* it locks the alloc_sem and jffs2_do_reserve_space() waits for erases
* to happen. I think the erases and/or the flush_wbuf want doing from
*
*/
if
(
!
down_trylock
(
&
c
->
alloc_sem
))
{
jffs2_flush_wbuf
(
c
,
2
);
up
(
&
c
->
alloc_sem
);
}
// else it stays dirty. FIXME.
}
...
...
@@ -232,16 +222,16 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
memset
(
ri
,
0
,
sizeof
(
*
ri
));
/* Set OS-specific defaults for new inodes */
ri
->
uid
=
c
urrent
->
fsuid
;
ri
->
uid
=
c
pu_to_je16
(
current
->
fsuid
)
;
if
(
dir_i
->
i_mode
&
S_ISGID
)
{
ri
->
gid
=
dir_i
->
i_gid
;
ri
->
gid
=
cpu_to_je16
(
dir_i
->
i_gid
)
;
if
(
S_ISDIR
(
mode
))
ri
->
mode
|=
S_ISGID
;
mode
|=
S_ISGID
;
}
else
{
ri
->
gid
=
c
urrent
->
fsgid
;
ri
->
gid
=
c
pu_to_je16
(
current
->
fsgid
)
;
}
ri
->
mode
=
mode
;
ri
->
mode
=
cpu_to_je32
(
mode
)
;
ret
=
jffs2_do_new_inode
(
c
,
f
,
mode
,
ri
);
if
(
ret
)
{
make_bad_inode
(
inode
);
...
...
@@ -249,12 +239,14 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
return
ERR_PTR
(
ret
);
}
inode
->
i_nlink
=
1
;
inode
->
i_ino
=
ri
->
ino
;
inode
->
i_mode
=
ri
->
mode
;
inode
->
i_gid
=
ri
->
gid
;
inode
->
i_uid
=
ri
->
uid
;
inode
->
i_atime
=
inode
->
i_ctime
=
inode
->
i_mtime
=
ri
->
atime
=
ri
->
mtime
=
ri
->
ctime
=
get_seconds
();
inode
->
i_ino
=
je32_to_cpu
(
ri
->
ino
);
inode
->
i_mode
=
je32_to_cpu
(
ri
->
mode
);
inode
->
i_gid
=
je16_to_cpu
(
ri
->
gid
);
inode
->
i_uid
=
je16_to_cpu
(
ri
->
uid
);
inode
->
i_atime
.
tv_nsec
=
inode
->
i_ctime
.
tv_nsec
=
inode
->
i_mtime
.
tv_nsec
=
0
;
inode
->
i_atime
.
tv_sec
=
inode
->
i_ctime
.
tv_sec
=
inode
->
i_mtime
.
tv_sec
=
get_seconds
();
ri
->
atime
=
ri
->
mtime
=
ri
->
ctime
=
cpu_to_je32
(
inode
->
i_mtime
.
tv_sec
);
inode
->
i_blksize
=
PAGE_SIZE
;
inode
->
i_blocks
=
0
;
inode
->
i_size
=
0
;
...
...
@@ -305,9 +297,10 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
if
(
!
c
->
wbuf
)
return
-
ENOMEM
;
/* Initiali
z
e process for timed wbuf flush */
/* Initiali
s
e process for timed wbuf flush */
INIT_WORK
(
&
c
->
wbuf_task
,(
void
*
)
jffs2_wbuf_process
,
(
void
*
)
c
);
/* Initialize timer for timed wbuf flush */
/* Initialise timer for timed wbuf flush */
init_timer
(
&
c
->
wbuf_timer
);
c
->
wbuf_timer
.
function
=
jffs2_wbuf_timeout
;
c
->
wbuf_timer
.
data
=
(
unsigned
long
)
c
;
...
...
fs/jffs2/gc.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: gc.c,v 1.
74 2002/05/20 14:56:3
8 dwmw2 Exp $
* $Id: gc.c,v 1.
88 2002/10/08 16:56:0
8 dwmw2 Exp $
*
*/
...
...
@@ -17,6 +17,7 @@
#include <linux/interrupt.h>
#include <linux/pagemap.h>
#include <linux/crc32.h>
#include <linux/compiler.h>
#include "nodelist.h"
static
int
jffs2_garbage_collect_metadata
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
...
...
@@ -87,6 +88,15 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
BUG
();
}
/* Have we accidentally picked a clean block with wasted space ? */
if
(
ret
->
wasted_size
)
{
D1
(
printk
(
KERN_DEBUG
"Converting wasted_size %08x to dirty_size
\n
"
,
ret
->
wasted_size
));
ret
->
dirty_size
+=
ret
->
wasted_size
;
c
->
wasted_size
-=
ret
->
wasted_size
;
c
->
dirty_size
+=
ret
->
wasted_size
;
ret
->
wasted_size
=
0
;
}
D1
(
jffs2_dump_block_lists
(
c
));
return
ret
;
}
...
...
@@ -113,6 +123,49 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
spin_lock_bh
(
&
c
->
erase_completion_lock
);
while
(
c
->
unchecked_size
)
{
/* We can't start doing GC yet. We haven't finished checking
the node CRCs etc. Do it now and wait for it. */
struct
jffs2_inode_cache
*
ic
;
if
(
c
->
checked_ino
>
c
->
highest_ino
)
{
printk
(
KERN_CRIT
"Checked all inodes but still 0x%x bytes of unchecked space?
\n
"
,
c
->
unchecked_size
);
D1
(
jffs2_dump_block_lists
(
c
));
BUG
();
}
ic
=
jffs2_get_ino_cache
(
c
,
c
->
checked_ino
++
);
if
(
!
ic
)
continue
;
if
(
!
ic
->
nlink
)
{
D1
(
printk
(
KERN_DEBUG
"Skipping check of ino #%d with nlink zero
\n
"
,
ic
->
ino
));
continue
;
}
if
(
ic
->
state
!=
INO_STATE_UNCHECKED
)
{
D1
(
printk
(
KERN_DEBUG
"Skipping check of ino #%d already in state %d
\n
"
,
ic
->
ino
,
ic
->
state
));
continue
;
}
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
D1
(
printk
(
KERN_DEBUG
"jffs2_garbage_collect_pass() triggering inode scan of ino#%d
\n
"
,
ic
->
ino
));
{
/* XXX: This wants doing more sensibly -- split the core of jffs2_do_read_inode up */
struct
inode
*
i
=
iget
(
OFNI_BS_2SFFJ
(
c
),
ic
->
ino
);
if
(
is_bad_inode
(
i
))
{
printk
(
KERN_NOTICE
"Eep. read_inode() failed for ino #%u
\n
"
,
ic
->
ino
);
ret
=
-
EIO
;
}
iput
(
i
);
}
up
(
&
c
->
alloc_sem
);
return
ret
;
}
/* First, work out which block we're garbage-collecting */
jeb
=
c
->
gcblock
;
...
...
@@ -128,15 +181,17 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
D1
(
printk
(
KERN_DEBUG
"GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
free_size
));
D1
(
if
(
c
->
nextblock
)
printk
(
KERN_DEBUG
"Nextblock at %08x, used_size %08x, dirty_size %08x,
free_size %08x
\n
"
,
c
->
nextblock
->
offset
,
c
->
nextblock
->
used_size
,
c
->
nextblock
->
dirty
_size
,
c
->
nextblock
->
free_size
));
printk
(
KERN_DEBUG
"Nextblock at %08x, used_size %08x, dirty_size %08x,
wasted_size %08x, free_size %08x
\n
"
,
c
->
nextblock
->
offset
,
c
->
nextblock
->
used_size
,
c
->
nextblock
->
dirty_size
,
c
->
nextblock
->
wasted
_size
,
c
->
nextblock
->
free_size
));
if
(
!
jeb
->
used_size
)
if
(
!
jeb
->
used_size
)
{
up
(
&
c
->
alloc_sem
);
goto
eraseit
;
}
raw
=
jeb
->
gc_node
;
while
(
r
aw
->
flash_offset
&
1
)
{
D1
(
printk
(
KERN_DEBUG
"Node at 0x%08x is obsolete... skipping
\n
"
,
r
aw
->
flash_offset
&~
3
));
while
(
r
ef_obsolete
(
raw
)
)
{
D1
(
printk
(
KERN_DEBUG
"Node at 0x%08x is obsolete... skipping
\n
"
,
r
ef_offset
(
raw
)
));
jeb
->
gc_node
=
raw
=
raw
->
next_phys
;
if
(
!
raw
)
{
printk
(
KERN_WARNING
"eep. End of raw list while still supposedly nodes to GC
\n
"
);
...
...
@@ -147,13 +202,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
BUG
();
}
}
D1
(
printk
(
KERN_DEBUG
"Going to garbage collect node at 0x%08x
\n
"
,
r
aw
->
flash_offset
&~
3
));
D1
(
printk
(
KERN_DEBUG
"Going to garbage collect node at 0x%08x
\n
"
,
r
ef_offset
(
raw
)
));
if
(
!
raw
->
next_in_ino
)
{
/* Inode-less node. Clean marker, snapshot or something like that */
/* FIXME: If it's something that needs to be copied, including something
we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
jffs2_mark_node_obsolete
(
c
,
raw
);
up
(
&
c
->
alloc_sem
);
goto
eraseit_lock
;
}
...
...
@@ -162,14 +218,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
D1
(
printk
(
KERN_DEBUG
"jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u
\n
"
,
jeb
->
offset
,
r
aw
->
flash_offset
&~
3
,
inum
));
D1
(
printk
(
KERN_DEBUG
"jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u
\n
"
,
jeb
->
offset
,
r
ef_offset
(
raw
)
,
inum
));
inode
=
iget
(
OFNI_BS_2SFFJ
(
c
),
inum
);
if
(
is_bad_inode
(
inode
))
{
printk
(
KERN_NOTICE
"Eep. read_inode() failed for ino #%u
\n
"
,
inum
);
/* NB. This will happen again. We need to do something appropriate here. */
iput
(
inode
);
up
(
&
c
->
alloc_sem
);
iput
(
inode
);
return
-
EIO
;
}
...
...
@@ -179,7 +235,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
/* Now we have the lock for this inode. Check that it's still the one at the head
of the list. */
if
(
r
aw
->
flash_offset
&
1
)
{
if
(
r
ef_obsolete
(
raw
)
)
{
D1
(
printk
(
KERN_DEBUG
"node to be GC'd was obsoleted in the meantime.
\n
"
));
/* They'll call again */
goto
upnout
;
...
...
@@ -191,10 +247,25 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
goto
upnout
;
}
for
(
frag
=
f
->
fraglist
;
frag
;
frag
=
frag
->
next
)
{
/* FIXME. Read node and do lookup? */
for
(
frag
=
frag_first
(
&
f
->
fragtree
);
frag
;
frag
=
frag_next
(
frag
))
{
if
(
frag
->
node
&&
frag
->
node
->
raw
==
raw
)
{
fn
=
frag
->
node
;
end
=
frag
->
ofs
+
frag
->
size
;
#if 1
/* Temporary debugging sanity checks, till we're ready to _trust_ the REF_PRISTINE flag stuff */
if
(
!
nrfrags
&&
ref_flags
(
fn
->
raw
)
==
REF_PRISTINE
)
{
if
(
fn
->
frags
>
1
)
printk
(
KERN_WARNING
"REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2
\n
"
,
ref_offset
(
raw
),
fn
->
frags
);
if
(
frag
->
ofs
&
(
PAGE_CACHE_SIZE
-
1
)
&&
frag_prev
(
frag
)
&&
frag_prev
(
frag
)
->
node
)
printk
(
KERN_WARNING
"REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2
\n
"
,
ref_offset
(
raw
));
if
((
frag
->
ofs
+
frag
->
size
)
&
(
PAGE_CACHE_SIZE
-
1
)
&&
frag_next
(
frag
)
&&
frag_next
(
frag
)
->
node
)
printk
(
KERN_WARNING
"REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2
\n
"
,
ref_offset
(
raw
),
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
);
}
#endif
if
(
!
nrfrags
++
)
start
=
frag
->
ofs
;
if
(
nrfrags
==
frag
->
node
->
frags
)
...
...
@@ -225,8 +296,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
ret
=
jffs2_garbage_collect_deletion_dirent
(
c
,
jeb
,
f
,
fd
);
}
else
{
printk
(
KERN_WARNING
"Raw node at 0x%08x wasn't in node lists for ino #%u
\n
"
,
r
aw
->
flash_offset
&~
3
,
f
->
inocache
->
ino
);
if
(
r
aw
->
flash_offset
&
1
)
{
r
ef_offset
(
raw
)
,
f
->
inocache
->
ino
);
if
(
r
ef_obsolete
(
raw
)
)
{
printk
(
KERN_WARNING
"But it's obsolete so we don't mind too much
\n
"
);
}
else
{
ret
=
-
EIO
;
...
...
@@ -234,6 +305,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
}
upnout:
up
(
&
f
->
sem
);
up
(
&
c
->
alloc_sem
);
iput
(
inode
);
eraseit_lock:
...
...
@@ -250,7 +322,6 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
jffs2_erase_pending_trigger
(
c
);
}
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
up
(
&
c
->
alloc_sem
);
return
ret
;
}
...
...
@@ -299,26 +370,26 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
}
memset
(
&
ri
,
0
,
sizeof
(
ri
));
ri
.
magic
=
JFFS2_MAGIC_BITMASK
;
ri
.
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
.
totlen
=
sizeof
(
ri
)
+
mdatalen
;
ri
.
hdr_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
.
ino
=
f
->
inocache
->
ino
;
ri
.
version
=
++
f
->
highest_version
;
ri
.
mode
=
JFFS2_F_I_MODE
(
f
);
ri
.
uid
=
JFFS2_F_I_UID
(
f
);
ri
.
gid
=
JFFS2_F_I_GID
(
f
);
ri
.
isize
=
JFFS2_F_I_SIZE
(
f
);
ri
.
atime
=
JFFS2_F_I_ATIME
(
f
);
ri
.
ctime
=
JFFS2_F_I_CTIME
(
f
);
ri
.
mtime
=
JFFS2_F_I_MTIME
(
f
);
ri
.
offset
=
0
;
ri
.
csize
=
mdatalen
;
ri
.
dsize
=
mdatalen
;
ri
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
.
totlen
=
cpu_to_je32
(
sizeof
(
ri
)
+
mdatalen
)
;
ri
.
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
.
ino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
ri
.
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
.
mode
=
cpu_to_je32
(
JFFS2_F_I_MODE
(
f
)
);
ri
.
uid
=
cpu_to_je16
(
JFFS2_F_I_UID
(
f
)
);
ri
.
gid
=
cpu_to_je16
(
JFFS2_F_I_GID
(
f
)
);
ri
.
isize
=
cpu_to_je32
(
JFFS2_F_I_SIZE
(
f
)
);
ri
.
atime
=
cpu_to_je32
(
JFFS2_F_I_ATIME
(
f
)
);
ri
.
ctime
=
cpu_to_je32
(
JFFS2_F_I_CTIME
(
f
)
);
ri
.
mtime
=
cpu_to_je32
(
JFFS2_F_I_MTIME
(
f
)
);
ri
.
offset
=
cpu_to_je32
(
0
)
;
ri
.
csize
=
cpu_to_je32
(
mdatalen
)
;
ri
.
dsize
=
cpu_to_je32
(
mdatalen
)
;
ri
.
compr
=
JFFS2_COMPR_NONE
;
ri
.
node_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
);
ri
.
data_crc
=
c
rc32
(
0
,
mdata
,
mdatalen
);
ri
.
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
)
);
ri
.
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
mdata
,
mdatalen
)
);
new_fn
=
jffs2_write_dnode
(
c
,
f
,
&
ri
,
mdata
,
mdatalen
,
phys_ofs
,
NULL
);
...
...
@@ -344,19 +415,19 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er
uint32_t
alloclen
,
phys_ofs
;
int
ret
;
rd
.
magic
=
JFFS2_MAGIC_BITMASK
;
rd
.
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
.
nsize
=
strlen
(
fd
->
name
);
rd
.
totlen
=
sizeof
(
rd
)
+
rd
.
nsize
;
rd
.
hdr_crc
=
c
rc32
(
0
,
&
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
.
totlen
=
cpu_to_je32
(
sizeof
(
rd
)
+
rd
.
nsize
)
;
rd
.
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
.
pino
=
f
->
inocache
->
ino
;
rd
.
version
=
++
f
->
highest_version
;
rd
.
ino
=
fd
->
ino
;
rd
.
mctime
=
max
(
JFFS2_F_I_MTIME
(
f
),
JFFS2_F_I_CTIME
(
f
));
rd
.
pino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
rd
.
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
rd
.
ino
=
cpu_to_je32
(
fd
->
ino
)
;
rd
.
mctime
=
cpu_to_je32
(
max
(
JFFS2_F_I_MTIME
(
f
),
JFFS2_F_I_CTIME
(
f
)
));
rd
.
type
=
fd
->
type
;
rd
.
node_crc
=
c
rc32
(
0
,
&
rd
,
sizeof
(
rd
)
-
8
);
rd
.
name_crc
=
c
rc32
(
0
,
fd
->
name
,
rd
.
nsize
);
rd
.
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
rd
,
sizeof
(
rd
)
-
8
)
);
rd
.
name_crc
=
c
pu_to_je32
(
crc32
(
0
,
fd
->
name
,
rd
.
nsize
)
);
ret
=
jffs2_reserve_space_gc
(
c
,
sizeof
(
rd
)
+
rd
.
nsize
,
&
phys_ofs
,
&
alloclen
);
if
(
ret
)
{
...
...
@@ -401,7 +472,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
for
(
raw
=
f
->
inocache
->
nodes
;
raw
!=
(
void
*
)
f
->
inocache
;
raw
=
raw
->
next_in_ino
)
{
/* We only care about obsolete ones */
if
(
!
(
r
aw
->
flash_offset
&
1
))
if
(
!
(
r
ef_obsolete
(
raw
)
))
continue
;
/* Doesn't matter if there's one in the same erase block. We're going to
...
...
@@ -411,40 +482,40 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
continue
;
/* This is an obsolete node belonging to the same directory */
ret
=
jffs2_flash_read
(
c
,
r
aw
->
flash_offset
&
~
3
,
sizeof
(
struct
jffs2_unknown_node
),
&
retlen
,
(
char
*
)
&
rd
);
ret
=
jffs2_flash_read
(
c
,
r
ef_offset
(
raw
)
,
sizeof
(
struct
jffs2_unknown_node
),
&
retlen
,
(
char
*
)
&
rd
);
if
(
ret
)
{
printk
(
KERN_WARNING
"jffs2_g_c_deletion_dirent(): Read error (%d) reading header from obsolete node at %08x
\n
"
,
ret
,
r
aw
->
flash_offset
&
~
3
);
/* If we can't read it, we don't need to continu
n
e to obsolete it. Continue */
printk
(
KERN_WARNING
"jffs2_g_c_deletion_dirent(): Read error (%d) reading header from obsolete node at %08x
\n
"
,
ret
,
r
ef_offset
(
raw
)
);
/* If we can't read it, we don't need to continue to obsolete it. Continue */
continue
;
}
if
(
retlen
!=
sizeof
(
struct
jffs2_unknown_node
))
{
printk
(
KERN_WARNING
"jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading header from obsolete node at %08x
\n
"
,
retlen
,
sizeof
(
struct
jffs2_unknown_node
),
r
aw
->
flash_offset
&
~
3
);
retlen
,
sizeof
(
struct
jffs2_unknown_node
),
r
ef_offset
(
raw
)
);
continue
;
}
if
(
rd
.
nodetype
!=
JFFS2_NODETYPE_DIRENT
||
PAD
(
rd
.
totlen
)
!=
PAD
(
sizeof
(
rd
)
+
name_len
))
if
(
je16_to_cpu
(
rd
.
nodetype
)
!=
JFFS2_NODETYPE_DIRENT
||
PAD
(
je32_to_cpu
(
rd
.
totlen
)
)
!=
PAD
(
sizeof
(
rd
)
+
name_len
))
continue
;
/* OK, it's a dirent node, it's the right length. We have to take a
closer look at it... */
ret
=
jffs2_flash_read
(
c
,
r
aw
->
flash_offset
&
~
3
,
sizeof
(
rd
),
&
retlen
,
(
char
*
)
&
rd
);
ret
=
jffs2_flash_read
(
c
,
r
ef_offset
(
raw
)
,
sizeof
(
rd
),
&
retlen
,
(
char
*
)
&
rd
);
if
(
ret
)
{
printk
(
KERN_WARNING
"jffs2_g_c_deletion_dirent(): Read error (%d) reading from obsolete node at %08x
\n
"
,
ret
,
r
aw
->
flash_offset
&
~
3
);
printk
(
KERN_WARNING
"jffs2_g_c_deletion_dirent(): Read error (%d) reading from obsolete node at %08x
\n
"
,
ret
,
r
ef_offset
(
raw
)
);
/* If we can't read it, we don't need to continune to obsolete it. Continue */
continue
;
}
if
(
retlen
!=
sizeof
(
struct
jffs2_unknown_node
))
{
if
(
retlen
!=
sizeof
(
rd
))
{
printk
(
KERN_WARNING
"jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading from obsolete node at %08x
\n
"
,
retlen
,
sizeof
(
struct
jffs2_unknown_node
),
raw
->
flash_offset
&
~
3
);
retlen
,
sizeof
(
rd
),
ref_offset
(
raw
)
);
continue
;
}
/* If the name CRC doesn't match, skip */
if
(
rd
.
name_crc
!=
name_crc
)
if
(
je32_to_cpu
(
rd
.
name_crc
)
!=
name_crc
)
continue
;
/* If the name length doesn't match, or it's another deletion dirent, skip */
if
(
rd
.
nsize
!=
name_len
||
!
rd
.
ino
)
if
(
rd
.
nsize
!=
name_len
||
!
je32_to_cpu
(
rd
.
ino
)
)
continue
;
/* OK, check the actual name now */
...
...
@@ -456,15 +527,15 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
}
}
/* We read the extra byte before it so it's a word-aligned read */
ret
=
jffs2_flash_read
(
c
,
(
r
aw
->
flash_offset
&
~
3
)
+
sizeof
(
rd
)
-
1
,
name_len
+
1
,
&
retlen
,
namebuf
);
ret
=
jffs2_flash_read
(
c
,
(
r
ef_offset
(
raw
)
)
+
sizeof
(
rd
)
-
1
,
name_len
+
1
,
&
retlen
,
namebuf
);
if
(
ret
)
{
printk
(
KERN_WARNING
"jffs2_g_c_deletion_dirent(): Read error (%d) reading name from obsolete node at %08x
\n
"
,
ret
,
r
aw
->
flash_offset
&
~
3
);
printk
(
KERN_WARNING
"jffs2_g_c_deletion_dirent(): Read error (%d) reading name from obsolete node at %08x
\n
"
,
ret
,
r
ef_offset
(
raw
)
);
/* If we can't read it, we don't need to continune to obsolete it. Continue */
continue
;
}
if
(
retlen
!=
sizeof
(
rd
)
)
{
if
(
retlen
!=
name_len
+
1
)
{
printk
(
KERN_WARNING
"jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading name from obsolete node at %08x
\n
"
,
retlen
,
name_len
,
raw
->
flash_offset
&
~
3
);
retlen
,
name_len
+
1
,
ref_offset
(
raw
)
);
continue
;
}
if
(
memcmp
(
namebuf
+
1
,
fd
->
name
,
name_len
))
...
...
@@ -524,59 +595,62 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
uint32_t
crc
;
/* It's partially obsoleted by a later write. So we have to
write it out again with the _same_ version as before */
ret
=
jffs2_flash_read
(
c
,
fn
->
raw
->
flash_offset
&
~
3
,
sizeof
(
ri
),
&
readlen
,
(
char
*
)
&
ri
);
ret
=
jffs2_flash_read
(
c
,
ref_offset
(
fn
->
raw
)
,
sizeof
(
ri
),
&
readlen
,
(
char
*
)
&
ri
);
if
(
readlen
!=
sizeof
(
ri
)
||
ret
)
{
printk
(
KERN_WARNING
"Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hol
d
node
\n
"
,
ret
,
readlen
);
printk
(
KERN_WARNING
"Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hol
e
node
\n
"
,
ret
,
readlen
);
goto
fill
;
}
if
(
ri
.
nodetype
!=
JFFS2_NODETYPE_INODE
)
{
if
(
je16_to_cpu
(
ri
.
nodetype
)
!=
JFFS2_NODETYPE_INODE
)
{
printk
(
KERN_WARNING
"jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)
\n
"
,
fn
->
raw
->
flash_offset
&
~
3
,
ri
.
nodetype
,
JFFS2_NODETYPE_INODE
);
ref_offset
(
fn
->
raw
),
je16_to_cpu
(
ri
.
nodetype
),
JFFS2_NODETYPE_INODE
);
return
-
EIO
;
}
if
(
ri
.
totlen
!=
sizeof
(
ri
))
{
if
(
je32_to_cpu
(
ri
.
totlen
)
!=
sizeof
(
ri
))
{
printk
(
KERN_WARNING
"jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x
\n
"
,
fn
->
raw
->
flash_offset
&
~
3
,
ri
.
totlen
,
sizeof
(
ri
));
ref_offset
(
fn
->
raw
),
je32_to_cpu
(
ri
.
totlen
),
sizeof
(
ri
));
return
-
EIO
;
}
crc
=
crc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
);
if
(
crc
!=
ri
.
node_crc
)
{
if
(
crc
!=
je32_to_cpu
(
ri
.
node_crc
)
)
{
printk
(
KERN_WARNING
"jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x
\n
"
,
fn
->
raw
->
flash_offset
&
~
3
,
ri
.
node_crc
,
crc
);
ref_offset
(
fn
->
raw
),
je32_to_cpu
(
ri
.
node_crc
),
crc
);
/* FIXME: We could possibly deal with this by writing new holes for each frag */
printk
(
KERN_WARNING
"Data in the range 0x%08x to 0x%08x of inode #%u will be lost
\n
"
,
start
,
end
,
f
->
inocache
->
ino
);
goto
fill
;
}
if
(
ri
.
compr
!=
JFFS2_COMPR_ZERO
)
{
printk
(
KERN_WARNING
"jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!
\n
"
,
fn
->
raw
->
flash_offset
&
~
3
);
printk
(
KERN_WARNING
"jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!
\n
"
,
ref_offset
(
fn
->
raw
)
);
printk
(
KERN_WARNING
"Data in the range 0x%08x to 0x%08x of inode #%u will be lost
\n
"
,
start
,
end
,
f
->
inocache
->
ino
);
goto
fill
;
}
}
else
{
fill:
ri
.
magic
=
JFFS2_MAGIC_BITMASK
;
ri
.
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
.
totlen
=
sizeof
(
ri
);
ri
.
hdr_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
.
ino
=
f
->
inocache
->
ino
;
ri
.
version
=
++
f
->
highest_version
;
ri
.
offset
=
start
;
ri
.
dsize
=
end
-
start
;
ri
.
csize
=
0
;
ri
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
.
totlen
=
cpu_to_je32
(
sizeof
(
ri
)
);
ri
.
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
.
ino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
ri
.
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
.
offset
=
cpu_to_je32
(
start
)
;
ri
.
dsize
=
cpu_to_je32
(
end
-
start
)
;
ri
.
csize
=
cpu_to_je32
(
0
)
;
ri
.
compr
=
JFFS2_COMPR_ZERO
;
}
ri
.
mode
=
JFFS2_F_I_MODE
(
f
);
ri
.
uid
=
JFFS2_F_I_UID
(
f
);
ri
.
gid
=
JFFS2_F_I_GID
(
f
);
ri
.
isize
=
JFFS2_F_I_SIZE
(
f
);
ri
.
atime
=
JFFS2_F_I_ATIME
(
f
);
ri
.
ctime
=
JFFS2_F_I_CTIME
(
f
);
ri
.
mtime
=
JFFS2_F_I_MTIME
(
f
);
ri
.
data_crc
=
0
;
ri
.
node_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
);
ri
.
mode
=
cpu_to_je32
(
JFFS2_F_I_MODE
(
f
)
);
ri
.
uid
=
cpu_to_je16
(
JFFS2_F_I_UID
(
f
)
);
ri
.
gid
=
cpu_to_je16
(
JFFS2_F_I_GID
(
f
)
);
ri
.
isize
=
cpu_to_je32
(
JFFS2_F_I_SIZE
(
f
)
);
ri
.
atime
=
cpu_to_je32
(
JFFS2_F_I_ATIME
(
f
)
);
ri
.
ctime
=
cpu_to_je32
(
JFFS2_F_I_CTIME
(
f
)
);
ri
.
mtime
=
cpu_to_je32
(
JFFS2_F_I_MTIME
(
f
)
);
ri
.
data_crc
=
cpu_to_je32
(
0
)
;
ri
.
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
)
);
ret
=
jffs2_reserve_space_gc
(
c
,
sizeof
(
ri
),
&
phys_ofs
,
&
alloclen
);
if
(
ret
)
{
...
...
@@ -590,7 +664,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
printk
(
KERN_WARNING
"Error writing new hole node: %ld
\n
"
,
PTR_ERR
(
new_fn
));
return
PTR_ERR
(
new_fn
);
}
if
(
ri
.
version
==
f
->
highest_version
)
{
if
(
je32_to_cpu
(
ri
.
version
)
==
f
->
highest_version
)
{
jffs2_add_full_dnode_to_inode
(
c
,
f
,
new_fn
);
if
(
f
->
metadata
)
{
jffs2_mark_node_obsolete
(
c
,
f
->
metadata
->
raw
);
...
...
@@ -608,10 +682,12 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
*/
D1
(
if
(
unlikely
(
fn
->
frags
<=
1
))
{
printk
(
KERN_WARNING
"jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d
\n
"
,
fn
->
frags
,
ri
.
version
,
f
->
highest_version
,
ri
.
ino
);
fn
->
frags
,
je32_to_cpu
(
ri
.
version
),
f
->
highest_version
,
je32_to_cpu
(
ri
.
ino
));
});
for
(
frag
=
f
->
fraglist
;
frag
;
frag
=
frag
->
next
)
{
for
(
frag
=
jffs2_lookup_node_frag
(
&
f
->
fragtree
,
fn
->
ofs
);
frag
;
frag
=
frag_next
(
frag
))
{
if
(
frag
->
ofs
>
fn
->
size
+
fn
->
ofs
)
break
;
if
(
frag
->
node
==
fn
)
{
...
...
@@ -655,7 +731,6 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
orig_end
=
end
;
/* If we're looking at the last node in the block we're
garbage-collecting, we allow ourselves to merge as if the
block was already erasing. We're likely to be GC'ing a
...
...
@@ -722,26 +797,26 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
}
else
{
datalen
=
cdatalen
;
}
ri
.
magic
=
JFFS2_MAGIC_BITMASK
;
ri
.
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
.
totlen
=
sizeof
(
ri
)
+
cdatalen
;
ri
.
hdr_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
.
ino
=
f
->
inocache
->
ino
;
ri
.
version
=
++
f
->
highest_version
;
ri
.
mode
=
JFFS2_F_I_MODE
(
f
);
ri
.
uid
=
JFFS2_F_I_UID
(
f
);
ri
.
gid
=
JFFS2_F_I_GID
(
f
);
ri
.
isize
=
JFFS2_F_I_SIZE
(
f
);
ri
.
atime
=
JFFS2_F_I_ATIME
(
f
);
ri
.
ctime
=
JFFS2_F_I_CTIME
(
f
);
ri
.
mtime
=
JFFS2_F_I_MTIME
(
f
);
ri
.
offset
=
offset
;
ri
.
csize
=
c
datalen
;
ri
.
dsize
=
datalen
;
ri
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
.
totlen
=
cpu_to_je32
(
sizeof
(
ri
)
+
cdatalen
)
;
ri
.
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
.
ino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
ri
.
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
.
mode
=
cpu_to_je32
(
JFFS2_F_I_MODE
(
f
)
);
ri
.
uid
=
cpu_to_je16
(
JFFS2_F_I_UID
(
f
)
);
ri
.
gid
=
cpu_to_je16
(
JFFS2_F_I_GID
(
f
)
);
ri
.
isize
=
cpu_to_je32
(
JFFS2_F_I_SIZE
(
f
)
);
ri
.
atime
=
cpu_to_je32
(
JFFS2_F_I_ATIME
(
f
)
);
ri
.
ctime
=
cpu_to_je32
(
JFFS2_F_I_CTIME
(
f
)
);
ri
.
mtime
=
cpu_to_je32
(
JFFS2_F_I_MTIME
(
f
)
);
ri
.
offset
=
cpu_to_je32
(
offset
)
;
ri
.
csize
=
c
pu_to_je32
(
cdatalen
)
;
ri
.
dsize
=
cpu_to_je32
(
datalen
)
;
ri
.
compr
=
comprtype
;
ri
.
node_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
);
ri
.
data_crc
=
c
rc32
(
0
,
writebuf
,
cdatalen
);
ri
.
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
)
);
ri
.
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
writebuf
,
cdatalen
)
);
new_fn
=
jffs2_write_dnode
(
c
,
f
,
&
ri
,
writebuf
,
cdatalen
,
phys_ofs
,
NULL
);
...
...
fs/jffs2/nodelist.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: nodelist.c,v 1.
47 2002/06/26 01:25:30
dwmw2 Exp $
* $Id: nodelist.c,v 1.
65 2002/11/12 09:50:13
dwmw2 Exp $
*
*/
...
...
@@ -15,6 +15,9 @@
#include <linux/fs.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
#include <linux/rbtree.h>
#include <linux/crc32.h>
#include <linux/slab.h>
#include "nodelist.h"
void
jffs2_add_fd_to_list
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_full_dirent
*
new
,
struct
jffs2_full_dirent
**
list
)
...
...
@@ -116,9 +119,9 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
for
(
ref
=
f
->
inocache
->
nodes
;
ref
&&
ref
->
next_in_ino
;
ref
=
ref
->
next_in_ino
)
{
/* Work out whether it's a data node or a dirent node */
if
(
ref
->
flash_offset
&
1
)
{
if
(
ref
_obsolete
(
ref
)
)
{
/* FIXME: On NAND flash we may need to read these */
D1
(
printk
(
KERN_DEBUG
"node at 0x%08x is obsoleted. Ignoring.
\n
"
,
ref
->
flash_offset
&~
3
));
D1
(
printk
(
KERN_DEBUG
"node at 0x%08x is obsoleted. Ignoring.
\n
"
,
ref
_offset
(
ref
)
));
continue
;
}
/* We can hold a pointer to a non-obsolete node without the spinlock,
...
...
@@ -126,9 +129,12 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
they're in gets erased */
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
err
=
jffs2_flash_read
(
c
,
(
ref
->
flash_offset
&
~
3
),
min
(
ref
->
totlen
,
sizeof
(
node
)),
&
retlen
,
(
void
*
)
&
node
);
cond_resched
();
/* FIXME: point() */
err
=
jffs2_flash_read
(
c
,
(
ref_offset
(
ref
)),
min
(
ref
->
totlen
,
sizeof
(
node
)),
&
retlen
,
(
void
*
)
&
node
);
if
(
err
)
{
printk
(
KERN_WARNING
"error %d reading node at 0x%08x in get_inode_nodes()
\n
"
,
err
,
(
ref
->
flash_offset
)
&
~
3
);
printk
(
KERN_WARNING
"error %d reading node at 0x%08x in get_inode_nodes()
\n
"
,
err
,
ref_offset
(
ref
)
);
goto
free_out
;
}
...
...
@@ -140,20 +146,24 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
goto
free_out
;
}
switch
(
node
.
u
.
nodetype
)
{
switch
(
je16_to_cpu
(
node
.
u
.
nodetype
)
)
{
case
JFFS2_NODETYPE_DIRENT
:
D1
(
printk
(
KERN_DEBUG
"Node at %08x is a dirent node
\n
"
,
ref
->
flash_offset
&~
3
));
D1
(
printk
(
KERN_DEBUG
"Node at %08x (%d) is a dirent node
\n
"
,
ref_offset
(
ref
),
ref_flags
(
ref
)));
if
(
ref_flags
(
ref
)
==
REF_UNCHECKED
)
{
printk
(
KERN_WARNING
"BUG: Dirent node at 0x%08x never got checked? How?
\n
"
,
ref_offset
(
ref
));
BUG
();
}
if
(
retlen
<
sizeof
(
node
.
d
))
{
printk
(
KERN_WARNING
"short read in get_inode_nodes()
\n
"
);
err
=
-
EIO
;
goto
free_out
;
}
if
(
node
.
d
.
version
>
*
highest_version
)
*
highest_version
=
node
.
d
.
version
;
if
(
ref
->
flash_offset
&
1
)
{
if
(
je32_to_cpu
(
node
.
d
.
version
)
>
*
highest_version
)
*
highest_version
=
je32_to_cpu
(
node
.
d
.
version
)
;
if
(
ref
_obsolete
(
ref
)
)
{
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
printk
(
KERN_ERR
"Dirent node at 0x%08x became obsolete while we weren't looking
\n
"
,
ref
->
flash_offset
&
~
3
);
ref
_offset
(
ref
)
);
BUG
();
}
fd
=
jffs2_alloc_full_dirent
(
node
.
d
.
nsize
+
1
);
...
...
@@ -163,14 +173,14 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
}
memset
(
fd
,
0
,
sizeof
(
struct
jffs2_full_dirent
)
+
node
.
d
.
nsize
+
1
);
fd
->
raw
=
ref
;
fd
->
version
=
node
.
d
.
version
;
fd
->
ino
=
node
.
d
.
ino
;
fd
->
version
=
je32_to_cpu
(
node
.
d
.
version
)
;
fd
->
ino
=
je32_to_cpu
(
node
.
d
.
ino
)
;
fd
->
type
=
node
.
d
.
type
;
/* Pick out the mctime of the latest dirent */
if
(
fd
->
version
>
*
mctime_ver
)
{
*
mctime_ver
=
fd
->
version
;
*
latest_mctime
=
node
.
d
.
mctime
;
*
latest_mctime
=
je32_to_cpu
(
node
.
d
.
mctime
)
;
}
/* memcpy as much of the name as possible from the raw
...
...
@@ -183,9 +193,10 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
from the flash?
*/
if
(
node
.
d
.
nsize
+
sizeof
(
struct
jffs2_raw_dirent
)
>
retlen
)
{
/* FIXME: point() */
int
already
=
retlen
-
sizeof
(
struct
jffs2_raw_dirent
);
err
=
jffs2_flash_read
(
c
,
(
ref
->
flash_offset
&
~
3
)
+
retlen
,
err
=
jffs2_flash_read
(
c
,
(
ref
_offset
(
ref
)
)
+
retlen
,
node
.
d
.
nsize
-
already
,
&
retlen
,
&
fd
->
name
[
already
]);
if
(
!
err
&&
retlen
!=
node
.
d
.
nsize
-
already
)
err
=
-
EIO
;
...
...
@@ -206,22 +217,75 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
break
;
case
JFFS2_NODETYPE_INODE
:
D1
(
printk
(
KERN_DEBUG
"Node at %08x
is a data node
\n
"
,
ref
->
flash_offset
&~
3
));
D1
(
printk
(
KERN_DEBUG
"Node at %08x
(%d) is a data node
\n
"
,
ref_offset
(
ref
),
ref_flags
(
ref
)
));
if
(
retlen
<
sizeof
(
node
.
i
))
{
printk
(
KERN_WARNING
"read too short for dnode
\n
"
);
err
=
-
EIO
;
goto
free_out
;
}
if
(
node
.
d
.
version
>
*
highest_version
)
*
highest_version
=
node
.
i
.
version
;
D1
(
printk
(
KERN_DEBUG
"version %d, highest_version now %d
\n
"
,
node
.
d
.
version
,
*
highest_version
));
if
(
je32_to_cpu
(
node
.
i
.
version
)
>
*
highest_version
)
*
highest_version
=
je32_to_cpu
(
node
.
i
.
version
)
;
D1
(
printk
(
KERN_DEBUG
"version %d, highest_version now %d
\n
"
,
je32_to_cpu
(
node
.
i
.
version
)
,
*
highest_version
));
if
(
ref
->
flash_offset
&
1
)
{
if
(
ref
_obsolete
(
ref
)
)
{
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
printk
(
KERN_ERR
"Inode node at 0x%08x became obsolete while we weren't looking
\n
"
,
ref
->
flash_offset
&
~
3
);
ref
_offset
(
ref
)
);
BUG
();
}
/* If we've never checked the CRCs on this node, check them now. */
if
(
ref_flags
(
ref
)
==
REF_UNCHECKED
)
{
uint32_t
crc
;
struct
jffs2_eraseblock
*
jeb
;
crc
=
crc32
(
0
,
&
node
,
sizeof
(
node
.
i
)
-
8
);
if
(
crc
!=
je32_to_cpu
(
node
.
i
.
node_crc
))
{
printk
(
KERN_NOTICE
"jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x
\n
"
,
ref_offset
(
ref
),
je32_to_cpu
(
node
.
i
.
node_crc
),
crc
);
jffs2_mark_node_obsolete
(
c
,
ref
);
spin_lock_bh
(
&
c
->
erase_completion_lock
);
continue
;
}
if
(
node
.
i
.
compr
!=
JFFS2_COMPR_ZERO
&&
je32_to_cpu
(
node
.
i
.
csize
))
{
/* FIXME: point() */
char
*
buf
=
kmalloc
(
je32_to_cpu
(
node
.
i
.
csize
),
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
err
=
jffs2_flash_read
(
c
,
ref_offset
(
ref
)
+
sizeof
(
node
.
i
),
je32_to_cpu
(
node
.
i
.
csize
),
&
retlen
,
buf
);
if
(
!
err
&&
retlen
!=
je32_to_cpu
(
node
.
i
.
csize
))
err
=
-
EIO
;
if
(
err
)
{
kfree
(
buf
);
return
err
;
}
crc
=
crc32
(
0
,
buf
,
je32_to_cpu
(
node
.
i
.
csize
));
kfree
(
buf
);
if
(
crc
!=
je32_to_cpu
(
node
.
i
.
data_crc
))
{
printk
(
KERN_NOTICE
"jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x
\n
"
,
ref_offset
(
ref
),
je32_to_cpu
(
node
.
i
.
data_crc
),
crc
);
jffs2_mark_node_obsolete
(
c
,
ref
);
spin_lock_bh
(
&
c
->
erase_completion_lock
);
continue
;
}
}
/* Mark the node as having been checked and fix the accounting accordingly */
jeb
=
&
c
->
blocks
[
ref
->
flash_offset
/
c
->
sector_size
];
jeb
->
used_size
+=
ref
->
totlen
;
jeb
->
unchecked_size
-=
ref
->
totlen
;
c
->
used_size
+=
ref
->
totlen
;
c
->
unchecked_size
-=
ref
->
totlen
;
mark_ref_normal
(
ref
);
}
tn
=
jffs2_alloc_tmp_dnode_info
();
if
(
!
tn
)
{
D1
(
printk
(
KERN_DEBUG
"alloc tn failed
\n
"
));
...
...
@@ -236,34 +300,66 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
jffs2_free_tmp_dnode_info
(
tn
);
goto
free_out
;
}
tn
->
version
=
node
.
i
.
version
;
tn
->
fn
->
ofs
=
node
.
i
.
offset
;
tn
->
version
=
je32_to_cpu
(
node
.
i
.
version
)
;
tn
->
fn
->
ofs
=
je32_to_cpu
(
node
.
i
.
offset
)
;
/* There was a bug where we wrote hole nodes out with
csize/dsize swapped. Deal with it */
if
(
node
.
i
.
compr
==
JFFS2_COMPR_ZERO
&&
!
node
.
i
.
dsize
&&
node
.
i
.
csize
)
tn
->
fn
->
size
=
node
.
i
.
csize
;
if
(
node
.
i
.
compr
==
JFFS2_COMPR_ZERO
&&
!
je32_to_cpu
(
node
.
i
.
dsize
)
&&
je32_to_cpu
(
node
.
i
.
csize
)
)
tn
->
fn
->
size
=
je32_to_cpu
(
node
.
i
.
csize
)
;
else
// normal case...
tn
->
fn
->
size
=
node
.
i
.
dsize
;
tn
->
fn
->
size
=
je32_to_cpu
(
node
.
i
.
dsize
)
;
tn
->
fn
->
raw
=
ref
;
D1
(
printk
(
KERN_DEBUG
"dnode @%08x: ver %u, offset %04x, dsize %04x
\n
"
,
ref
->
flash_offset
&~
3
,
node
.
i
.
version
,
node
.
i
.
offset
,
node
.
i
.
dsize
));
D1
(
printk
(
KERN_DEBUG
"dnode @%08x: ver %u, offset %04x, dsize %04x
\n
"
,
ref_offset
(
ref
),
je32_to_cpu
(
node
.
i
.
version
),
je32_to_cpu
(
node
.
i
.
offset
),
je32_to_cpu
(
node
.
i
.
dsize
)));
jffs2_add_tn_to_list
(
tn
,
&
ret_tn
);
break
;
default:
switch
(
node
.
u
.
nodetype
&
JFFS2_COMPAT_MASK
)
{
if
(
ref_flags
(
ref
)
==
REF_UNCHECKED
)
{
struct
jffs2_eraseblock
*
jeb
;
printk
(
KERN_ERR
"Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED
\n
"
,
je16_to_cpu
(
node
.
u
.
nodetype
),
ref_offset
(
ref
));
/* Mark the node as having been checked and fix the accounting accordingly */
jeb
=
&
c
->
blocks
[
ref
->
flash_offset
/
c
->
sector_size
];
jeb
->
used_size
+=
ref
->
totlen
;
jeb
->
unchecked_size
-=
ref
->
totlen
;
c
->
used_size
+=
ref
->
totlen
;
c
->
unchecked_size
-=
ref
->
totlen
;
mark_ref_normal
(
ref
);
}
node
.
u
.
nodetype
=
cpu_to_je16
(
JFFS2_NODE_ACCURATE
|
je16_to_cpu
(
node
.
u
.
nodetype
));
if
(
crc32
(
0
,
&
node
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
!=
je32_to_cpu
(
node
.
u
.
hdr_crc
))
{
/* Hmmm. This should have been caught at scan time. */
printk
(
KERN_ERR
"Node header CRC failed at %08x. But it must have been OK earlier.
\n
"
,
ref_offset
(
ref
));
printk
(
KERN_ERR
"Node was: { %04x, %04x, %08x, %08x }
\n
"
,
je16_to_cpu
(
node
.
u
.
magic
),
je16_to_cpu
(
node
.
u
.
nodetype
),
je32_to_cpu
(
node
.
u
.
totlen
),
je32_to_cpu
(
node
.
u
.
hdr_crc
));
jffs2_mark_node_obsolete
(
c
,
ref
);
}
else
switch
(
je16_to_cpu
(
node
.
u
.
nodetype
)
&
JFFS2_COMPAT_MASK
)
{
case
JFFS2_FEATURE_INCOMPAT
:
printk
(
KERN_NOTICE
"Unknown INCOMPAT nodetype %04X at %08X
\n
"
,
node
.
u
.
nodetype
,
ref
->
flash_offset
&
~
3
);
printk
(
KERN_NOTICE
"Unknown INCOMPAT nodetype %04X at %08x
\n
"
,
je16_to_cpu
(
node
.
u
.
nodetype
),
ref_offset
(
ref
));
/* EEP */
BUG
();
break
;
case
JFFS2_FEATURE_ROCOMPAT
:
printk
(
KERN_NOTICE
"Unknown ROCOMPAT nodetype %04X at %08X
\n
"
,
node
.
u
.
nodetype
,
ref
->
flash_offset
&
~
3
);
printk
(
KERN_NOTICE
"Unknown ROCOMPAT nodetype %04X at %08x
\n
"
,
je16_to_cpu
(
node
.
u
.
nodetype
),
ref_offset
(
ref
));
if
(
!
(
c
->
flags
&
JFFS2_SB_FLAG_RO
))
BUG
();
break
;
case
JFFS2_FEATURE_RWCOMPAT_COPY
:
printk
(
KERN_NOTICE
"Unknown RWCOMPAT_COPY nodetype %04X at %08
X
\n
"
,
node
.
u
.
nodetype
,
ref
->
flash_offset
&
~
3
);
printk
(
KERN_NOTICE
"Unknown RWCOMPAT_COPY nodetype %04X at %08
x
\n
"
,
je16_to_cpu
(
node
.
u
.
nodetype
),
ref_offset
(
ref
)
);
break
;
case
JFFS2_FEATURE_RWCOMPAT_DELETE
:
printk
(
KERN_NOTICE
"Unknown RWCOMPAT_DELETE nodetype %04X at %08X
\n
"
,
node
.
u
.
nodetype
,
ref
->
flash_offset
&
~
3
);
printk
(
KERN_NOTICE
"Unknown RWCOMPAT_DELETE nodetype %04X at %08x
\n
"
,
je16_to_cpu
(
node
.
u
.
nodetype
),
ref_offset
(
ref
));
jffs2_mark_node_obsolete
(
c
,
ref
);
break
;
}
}
spin_lock_bh
(
&
c
->
erase_completion_lock
);
...
...
@@ -369,3 +465,126 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c)
}
}
struct
jffs2_node_frag
*
jffs2_lookup_node_frag
(
struct
rb_root
*
fragtree
,
uint32_t
offset
)
{
/* The common case in lookup is that there will be a node
which precisely matches. So we go looking for that first */
struct
rb_node
*
next
;
struct
jffs2_node_frag
*
prev
=
NULL
;
struct
jffs2_node_frag
*
frag
=
NULL
;
D2
(
printk
(
KERN_DEBUG
"jffs2_lookup_node_frag(%p, %d)
\n
"
,
fragtree
,
offset
));
next
=
fragtree
->
rb_node
;
while
(
next
)
{
frag
=
rb_entry
(
next
,
struct
jffs2_node_frag
,
rb
);
D2
(
printk
(
KERN_DEBUG
"Considering frag %d-%d (%p). left %p, right %p
\n
"
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
,
frag
,
frag
->
rb
.
rb_left
,
frag
->
rb
.
rb_right
));
if
(
frag
->
ofs
+
frag
->
size
<=
offset
)
{
D2
(
printk
(
KERN_DEBUG
"Going right from frag %d-%d, before the region we care about
\n
"
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
));
/* Remember the closest smaller match on the way down */
if
(
!
prev
||
frag
->
ofs
>
prev
->
ofs
)
prev
=
frag
;
next
=
frag
->
rb
.
rb_right
;
}
else
if
(
frag
->
ofs
>
offset
)
{
D2
(
printk
(
KERN_DEBUG
"Going left from frag %d-%d, after the region we care about
\n
"
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
));
next
=
frag
->
rb
.
rb_left
;
}
else
{
D2
(
printk
(
KERN_DEBUG
"Returning frag %d,%d, matched
\n
"
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
));
return
frag
;
}
}
/* Exact match not found. Go back up looking at each parent,
and return the closest smaller one */
if
(
prev
)
D2
(
printk
(
KERN_DEBUG
"No match. Returning frag %d,%d, closest previous
\n
"
,
prev
->
ofs
,
prev
->
ofs
+
prev
->
size
));
else
D2
(
printk
(
KERN_DEBUG
"Returning NULL, empty fragtree
\n
"
));
return
prev
;
}
/* Pass 'c' argument to indicate that nodes should be marked obsolete as
they're killed. */
void
jffs2_kill_fragtree
(
struct
rb_root
*
root
,
struct
jffs2_sb_info
*
c
)
{
struct
jffs2_node_frag
*
frag
;
struct
jffs2_node_frag
*
parent
;
if
(
!
root
->
rb_node
)
return
;
frag
=
(
rb_entry
(
root
->
rb_node
,
struct
jffs2_node_frag
,
rb
));
while
(
frag
)
{
if
(
frag
->
rb
.
rb_left
)
{
D2
(
printk
(
KERN_DEBUG
"Going left from frag (%p) %d-%d
\n
"
,
frag
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
));
frag
=
frag_left
(
frag
);
continue
;
}
if
(
frag
->
rb
.
rb_right
)
{
D2
(
printk
(
KERN_DEBUG
"Going right from frag (%p) %d-%d
\n
"
,
frag
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
));
frag
=
frag_right
(
frag
);
continue
;
}
D2
(
printk
(
KERN_DEBUG
"jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--
\n
"
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
,
frag
->
node
,
frag
->
node
?
frag
->
node
->
frags
:
0
));
if
(
frag
->
node
&&
!
(
--
frag
->
node
->
frags
))
{
/* Not a hole, and it's the final remaining frag
of this node. Free the node */
if
(
c
)
jffs2_mark_node_obsolete
(
c
,
frag
->
node
->
raw
);
jffs2_free_full_dnode
(
frag
->
node
);
}
parent
=
frag_parent
(
frag
);
if
(
parent
)
{
if
(
frag_left
(
parent
)
==
frag
)
parent
->
rb
.
rb_left
=
NULL
;
else
parent
->
rb
.
rb_right
=
NULL
;
}
jffs2_free_node_frag
(
frag
);
frag
=
parent
;
}
}
void
jffs2_fragtree_insert
(
struct
jffs2_node_frag
*
newfrag
,
struct
jffs2_node_frag
*
base
)
{
struct
rb_node
*
parent
=
&
base
->
rb
;
struct
rb_node
**
link
=
&
parent
;
D2
(
printk
(
KERN_DEBUG
"jffs2_fragtree_insert(%p; %d-%d, %p)
\n
"
,
newfrag
,
newfrag
->
ofs
,
newfrag
->
ofs
+
newfrag
->
size
,
base
));
while
(
*
link
)
{
parent
=
*
link
;
base
=
rb_entry
(
parent
,
struct
jffs2_node_frag
,
rb
);
D2
(
printk
(
KERN_DEBUG
"fragtree_insert considering frag at 0x%x
\n
"
,
base
->
ofs
));
if
(
newfrag
->
ofs
>
base
->
ofs
)
link
=
&
base
->
rb
.
rb_right
;
else
if
(
newfrag
->
ofs
<
base
->
ofs
)
link
=
&
base
->
rb
.
rb_left
;
else
{
printk
(
KERN_CRIT
"Duplicate frag at %08x (%p,%p)
\n
"
,
newfrag
->
ofs
,
newfrag
,
base
);
BUG
();
}
}
rb_link_node
(
&
newfrag
->
rb
,
&
base
->
rb
,
link
);
}
fs/jffs2/nodelist.h
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: nodelist.h,v 1.
74 2002/06/26 01:20:43
dwmw2 Exp $
* $Id: nodelist.h,v 1.
87 2002/11/12 13:36:18
dwmw2 Exp $
*
*/
...
...
@@ -53,16 +53,22 @@ struct jffs2_raw_node_ref
for this inode instead. The inode_cache will have NULL in the first
word so you know when you've got there :) */
struct
jffs2_raw_node_ref
*
next_phys
;
// uint32_t ino;
uint32_t
flash_offset
;
uint32_t
totlen
;
// uint16_t nodetype;
/* flash_offset & 3 always has to be zero, because nodes are
always aligned at 4 bytes. So we have a couple of extra bits
to play with. So we set the least significant bit to 1 to
signify that the node is obsoleted by later nodes.
*/
#define REF_UNCHECKED 0
/* We haven't yet checked the CRC or built its inode */
#define REF_OBSOLETE 1
/* Obsolete, can be completely ignored */
#define REF_PRISTINE 2
/* Completely clean. GC without looking */
#define REF_NORMAL 3
/* Possibly overlapped. Read the page and write again on GC */
#define ref_flags(ref) ((ref)->flash_offset & 3)
#define ref_offset(ref) ((ref)->flash_offset & ~3)
#define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE)
#define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
};
/*
...
...
@@ -83,14 +89,20 @@ struct jffs2_raw_node_ref_list {
a pointer to the first physical node which is part of this inode, too.
*/
struct
jffs2_inode_cache
{
struct
jffs2_
scan_info
*
scan
;
/* Used during scan to hold
temporary lists of
node
s, and later must be set to
struct
jffs2_
full_dirent
*
scan_dents
;
/* Used during scan to hold
temporary lists of
dirent
s, and later must be set to
NULL to mark the end of the raw_node_ref->next_in_ino
chain. */
struct
jffs2_inode_cache
*
next
;
struct
jffs2_raw_node_ref
*
nodes
;
uint32_t
ino
;
int
nlink
;
int
state
;
#define INO_STATE_UNCHECKED 0
#define INO_STATE_CHECKING 1
#define INO_STATE_CHECKEDABSENT 2
#define INO_STATE_READINGINODE 3
#define INO_STATE_PRESENT 5
};
#define INOCACHE_HASHSIZE 128
...
...
@@ -146,7 +158,7 @@ struct jffs2_full_dirent
*/
struct
jffs2_node_frag
{
struct
jffs2_node_frag
*
next
;
struct
rb_node
rb
;
struct
jffs2_full_dnode
*
node
;
/* NULL for holes */
uint32_t
size
;
uint32_t
ofs
;
/* Don't really need this, but optimisation */
...
...
@@ -158,8 +170,10 @@ struct jffs2_eraseblock
int
bad_count
;
uint32_t
offset
;
/* of this block in the MTD */
uint32_t
unchecked_size
;
uint32_t
used_size
;
uint32_t
dirty_size
;
uint32_t
wasted_size
;
uint32_t
free_size
;
/* Note that sector_size - free_size
is the address of the first free space */
struct
jffs2_raw_node_ref
*
first_node
;
...
...
@@ -177,25 +191,28 @@ struct jffs2_eraseblock
};
#define ACCT_SANITY_CHECK(c, jeb) do { \
if (jeb->used_size + jeb->dirty_size + jeb->free_size != c->sector_size) { \
if (jeb->used_size + jeb->dirty_size + jeb->free_size
+ jeb->wasted_size + jeb->unchecked_size
!= c->sector_size) { \
printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", jeb->offset); \
printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x != total %08x\n", \
jeb->free_size, jeb->dirty_size, jeb->used_size, c->sector_size); \
printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x
+ wasted %08x + unchecked %08x
!= total %08x\n", \
jeb->free_size, jeb->dirty_size, jeb->used_size,
jeb->wasted_size, jeb->unchecked_size,
c->sector_size); \
BUG(); \
} \
if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size != c->flash_size) { \
if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size
+ c->wasted_size + c->unchecked_size
!= c->flash_size) { \
printk(KERN_NOTICE "Eeep. Space accounting superblock info is screwed\n"); \
printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x != total %08x\n", \
c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->flash_size); \
printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x
+ wasted %08x + unchecked %08x
!= total %08x\n", \
c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->
wasted_size, c->unchecked_size, c->
flash_size); \
BUG(); \
} \
} while(0)
#define ACCT_PARANOIA_CHECK(jeb) do { \
uint32_t my_used_size = 0; \
uint32_t my_unchecked_size = 0; \
struct jffs2_raw_node_ref *ref2 = jeb->first_node; \
while (ref2) { \
if (!(ref2->flash_offset & 1)) \
if (ref_flags(ref2) == REF_UNCHECKED) \
my_unchecked_size += ref2->totlen; \
else if (!ref_obsolete(ref2)) \
my_used_size += ref2->totlen; \
ref2 = ref2->next_phys; \
} \
...
...
@@ -203,6 +220,10 @@ struct jffs2_eraseblock
printk(KERN_NOTICE "Calculated used size %08x != stored used size %08x\n", my_used_size, jeb->used_size); \
BUG(); \
} \
if (my_unchecked_size != jeb->unchecked_size) { \
printk(KERN_NOTICE "Calculated unchecked size %08x != stored unchecked size %08x\n", my_unchecked_size, jeb->unchecked_size); \
BUG(); \
} \
} while(0)
#define ALLOC_NORMAL 0
/* Normal allocation */
...
...
@@ -211,7 +232,7 @@ struct jffs2_eraseblock
#define JFFS2_RESERVED_BLOCKS_BASE 3
/* Number of free blocks there must be before we... */
#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 2)
/* ... allow a normal filesystem write */
#define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE
+ 1
)
/* ... allow a normal filesystem deletion */
#define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE)
/* ... allow a normal filesystem deletion */
#define JFFS2_RESERVED_BLOCKS_GCTRIGGER (JFFS2_RESERVED_BLOCKS_BASE + 3)
/* ... wake up the GC thread */
#define JFFS2_RESERVED_BLOCKS_GCBAD (JFFS2_RESERVED_BLOCKS_BASE + 1)
/* ... pick a block from the bad_list to GC */
#define JFFS2_RESERVED_BLOCKS_GCMERGE (JFFS2_RESERVED_BLOCKS_BASE)
/* ... merge pages when garbage collecting */
...
...
@@ -220,6 +241,9 @@ struct jffs2_eraseblock
/* How much dirty space before it goes on the very_dirty_list */
#define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2))
/* check if dirty space is more than 255 Byte */
#define ISDIRTY(size) ((size) > sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN)
#define PAD(x) (((x)+3)&~3)
static
inline
int
jffs2_raw_ref_to_inum
(
struct
jffs2_raw_node_ref
*
raw
)
...
...
@@ -231,6 +255,24 @@ static inline int jffs2_raw_ref_to_inum(struct jffs2_raw_node_ref *raw)
return
((
struct
jffs2_inode_cache
*
)
raw
)
->
ino
;
}
static
inline
struct
jffs2_node_frag
*
frag_first
(
struct
rb_root
*
root
)
{
struct
rb_node
*
node
=
root
->
rb_node
;
if
(
!
node
)
return
NULL
;
while
(
node
->
rb_left
)
node
=
node
->
rb_left
;
return
rb_entry
(
node
,
struct
jffs2_node_frag
,
rb
);
}
#define rb_parent(rb) ((rb)->rb_parent)
#define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb)
#define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb)
#define frag_parent(frag) rb_entry(rb_parent(&(frag)->rb), struct jffs2_node_frag, rb)
#define frag_left(frag) rb_entry((frag)->rb.rb_left, struct jffs2_node_frag, rb)
#define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb)
#define frag_erase(frag, list) rb_erase(&frag->rb, list);
/* nodelist.c */
D1
(
void
jffs2_print_frag_list
(
struct
jffs2_inode_info
*
f
));
void
jffs2_add_fd_to_list
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_full_dirent
*
new
,
struct
jffs2_full_dirent
**
list
);
...
...
@@ -244,11 +286,17 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new
void
jffs2_del_ino_cache
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_inode_cache
*
old
);
void
jffs2_free_ino_caches
(
struct
jffs2_sb_info
*
c
);
void
jffs2_free_raw_node_refs
(
struct
jffs2_sb_info
*
c
);
struct
jffs2_node_frag
*
jffs2_lookup_node_frag
(
struct
rb_root
*
fragtree
,
uint32_t
offset
);
void
jffs2_kill_fragtree
(
struct
rb_root
*
root
,
struct
jffs2_sb_info
*
c_delete
);
void
jffs2_fragtree_insert
(
struct
jffs2_node_frag
*
newfrag
,
struct
jffs2_node_frag
*
base
);
struct
rb_node
*
rb_next
(
struct
rb_node
*
);
struct
rb_node
*
rb_prev
(
struct
rb_node
*
);
void
rb_replace_node
(
struct
rb_node
*
victim
,
struct
rb_node
*
new
,
struct
rb_root
*
root
);
/* nodemgmt.c */
int
jffs2_reserve_space
(
struct
jffs2_sb_info
*
c
,
uint32_t
minsize
,
uint32_t
*
ofs
,
uint32_t
*
len
,
int
prio
);
int
jffs2_reserve_space_gc
(
struct
jffs2_sb_info
*
c
,
uint32_t
minsize
,
uint32_t
*
ofs
,
uint32_t
*
len
);
int
jffs2_add_physical_node_ref
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_raw_node_ref
*
new
,
uint32_t
len
,
int
dirty
);
int
jffs2_add_physical_node_ref
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_raw_node_ref
*
new
);
void
jffs2_complete_reservation
(
struct
jffs2_sb_info
*
c
);
void
jffs2_mark_node_obsolete
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_raw_node_ref
*
raw
);
void
jffs2_dump_block_lists
(
struct
jffs2_sb_info
*
c
);
...
...
@@ -266,8 +314,8 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
/* readinode.c */
void
jffs2_truncate_fraglist
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_node_frag
*
*
list
,
uint32_t
size
);
int
jffs2_add_full_dnode_to_fraglist
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_node_frag
*
*
list
,
struct
jffs2_full_dnode
*
fn
);
void
jffs2_truncate_fraglist
(
struct
jffs2_sb_info
*
c
,
struct
rb_root
*
list
,
uint32_t
size
);
int
jffs2_add_full_dnode_to_fraglist
(
struct
jffs2_sb_info
*
c
,
struct
rb_root
*
list
,
struct
jffs2_full_dnode
*
fn
);
int
jffs2_add_full_dnode_to_inode
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_inode_info
*
f
,
struct
jffs2_full_dnode
*
fn
);
int
jffs2_do_read_inode
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_inode_info
*
f
,
uint32_t
ino
,
struct
jffs2_raw_inode
*
latest_node
);
...
...
@@ -320,7 +368,6 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c);
/* erase.c */
void
jffs2_erase_block
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
);
void
jffs2_erase_pending_blocks
(
struct
jffs2_sb_info
*
c
);
void
jffs2_mark_erased_blocks
(
struct
jffs2_sb_info
*
c
);
void
jffs2_erase_pending_trigger
(
struct
jffs2_sb_info
*
c
);
#ifdef CONFIG_JFFS2_FS_NAND
...
...
fs/jffs2/nodemgmt.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: nodemgmt.c,v 1.
70 2002/07/02 22:48:24
dwmw2 Exp $
* $Id: nodemgmt.c,v 1.
84 2002/11/12 11:17:29
dwmw2 Exp $
*
*/
...
...
@@ -62,14 +62,17 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
int
ret
;
up
(
&
c
->
alloc_sem
);
if
(
c
->
dirty_size
<
c
->
sector_size
)
{
D1
(
printk
(
KERN_DEBUG
"Short on space, but total dirty size 0x%08x < sector size 0x%08x, so -ENOSPC
\n
"
,
c
->
dirty_size
,
c
->
sector_size
));
if
(
c
->
dirty_size
+
c
->
unchecked_size
<
c
->
sector_size
)
{
D1
(
printk
(
KERN_DEBUG
"dirty size 0x%08x + unchecked_size 0x%08x < sector size 0x%08x, returning -ENOSPC
\n
"
,
c
->
dirty_size
,
c
->
unchecked_size
,
c
->
sector_size
));
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
return
-
ENOSPC
;
}
D1
(
printk
(
KERN_DEBUG
"Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)
\n
"
,
c
->
nr_free_blocks
,
c
->
nr_erasing_blocks
,
c
->
free_size
,
c
->
dirty_size
,
c
->
used_size
,
c
->
erasing_size
,
c
->
bad_size
,
c
->
free_size
+
c
->
dirty_size
+
c
->
used_size
+
c
->
erasing_size
+
c
->
bad_size
,
c
->
flash_size
));
D1
(
printk
(
KERN_DEBUG
"Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)
\n
"
,
c
->
nr_free_blocks
,
c
->
nr_erasing_blocks
,
c
->
free_size
,
c
->
dirty_size
,
c
->
wasted_size
,
c
->
used_size
,
c
->
erasing_size
,
c
->
bad_size
,
c
->
free_size
+
c
->
dirty_size
+
c
->
wasted_size
+
c
->
used_size
+
c
->
erasing_size
+
c
->
bad_size
,
c
->
flash_size
));
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
ret
=
jffs2_garbage_collect_pass
(
c
);
...
...
@@ -130,10 +133,17 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
spin_lock_bh
(
&
c
->
erase_completion_lock
);
/* We know nobody's going to have changed nextblock. Just continue */
}
c
->
dirty
_size
+=
jeb
->
free_size
;
c
->
wasted
_size
+=
jeb
->
free_size
;
c
->
free_size
-=
jeb
->
free_size
;
jeb
->
dirty
_size
+=
jeb
->
free_size
;
jeb
->
wasted
_size
+=
jeb
->
free_size
;
jeb
->
free_size
=
0
;
/* Check, if we have a dirty block now, or if it was dirty already */
if
(
ISDIRTY
(
jeb
->
wasted_size
+
jeb
->
dirty_size
))
{
c
->
dirty_size
+=
jeb
->
wasted_size
;
c
->
wasted_size
-=
jeb
->
wasted_size
;
jeb
->
dirty_size
+=
jeb
->
wasted_size
;
jeb
->
wasted_size
=
0
;
if
(
VERYDIRTY
(
c
,
jeb
->
dirty_size
))
{
D1
(
printk
(
KERN_DEBUG
"Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x
\n
"
,
jeb
->
offset
,
jeb
->
free_size
,
jeb
->
dirty_size
,
jeb
->
used_size
));
...
...
@@ -143,6 +153,11 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
jeb
->
offset
,
jeb
->
free_size
,
jeb
->
dirty_size
,
jeb
->
used_size
));
list_add_tail
(
&
jeb
->
list
,
&
c
->
dirty_list
);
}
}
else
{
D1
(
printk
(
KERN_DEBUG
"Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x
\n
"
,
jeb
->
offset
,
jeb
->
free_size
,
jeb
->
dirty_size
,
jeb
->
used_size
));
list_add_tail
(
&
jeb
->
list
,
&
c
->
clean_list
);
}
c
->
nextblock
=
jeb
=
NULL
;
}
...
...
@@ -225,7 +240,7 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
*
ofs
=
jeb
->
offset
+
(
c
->
sector_size
-
jeb
->
free_size
);
*
len
=
jeb
->
free_size
;
if
(
jeb
->
used_size
==
PAD
(
sizeof
(
struct
jffs2_unknown_node
))
&&
if
(
c
->
cleanmarker_size
&&
jeb
->
used_size
==
c
->
cleanmarker_size
&&
!
jeb
->
first_node
->
next_in_ino
)
{
/* Only node in it beforehand was a CLEANMARKER node (we think).
So mark it obsolete now that there's going to be another node
...
...
@@ -255,15 +270,15 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
* Must be called with the alloc_sem held.
*/
int
jffs2_add_physical_node_ref
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_raw_node_ref
*
new
,
uint32_t
len
,
int
dirty
)
int
jffs2_add_physical_node_ref
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_raw_node_ref
*
new
)
{
struct
jffs2_eraseblock
*
jeb
;
uint32_t
len
=
new
->
totlen
;
len
=
PAD
(
len
);
jeb
=
&
c
->
blocks
[
new
->
flash_offset
/
c
->
sector_size
];
D1
(
printk
(
KERN_DEBUG
"jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x
\n
"
,
new
->
flash_offset
&
~
3
,
len
));
D1
(
printk
(
KERN_DEBUG
"jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x
\n
"
,
ref_offset
(
new
)
,
len
));
#if 1
if
(
jeb
!=
c
->
nextblock
||
(
new
->
flash_offset
&
~
3
)
!=
jeb
->
offset
+
(
c
->
sector_size
-
jeb
->
free_size
))
{
if
(
jeb
!=
c
->
nextblock
||
(
ref_offset
(
new
)
)
!=
jeb
->
offset
+
(
c
->
sector_size
-
jeb
->
free_size
))
{
printk
(
KERN_WARNING
"argh. node added in wrong place
\n
"
);
jffs2_free_raw_node_ref
(
new
);
return
-
EINVAL
;
...
...
@@ -279,8 +294,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
jeb
->
free_size
-=
len
;
c
->
free_size
-=
len
;
if
(
dirty
)
{
new
->
flash_offset
|=
1
;
if
(
ref_obsolete
(
new
))
{
jeb
->
dirty_size
+=
len
;
c
->
dirty_size
+=
len
;
}
else
{
...
...
@@ -303,7 +317,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
c
->
nextblock
=
NULL
;
}
ACCT_SANITY_CHECK
(
c
,
jeb
);
ACCT_PARANOIA_CHECK
(
jeb
);
D1
(
ACCT_PARANOIA_CHECK
(
jeb
)
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
...
...
@@ -330,8 +344,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
printk
(
KERN_NOTICE
"EEEEEK. jffs2_mark_node_obsolete called with NULL node
\n
"
);
return
;
}
if
(
ref
->
flash_offset
&
1
)
{
D1
(
printk
(
KERN_DEBUG
"jffs2_mark_node_obsolete called with already obsolete node at 0x%08x
\n
"
,
ref
->
flash_offset
&~
3
));
if
(
ref
_obsolete
(
ref
)
)
{
D1
(
printk
(
KERN_DEBUG
"jffs2_mark_node_obsolete called with already obsolete node at 0x%08x
\n
"
,
ref
_offset
(
ref
)
));
return
;
}
blocknr
=
ref
->
flash_offset
/
c
->
sector_size
;
...
...
@@ -340,22 +354,45 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
BUG
();
}
jeb
=
&
c
->
blocks
[
blocknr
];
if
(
jeb
->
used_size
<
ref
->
totlen
)
{
spin_lock_bh
(
&
c
->
erase_completion_lock
);
if
(
ref_flags
(
ref
)
==
REF_UNCHECKED
)
{
D1
(
if
(
unlikely
(
jeb
->
unchecked_size
<
ref
->
totlen
))
{
printk
(
KERN_NOTICE
"raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x
\n
"
,
ref
->
totlen
,
blocknr
,
ref
->
flash_offset
,
jeb
->
used_size
);
BUG
();
})
D1
(
printk
(
KERN_DEBUG
"Obsoleting previously unchecked node at 0x%08x of len %x: "
,
ref_offset
(
ref
),
ref
->
totlen
));
jeb
->
unchecked_size
-=
ref
->
totlen
;
c
->
unchecked_size
-=
ref
->
totlen
;
}
else
{
D1
(
if
(
unlikely
(
jeb
->
used_size
<
ref
->
totlen
))
{
printk
(
KERN_NOTICE
"raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x
\n
"
,
ref
->
totlen
,
blocknr
,
ref
->
flash_offset
,
jeb
->
used_size
);
BUG
();
}
spin_lock_bh
(
&
c
->
erase_completion_lock
);
})
D1
(
printk
(
KERN_DEBUG
"Obsoleting node at 0x%08x of len %x: "
,
ref_offset
(
ref
),
ref
->
totlen
));
jeb
->
used_size
-=
ref
->
totlen
;
jeb
->
dirty_size
+=
ref
->
totlen
;
c
->
used_size
-=
ref
->
totlen
;
c
->
dirty_size
+=
ref
->
totlen
;
ref
->
flash_offset
|=
1
;
}
if
((
jeb
->
dirty_size
||
ISDIRTY
(
jeb
->
wasted_size
+
ref
->
totlen
))
&&
jeb
!=
c
->
nextblock
)
{
D1
(
printk
(
"Dirtying
\n
"
));
jeb
->
dirty_size
+=
ref
->
totlen
+
jeb
->
wasted_size
;
c
->
dirty_size
+=
ref
->
totlen
+
jeb
->
wasted_size
;
c
->
wasted_size
-=
jeb
->
wasted_size
;
jeb
->
wasted_size
=
0
;
}
else
{
D1
(
printk
(
"Wasting
\n
"
));
jeb
->
wasted_size
+=
ref
->
totlen
;
c
->
wasted_size
+=
ref
->
totlen
;
}
ref
->
flash_offset
=
ref_offset
(
ref
)
|
REF_OBSOLETE
;
ACCT_SANITY_CHECK
(
c
,
jeb
);
ACCT_PARANOIA_CHECK
(
jeb
);
D1
(
ACCT_PARANOIA_CHECK
(
jeb
)
);
if
(
c
->
flags
&
JFFS2_SB_FLAG_MOUNTING
)
{
/* Mount in progress. Don't muck about with the block
...
...
@@ -369,7 +406,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
if
(
jeb
==
c
->
nextblock
)
{
D2
(
printk
(
KERN_DEBUG
"Not moving nextblock 0x%08x to dirty/erase_pending list
\n
"
,
jeb
->
offset
));
}
else
if
(
!
jeb
->
used_size
)
{
}
else
if
(
!
jeb
->
used_size
&&
!
jeb
->
unchecked_size
)
{
if
(
jeb
==
c
->
gcblock
)
{
D1
(
printk
(
KERN_DEBUG
"gcblock at 0x%08x completely dirtied. Clearing gcblock...
\n
"
,
jeb
->
offset
));
c
->
gcblock
=
NULL
;
...
...
@@ -417,7 +454,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
D1
(
printk
(
KERN_DEBUG
"Done OK
\n
"
));
}
else
if
(
jeb
==
c
->
gcblock
)
{
D2
(
printk
(
KERN_DEBUG
"Not moving gcblock 0x%08x to dirty_list
\n
"
,
jeb
->
offset
));
}
else
if
(
jeb
->
dirty_size
==
ref
->
totlen
)
{
}
else
if
(
ISDIRTY
(
jeb
->
dirty_size
)
&&
!
ISDIRTY
(
jeb
->
dirty_size
-
ref
->
totlen
)
)
{
D1
(
printk
(
KERN_DEBUG
"Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...
\n
"
,
jeb
->
offset
));
list_del
(
&
jeb
->
list
);
D1
(
printk
(
KERN_DEBUG
"...and adding to dirty_list
\n
"
));
...
...
@@ -428,6 +465,9 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
list_del
(
&
jeb
->
list
);
D1
(
printk
(
KERN_DEBUG
"...and adding to very_dirty_list
\n
"
));
list_add_tail
(
&
jeb
->
list
,
&
c
->
very_dirty_list
);
}
else
{
D1
(
printk
(
KERN_DEBUG
"Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)
\n
"
,
jeb
->
offset
,
jeb
->
free_size
,
jeb
->
dirty_size
,
jeb
->
used_size
));
}
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
...
...
@@ -437,32 +477,33 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
if
(
jffs2_is_readonly
(
c
))
return
;
D1
(
printk
(
KERN_DEBUG
"obliterating obsoleted node at 0x%08x
\n
"
,
ref
->
flash_offset
&~
3
));
ret
=
jffs2_flash_read
(
c
,
ref
->
flash_offset
&~
3
,
sizeof
(
n
),
&
retlen
,
(
char
*
)
&
n
);
D1
(
printk
(
KERN_DEBUG
"obliterating obsoleted node at 0x%08x
\n
"
,
ref
_offset
(
ref
)
));
ret
=
jffs2_flash_read
(
c
,
ref
_offset
(
ref
)
,
sizeof
(
n
),
&
retlen
,
(
char
*
)
&
n
);
if
(
ret
)
{
printk
(
KERN_WARNING
"Read error reading from obsoleted node at 0x%08x: %d
\n
"
,
ref
->
flash_offset
&~
3
,
ret
);
printk
(
KERN_WARNING
"Read error reading from obsoleted node at 0x%08x: %d
\n
"
,
ref
_offset
(
ref
)
,
ret
);
return
;
}
if
(
retlen
!=
sizeof
(
n
))
{
printk
(
KERN_WARNING
"Short read from obsoleted node at 0x%08x: %d
\n
"
,
ref
->
flash_offset
&~
3
,
retlen
);
printk
(
KERN_WARNING
"Short read from obsoleted node at 0x%08x: %d
\n
"
,
ref
_offset
(
ref
)
,
retlen
);
return
;
}
if
(
PAD
(
n
.
totlen
)
!=
PAD
(
ref
->
totlen
))
{
printk
(
KERN_WARNING
"Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)
\n
"
,
n
.
totlen
,
ref
->
totlen
);
if
(
PAD
(
je32_to_cpu
(
n
.
totlen
)
)
!=
PAD
(
ref
->
totlen
))
{
printk
(
KERN_WARNING
"Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)
\n
"
,
je32_to_cpu
(
n
.
totlen
)
,
ref
->
totlen
);
return
;
}
if
(
!
(
n
.
nodetype
&
JFFS2_NODE_ACCURATE
))
{
D1
(
printk
(
KERN_DEBUG
"Node at 0x%08x was already marked obsolete (nodetype 0x%04x
\n
"
,
ref
->
flash_offset
&~
3
,
n
.
nodetype
));
if
(
!
(
je16_to_cpu
(
n
.
nodetype
)
&
JFFS2_NODE_ACCURATE
))
{
D1
(
printk
(
KERN_DEBUG
"Node at 0x%08x was already marked obsolete (nodetype 0x%04x
\n
"
,
ref
_offset
(
ref
),
je16_to_cpu
(
n
.
nodetype
)
));
return
;
}
n
.
nodetype
&=
~
JFFS2_NODE_ACCURATE
;
ret
=
jffs2_flash_write
(
c
,
ref
->
flash_offset
&~
3
,
sizeof
(
n
),
&
retlen
,
(
char
*
)
&
n
);
/* XXX FIXME: This is ugly now */
n
.
nodetype
=
cpu_to_je16
(
je16_to_cpu
(
n
.
nodetype
)
&
~
JFFS2_NODE_ACCURATE
);
ret
=
jffs2_flash_write
(
c
,
ref_offset
(
ref
),
sizeof
(
n
),
&
retlen
,
(
char
*
)
&
n
);
if
(
ret
)
{
printk
(
KERN_WARNING
"Write error in obliterating obsoleted node at 0x%08x: %d
\n
"
,
ref
->
flash_offset
&~
3
,
ret
);
printk
(
KERN_WARNING
"Write error in obliterating obsoleted node at 0x%08x: %d
\n
"
,
ref
_offset
(
ref
)
,
ret
);
return
;
}
if
(
retlen
!=
sizeof
(
n
))
{
printk
(
KERN_WARNING
"Short write in obliterating obsoleted node at 0x%08x: %d
\n
"
,
ref
->
flash_offset
&~
3
,
retlen
);
printk
(
KERN_WARNING
"Short write in obliterating obsoleted node at 0x%08x: %d
\n
"
,
ref
_offset
(
ref
)
,
retlen
);
return
;
}
}
...
...
@@ -470,10 +511,14 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
#if CONFIG_JFFS2_FS_DEBUG > 0
void
jffs2_dump_block_lists
(
struct
jffs2_sb_info
*
c
)
{
printk
(
KERN_DEBUG
"jffs2_dump_block_lists:
\n
"
);
printk
(
KERN_DEBUG
"flash_size: %08x
\n
"
,
c
->
flash_size
);
printk
(
KERN_DEBUG
"used_size: %08x
\n
"
,
c
->
used_size
);
printk
(
KERN_DEBUG
"dirty_size: %08x
\n
"
,
c
->
dirty_size
);
printk
(
KERN_DEBUG
"wasted_size: %08x
\n
"
,
c
->
wasted_size
);
printk
(
KERN_DEBUG
"unchecked_size: %08x
\n
"
,
c
->
unchecked_size
);
printk
(
KERN_DEBUG
"free_size: %08x
\n
"
,
c
->
free_size
);
printk
(
KERN_DEBUG
"erasing_size: %08x
\n
"
,
c
->
erasing_size
);
printk
(
KERN_DEBUG
"bad_size: %08x
\n
"
,
c
->
bad_size
);
...
...
@@ -481,12 +526,14 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
printk
(
KERN_DEBUG
"jffs2_reserved_blocks size: %08x
\n
"
,
c
->
sector_size
*
JFFS2_RESERVED_BLOCKS_WRITE
);
if
(
c
->
nextblock
)
{
printk
(
KERN_DEBUG
"nextblock: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
c
->
nextblock
->
offset
,
c
->
nextblock
->
used_size
,
c
->
nextblock
->
dirty_size
,
c
->
nextblock
->
free_size
);
printk
(
KERN_DEBUG
"nextblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
c
->
nextblock
->
offset
,
c
->
nextblock
->
used_size
,
c
->
nextblock
->
dirty_size
,
c
->
nextblock
->
wasted_size
,
c
->
nextblock
->
unchecked_size
,
c
->
nextblock
->
free_size
);
}
else
{
printk
(
KERN_DEBUG
"nextblock: NULL
\n
"
);
}
if
(
c
->
gcblock
)
{
printk
(
KERN_DEBUG
"gcblock: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
c
->
gcblock
->
offset
,
c
->
gcblock
->
used_size
,
c
->
gcblock
->
dirty_size
,
c
->
gcblock
->
free_size
);
printk
(
KERN_DEBUG
"gcblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
c
->
gcblock
->
offset
,
c
->
gcblock
->
used_size
,
c
->
gcblock
->
dirty_size
,
c
->
gcblock
->
wasted_size
,
c
->
gcblock
->
unchecked_size
,
c
->
gcblock
->
free_size
);
}
else
{
printk
(
KERN_DEBUG
"gcblock: NULL
\n
"
);
}
...
...
@@ -494,31 +541,50 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
printk
(
KERN_DEBUG
"clean_list: empty
\n
"
);
}
else
{
struct
list_head
*
this
;
int
numblocks
=
0
;
uint32_t
dirty
=
0
;
list_for_each
(
this
,
&
c
->
clean_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
list
);
printk
(
KERN_DEBUG
"clean_list: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
free_size
);
numblocks
++
;
dirty
+=
jeb
->
wasted_size
;
printk
(
KERN_DEBUG
"clean_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
wasted_size
,
jeb
->
unchecked_size
,
jeb
->
free_size
);
}
printk
(
KERN_DEBUG
"Contains %d blocks with total wasted size %u, average wasted size: %u
\n
"
,
numblocks
,
dirty
,
dirty
/
numblocks
);
}
if
(
list_empty
(
&
c
->
very_dirty_list
))
{
printk
(
KERN_DEBUG
"very_dirty_list: empty
\n
"
);
}
else
{
struct
list_head
*
this
;
int
numblocks
=
0
;
uint32_t
dirty
=
0
;
list_for_each
(
this
,
&
c
->
very_dirty_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
list
);
printk
(
KERN_DEBUG
"very_dirty_list: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
free_size
);
numblocks
++
;
dirty
+=
jeb
->
dirty_size
;
printk
(
KERN_DEBUG
"very_dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
wasted_size
,
jeb
->
unchecked_size
,
jeb
->
free_size
);
}
printk
(
KERN_DEBUG
"Contains %d blocks with total dirty size %u, average dirty size: %u
\n
"
,
numblocks
,
dirty
,
dirty
/
numblocks
);
}
if
(
list_empty
(
&
c
->
dirty_list
))
{
printk
(
KERN_DEBUG
"dirty_list: empty
\n
"
);
}
else
{
struct
list_head
*
this
;
int
numblocks
=
0
;
uint32_t
dirty
=
0
;
list_for_each
(
this
,
&
c
->
dirty_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
list
);
printk
(
KERN_DEBUG
"dirty_list: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
free_size
);
numblocks
++
;
dirty
+=
jeb
->
dirty_size
;
printk
(
KERN_DEBUG
"dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
wasted_size
,
jeb
->
unchecked_size
,
jeb
->
free_size
);
}
printk
(
KERN_DEBUG
"Contains %d blocks with total dirty size %u, average dirty size: %u
\n
"
,
numblocks
,
dirty
,
dirty
/
numblocks
);
}
if
(
list_empty
(
&
c
->
erasable_list
))
{
printk
(
KERN_DEBUG
"erasable_list: empty
\n
"
);
...
...
@@ -527,7 +593,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
erasable_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
list
);
printk
(
KERN_DEBUG
"erasable_list: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
free_size
);
printk
(
KERN_DEBUG
"erasable_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
wasted_size
,
jeb
->
unchecked_size
,
jeb
->
free_size
);
}
}
if
(
list_empty
(
&
c
->
erasing_list
))
{
...
...
@@ -537,7 +604,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
erasing_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
list
);
printk
(
KERN_DEBUG
"erasing_list: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
free_size
);
printk
(
KERN_DEBUG
"erasing_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
wasted_size
,
jeb
->
unchecked_size
,
jeb
->
free_size
);
}
}
if
(
list_empty
(
&
c
->
erase_pending_list
))
{
...
...
@@ -547,7 +615,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
erase_pending_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
list
);
printk
(
KERN_DEBUG
"erase_pending_list: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
free_size
);
printk
(
KERN_DEBUG
"erase_pending_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
wasted_size
,
jeb
->
unchecked_size
,
jeb
->
free_size
);
}
}
if
(
list_empty
(
&
c
->
erasable_pending_wbuf_list
))
{
...
...
@@ -557,7 +626,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
erasable_pending_wbuf_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
list
);
printk
(
KERN_DEBUG
"erase_pending_wbuf_list: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
free_size
);
printk
(
KERN_DEBUG
"erase_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
wasted_size
,
jeb
->
unchecked_size
,
jeb
->
free_size
);
}
}
if
(
list_empty
(
&
c
->
free_list
))
{
...
...
@@ -567,7 +637,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
free_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
list
);
printk
(
KERN_DEBUG
"free_list: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
free_size
);
printk
(
KERN_DEBUG
"free_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
wasted_size
,
jeb
->
unchecked_size
,
jeb
->
free_size
);
}
}
if
(
list_empty
(
&
c
->
bad_list
))
{
...
...
@@ -577,7 +648,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
bad_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
list
);
printk
(
KERN_DEBUG
"bad_list: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
free_size
);
printk
(
KERN_DEBUG
"bad_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
wasted_size
,
jeb
->
unchecked_size
,
jeb
->
free_size
);
}
}
if
(
list_empty
(
&
c
->
bad_used_list
))
{
...
...
@@ -587,7 +659,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
bad_used_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
list
);
printk
(
KERN_DEBUG
"bad_used_list: %08x (used %08x, dirty %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
free_size
);
printk
(
KERN_DEBUG
"bad_used_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)
\n
"
,
jeb
->
offset
,
jeb
->
used_size
,
jeb
->
dirty_size
,
jeb
->
wasted_size
,
jeb
->
unchecked_size
,
jeb
->
free_size
);
}
}
}
...
...
fs/jffs2/os-linux.h
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: os-linux.h,v 1.
19 2002/05/20 14:56:38
dwmw2 Exp $
* $Id: os-linux.h,v 1.
21 2002/11/12 09:44:30
dwmw2 Exp $
*
*/
...
...
@@ -49,11 +49,19 @@
#define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
#endif
/* Hmmm. P'raps generic code should only ever see versions of signal
functions which do the locking automatically? */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40)
#define current_sig_lock current->sigmask_lock
#else
#define current_sig_lock current->sig->siglock
#endif
static
inline
void
jffs2_init_inode_info
(
struct
jffs2_inode_info
*
f
)
{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
f
->
highest_version
=
0
;
f
->
frag
list
=
NULL
;
f
->
frag
tree
=
RB_ROOT
;
f
->
metadata
=
NULL
;
f
->
dents
=
NULL
;
f
->
flags
=
0
;
...
...
fs/jffs2/read.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: read.c,v 1.2
3 2002/05/20 14:56:38
dwmw2 Exp $
* $Id: read.c,v 1.2
9 2002/11/12 09:51:22
dwmw2 Exp $
*
*/
...
...
@@ -31,35 +31,41 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
if
(
!
ri
)
return
-
ENOMEM
;
ret
=
jffs2_flash_read
(
c
,
fd
->
raw
->
flash_offset
&
~
3
,
sizeof
(
*
ri
),
&
readlen
,
(
char
*
)
ri
);
ret
=
jffs2_flash_read
(
c
,
ref_offset
(
fd
->
raw
)
,
sizeof
(
*
ri
),
&
readlen
,
(
char
*
)
ri
);
if
(
ret
)
{
jffs2_free_raw_inode
(
ri
);
printk
(
KERN_WARNING
"Error reading node from 0x%08x: %d
\n
"
,
fd
->
raw
->
flash_offset
&
~
3
,
ret
);
printk
(
KERN_WARNING
"Error reading node from 0x%08x: %d
\n
"
,
ref_offset
(
fd
->
raw
)
,
ret
);
return
ret
;
}
if
(
readlen
!=
sizeof
(
*
ri
))
{
jffs2_free_raw_inode
(
ri
);
printk
(
KERN_WARNING
"Short read from 0x%08x: wanted 0x%x bytes, got 0x%x
\n
"
,
fd
->
raw
->
flash_offset
&
~
3
,
sizeof
(
*
ri
),
readlen
);
ref_offset
(
fd
->
raw
)
,
sizeof
(
*
ri
),
readlen
);
return
-
EIO
;
}
crc
=
crc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
D1
(
printk
(
KERN_DEBUG
"Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p
\n
"
,
fd
->
raw
->
flash_offset
&
~
3
,
ri
->
node_crc
,
crc
,
ri
->
dsize
,
ri
->
csize
,
ri
->
offset
,
buf
));
if
(
crc
!=
ri
->
node_crc
)
{
printk
(
KERN_WARNING
"Node CRC %08x != calculated CRC %08x for node at %08x
\n
"
,
ri
->
node_crc
,
crc
,
fd
->
raw
->
flash_offset
&
~
3
);
D1
(
printk
(
KERN_DEBUG
"Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p
\n
"
,
ref_offset
(
fd
->
raw
),
je32_to_cpu
(
ri
->
node_crc
),
crc
,
je32_to_cpu
(
ri
->
dsize
),
je32_to_cpu
(
ri
->
csize
),
je32_to_cpu
(
ri
->
offset
),
buf
));
if
(
crc
!=
je32_to_cpu
(
ri
->
node_crc
))
{
printk
(
KERN_WARNING
"Node CRC %08x != calculated CRC %08x for node at %08x
\n
"
,
je32_to_cpu
(
ri
->
node_crc
),
crc
,
ref_offset
(
fd
->
raw
));
ret
=
-
EIO
;
goto
out_ri
;
}
/* There was a bug where we wrote hole nodes out with csize/dsize
swapped. Deal with it */
if
(
ri
->
compr
==
JFFS2_COMPR_ZERO
&&
!
ri
->
dsize
&&
ri
->
csize
)
{
if
(
ri
->
compr
==
JFFS2_COMPR_ZERO
&&
!
je32_to_cpu
(
ri
->
dsize
)
&&
je32_to_cpu
(
ri
->
csize
))
{
ri
->
dsize
=
ri
->
csize
;
ri
->
csize
=
0
;
ri
->
csize
=
cpu_to_je32
(
0
)
;
}
D1
(
if
(
ofs
+
len
>
ri
->
dsize
)
{
printk
(
KERN_WARNING
"jffs2_read_dnode() asked for %d bytes at %d from %d-byte node
\n
"
,
len
,
ofs
,
ri
->
dsize
);
D1
(
if
(
ofs
+
len
>
je32_to_cpu
(
ri
->
dsize
))
{
printk
(
KERN_WARNING
"jffs2_read_dnode() asked for %d bytes at %d from %d-byte node
\n
"
,
len
,
ofs
,
je32_to_cpu
(
ri
->
dsize
));
ret
=
-
EINVAL
;
goto
out_ri
;
});
...
...
@@ -76,18 +82,18 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy
Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy
*/
if
(
ri
->
compr
==
JFFS2_COMPR_NONE
&&
len
==
ri
->
dsize
)
{
if
(
ri
->
compr
==
JFFS2_COMPR_NONE
&&
len
==
je32_to_cpu
(
ri
->
dsize
)
)
{
readbuf
=
buf
;
}
else
{
readbuf
=
kmalloc
(
ri
->
csize
,
GFP_KERNEL
);
readbuf
=
kmalloc
(
je32_to_cpu
(
ri
->
csize
)
,
GFP_KERNEL
);
if
(
!
readbuf
)
{
ret
=
-
ENOMEM
;
goto
out_ri
;
}
}
if
(
ri
->
compr
!=
JFFS2_COMPR_NONE
)
{
if
(
len
<
ri
->
dsize
)
{
decomprbuf
=
kmalloc
(
ri
->
dsize
,
GFP_KERNEL
);
if
(
len
<
je32_to_cpu
(
ri
->
dsize
)
)
{
decomprbuf
=
kmalloc
(
je32_to_cpu
(
ri
->
dsize
)
,
GFP_KERNEL
);
if
(
!
decomprbuf
)
{
ret
=
-
ENOMEM
;
goto
out_readbuf
;
...
...
@@ -99,31 +105,35 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
decomprbuf
=
readbuf
;
}
D2
(
printk
(
KERN_DEBUG
"Read %d bytes to %p
\n
"
,
ri
->
csize
,
readbuf
));
ret
=
jffs2_flash_read
(
c
,
(
fd
->
raw
->
flash_offset
&~
3
)
+
sizeof
(
*
ri
),
ri
->
csize
,
&
readlen
,
readbuf
);
D2
(
printk
(
KERN_DEBUG
"Read %d bytes to %p
\n
"
,
je32_to_cpu
(
ri
->
csize
),
readbuf
));
ret
=
jffs2_flash_read
(
c
,
(
ref_offset
(
fd
->
raw
))
+
sizeof
(
*
ri
),
je32_to_cpu
(
ri
->
csize
),
&
readlen
,
readbuf
);
if
(
!
ret
&&
readlen
!=
ri
->
csize
)
if
(
!
ret
&&
readlen
!=
je32_to_cpu
(
ri
->
csize
)
)
ret
=
-
EIO
;
if
(
ret
)
goto
out_decomprbuf
;
crc
=
crc32
(
0
,
readbuf
,
ri
->
csize
);
if
(
crc
!=
ri
->
data_crc
)
{
printk
(
KERN_WARNING
"Data CRC %08x != calculated CRC %08x for node at %08x
\n
"
,
ri
->
data_crc
,
crc
,
fd
->
raw
->
flash_offset
&
~
3
);
crc
=
crc32
(
0
,
readbuf
,
je32_to_cpu
(
ri
->
csize
));
if
(
crc
!=
je32_to_cpu
(
ri
->
data_crc
))
{
printk
(
KERN_WARNING
"Data CRC %08x != calculated CRC %08x for node at %08x
\n
"
,
je32_to_cpu
(
ri
->
data_crc
),
crc
,
ref_offset
(
fd
->
raw
));
ret
=
-
EIO
;
goto
out_decomprbuf
;
}
D2
(
printk
(
KERN_DEBUG
"Data CRC matches calculated CRC %08x
\n
"
,
crc
));
if
(
ri
->
compr
!=
JFFS2_COMPR_NONE
)
{
D2
(
printk
(
KERN_DEBUG
"Decompress %d bytes from %p to %d bytes at %p
\n
"
,
ri
->
csize
,
readbuf
,
ri
->
dsize
,
decomprbuf
));
ret
=
jffs2_decompress
(
ri
->
compr
,
readbuf
,
decomprbuf
,
ri
->
csize
,
ri
->
dsize
);
D2
(
printk
(
KERN_DEBUG
"Decompress %d bytes from %p to %d bytes at %p
\n
"
,
je32_to_cpu
(
ri
->
csize
),
readbuf
,
je32_to_cpu
(
ri
->
dsize
),
decomprbuf
));
ret
=
jffs2_decompress
(
ri
->
compr
,
readbuf
,
decomprbuf
,
je32_to_cpu
(
ri
->
csize
),
je32_to_cpu
(
ri
->
dsize
));
if
(
ret
)
{
printk
(
KERN_WARNING
"Error: jffs2_decompress returned %d
\n
"
,
ret
);
goto
out_decomprbuf
;
}
}
if
(
len
<
ri
->
dsize
)
{
if
(
len
<
je32_to_cpu
(
ri
->
dsize
)
)
{
memcpy
(
buf
,
decomprbuf
+
ofs
,
len
);
}
out_decomprbuf:
...
...
@@ -142,16 +152,14 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
unsigned
char
*
buf
,
uint32_t
offset
,
uint32_t
len
)
{
uint32_t
end
=
offset
+
len
;
struct
jffs2_node_frag
*
frag
=
f
->
fraglist
;
struct
jffs2_node_frag
*
frag
;
int
ret
;
D1
(
printk
(
KERN_DEBUG
"jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x
\n
"
,
f
->
inocache
->
ino
,
offset
,
offset
+
len
));
while
(
frag
&&
frag
->
ofs
+
frag
->
size
<=
offset
)
{
D2
(
printk
(
KERN_DEBUG
"skipping frag %d-%d; before the region we care about
\n
"
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
));
frag
=
frag
->
next
;
}
frag
=
jffs2_lookup_node_frag
(
&
f
->
fragtree
,
offset
);
/* XXX FIXME: Where a single physical node actually shows up in two
frags, we read it twice. Don't do that. */
/* Now we're pointing at the first frag which overlaps our page */
...
...
@@ -181,25 +189,29 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
memset
(
buf
,
0
,
holeend
-
offset
);
buf
+=
holeend
-
offset
;
offset
=
holeend
;
frag
=
frag
->
next
;
frag
=
frag
_next
(
frag
)
;
continue
;
}
else
{
uint32_t
readlen
;
readlen
=
min
(
frag
->
size
,
end
-
offset
);
D1
(
printk
(
KERN_DEBUG
"Reading %d-%d from node at 0x%x
\n
"
,
frag
->
ofs
,
frag
->
ofs
+
readlen
,
frag
->
node
->
raw
->
flash_offset
&
~
3
));
ret
=
jffs2_read_dnode
(
c
,
frag
->
node
,
buf
,
frag
->
ofs
-
frag
->
node
->
ofs
,
readlen
);
uint32_t
fragofs
;
/* offset within the frag to start reading */
fragofs
=
offset
-
frag
->
ofs
;
readlen
=
min
(
frag
->
size
-
fragofs
,
end
-
offset
);
D1
(
printk
(
KERN_DEBUG
"Reading %d-%d from node at 0x%x
\n
"
,
frag
->
ofs
+
fragofs
,
frag
->
ofs
+
fragofs
+
readlen
,
ref_offset
(
frag
->
node
->
raw
)));
ret
=
jffs2_read_dnode
(
c
,
frag
->
node
,
buf
,
fragofs
+
frag
->
ofs
-
frag
->
node
->
ofs
,
readlen
);
D2
(
printk
(
KERN_DEBUG
"node read done
\n
"
));
if
(
ret
)
{
D1
(
printk
(
KERN_DEBUG
"jffs2_read_inode_range error %d
\n
"
,
ret
));
memset
(
buf
,
0
,
frag
->
size
);
memset
(
buf
,
0
,
readlen
);
return
ret
;
}
}
buf
+=
frag
->
size
;
offset
+=
frag
->
size
;
frag
=
frag
->
next
;
buf
+=
readlen
;
offset
+=
readlen
;
frag
=
frag_next
(
frag
);
D2
(
printk
(
KERN_DEBUG
"node read was OK. Looping
\n
"
));
}
}
return
0
;
}
...
...
fs/jffs2/readinode.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: readinode.c,v 1.
73 2002/05/20 14:56:38
dwmw2 Exp $
* $Id: readinode.c,v 1.
95 2002/11/12 11:17:29
dwmw2 Exp $
*
*/
...
...
@@ -15,24 +15,43 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/crc32.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
#include "nodelist.h"
D1
(
void
jffs2_print_frag_list
(
struct
jffs2_inode_info
*
f
)
D1
(
static
void
jffs2_print_fragtree
(
struct
rb_root
*
list
,
int
permitbug
)
{
struct
jffs2_node_frag
*
this
=
f
->
fraglist
;
struct
jffs2_node_frag
*
this
=
frag_first
(
list
);
uint32_t
lastofs
=
0
;
int
buggy
=
0
;
while
(
this
)
{
if
(
this
->
node
)
printk
(
KERN_DEBUG
"frag %04x-%04x: 0x%08x on flash (*%p->%p)
\n
"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
,
this
->
node
->
raw
->
flash_offset
&~
3
,
this
,
this
->
next
);
printk
(
KERN_DEBUG
"frag %04x-%04x: 0x%08x(%d) on flash (*%p). left (%p), right (%p), parent (%p)
\n
"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
,
ref_offset
(
this
->
node
->
raw
),
ref_flags
(
this
->
node
->
raw
),
this
,
frag_left
(
this
),
frag_right
(
this
),
frag_parent
(
this
));
else
printk
(
KERN_DEBUG
"frag %04x-%04x: hole (*%p->%p)
\n
"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
,
this
,
this
->
next
);
this
=
this
->
next
;
printk
(
KERN_DEBUG
"frag %04x-%04x: hole (*%p). left (%p} right (%p), parent (%p)
\n
"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
,
this
,
frag_left
(
this
),
frag_right
(
this
),
frag_parent
(
this
));
if
(
this
->
ofs
!=
lastofs
)
buggy
=
1
;
lastofs
=
this
->
ofs
+
this
->
size
;
this
=
frag_next
(
this
);
}
if
(
buggy
&&
!
permitbug
)
{
printk
(
KERN_CRIT
"Frag tree got a hole in it
\n
"
);
BUG
();
}
})
D1
(
void
jffs2_print_frag_list
(
struct
jffs2_inode_info
*
f
)
{
jffs2_print_fragtree
(
&
f
->
fragtree
,
0
);
if
(
f
->
metadata
)
{
printk
(
KERN_DEBUG
"metadata at 0x%08x
\n
"
,
f
->
metadata
->
raw
->
flash_offset
&~
3
);
printk
(
KERN_DEBUG
"metadata at 0x%08x
\n
"
,
ref_offset
(
f
->
metadata
->
raw
)
);
}
})
...
...
@@ -45,7 +64,7 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in
int
ret
;
D1
(
printk
(
KERN_DEBUG
"jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)
\n
"
,
f
->
inocache
->
ino
,
f
,
fn
));
ret
=
jffs2_add_full_dnode_to_fraglist
(
c
,
&
f
->
frag
list
,
fn
);
ret
=
jffs2_add_full_dnode_to_fraglist
(
c
,
&
f
->
frag
tree
,
fn
);
D2
(
jffs2_print_frag_list
(
f
));
return
ret
;
...
...
@@ -58,13 +77,14 @@ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_
if
(
!
this
->
node
->
frags
)
{
/* The node has no valid frags left. It's totally obsoleted */
D2
(
printk
(
KERN_DEBUG
"Marking old node @0x%08x (0x%04x-0x%04x) obsolete
\n
"
,
this
->
node
->
raw
->
flash_offset
&~
3
,
this
->
node
->
ofs
,
this
->
node
->
ofs
+
this
->
node
->
size
));
ref_offset
(
this
->
node
->
raw
)
,
this
->
node
->
ofs
,
this
->
node
->
ofs
+
this
->
node
->
size
));
jffs2_mark_node_obsolete
(
c
,
this
->
node
->
raw
);
jffs2_free_full_dnode
(
this
->
node
);
}
else
{
D2
(
printk
(
KERN_DEBUG
"
Not marking old node @0x%08x (0x%04x-0x%04x) obsolete
. frags is %d
\n
"
,
this
->
node
->
raw
->
flash_offset
&~
3
,
this
->
node
->
ofs
,
this
->
node
->
ofs
+
this
->
node
->
size
,
D2
(
printk
(
KERN_DEBUG
"
Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL
. frags is %d
\n
"
,
ref_offset
(
this
->
node
->
raw
)
,
this
->
node
->
ofs
,
this
->
node
->
ofs
+
this
->
node
->
size
,
this
->
node
->
frags
));
mark_ref_normal
(
this
->
node
->
raw
);
}
}
...
...
@@ -72,26 +92,23 @@ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_
}
/* Doesn't set inode->i_size */
int
jffs2_add_full_dnode_to_fraglist
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_node_frag
*
*
list
,
struct
jffs2_full_dnode
*
fn
)
int
jffs2_add_full_dnode_to_fraglist
(
struct
jffs2_sb_info
*
c
,
struct
rb_root
*
list
,
struct
jffs2_full_dnode
*
fn
)
{
struct
jffs2_node_frag
*
this
,
**
prev
,
*
old
;
struct
jffs2_node_frag
*
newfrag
,
*
newfrag2
;
uint32_t
lastend
=
0
;
struct
jffs2_node_frag
*
this
;
struct
jffs2_node_frag
*
newfrag
;
uint32_t
lastend
;
newfrag
=
jffs2_alloc_node_frag
();
if
(
!
newfrag
)
{
return
-
ENOMEM
;
}
D2
(
if
(
fn
->
raw
)
printk
(
KERN_
DEBUG
"adding node %04x-%04x @0x%08x on flash, newfrag *%p
\n
"
,
fn
->
ofs
,
fn
->
ofs
+
fn
->
size
,
fn
->
raw
->
flash_offset
&~
3
,
newfrag
);
else
printk
(
KERN_DEBUG
"adding hole node %04x-%04x on flash, newfrag *%p
\n
"
,
fn
->
ofs
,
fn
->
ofs
+
fn
->
size
,
newfrag
));
if
(
!
fn
->
raw
)
{
printk
(
KERN_
WARNING
"dwmw2 is stupid. j_a_f_d_t_f should never happen with ->raw == NULL
\n
"
);
BUG
();
}
prev
=
list
;
this
=
*
list
;
D2
(
printk
(
KERN_DEBUG
"adding node %04x-%04x @0x%08x on flash, newfrag *%p
\n
"
,
fn
->
ofs
,
fn
->
ofs
+
fn
->
size
,
ref_offset
(
fn
->
raw
),
newfrag
));
if
(
!
fn
->
size
)
{
jffs2_free_node_frag
(
newfrag
);
...
...
@@ -102,21 +119,33 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_
newfrag
->
size
=
fn
->
size
;
newfrag
->
node
=
fn
;
newfrag
->
node
->
frags
=
1
;
newfrag
->
next
=
(
void
*
)
0xdeadbeef
;
/* Skip all the nodes which are completed before this one starts */
while
(
this
&&
fn
->
ofs
>=
this
->
ofs
+
this
->
size
)
{
lastend
=
this
->
ofs
+
this
->
size
;
this
=
jffs2_lookup_node_frag
(
list
,
fn
->
ofs
);
D2
(
printk
(
KERN_DEBUG
"j_a_f_d_t_f: skipping frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)
\n
"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
,
this
->
node
?
(
this
->
node
->
raw
->
flash_offset
&~
3
)
:
0xffffffff
,
this
,
this
->
next
));
prev
=
&
this
->
next
;
this
=
this
->
next
;
if
(
this
)
{
D2
(
printk
(
KERN_DEBUG
"j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)
\n
"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
,
this
->
node
?
(
ref_offset
(
this
->
node
->
raw
))
:
0xffffffff
,
this
));
lastend
=
this
->
ofs
+
this
->
size
;
}
else
{
D2
(
printk
(
KERN_DEBUG
"j_a_f_d_t_f: Lookup gave no frag
\n
"
));
lastend
=
0
;
}
/* See if we ran off the end of the list */
if
(
!
thi
s
)
{
if
(
lastend
<=
newfrag
->
of
s
)
{
/* We did */
/* Check if 'this' node was on the same page as the new node.
If so, both 'this' and the new node get marked REF_NORMAL so
the GC can take a look.
*/
if
((
lastend
-
1
)
>>
PAGE_CACHE_SHIFT
==
newfrag
->
ofs
>>
PAGE_CACHE_SHIFT
)
{
if
(
this
->
node
)
mark_ref_normal
(
this
->
node
->
raw
);
mark_ref_normal
(
fn
->
raw
);
}
if
(
lastend
<
fn
->
ofs
)
{
/* ... and we need to put a hole in before the new node */
struct
jffs2_node_frag
*
holefrag
=
jffs2_alloc_node_frag
();
...
...
@@ -124,96 +153,162 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_
return
-
ENOMEM
;
holefrag
->
ofs
=
lastend
;
holefrag
->
size
=
fn
->
ofs
-
lastend
;
holefrag
->
next
=
NULL
;
holefrag
->
node
=
NULL
;
*
prev
=
holefrag
;
prev
=
&
holefrag
->
next
;
if
(
this
)
{
/* By definition, the 'this' node has no right-hand child,
because there are no frags with offset greater than it.
So that's where we want to put the hole */
D2
(
printk
(
KERN_DEBUG
"Adding hole frag (%p) on right of node at (%p)
\n
"
,
holefrag
,
this
));
rb_link_node
(
&
holefrag
->
rb
,
&
this
->
rb
,
&
this
->
rb
.
rb_right
);
}
else
{
D2
(
printk
(
KERN_DEBUG
"Adding hole frag (%p) at root of tree
\n
"
,
holefrag
));
rb_link_node
(
&
holefrag
->
rb
,
NULL
,
&
list
->
rb_node
);
}
rb_insert_color
(
&
holefrag
->
rb
,
list
);
this
=
holefrag
;
}
if
(
this
)
{
/* By definition, the 'this' node has no right-hand child,
because there are no frags with offset greater than it.
So that's where we want to put the hole */
D2
(
printk
(
KERN_DEBUG
"Adding new frag (%p) on right of node at (%p)
\n
"
,
newfrag
,
this
));
rb_link_node
(
&
newfrag
->
rb
,
&
this
->
rb
,
&
this
->
rb
.
rb_right
);
}
else
{
D2
(
printk
(
KERN_DEBUG
"Adding new frag (%p) at root of tree
\n
"
,
newfrag
));
rb_link_node
(
&
newfrag
->
rb
,
NULL
,
&
list
->
rb_node
);
}
newfrag
->
next
=
NULL
;
*
prev
=
newfrag
;
rb_insert_color
(
&
newfrag
->
rb
,
list
);
return
0
;
}
D2
(
printk
(
KERN_DEBUG
"j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p
->%p
)
\n
"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
,
this
->
node
?
(
this
->
node
->
raw
->
flash_offset
&~
3
)
:
0xffffffff
,
this
,
this
->
next
));
D2
(
printk
(
KERN_DEBUG
"j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)
\n
"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
,
this
->
node
?
(
ref_offset
(
this
->
node
->
raw
))
:
0xffffffff
,
this
));
/* OK. 'this' is pointing at the first frag that
fn
->ofs at least partially obsoletes,
* - i.e.
fn->ofs < this->ofs+this->size && fn
->ofs >= this->ofs
/* OK. 'this' is pointing at the first frag that
newfrag
->ofs at least partially obsoletes,
* - i.e.
newfrag->ofs < this->ofs+this->size && newfrag
->ofs >= this->ofs
*/
if
(
fn
->
ofs
>
this
->
ofs
)
{
if
(
newfrag
->
ofs
>
this
->
ofs
)
{
/* This node isn't completely obsoleted. The start of it remains valid */
if
(
this
->
ofs
+
this
->
size
>
fn
->
ofs
+
fn
->
size
)
{
/* Mark the new node and the partially covered node REF_NORMAL -- let
the GC take a look at them */
mark_ref_normal
(
fn
->
raw
);
if
(
this
->
node
)
mark_ref_normal
(
this
->
node
->
raw
);
if
(
this
->
ofs
+
this
->
size
>
newfrag
->
ofs
+
newfrag
->
size
)
{
/* The new node splits 'this' frag into two */
newfrag2
=
jffs2_alloc_node_frag
();
struct
jffs2_node_frag
*
newfrag2
=
jffs2_alloc_node_frag
();
if
(
!
newfrag2
)
{
jffs2_free_node_frag
(
newfrag
);
return
-
ENOMEM
;
}
D
1
(
printk
(
KERN_DEBUG
"split old frag 0x%04x-0x%04x -->"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
);
D
2
(
printk
(
KERN_DEBUG
"split old frag 0x%04x-0x%04x -->"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
);
if
(
this
->
node
)
printk
(
"phys 0x%08x
\n
"
,
this
->
node
->
raw
->
flash_offset
&~
3
);
printk
(
"phys 0x%08x
\n
"
,
ref_offset
(
this
->
node
->
raw
)
);
else
printk
(
"hole
\n
"
);
)
newfrag2
->
ofs
=
fn
->
ofs
+
fn
->
size
;
/* New second frag pointing to this's node */
newfrag2
->
ofs
=
newfrag
->
ofs
+
newfrag
->
size
;
newfrag2
->
size
=
(
this
->
ofs
+
this
->
size
)
-
newfrag2
->
ofs
;
newfrag2
->
next
=
this
->
next
;
newfrag2
->
node
=
this
->
node
;
if
(
this
->
node
)
this
->
node
->
frags
++
;
newfrag
->
next
=
newfrag2
;
this
->
next
=
newfrag
;
/* Adjust size of original 'this' */
this
->
size
=
newfrag
->
ofs
-
this
->
ofs
;
/* Now, we know there's no node with offset
greater than this->ofs but smaller than
newfrag2->ofs or newfrag->ofs, for obvious
reasons. So we can do a tree insert from
'this' to insert newfrag, and a tree insert
from newfrag to insert newfrag2. */
jffs2_fragtree_insert
(
newfrag
,
this
);
rb_insert_color
(
&
newfrag
->
rb
,
list
);
jffs2_fragtree_insert
(
newfrag2
,
newfrag
);
rb_insert_color
(
&
newfrag2
->
rb
,
list
);
return
0
;
}
/* New node just reduces 'this' frag in size, doesn't split it */
this
->
size
=
fn
->
ofs
-
this
->
ofs
;
newfrag
->
next
=
this
->
next
;
this
->
next
=
newfrag
;
this
=
newfrag
->
next
;
this
->
size
=
newfrag
->
ofs
-
this
->
ofs
;
/* Again, we know it lives down here in the tree */
jffs2_fragtree_insert
(
newfrag
,
this
);
rb_insert_color
(
&
newfrag
->
rb
,
list
);
}
else
{
/* New frag starts at the same point as 'this' used to. Replace
it in the tree without doing a delete and insertion */
D2
(
printk
(
KERN_DEBUG
"Inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d
\n
"
,
newfrag
,
newfrag
->
ofs
,
newfrag
->
ofs
+
newfrag
->
size
,
this
,
this
->
ofs
,
this
->
ofs
+
this
->
size
));
rb_replace_node
(
&
this
->
rb
,
&
newfrag
->
rb
,
list
);
if
(
newfrag
->
ofs
+
newfrag
->
size
>=
this
->
ofs
+
this
->
size
)
{
D2
(
printk
(
KERN_DEBUG
"Obsoleting node frag %p (%x-%x)
\n
"
,
this
,
this
->
ofs
,
this
->
ofs
+
this
->
size
));
jffs2_obsolete_node_frag
(
c
,
this
);
}
else
{
D2
(
printk
(
KERN_DEBUG
"Inserting newfrag (*%p) in before 'this' (*%p)
\n
"
,
newfrag
,
this
));
*
prev
=
newfrag
;
newfrag
->
next
=
this
;
this
->
ofs
+=
newfrag
->
size
;
this
->
size
-=
newfrag
->
size
;
jffs2_fragtree_insert
(
this
,
newfrag
);
rb_insert_color
(
&
this
->
rb
,
list
);
return
0
;
}
/* OK, now we have newfrag added in the correct place in the list, but
newfrag->next points to a fragment which may be overlapping it
}
/* OK, now we have newfrag added in the correct place in the tree, but
frag_next(newfrag) may be a fragment which is overlapped by it
*/
while
(
this
&&
newfrag
->
ofs
+
newfrag
->
size
>=
this
->
ofs
+
this
->
size
)
{
/* 'this' frag is obsoleted. */
old
=
this
;
this
=
old
->
next
;
jffs2_obsolete_node_frag
(
c
,
old
);
while
(
(
this
=
frag_next
(
newfrag
))
&&
newfrag
->
ofs
+
newfrag
->
size
>=
this
->
ofs
+
this
->
size
)
{
/* 'this' frag is obsoleted
completely
. */
D2
(
printk
(
KERN_DEBUG
"Obsoleting node frag %p (%x-%x) and removing from tree
\n
"
,
this
,
this
->
ofs
,
this
->
ofs
+
this
->
size
))
;
rb_erase
(
&
this
->
rb
,
list
)
;
jffs2_obsolete_node_frag
(
c
,
this
);
}
/* Now we're pointing at the first frag which isn't totally obsoleted by
the new frag */
newfrag
->
next
=
this
;
if
(
!
this
||
newfrag
->
ofs
+
newfrag
->
size
==
this
->
ofs
)
{
return
0
;
}
/* Still some overlap */
/* Still some overlap
but we don't need to move it in the tree
*/
this
->
size
=
(
this
->
ofs
+
this
->
size
)
-
(
newfrag
->
ofs
+
newfrag
->
size
);
this
->
ofs
=
newfrag
->
ofs
+
newfrag
->
size
;
/* And mark them REF_NORMAL so the GC takes a look at them */
if
(
this
->
node
)
mark_ref_normal
(
this
->
node
->
raw
);
mark_ref_normal
(
fn
->
raw
);
return
0
;
}
void
jffs2_truncate_fraglist
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_node_frag
*
*
list
,
uint32_t
size
)
void
jffs2_truncate_fraglist
(
struct
jffs2_sb_info
*
c
,
struct
rb_root
*
list
,
uint32_t
size
)
{
struct
jffs2_node_frag
*
frag
=
jffs2_lookup_node_frag
(
list
,
size
);
D1
(
printk
(
KERN_DEBUG
"Truncating fraglist to 0x%08x bytes
\n
"
,
size
));
while
(
*
list
)
{
if
((
*
list
)
->
ofs
>=
size
)
{
struct
jffs2_node_frag
*
this
=
*
list
;
*
list
=
this
->
next
;
D1
(
printk
(
KERN_DEBUG
"Removing frag 0x%08x-0x%08x
\n
"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
));
jffs2_obsolete_node_frag
(
c
,
this
);
continue
;
}
else
if
((
*
list
)
->
ofs
+
(
*
list
)
->
size
>
size
)
{
D1
(
printk
(
KERN_DEBUG
"Truncating frag 0x%08x-0x%08x
\n
"
,
(
*
list
)
->
ofs
,
(
*
list
)
->
ofs
+
(
*
list
)
->
size
));
(
*
list
)
->
size
=
size
-
(
*
list
)
->
ofs
;
/* We know frag->ofs <= size. That's what lookup does for us */
if
(
frag
&&
frag
->
ofs
!=
size
)
{
if
(
frag
->
ofs
+
frag
->
size
>=
size
)
{
D1
(
printk
(
KERN_DEBUG
"Truncating frag 0x%08x-0x%08x
\n
"
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
));
frag
->
size
=
size
-
frag
->
ofs
;
}
list
=
&
(
*
list
)
->
next
;
frag
=
frag_next
(
frag
);
}
while
(
frag
&&
frag
->
ofs
>=
size
)
{
struct
jffs2_node_frag
*
next
=
frag_next
(
frag
);
D1
(
printk
(
KERN_DEBUG
"Removing frag 0x%08x-0x%08x
\n
"
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
));
frag_erase
(
frag
,
list
);
jffs2_obsolete_node_frag
(
c
,
frag
);
frag
=
next
;
}
}
...
...
@@ -271,7 +366,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
fn
=
tn
->
fn
;
if
(
f
->
metadata
&&
tn
->
version
>
mdata_ver
)
{
D1
(
printk
(
KERN_DEBUG
"Obsoleting old metadata at 0x%08x
\n
"
,
f
->
metadata
->
raw
->
flash_offset
&~
3
));
D1
(
printk
(
KERN_DEBUG
"Obsoleting old metadata at 0x%08x
\n
"
,
ref_offset
(
f
->
metadata
->
raw
)
));
jffs2_mark_node_obsolete
(
c
,
f
->
metadata
->
raw
);
jffs2_free_full_dnode
(
f
->
metadata
);
f
->
metadata
=
NULL
;
...
...
@@ -283,7 +378,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
jffs2_add_full_dnode_to_inode
(
c
,
f
,
fn
);
}
else
{
/* Zero-sized node at end of version list. Just a metadata update */
D1
(
printk
(
KERN_DEBUG
"metadata @%08x: ver %d
\n
"
,
fn
->
raw
->
flash_offset
&~
3
,
tn
->
version
));
D1
(
printk
(
KERN_DEBUG
"metadata @%08x: ver %d
\n
"
,
ref_offset
(
fn
->
raw
)
,
tn
->
version
));
f
->
metadata
=
fn
;
mdata_ver
=
tn
->
version
;
}
...
...
@@ -299,16 +394,16 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
}
printk
(
KERN_WARNING
"jffs2_do_read_inode(): But it has children so we fake some modes for it
\n
"
);
}
latest_node
->
mode
=
S_IFDIR
|
S_IRUGO
|
S_IWUSR
|
S_IXUGO
;
latest_node
->
version
=
0
;
latest_node
->
atime
=
latest_node
->
ctime
=
latest_node
->
mtime
=
0
;
latest_node
->
isize
=
0
;
latest_node
->
gid
=
0
;
latest_node
->
uid
=
0
;
latest_node
->
mode
=
cpu_to_je32
(
S_IFDIR
|
S_IRUGO
|
S_IWUSR
|
S_IXUGO
)
;
latest_node
->
version
=
cpu_to_je32
(
0
)
;
latest_node
->
atime
=
latest_node
->
ctime
=
latest_node
->
mtime
=
cpu_to_je32
(
0
)
;
latest_node
->
isize
=
cpu_to_je32
(
0
)
;
latest_node
->
gid
=
cpu_to_je16
(
0
)
;
latest_node
->
uid
=
cpu_to_je16
(
0
)
;
return
0
;
}
ret
=
jffs2_flash_read
(
c
,
fn
->
raw
->
flash_offset
&
~
3
,
sizeof
(
*
latest_node
),
&
retlen
,
(
void
*
)
latest_node
);
ret
=
jffs2_flash_read
(
c
,
ref_offset
(
fn
->
raw
)
,
sizeof
(
*
latest_node
),
&
retlen
,
(
void
*
)
latest_node
);
if
(
ret
||
retlen
!=
sizeof
(
*
latest_node
))
{
printk
(
KERN_NOTICE
"MTD read in jffs2_do_read_inode() failed: Returned %d, %ld of %d bytes read
\n
"
,
ret
,
(
long
)
retlen
,
sizeof
(
*
latest_node
));
...
...
@@ -319,26 +414,26 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
}
crc
=
crc32
(
0
,
latest_node
,
sizeof
(
*
latest_node
)
-
8
);
if
(
crc
!=
latest_node
->
node_crc
)
{
printk
(
KERN_NOTICE
"CRC failed for read_inode of inode %u at physical location 0x%x
\n
"
,
ino
,
fn
->
raw
->
flash_offset
&
~
3
);
if
(
crc
!=
je32_to_cpu
(
latest_node
->
node_crc
)
)
{
printk
(
KERN_NOTICE
"CRC failed for read_inode of inode %u at physical location 0x%x
\n
"
,
ino
,
ref_offset
(
fn
->
raw
)
);
up
(
&
f
->
sem
);
jffs2_do_clear_inode
(
c
,
f
);
return
-
EIO
;
}
switch
(
latest_node
->
mode
&
S_IFMT
)
{
switch
(
je32_to_cpu
(
latest_node
->
mode
)
&
S_IFMT
)
{
case
S_IFDIR
:
if
(
mctime_ver
>
latest_node
->
version
)
{
if
(
mctime_ver
>
je32_to_cpu
(
latest_node
->
version
)
)
{
/* The times in the latest_node are actually older than
mctime in the latest dirent. Cheat. */
latest_node
->
ctime
=
latest_node
->
mtime
=
latest_mctime
;
latest_node
->
ctime
=
latest_node
->
mtime
=
cpu_to_je32
(
latest_mctime
)
;
}
break
;
case
S_IFREG
:
/* If it was a regular file, truncate it to the latest node's isize */
jffs2_truncate_fraglist
(
c
,
&
f
->
frag
list
,
latest_node
->
isize
);
jffs2_truncate_fraglist
(
c
,
&
f
->
frag
tree
,
je32_to_cpu
(
latest_node
->
isize
)
);
break
;
case
S_IFLNK
:
...
...
@@ -346,7 +441,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
Remove this when dwmw2 comes to his senses and stops
symlinks from being an entirely gratuitous special
case. */
if
(
!
latest_node
->
isize
)
if
(
!
je32_to_cpu
(
latest_node
->
isize
)
)
latest_node
->
isize
=
latest_node
->
dsize
;
/* fall through... */
...
...
@@ -355,82 +450,79 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
/* Xertain inode types should have only one data node, and it's
kept as the metadata node */
if
(
f
->
metadata
)
{
printk
(
KERN_WARNING
"Argh. Special inode #%u with mode 0%o had metadata node
\n
"
,
ino
,
latest_node
->
mode
);
printk
(
KERN_WARNING
"Argh. Special inode #%u with mode 0%o had metadata node
\n
"
,
ino
,
je32_to_cpu
(
latest_node
->
mode
)
);
up
(
&
f
->
sem
);
jffs2_do_clear_inode
(
c
,
f
);
return
-
EIO
;
}
if
(
!
f
->
fraglist
)
{
printk
(
KERN_WARNING
"Argh. Special inode #%u with mode 0%o has no fragments
\n
"
,
ino
,
latest_node
->
mode
);
if
(
!
f
rag_first
(
&
f
->
fragtree
)
)
{
printk
(
KERN_WARNING
"Argh. Special inode #%u with mode 0%o has no fragments
\n
"
,
ino
,
je32_to_cpu
(
latest_node
->
mode
)
);
up
(
&
f
->
sem
);
jffs2_do_clear_inode
(
c
,
f
);
return
-
EIO
;
}
/* ASSERT: f->fraglist != NULL */
if
(
f
->
fraglist
->
next
)
{
printk
(
KERN_WARNING
"Argh. Special inode #%u with mode 0%o had more than one node
\n
"
,
ino
,
latest_node
->
mode
);
if
(
f
rag_next
(
frag_first
(
&
f
->
fragtree
))
)
{
printk
(
KERN_WARNING
"Argh. Special inode #%u with mode 0%o had more than one node
\n
"
,
ino
,
je32_to_cpu
(
latest_node
->
mode
)
);
/* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
up
(
&
f
->
sem
);
jffs2_do_clear_inode
(
c
,
f
);
return
-
EIO
;
}
/* OK. We're happy */
f
->
metadata
=
f
->
fraglist
->
node
;
jffs2_free_node_frag
(
f
->
fraglist
);
f
->
frag
list
=
NULL
;
f
->
metadata
=
f
rag_first
(
&
f
->
fragtree
)
->
node
;
jffs2_free_node_frag
(
f
rag_first
(
&
f
->
fragtree
)
);
f
->
frag
tree
=
RB_ROOT
;
break
;
}
f
->
inocache
->
state
=
INO_STATE_PRESENT
;
return
0
;
}
void
jffs2_do_clear_inode
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_inode_info
*
f
)
{
struct
jffs2_node_frag
*
frag
,
*
frags
;
struct
jffs2_full_dirent
*
fd
,
*
fds
;
/* If it's a deleted inode, grab the alloc_sem to keep the
(maybe temporary) BUG() in jffs2_mark_node_obsolete()
from triggering */
if
(
!
f
->
inocache
->
nlink
)
/* I don't think we care about the potential race due to reading this
without f->sem. It can never get undeleted. */
int
deleted
=
f
->
inocache
&&
!
f
->
inocache
->
nlink
;
/* If it's a deleted inode, grab the alloc_sem. This prevents
jffs2_garbage_collect_pass() from deciding that it wants to
garbage collect one of the nodes we're just about to mark
obsolete -- by the time we drop alloc_sem and return, all
the nodes are marked obsolete, and jffs2_g_c_pass() won't
call iget() for the inode in question.
We also do this to keep the (maybe temporary) BUG() in
jffs2_mark_node_obsolete() from triggering.
*/
if
(
deleted
)
down
(
&
c
->
alloc_sem
);
down
(
&
f
->
sem
);
frags
=
f
->
fraglist
;
fds
=
f
->
dents
;
if
(
f
->
metadata
)
{
if
(
!
f
->
inocache
->
nlink
)
if
(
deleted
)
jffs2_mark_node_obsolete
(
c
,
f
->
metadata
->
raw
);
jffs2_free_full_dnode
(
f
->
metadata
);
}
while
(
frags
)
{
frag
=
frags
;
frags
=
frag
->
next
;
D2
(
printk
(
KERN_DEBUG
"jffs2_do_clear_inode: frag at 0x%x-0x%x: node %p, frags %d--
\n
"
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
,
frag
->
node
,
frag
->
node
?
frag
->
node
->
frags
:
0
));
jffs2_kill_fragtree
(
&
f
->
fragtree
,
deleted
?
c
:
NULL
);
if
(
frag
->
node
&&
!
(
--
frag
->
node
->
frags
))
{
/* Not a hole, and it's the final remaining frag of this node. Free the node */
if
(
!
f
->
inocache
->
nlink
)
jffs2_mark_node_obsolete
(
c
,
frag
->
node
->
raw
);
fds
=
f
->
dents
;
jffs2_free_full_dnode
(
frag
->
node
);
}
jffs2_free_node_frag
(
frag
);
}
while
(
fds
)
{
fd
=
fds
;
fds
=
fd
->
next
;
jffs2_free_full_dirent
(
fd
);
}
/* Urgh. Is there a nicer way to do this? */
if
(
!
f
->
inocache
->
nlink
)
{
if
(
f
->
inocache
)
f
->
inocache
->
state
=
INO_STATE_CHECKEDABSENT
;
up
(
&
f
->
sem
);
if
(
deleted
)
up
(
&
c
->
alloc_sem
);
}
else
{
up
(
&
f
->
sem
);
}
}
fs/jffs2/scan.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: scan.c,v 1.
79 2002/07/25 20:48:51
dwmw2 Exp $
* $Id: scan.c,v 1.
92 2002/09/09 16:29:08
dwmw2 Exp $
*
*/
#include <linux/kernel.h>
...
...
@@ -15,8 +15,10 @@
#include <linux/mtd/mtd.h>
#include <linux/pagemap.h>
#include <linux/crc32.h>
#include <linux/compiler.h>
#include "nodelist.h"
#define EMPTY_SCAN_SIZE 1024
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->dirty_size += _x; \
...
...
@@ -26,6 +28,10 @@
c->free_size -= _x; c->used_size += _x; \
jeb->free_size -= _x ; jeb->used_size += _x; \
}while(0)
#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->unchecked_size += _x; \
jeb->free_size -= _x ; jeb->unchecked_size += _x; \
}while(0)
#define noisy_printk(noise, args...) do { \
if (*(noise)) { \
...
...
@@ -39,15 +45,17 @@
static
uint32_t
pseudo_random
;
static
int
jffs2_scan_eraseblock
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
);
static
int
jffs2_scan_eraseblock
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
unsigned
char
*
buf
,
uint32_t
buf_size
);
/* These helper functions _must_ increase ofs and also do the dirty/used space accounting.
* Returning an error will abort the mount - bad checksums etc. should just mark the space
* as dirty.
*/
static
int
jffs2_scan_empty
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
uint32_t
*
ofs
,
int
*
noise
);
static
int
jffs2_scan_inode_node
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
uint32_t
*
ofs
);
static
int
jffs2_scan_dirent_node
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
uint32_t
*
ofs
);
static
int
jffs2_scan_inode_node
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
struct
jffs2_raw_inode
*
ri
,
uint32_t
ofs
);
static
int
jffs2_scan_dirent_node
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
struct
jffs2_raw_dirent
*
rd
,
uint32_t
ofs
);
#define BLK_STATE_ALLFF 0
#define BLK_STATE_CLEAN 1
...
...
@@ -60,15 +68,44 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
{
int
i
,
ret
;
uint32_t
empty_blocks
=
0
,
bad_blocks
=
0
;
unsigned
char
*
flashbuf
=
NULL
;
uint32_t
buf_size
=
0
;
size_t
pointlen
;
if
(
!
c
->
blocks
)
{
printk
(
KERN_WARNING
"EEEK! c->blocks is NULL!
\n
"
);
return
-
EINVAL
;
}
if
(
c
->
mtd
->
point
)
{
ret
=
c
->
mtd
->
point
(
c
->
mtd
,
0
,
c
->
mtd
->
size
,
&
pointlen
,
&
flashbuf
);
if
(
!
ret
&&
pointlen
<
c
->
mtd
->
size
)
{
/* Don't muck about if it won't let us point to the whole flash */
D1
(
printk
(
KERN_DEBUG
"MTD point returned len too short: 0x%x
\n
"
,
pointlen
));
c
->
mtd
->
unpoint
(
c
->
mtd
,
flashbuf
);
flashbuf
=
NULL
;
}
if
(
ret
)
D1
(
printk
(
KERN_DEBUG
"MTD point failed %d
\n
"
,
ret
));
}
if
(
!
flashbuf
)
{
/* For NAND it's quicker to read a whole eraseblock at a time,
apparently */
if
(
jffs2_cleanmarker_oob
(
c
))
buf_size
=
c
->
sector_size
;
else
buf_size
=
PAGE_SIZE
;
D1
(
printk
(
KERN_DEBUG
"Allocating readbuf of %d bytes
\n
"
,
buf_size
));
flashbuf
=
kmalloc
(
buf_size
,
GFP_KERNEL
);
if
(
!
flashbuf
)
return
-
ENOMEM
;
}
for
(
i
=
0
;
i
<
c
->
nr_blocks
;
i
++
)
{
struct
jffs2_eraseblock
*
jeb
=
&
c
->
blocks
[
i
];
ret
=
jffs2_scan_eraseblock
(
c
,
jeb
);
ret
=
jffs2_scan_eraseblock
(
c
,
jeb
,
buf_size
?
flashbuf
:
(
flashbuf
+
jeb
->
offset
),
buf_size
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -120,6 +157,11 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
(
!
c
->
nextblock
||
c
->
nextblock
->
free_size
<
jeb
->
free_size
))
{
/* Better candidate for the next writes to go to */
if
(
c
->
nextblock
)
{
c
->
nextblock
->
dirty_size
+=
c
->
nextblock
->
free_size
+
c
->
nextblock
->
wasted_size
;
c
->
dirty_size
+=
c
->
nextblock
->
free_size
+
c
->
nextblock
->
wasted_size
;
c
->
free_size
-=
c
->
nextblock
->
free_size
;
c
->
wasted_size
-=
c
->
nextblock
->
wasted_size
;
c
->
nextblock
->
free_size
=
c
->
nextblock
->
wasted_size
=
0
;
if
(
VERYDIRTY
(
c
,
c
->
nextblock
->
dirty_size
))
{
list_add
(
&
c
->
nextblock
->
list
,
&
c
->
very_dirty_list
);
}
else
{
...
...
@@ -128,6 +170,11 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
}
c
->
nextblock
=
jeb
;
}
else
{
jeb
->
dirty_size
+=
jeb
->
free_size
+
jeb
->
wasted_size
;
c
->
dirty_size
+=
jeb
->
free_size
+
jeb
->
wasted_size
;
c
->
free_size
-=
jeb
->
free_size
;
c
->
wasted_size
-=
jeb
->
wasted_size
;
jeb
->
free_size
=
jeb
->
wasted_size
=
0
;
if
(
VERYDIRTY
(
c
,
jeb
->
dirty_size
))
{
list_add
(
&
jeb
->
list
,
&
c
->
very_dirty_list
);
}
else
{
...
...
@@ -157,6 +204,14 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
}
}
/* Nextblock dirty is always seen as wasted, because we cannot recycle it now */
if
(
c
->
nextblock
&&
(
c
->
nextblock
->
dirty_size
))
{
c
->
nextblock
->
wasted_size
+=
c
->
nextblock
->
dirty_size
;
c
->
wasted_size
+=
c
->
nextblock
->
dirty_size
;
c
->
dirty_size
-=
c
->
nextblock
->
dirty_size
;
c
->
nextblock
->
dirty_size
=
0
;
}
if
(
!
jffs2_can_mark_obsolete
(
c
)
&&
c
->
nextblock
&&
(
c
->
nextblock
->
free_size
&
(
c
->
wbuf_pagesize
-
1
)))
{
/* If we're going to start writing into a block which already
contains data, and the end of the data isn't page-aligned,
...
...
@@ -166,8 +221,8 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
D1
(
printk
(
KERN_DEBUG
"jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment
\n
"
,
skip
));
c
->
nextblock
->
dirty
_size
+=
skip
;
c
->
dirty
_size
+=
skip
;
c
->
nextblock
->
wasted
_size
+=
skip
;
c
->
wasted
_size
+=
skip
;
c
->
nextblock
->
free_size
-=
skip
;
c
->
free_size
-=
skip
;
...
...
@@ -180,17 +235,47 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
}
jffs2_erase_pending_trigger
(
c
);
}
if
(
buf_size
)
kfree
(
flashbuf
);
else
c
->
mtd
->
unpoint
(
c
->
mtd
,
flashbuf
);
return
0
;
}
static
int
jffs2_scan_eraseblock
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
)
{
struct
jffs2_unknown_node
node
;
static
int
jffs2_fill_scan_buf
(
struct
jffs2_sb_info
*
c
,
unsigned
char
*
buf
,
uint32_t
ofs
,
uint32_t
len
)
{
int
ret
;
size_t
retlen
;
ret
=
jffs2_flash_read
(
c
,
ofs
,
len
,
&
retlen
,
buf
);
if
(
ret
)
{
D1
(
printk
(
KERN_WARNING
"mtd->read(0x%x bytes from 0x%x) returned %d
\n
"
,
len
,
ofs
,
ret
));
return
ret
;
}
if
(
retlen
<
len
)
{
D1
(
printk
(
KERN_WARNING
"Read at 0x%x gave only 0x%x bytes
\n
"
,
ofs
,
retlen
));
return
-
EIO
;
}
D2
(
printk
(
KERN_DEBUG
"Read 0x%x bytes from 0x%08x into buf
\n
"
,
len
,
ofs
));
D2
(
printk
(
KERN_DEBUG
"000: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x
\n
"
,
buf
[
0
],
buf
[
1
],
buf
[
2
],
buf
[
3
],
buf
[
4
],
buf
[
5
],
buf
[
6
],
buf
[
7
],
buf
[
8
],
buf
[
9
],
buf
[
10
],
buf
[
11
],
buf
[
12
],
buf
[
13
],
buf
[
14
],
buf
[
15
]));
return
0
;
}
static
int
jffs2_scan_eraseblock
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
unsigned
char
*
buf
,
uint32_t
buf_size
)
{
struct
jffs2_unknown_node
*
node
;
struct
jffs2_unknown_node
crcnode
;
uint32_t
ofs
,
prevofs
;
uint32_t
hdr_crc
,
nodetype
;
uint32_t
hdr_crc
,
buf_ofs
,
buf_len
;
int
err
;
int
noise
=
0
;
int
wasempty
=
0
;
uint32_t
empty_start
=
0
;
#ifdef CONFIG_JFFS2_FS_NAND
int
cleanmarkerfound
=
0
;
int
cleanmarkerfound
=
0
;
#endif
ofs
=
jeb
->
offset
;
...
...
@@ -214,16 +299,30 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
}
}
#endif
err
=
jffs2_scan_empty
(
c
,
jeb
,
&
ofs
,
&
noise
);
buf_ofs
=
jeb
->
offset
;
if
(
!
buf_size
)
{
buf_len
=
c
->
sector_size
;
}
else
{
buf_len
=
EMPTY_SCAN_SIZE
;
err
=
jffs2_fill_scan_buf
(
c
,
buf
,
buf_ofs
,
buf_len
);
if
(
err
)
return
err
;
}
/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
ofs
=
0
;
if
(
ofs
==
jeb
->
offset
+
c
->
sector_size
)
{
/* Scan only 4KiB of 0xFF before declaring it's empty */
while
(
ofs
<
EMPTY_SCAN_SIZE
&&
*
(
uint32_t
*
)(
&
buf
[
ofs
])
==
0xFFFFFFFF
)
ofs
+=
4
;
if
(
ofs
==
EMPTY_SCAN_SIZE
)
{
#ifdef CONFIG_JFFS2_FS_NAND
if
(
jffs2_cleanmarker_oob
(
c
))
{
/* scan oob, take care of cleanmarker */
int
ret
=
jffs2_check_oob_empty
(
c
,
jeb
,
cleanmarkerfound
);
D2
(
printk
(
KERN_NOTICE
"jffs_check_oob_empty returned %d
\n
"
,
ret
));
D2
(
printk
(
KERN_NOTICE
"jffs
2
_check_oob_empty returned %d
\n
"
,
ret
));
switch
(
ret
)
{
case
0
:
return
cleanmarkerfound
?
BLK_STATE_CLEANMARKER
:
BLK_STATE_ALLFF
;
case
1
:
return
BLK_STATE_ALLDIRTY
;
...
...
@@ -236,12 +335,20 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
D1
(
printk
(
KERN_DEBUG
"Block at 0x%08x is empty (erased)
\n
"
,
jeb
->
offset
));
return
BLK_STATE_ALLFF
;
/* OK to erase if all blocks are like this */
}
if
(
ofs
)
{
D1
(
printk
(
KERN_DEBUG
"Free space at %08x ends at %08x
\n
"
,
jeb
->
offset
,
jeb
->
offset
+
ofs
));
DIRTY_SPACE
(
ofs
);
}
/* Now ofs is a complete physical flash offset as it always was... */
ofs
+=
jeb
->
offset
;
noise
=
10
;
while
(
ofs
<
jeb
->
offset
+
c
->
sector_size
)
{
size_t
retlen
;
ACCT_PARANOIA_CHECK
(
jeb
);
D1
(
ACCT_PARANOIA_CHECK
(
jeb
)
);
cond_resched
();
...
...
@@ -258,109 +365,173 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
}
prevofs
=
ofs
;
if
(
jeb
->
offset
+
c
->
sector_size
<
ofs
+
sizeof
(
node
))
{
D1
(
printk
(
KERN_DEBUG
"Fewer than %d bytes left to end of block. Not reading
\n
"
,
sizeof
(
struct
jffs2_unknown_node
)));
if
(
jeb
->
offset
+
c
->
sector_size
<
ofs
+
sizeof
(
*
node
))
{
D1
(
printk
(
KERN_DEBUG
"Fewer than %d bytes left to end of block. (%x+%x<%x+%x) Not reading
\n
"
,
sizeof
(
struct
jffs2_unknown_node
),
jeb
->
offset
,
c
->
sector_size
,
ofs
,
sizeof
(
*
node
)));
DIRTY_SPACE
((
jeb
->
offset
+
c
->
sector_size
)
-
ofs
);
break
;
}
err
=
jffs2_flash_read
(
c
,
ofs
,
sizeof
(
node
),
&
retlen
,
(
char
*
)
&
node
);
if
(
err
)
{
D1
(
printk
(
KERN_WARNING
"mtd->read(0x%x bytes from 0x%x) returned %d
\n
"
,
sizeof
(
node
),
ofs
,
err
));
if
(
buf_ofs
+
buf_len
<
ofs
+
sizeof
(
*
node
))
{
buf_len
=
min_t
(
uint32_t
,
buf_size
,
jeb
->
offset
+
c
->
sector_size
-
ofs
);
D1
(
printk
(
KERN_DEBUG
"Fewer than %d bytes (node header) left to end of buf. Reading 0x%x at 0x%08x
\n
"
,
sizeof
(
struct
jffs2_unknown_node
),
buf_len
,
ofs
));
err
=
jffs2_fill_scan_buf
(
c
,
buf
,
ofs
,
buf_len
);
if
(
err
)
return
err
;
buf_ofs
=
ofs
;
}
if
(
retlen
<
sizeof
(
node
))
{
D1
(
printk
(
KERN_WARNING
"Read at 0x%x gave only 0x%x bytes
\n
"
,
ofs
,
retlen
));
DIRTY_SPACE
(
retlen
);
ofs
+=
retlen
;
continue
;
node
=
(
struct
jffs2_unknown_node
*
)
&
buf
[
ofs
-
buf_ofs
];
if
(
*
(
uint32_t
*
)(
&
buf
[
ofs
-
buf_ofs
])
==
0xffffffff
)
{
uint32_t
inbuf_ofs
=
ofs
-
buf_ofs
+
4
;
uint32_t
scanend
;
empty_start
=
ofs
;
ofs
+=
4
;
/* If scanning empty space after only a cleanmarker, don't
bother scanning the whole block */
if
(
unlikely
(
empty_start
==
jeb
->
offset
+
c
->
cleanmarker_size
&&
jeb
->
offset
+
EMPTY_SCAN_SIZE
<
buf_ofs
+
buf_len
))
scanend
=
jeb
->
offset
+
EMPTY_SCAN_SIZE
-
buf_ofs
;
else
scanend
=
buf_len
;
D1
(
printk
(
KERN_DEBUG
"Found empty flash at 0x%08x
\n
"
,
ofs
));
while
(
inbuf_ofs
<
scanend
)
{
if
(
*
(
uint32_t
*
)(
&
buf
[
inbuf_ofs
])
!=
0xffffffff
)
goto
emptyends
;
inbuf_ofs
+=
4
;
ofs
+=
4
;
}
/* Ran off end. */
D1
(
printk
(
KERN_DEBUG
"Empty flash ends normally at 0x%08x
\n
"
,
ofs
));
if
(
node
.
magic
==
JFFS2_EMPTY_BITMASK
&&
node
.
nodetype
==
JFFS2_EMPTY_BITMASK
)
{
D1
(
printk
(
KERN_DEBUG
"Found empty flash at 0x%x
\n
"
,
ofs
));
err
=
jffs2_scan_empty
(
c
,
jeb
,
&
ofs
,
&
noise
);
if
(
err
)
return
err
;
if
(
buf_ofs
==
jeb
->
offset
&&
jeb
->
used_size
==
PAD
(
c
->
cleanmarker_size
)
&&
!
jeb
->
first_node
->
next_in_ino
&&
!
jeb
->
dirty_size
)
return
BLK_STATE_CLEANMARKER
;
wasempty
=
1
;
continue
;
}
else
if
(
wasempty
)
{
emptyends:
printk
(
KERN_WARNING
"Empty flash at 0x%08x ends at 0x%08x
\n
"
,
empty_start
,
ofs
);
DIRTY_SPACE
(
ofs
-
empty_start
);
wasempty
=
0
;
continue
;
}
if
(
ofs
==
jeb
->
offset
&&
node
.
magic
==
KSAMTIB_CIGAM_2SFFJ
)
{
if
(
ofs
==
jeb
->
offset
&&
je16_to_cpu
(
node
->
magic
)
==
KSAMTIB_CIGAM_2SFFJ
)
{
printk
(
KERN_WARNING
"Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?
\n
"
,
ofs
);
DIRTY_SPACE
(
4
);
ofs
+=
4
;
continue
;
}
if
(
node
.
magic
==
JFFS2_DIRTY_BITMASK
)
{
if
(
je16_to_cpu
(
node
->
magic
)
==
JFFS2_DIRTY_BITMASK
)
{
D1
(
printk
(
KERN_DEBUG
"Empty bitmask at 0x%08x
\n
"
,
ofs
));
DIRTY_SPACE
(
4
);
ofs
+=
4
;
continue
;
}
if
(
node
.
magic
==
JFFS2_OLD_MAGIC_BITMASK
)
{
if
(
je16_to_cpu
(
node
->
magic
)
==
JFFS2_OLD_MAGIC_BITMASK
)
{
printk
(
KERN_WARNING
"Old JFFS2 bitmask found at 0x%08x
\n
"
,
ofs
);
printk
(
KERN_WARNING
"You cannot use older JFFS2 filesystems with newer kernels
\n
"
);
DIRTY_SPACE
(
4
);
ofs
+=
4
;
continue
;
}
if
(
node
.
magic
!=
JFFS2_MAGIC_BITMASK
)
{
if
(
je16_to_cpu
(
node
->
magic
)
!=
JFFS2_MAGIC_BITMASK
)
{
/* OK. We're out of possibilities. Whinge and move on */
noisy_printk
(
&
noise
,
"jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead
\n
"
,
JFFS2_MAGIC_BITMASK
,
ofs
,
node
.
magic
);
noisy_printk
(
&
noise
,
"jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead
\n
"
,
JFFS2_MAGIC_BITMASK
,
ofs
,
je16_to_cpu
(
node
->
magic
));
DIRTY_SPACE
(
4
);
ofs
+=
4
;
continue
;
}
/* We seem to have a node of sorts. Check the CRC */
nodetype
=
node
.
nodetype
;
node
.
nodetype
|=
JFFS2_NODE_ACCURATE
;
hdr_crc
=
crc32
(
0
,
&
node
,
sizeof
(
node
)
-
4
);
node
.
nodetype
=
nodetype
;
if
(
hdr_crc
!=
node
.
hdr_crc
)
{
crcnode
.
magic
=
node
->
magic
;
crcnode
.
nodetype
=
cpu_to_je16
(
je16_to_cpu
(
node
->
nodetype
)
|
JFFS2_NODE_ACCURATE
);
crcnode
.
totlen
=
node
->
totlen
;
hdr_crc
=
crc32
(
0
,
&
crcnode
,
sizeof
(
crcnode
)
-
4
);
if
(
hdr_crc
!=
je32_to_cpu
(
node
->
hdr_crc
))
{
noisy_printk
(
&
noise
,
"jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)
\n
"
,
ofs
,
node
.
magic
,
node
.
nodetype
,
node
.
totlen
,
node
.
hdr_crc
,
hdr_crc
);
ofs
,
je16_to_cpu
(
node
->
magic
),
je16_to_cpu
(
node
->
nodetype
),
je32_to_cpu
(
node
->
totlen
),
je32_to_cpu
(
node
->
hdr_crc
),
hdr_crc
);
DIRTY_SPACE
(
4
);
ofs
+=
4
;
continue
;
}
if
(
ofs
+
node
.
totlen
>
jeb
->
offset
+
c
->
sector_size
)
{
if
(
ofs
+
je32_to_cpu
(
node
->
totlen
)
>
jeb
->
offset
+
c
->
sector_size
)
{
/* Eep. Node goes over the end of the erase block. */
printk
(
KERN_WARNING
"Node at 0x%08x with length 0x%08x would run over the end of the erase block
\n
"
,
ofs
,
node
.
totlen
);
ofs
,
je32_to_cpu
(
node
->
totlen
)
);
printk
(
KERN_WARNING
"Perhaps the file system was created with the wrong erase size?
\n
"
);
DIRTY_SPACE
(
4
);
ofs
+=
4
;
continue
;
}
if
(
!
(
node
.
nodetype
&
JFFS2_NODE_ACCURATE
))
{
if
(
!
(
je16_to_cpu
(
node
->
nodetype
)
&
JFFS2_NODE_ACCURATE
))
{
/* Wheee. This is an obsoleted node */
D2
(
printk
(
KERN_DEBUG
"Node at 0x%08x is obsolete. Skipping
\n
"
,
ofs
));
DIRTY_SPACE
(
PAD
(
node
.
totlen
));
ofs
+=
PAD
(
node
.
totlen
);
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
node
->
totlen
)
));
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
)
);
continue
;
}
switch
(
node
.
nodetype
)
{
switch
(
je16_to_cpu
(
node
->
nodetype
)
)
{
case
JFFS2_NODETYPE_INODE
:
err
=
jffs2_scan_inode_node
(
c
,
jeb
,
&
ofs
);
if
(
buf_ofs
+
buf_len
<
ofs
+
sizeof
(
struct
jffs2_raw_inode
))
{
buf_len
=
min_t
(
uint32_t
,
buf_size
,
jeb
->
offset
+
c
->
sector_size
-
ofs
);
D1
(
printk
(
KERN_DEBUG
"Fewer than %d bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x
\n
"
,
sizeof
(
struct
jffs2_raw_inode
),
buf_len
,
ofs
));
err
=
jffs2_fill_scan_buf
(
c
,
buf
,
ofs
,
buf_len
);
if
(
err
)
return
err
;
buf_ofs
=
ofs
;
node
=
(
void
*
)
buf
;
}
err
=
jffs2_scan_inode_node
(
c
,
jeb
,
(
void
*
)
node
,
ofs
);
if
(
err
)
return
err
;
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
));
break
;
case
JFFS2_NODETYPE_DIRENT
:
err
=
jffs2_scan_dirent_node
(
c
,
jeb
,
&
ofs
);
if
(
buf_ofs
+
buf_len
<
ofs
+
je32_to_cpu
(
node
->
totlen
))
{
buf_len
=
min_t
(
uint32_t
,
buf_size
,
jeb
->
offset
+
c
->
sector_size
-
ofs
);
D1
(
printk
(
KERN_DEBUG
"Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x
\n
"
,
je32_to_cpu
(
node
->
totlen
),
buf_len
,
ofs
));
err
=
jffs2_fill_scan_buf
(
c
,
buf
,
ofs
,
buf_len
);
if
(
err
)
return
err
;
buf_ofs
=
ofs
;
node
=
(
void
*
)
buf
;
}
err
=
jffs2_scan_dirent_node
(
c
,
jeb
,
(
void
*
)
node
,
ofs
);
if
(
err
)
return
err
;
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
));
break
;
case
JFFS2_NODETYPE_CLEANMARKER
:
if
(
node
.
totlen
!=
c
->
cleanmarker_size
)
{
D1
(
printk
(
KERN_DEBUG
"CLEANMARKER node found at 0x%08x
\n
"
,
ofs
));
if
(
je32_to_cpu
(
node
->
totlen
)
!=
c
->
cleanmarker_size
)
{
printk
(
KERN_NOTICE
"CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x
\n
"
,
ofs
,
node
.
totlen
,
c
->
cleanmarker_size
);
ofs
,
je32_to_cpu
(
node
->
totlen
)
,
c
->
cleanmarker_size
);
DIRTY_SPACE
(
PAD
(
sizeof
(
struct
jffs2_unknown_node
)));
ofs
+=
PAD
(
sizeof
(
struct
jffs2_unknown_node
));
}
else
if
(
jeb
->
first_node
)
{
printk
(
KERN_NOTICE
"CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)
\n
"
,
ofs
,
jeb
->
offset
);
DIRTY_SPACE
(
PAD
(
sizeof
(
struct
jffs2_unknown_node
)));
ofs
+=
PAD
(
sizeof
(
struct
jffs2_unknown_node
));
continue
;
}
else
{
struct
jffs2_raw_node_ref
*
marker_ref
=
jffs2_alloc_raw_node_ref
();
if
(
!
marker_ref
)
{
...
...
@@ -369,45 +540,45 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
}
marker_ref
->
next_in_ino
=
NULL
;
marker_ref
->
next_phys
=
NULL
;
marker_ref
->
flash_offset
=
ofs
;
marker_ref
->
totlen
=
sizeof
(
struct
jffs2_unknown_node
)
;
marker_ref
->
flash_offset
=
ofs
|
REF_NORMAL
;
marker_ref
->
totlen
=
c
->
cleanmarker_size
;
jeb
->
first_node
=
jeb
->
last_node
=
marker_ref
;
USED_SPACE
(
PAD
(
sizeof
(
struct
jffs2_unknown_node
)));
USED_SPACE
(
PAD
(
c
->
cleanmarker_size
));
ofs
+=
PAD
(
c
->
cleanmarker_size
);
}
ofs
+=
PAD
(
sizeof
(
struct
jffs2_unknown_node
));
break
;
case
JFFS2_NODETYPE_PADDING
:
DIRTY_SPACE
(
PAD
(
node
.
totlen
));
ofs
+=
PAD
(
node
.
totlen
);
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
node
->
totlen
)
));
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
)
);
break
;
default:
switch
(
node
.
nodetype
&
JFFS2_COMPAT_MASK
)
{
switch
(
je16_to_cpu
(
node
->
nodetype
)
&
JFFS2_COMPAT_MASK
)
{
case
JFFS2_FEATURE_ROCOMPAT
:
printk
(
KERN_NOTICE
"Read-only compatible feature node (0x%04x) found at offset 0x%08x
\n
"
,
node
.
nodetype
,
ofs
);
printk
(
KERN_NOTICE
"Read-only compatible feature node (0x%04x) found at offset 0x%08x
\n
"
,
je16_to_cpu
(
node
->
nodetype
)
,
ofs
);
c
->
flags
|=
JFFS2_SB_FLAG_RO
;
if
(
!
(
jffs2_is_readonly
(
c
)))
return
-
EROFS
;
DIRTY_SPACE
(
PAD
(
node
.
totlen
));
ofs
+=
PAD
(
node
.
totlen
);
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
node
->
totlen
)
));
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
)
);
break
;
case
JFFS2_FEATURE_INCOMPAT
:
printk
(
KERN_NOTICE
"Incompatible feature node (0x%04x) found at offset 0x%08x
\n
"
,
node
.
nodetype
,
ofs
);
printk
(
KERN_NOTICE
"Incompatible feature node (0x%04x) found at offset 0x%08x
\n
"
,
je16_to_cpu
(
node
->
nodetype
)
,
ofs
);
return
-
EINVAL
;
case
JFFS2_FEATURE_RWCOMPAT_DELETE
:
D1
(
printk
(
KERN_NOTICE
"Unknown but compatible feature node (0x%04x) found at offset 0x%08x
\n
"
,
node
.
nodetype
,
ofs
));
DIRTY_SPACE
(
PAD
(
node
.
totlen
));
ofs
+=
PAD
(
node
.
totlen
);
D1
(
printk
(
KERN_NOTICE
"Unknown but compatible feature node (0x%04x) found at offset 0x%08x
\n
"
,
je16_to_cpu
(
node
->
nodetype
)
,
ofs
));
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
node
->
totlen
)
));
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
)
);
break
;
case
JFFS2_FEATURE_RWCOMPAT_COPY
:
D1
(
printk
(
KERN_NOTICE
"Unknown but compatible feature node (0x%04x) found at offset 0x%08x
\n
"
,
node
.
nodetype
,
ofs
));
USED_SPACE
(
PAD
(
node
.
totlen
));
ofs
+=
PAD
(
node
.
totlen
);
D1
(
printk
(
KERN_NOTICE
"Unknown but compatible feature node (0x%04x) found at offset 0x%08x
\n
"
,
je16_to_cpu
(
node
->
nodetype
)
,
ofs
));
USED_SPACE
(
PAD
(
je32_to_cpu
(
node
->
totlen
)
));
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
)
);
break
;
}
}
...
...
@@ -417,64 +588,30 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
D1
(
printk
(
KERN_DEBUG
"Block at 0x%08x: free 0x%08x, dirty 0x%08x, used 0x%08x
\n
"
,
jeb
->
offset
,
jeb
->
free_size
,
jeb
->
dirty_size
,
jeb
->
used_size
));
if
(
jeb
->
used_size
==
PAD
(
sizeof
(
struct
jffs2_unknown_node
))
&&
/* mark_node_obsolete can add to wasted !! */
if
(
jeb
->
wasted_size
)
{
jeb
->
dirty_size
+=
jeb
->
wasted_size
;
c
->
dirty_size
+=
jeb
->
wasted_size
;
c
->
wasted_size
-=
jeb
->
wasted_size
;
jeb
->
wasted_size
=
0
;
}
if
((
jeb
->
used_size
+
jeb
->
unchecked_size
)
==
PAD
(
c
->
cleanmarker_size
)
&&
!
jeb
->
first_node
->
next_in_ino
&&
!
jeb
->
dirty_size
)
return
BLK_STATE_CLEANMARKER
;
else
if
(
jeb
->
used_size
>
c
->
sector_size
-
(
2
*
sizeof
(
struct
jffs2_raw_inode
)))
/* move blocks with max 4 byte dirty space to cleanlist */
else
if
(
!
ISDIRTY
(
c
->
sector_size
-
(
jeb
->
used_size
+
jeb
->
unchecked_size
)))
{
c
->
dirty_size
-=
jeb
->
dirty_size
;
c
->
wasted_size
+=
jeb
->
dirty_size
;
jeb
->
wasted_size
+=
jeb
->
dirty_size
;
jeb
->
dirty_size
=
0
;
return
BLK_STATE_CLEAN
;
else
if
(
jeb
->
us
ed_size
)
}
else
if
(
jeb
->
used_size
||
jeb
->
uncheck
ed_size
)
return
BLK_STATE_PARTDIRTY
;
else
return
BLK_STATE_ALLDIRTY
;
}
/* We're pointing at the first empty word on the flash. Scan and account for the whole dirty region */
static
int
jffs2_scan_empty
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
uint32_t
*
startofs
,
int
*
noise
)
{
uint32_t
*
buf
;
uint32_t
scanlen
=
(
jeb
->
offset
+
c
->
sector_size
)
-
*
startofs
;
uint32_t
curofs
=
*
startofs
;
buf
=
kmalloc
(
min
((
uint32_t
)
PAGE_SIZE
,
scanlen
),
GFP_KERNEL
);
if
(
!
buf
)
{
printk
(
KERN_WARNING
"Scan buffer allocation failed
\n
"
);
return
-
ENOMEM
;
}
while
(
scanlen
)
{
size_t
retlen
;
int
ret
,
i
;
ret
=
jffs2_flash_read
(
c
,
curofs
,
min
((
uint32_t
)
PAGE_SIZE
,
scanlen
),
&
retlen
,
(
char
*
)
buf
);
if
(
ret
)
{
D1
(
printk
(
KERN_WARNING
"jffs2_scan_empty(): Read 0x%x bytes at 0x%08x returned %d
\n
"
,
min
((
uint32_t
)
PAGE_SIZE
,
scanlen
),
curofs
,
ret
));
kfree
(
buf
);
return
ret
;
}
if
(
retlen
<
4
)
{
D1
(
printk
(
KERN_WARNING
"Eep. too few bytes read in scan_empty()
\n
"
));
kfree
(
buf
);
return
-
EIO
;
}
for
(
i
=
0
;
i
<
(
retlen
/
4
);
i
++
)
{
if
(
buf
[
i
]
!=
0xffffffff
)
{
curofs
+=
i
*
4
;
noisy_printk
(
noise
,
"jffs2_scan_empty(): Empty block at 0x%08x ends at 0x%08x (with 0x%08x)! Marking dirty
\n
"
,
*
startofs
,
curofs
,
buf
[
i
]);
DIRTY_SPACE
(
curofs
-
(
*
startofs
));
*
startofs
=
curofs
;
kfree
(
buf
);
return
0
;
}
}
scanlen
-=
retlen
&~
3
;
curofs
+=
retlen
&~
3
;
}
D1
(
printk
(
KERN_DEBUG
"Empty flash detected from 0x%08x to 0x%08x
\n
"
,
*
startofs
,
curofs
));
kfree
(
buf
);
*
startofs
=
curofs
;
return
0
;
}
static
struct
jffs2_inode_cache
*
jffs2_scan_make_ino_cache
(
struct
jffs2_sb_info
*
c
,
uint32_t
ino
)
{
struct
jffs2_inode_cache
*
ic
;
...
...
@@ -489,13 +626,7 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
return
NULL
;
}
memset
(
ic
,
0
,
sizeof
(
*
ic
));
ic
->
scan
=
kmalloc
(
sizeof
(
struct
jffs2_scan_info
),
GFP_KERNEL
);
if
(
!
ic
->
scan
)
{
printk
(
KERN_NOTICE
"jffs2_scan_make_inode_cache(): allocation of scan info for inode cache failed
\n
"
);
jffs2_free_inode_cache
(
ic
);
return
NULL
;
}
memset
(
ic
->
scan
,
0
,
sizeof
(
*
ic
->
scan
));
ic
->
ino
=
ino
;
ic
->
nodes
=
(
void
*
)
ic
;
jffs2_add_ino_cache
(
c
,
ic
);
...
...
@@ -504,116 +635,58 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
return
ic
;
}
static
int
jffs2_scan_inode_node
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
uint32_t
*
ofs
)
static
int
jffs2_scan_inode_node
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
struct
jffs2_raw_inode
*
ri
,
uint32_t
ofs
)
{
struct
jffs2_raw_node_ref
*
raw
;
struct
jffs2_full_dnode
*
fn
;
struct
jffs2_tmp_dnode_info
*
tn
,
**
tn_list
;
struct
jffs2_inode_cache
*
ic
;
struct
jffs2_raw_inode
ri
;
uint32_t
crc
;
uint16_t
oldnodetype
;
int
ret
;
size_t
retlen
;
D1
(
printk
(
KERN_DEBUG
"jffs2_scan_inode_node(): Node at 0x%08x
\n
"
,
*
ofs
));
uint32_t
ino
=
je32_to_cpu
(
ri
->
ino
);
ret
=
jffs2_flash_read
(
c
,
*
ofs
,
sizeof
(
ri
),
&
retlen
,
(
char
*
)
&
ri
);
if
(
ret
)
{
printk
(
KERN_NOTICE
"jffs2_scan_inode_node(): Read error at 0x%08x: %d
\n
"
,
*
ofs
,
ret
);
return
ret
;
}
if
(
retlen
!=
sizeof
(
ri
))
{
printk
(
KERN_NOTICE
"Short read: 0x%x bytes at 0x%08x instead of requested %x
\n
"
,
retlen
,
*
ofs
,
sizeof
(
ri
));
return
-
EIO
;
}
/* We sort of assume that the node was accurate when it was
first written to the medium :) */
oldnodetype
=
ri
.
nodetype
;
ri
.
nodetype
|=
JFFS2_NODE_ACCURATE
;
crc
=
crc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
);
ri
.
nodetype
=
oldnodetype
;
if
(
crc
!=
ri
.
node_crc
)
{
printk
(
KERN_NOTICE
"jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x
\n
"
,
*
ofs
,
ri
.
node_crc
,
crc
);
/* FIXME: Why do we believe totlen? */
DIRTY_SPACE
(
4
);
*
ofs
+=
4
;
return
0
;
}
/* There was a bug where we wrote hole nodes out with csize/dsize
swapped. Deal with it */
if
(
ri
.
compr
==
JFFS2_COMPR_ZERO
&&
!
ri
.
dsize
&&
ri
.
csize
)
{
ri
.
dsize
=
ri
.
csize
;
ri
.
csize
=
0
;
}
D1
(
printk
(
KERN_DEBUG
"jffs2_scan_inode_node(): Node at 0x%08x
\n
"
,
ofs
));
if
(
ri
.
csize
)
{
/* Check data CRC too */
unsigned
char
*
dbuf
;
uint32_t
crc
;
/* We do very little here now. Just check the ino# to which we should attribute
this node; we can do all the CRC checking etc. later. There's a tradeoff here --
we used to scan the flash once only, reading everything we want from it into
memory, then building all our in-core data structures and freeing the extra
information. Now we allow the first part of the mount to complete a lot quicker,
but we have to go _back_ to the flash in order to finish the CRC checking, etc.
Which means that the _full_ amount of time to get to proper write mode with GC
operational may actually be _longer_ than before. Sucks to be me. */
dbuf
=
kmalloc
(
PAGE_CACHE_SIZE
,
GFP_KERNEL
);
if
(
!
dbuf
)
{
printk
(
KERN_NOTICE
"jffs2_scan_inode_node(): allocation of temporary data buffer for CRC check failed
\n
"
);
return
-
ENOMEM
;
}
ret
=
jffs2_flash_read
(
c
,
*
ofs
+
sizeof
(
ri
),
ri
.
csize
,
&
retlen
,
dbuf
);
if
(
ret
)
{
printk
(
KERN_NOTICE
"jffs2_scan_inode_node(): Read error at 0x%08x: %d
\n
"
,
*
ofs
+
sizeof
(
ri
),
ret
);
kfree
(
dbuf
);
return
ret
;
}
if
(
retlen
!=
ri
.
csize
)
{
printk
(
KERN_NOTICE
"Short read: 0x%x bytes at 0x%08x instead of requested %x
\n
"
,
retlen
,
*
ofs
+
sizeof
(
ri
),
ri
.
csize
);
kfree
(
dbuf
);
return
-
EIO
;
}
crc
=
crc32
(
0
,
dbuf
,
ri
.
csize
);
kfree
(
dbuf
);
if
(
crc
!=
ri
.
data_crc
)
{
printk
(
KERN_NOTICE
"jffs2_scan_inode_node(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x
\n
"
,
*
ofs
,
ri
.
data_crc
,
crc
);
DIRTY_SPACE
(
PAD
(
ri
.
totlen
));
*
ofs
+=
PAD
(
ri
.
totlen
);
return
0
;
}
}
/* Wheee. It worked */
raw
=
jffs2_alloc_raw_node_ref
();
if
(
!
raw
)
{
printk
(
KERN_NOTICE
"jffs2_scan_inode_node(): allocation of node reference failed
\n
"
);
return
-
ENOMEM
;
}
tn
=
jffs2_alloc_tmp_dnode_info
();
if
(
!
tn
)
{
jffs2_free_raw_node_ref
(
raw
);
return
-
ENOMEM
;
}
fn
=
jffs2_alloc_full_dnode
();
if
(
!
fn
)
{
jffs2_free_tmp_dnode_info
(
tn
);
jffs2_free_raw_node_ref
(
raw
);
return
-
ENOMEM
;
ic
=
jffs2_get_ino_cache
(
c
,
ino
);
if
(
!
ic
)
{
/* Inocache get failed. Either we read a bogus ino# or it's just genuinely the
first node we found for this inode. Do a CRC check to protect against the former
case */
uint32_t
crc
=
crc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
if
(
crc
!=
je32_to_cpu
(
ri
->
node_crc
))
{
printk
(
KERN_NOTICE
"jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x
\n
"
,
ofs
,
je32_to_cpu
(
ri
->
node_crc
),
crc
);
/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
ri
->
totlen
)));
return
0
;
}
ic
=
jffs2_scan_make_ino_cache
(
c
,
ri
.
ino
);
ic
=
jffs2_scan_make_ino_cache
(
c
,
ino
);
if
(
!
ic
)
{
jffs2_free_full_dnode
(
fn
);
jffs2_free_tmp_dnode_info
(
tn
);
jffs2_free_raw_node_ref
(
raw
);
return
-
ENOMEM
;
}
}
/* Wheee. It worked */
/* Build the data structures and file them for later */
raw
->
flash_offset
=
*
ofs
;
raw
->
totlen
=
PAD
(
ri
.
totlen
);
raw
->
flash_offset
=
ofs
|
REF_UNCHECKED
;
raw
->
totlen
=
PAD
(
je32_to_cpu
(
ri
->
totlen
));
raw
->
next_phys
=
NULL
;
raw
->
next_in_ino
=
ic
->
nodes
;
ic
->
nodes
=
raw
;
if
(
!
jeb
->
first_node
)
jeb
->
first_node
=
raw
;
...
...
@@ -622,146 +695,56 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
jeb
->
last_node
=
raw
;
D1
(
printk
(
KERN_DEBUG
"Node is ino #%u, version %d. Range 0x%x-0x%x
\n
"
,
ri
.
ino
,
ri
.
version
,
ri
.
offset
,
ri
.
offset
+
ri
.
dsize
));
pseudo_random
+=
ri
.
version
;
for
(
tn_list
=
&
ic
->
scan
->
tmpnodes
;
*
tn_list
;
tn_list
=
&
((
*
tn_list
)
->
next
))
{
if
((
*
tn_list
)
->
version
<
ri
.
version
)
continue
;
if
((
*
tn_list
)
->
version
>
ri
.
version
)
break
;
/* Wheee. We've found another instance of the same version number.
We should obsolete one of them.
*/
D1
(
printk
(
KERN_DEBUG
"Duplicate version %d found in ino #%u. Previous one is at 0x%08x
\n
"
,
ri
.
version
,
ic
->
ino
,
(
*
tn_list
)
->
fn
->
raw
->
flash_offset
&~
3
));
if
(
!
jeb
->
used_size
)
{
D1
(
printk
(
KERN_DEBUG
"No valid nodes yet found in this eraseblock 0x%08x, so obsoleting the new instance at 0x%08x
\n
"
,
jeb
->
offset
,
raw
->
flash_offset
&
~
3
));
ri
.
nodetype
&=
~
JFFS2_NODE_ACCURATE
;
/* Perhaps we could also mark it as such on the medium. Maybe later */
}
break
;
}
if
(
ri
.
nodetype
&
JFFS2_NODE_ACCURATE
)
{
/* Only do fraglist truncation in pass1 for S_IFREG inodes */
if
(
S_ISREG
(
ri
.
mode
)
&&
ic
->
scan
->
version
<
ri
.
version
)
{
ic
->
scan
->
version
=
ri
.
version
;
ic
->
scan
->
isize
=
ri
.
isize
;
}
memset
(
fn
,
0
,
sizeof
(
*
fn
));
fn
->
ofs
=
ri
.
offset
;
fn
->
size
=
ri
.
dsize
;
fn
->
frags
=
0
;
fn
->
raw
=
raw
;
tn
->
next
=
NULL
;
tn
->
fn
=
fn
;
tn
->
version
=
ri
.
version
;
USED_SPACE
(
PAD
(
ri
.
totlen
));
/* No need to scan from the beginning of the list again.
We can start from tn_list instead (Thanks Jocke) */
jffs2_add_tn_to_list
(
tn
,
tn_list
);
je32_to_cpu
(
ri
->
ino
),
je32_to_cpu
(
ri
->
version
),
je32_to_cpu
(
ri
->
offset
),
je32_to_cpu
(
ri
->
offset
)
+
je32_to_cpu
(
ri
->
dsize
)));
/* Make sure the one we just added is the _last_ in the list
with this version number, so the older ones get obsoleted */
while
(
tn
->
next
&&
tn
->
next
->
version
==
tn
->
version
)
{
pseudo_random
+=
je32_to_cpu
(
ri
->
version
);
D1
(
printk
(
KERN_DEBUG
"Shifting new node at 0x%08x after other node at 0x%08x for version %d in list
\n
"
,
fn
->
raw
->
flash_offset
&~
3
,
tn
->
next
->
fn
->
raw
->
flash_offset
&~
3
,
ri
.
version
));
if
(
tn
->
fn
!=
fn
)
BUG
();
tn
->
fn
=
tn
->
next
->
fn
;
tn
->
next
->
fn
=
fn
;
tn
=
tn
->
next
;
}
}
else
{
jffs2_free_full_dnode
(
fn
);
jffs2_free_tmp_dnode_info
(
tn
);
raw
->
flash_offset
|=
1
;
DIRTY_SPACE
(
PAD
(
ri
.
totlen
));
}
*
ofs
+=
PAD
(
ri
.
totlen
);
UNCHECKED_SPACE
(
PAD
(
je32_to_cpu
(
ri
->
totlen
)));
return
0
;
}
static
int
jffs2_scan_dirent_node
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
uint32_t
*
ofs
)
static
int
jffs2_scan_dirent_node
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
struct
jffs2_raw_dirent
*
rd
,
uint32_t
ofs
)
{
struct
jffs2_raw_node_ref
*
raw
;
struct
jffs2_full_dirent
*
fd
;
struct
jffs2_inode_cache
*
ic
;
struct
jffs2_raw_dirent
rd
;
uint16_t
oldnodetype
;
int
ret
;
uint32_t
crc
;
size_t
retlen
;
D1
(
printk
(
KERN_DEBUG
"jffs2_scan_dirent_node(): Node at 0x%08x
\n
"
,
*
ofs
));
D1
(
printk
(
KERN_DEBUG
"jffs2_scan_dirent_node(): Node at 0x%08x
\n
"
,
ofs
));
ret
=
jffs2_flash_read
(
c
,
*
ofs
,
sizeof
(
rd
),
&
retlen
,
(
char
*
)
&
rd
);
if
(
ret
)
{
printk
(
KERN_NOTICE
"jffs2_scan_dirent_node(): Read error at 0x%08x: %d
\n
"
,
*
ofs
,
ret
);
return
ret
;
}
if
(
retlen
!=
sizeof
(
rd
))
{
printk
(
KERN_NOTICE
"Short read: 0x%x bytes at 0x%08x instead of requested %x
\n
"
,
retlen
,
*
ofs
,
sizeof
(
rd
));
return
-
EIO
;
}
/* We sort of assume that the node was accurate when it was
first written to the medium :) */
oldnodetype
=
rd
.
nodetype
;
rd
.
nodetype
|=
JFFS2_NODE_ACCURATE
;
crc
=
crc32
(
0
,
&
rd
,
sizeof
(
rd
)
-
8
);
rd
.
nodetype
=
oldnodetype
;
/* We don't get here unless the node is still valid, so we don't have to
mask in the ACCURATE bit any more. */
crc
=
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
if
(
crc
!=
rd
.
node_crc
)
{
if
(
crc
!=
je32_to_cpu
(
rd
->
node_crc
)
)
{
printk
(
KERN_NOTICE
"jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x
\n
"
,
*
ofs
,
rd
.
node_crc
,
crc
);
/* FIXME: Why do we believe totlen? */
DIRTY_SPACE
(
4
);
*
ofs
+=
4
;
ofs
,
je32_to_cpu
(
rd
->
node_crc
),
crc
);
/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
rd
->
totlen
)));
return
0
;
}
pseudo_random
+=
rd
.
version
;
pseudo_random
+=
je32_to_cpu
(
rd
->
version
)
;
fd
=
jffs2_alloc_full_dirent
(
rd
.
nsize
+
1
);
fd
=
jffs2_alloc_full_dirent
(
rd
->
nsize
+
1
);
if
(
!
fd
)
{
return
-
ENOMEM
;
}
ret
=
jffs2_flash_read
(
c
,
*
ofs
+
sizeof
(
rd
),
rd
.
nsize
,
&
retlen
,
&
fd
->
name
[
0
]);
if
(
ret
)
{
jffs2_free_full_dirent
(
fd
);
printk
(
KERN_NOTICE
"jffs2_scan_dirent_node(): Read error at 0x%08x: %d
\n
"
,
*
ofs
+
sizeof
(
rd
),
ret
);
return
ret
;
}
if
(
retlen
!=
rd
.
nsize
)
{
jffs2_free_full_dirent
(
fd
);
printk
(
KERN_NOTICE
"Short read: 0x%x bytes at 0x%08x instead of requested %x
\n
"
,
retlen
,
*
ofs
+
sizeof
(
rd
),
rd
.
nsize
);
return
-
EIO
;
}
memcpy
(
&
fd
->
name
,
rd
->
name
,
rd
->
nsize
);
fd
->
name
[
rd
->
nsize
]
=
0
;
crc
=
crc32
(
0
,
fd
->
name
,
rd
.
nsize
);
if
(
crc
!=
rd
.
name_crc
)
{
crc
=
crc32
(
0
,
fd
->
name
,
rd
->
nsize
);
if
(
crc
!=
je32_to_cpu
(
rd
->
name_crc
)
)
{
printk
(
KERN_NOTICE
"jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x
\n
"
,
*
ofs
,
rd
.
name_crc
,
crc
);
fd
->
name
[
rd
.
nsize
]
=
0
;
D1
(
printk
(
KERN_NOTICE
"Name for which CRC failed is (now) '%s', ino #%d
\n
"
,
fd
->
name
,
rd
.
ino
));
ofs
,
je32_to_cpu
(
rd
->
name_crc
),
crc
);
D1
(
printk
(
KERN_NOTICE
"Name for which CRC failed is (now) '%s', ino #%d
\n
"
,
fd
->
name
,
je32_to_cpu
(
rd
->
ino
)));
jffs2_free_full_dirent
(
fd
);
/* FIXME: Why do we believe totlen? */
DIRTY_SPACE
(
PAD
(
rd
.
totlen
));
*
ofs
+=
PAD
(
rd
.
totlen
);
/* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
rd
->
totlen
))
);
return
0
;
}
raw
=
jffs2_alloc_raw_node_ref
();
...
...
@@ -770,15 +753,15 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
printk
(
KERN_NOTICE
"jffs2_scan_dirent_node(): allocation of node reference failed
\n
"
);
return
-
ENOMEM
;
}
ic
=
jffs2_scan_make_ino_cache
(
c
,
rd
.
pino
);
ic
=
jffs2_scan_make_ino_cache
(
c
,
je32_to_cpu
(
rd
->
pino
)
);
if
(
!
ic
)
{
jffs2_free_full_dirent
(
fd
);
jffs2_free_raw_node_ref
(
raw
);
return
-
ENOMEM
;
}
raw
->
totlen
=
PAD
(
rd
.
totlen
);
raw
->
flash_offset
=
*
ofs
;
raw
->
totlen
=
PAD
(
je32_to_cpu
(
rd
->
totlen
)
);
raw
->
flash_offset
=
ofs
|
REF_PRISTINE
;
raw
->
next_phys
=
NULL
;
raw
->
next_in_ino
=
ic
->
nodes
;
ic
->
nodes
=
raw
;
...
...
@@ -788,22 +771,15 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
jeb
->
last_node
->
next_phys
=
raw
;
jeb
->
last_node
=
raw
;
if
(
rd
.
nodetype
&
JFFS2_NODE_ACCURATE
)
{
fd
->
raw
=
raw
;
fd
->
next
=
NULL
;
fd
->
version
=
rd
.
version
;
fd
->
ino
=
rd
.
ino
;
fd
->
name
[
rd
.
nsize
]
=
0
;
fd
->
nhash
=
full_name_hash
(
fd
->
name
,
rd
.
nsize
);
fd
->
type
=
rd
.
type
;
USED_SPACE
(
PAD
(
rd
.
totlen
));
jffs2_add_fd_to_list
(
c
,
fd
,
&
ic
->
scan
->
dents
);
}
else
{
raw
->
flash_offset
|=
1
;
jffs2_free_full_dirent
(
fd
);
DIRTY_SPACE
(
PAD
(
rd
.
totlen
));
}
*
ofs
+=
PAD
(
rd
.
totlen
);
fd
->
version
=
je32_to_cpu
(
rd
->
version
);
fd
->
ino
=
je32_to_cpu
(
rd
->
ino
);
fd
->
nhash
=
full_name_hash
(
fd
->
name
,
rd
->
nsize
);
fd
->
type
=
rd
->
type
;
USED_SPACE
(
PAD
(
je32_to_cpu
(
rd
->
totlen
)));
jffs2_add_fd_to_list
(
c
,
fd
,
&
ic
->
scan_dents
);
return
0
;
}
...
...
fs/jffs2/super.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: super.c,v 1.7
3 2002/07/23 17:00:45
dwmw2 Exp $
* $Id: super.c,v 1.7
4 2002/11/12 09:37:39
dwmw2 Exp $
*
*/
...
...
fs/jffs2/wbuf.c
View file @
20fed049
...
...
@@ -7,8 +7,9 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: wbuf.c,v 1.12 2002/05/20 14:56:39 dwmw2 Exp $
* -- with the NAND definitions added back pending MTD update for 2.5.
* $Id: wbuf.c,v 1.20 2002/11/12 11:33:02 dwmw2 Exp $
* + some of the dependencies on later MTD NAND code temporarily reverted.
*
*/
#include <linux/kernel.h>
...
...
@@ -16,17 +17,22 @@
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
#include <linux/crc32.h>
#include <linux/mtd/nand.h>
#include "nodelist.h"
/* FIXME duplicated defines in wbuf.c and nand.c
* Constants for out of band layout
*/
#ifndef NAND_BADBLOCK_POS
#define NAND_BADBLOCK_POS 5
#endif
#ifndef NAND_JFFS2_OOB_BADBPOS
#define NAND_JFFS2_OOB_BADBPOS 5
#define NAND_JFFS2_OOB8_FSDAPOS 6
#define NAND_JFFS2_OOB16_FSDAPOS 8
#define NAND_JFFS2_OOB8_FSDALEN 2
#define NAND_JFFS2_OOB16_FSDALEN 8
#endif
/* max. erase failures before we mark a block bad */
#define MAX_ERASE_FAILURES 5
...
...
@@ -89,17 +95,39 @@ void jffs2_wbuf_process (void *data)
D1
(
printk
(
KERN_DEBUG
"jffs2_wbuf_process() entered
\n
"
));
if
(
!
down_trylock
(
&
c
->
alloc_sem
))
{
/* Check, if the timer is active again */
if
(
timer_pending
(
&
c
->
wbuf_timer
))
{
D1
(
printk
(
KERN_DEBUG
"Nothing to do, timer is active again
\n
"
));
return
;
}
if
(
down_trylock
(
&
c
->
alloc_sem
))
{
/* If someone else has the alloc_sem, they're about to
write anyway. So no need to waste space by
padding */
D1
(
printk
(
KERN_DEBUG
"jffs2_wbuf_process() alloc_sem already occupied
\n
"
));
return
;
}
D1
(
printk
(
KERN_DEBUG
"jffs2_wbuf_process() alloc_sem got
\n
"
));
if
(
!
c
->
nextblock
||
(
c
->
nextblock
->
free_size
<
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
)))
jffs2_flush_wbuf
(
c
,
1
);
/* pad only */
else
jffs2_flush_wbuf
(
c
,
2
);
/* pad and adjust nextblock */
if
(
!
c
->
nextblock
)
{
D1
(
printk
(
KERN_DEBUG
"jffs2_wbuf_process(): nextblock NULL, nothing to do
\n
"
));
if
(
c
->
wbuf_len
)
{
printk
(
KERN_WARNING
"jffs2_wbuf_process(): c->wbuf_len is 0x%03x but nextblock is NULL!
\n
"
,
c
->
wbuf_len
);
up
(
&
c
->
alloc_sem
);
}
else
{
D1
(
printk
(
KERN_DEBUG
"jffs2_wbuf_process() alloc_sem already occupied
\n
"
));
BUG
();
}
return
;
}
/* if !c->nextblock then the tail will have got flushed from
jffs2_do_reserve_space() anyway. */
if
(
c
->
nextblock
)
jffs2_flush_wbuf
(
c
,
2
);
/* pad and adjust nextblock */
up
(
&
c
->
alloc_sem
);
}
...
...
@@ -113,6 +141,11 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
int
ret
;
size_t
retlen
;
/* Nothing to do if not NAND flash. In particular, we shouldn't
del_timer() the timer we never initialised. */
if
(
jffs2_can_mark_obsolete
(
c
))
return
0
;
if
(
!
down_trylock
(
&
c
->
alloc_sem
))
{
up
(
&
c
->
alloc_sem
);
printk
(
KERN_CRIT
"jffs2_flush_wbuf() called with alloc_sem not locked!
\n
"
);
...
...
@@ -136,10 +169,10 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
if
(
c
->
wbuf_len
+
sizeof
(
struct
jffs2_unknown_node
)
<
c
->
wbuf_pagesize
)
{
struct
jffs2_unknown_node
*
padnode
=
(
void
*
)(
c
->
wbuf
+
c
->
wbuf_len
);
padnode
->
magic
=
JFFS2_MAGIC_BITMASK
;
padnode
->
nodetype
=
JFFS2_NODETYPE_PADDING
;
padnode
->
totlen
=
c
->
wbuf_pagesize
-
c
->
wbuf_len
;
padnode
->
hdr_crc
=
c
rc32
(
0
,
padnode
,
sizeof
(
*
padnode
)
-
4
);
padnode
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
padnode
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_PADDING
)
;
padnode
->
totlen
=
c
pu_to_je32
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
)
;
padnode
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
padnode
,
sizeof
(
*
padnode
)
-
4
)
);
}
}
/* else jffs2_flash_writev has actually filled in the rest of the
...
...
@@ -175,10 +208,20 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
spin_lock_bh
(
&
c
->
erase_completion_lock
);
if
(
!
c
->
nextblock
)
BUG
();
if
(
c
->
nextblock
->
free_size
<
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
))
/* wbuf_pagesize - wbuf_len is the amount of space that's to be
padded. If there is less free space in the block than that,
something screwed up */
if
(
c
->
nextblock
->
free_size
<
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
))
{
printk
(
KERN_CRIT
"jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.
\n
"
,
c
->
wbuf_ofs
,
c
->
wbuf_len
,
c
->
wbuf_pagesize
-
c
->
wbuf_len
);
printk
(
KERN_CRIT
"jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x
\n
"
,
c
->
nextblock
->
offset
,
c
->
nextblock
->
free_size
);
BUG
();
}
c
->
nextblock
->
free_size
-=
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
);
c
->
nextblock
->
dirty_size
+=
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
);
c
->
free_size
-=
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
);
c
->
nextblock
->
wasted_size
+=
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
);
c
->
wasted_size
+=
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
}
...
...
@@ -415,9 +458,10 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
int
ret
;
/* Read flash */
if
(
!
jffs2_can_mark_obsolete
(
c
))
{
ret
=
c
->
mtd
->
read
(
c
->
mtd
,
ofs
,
len
,
retlen
,
buf
);
if
(
!
jffs2_can_mark_obsolete
(
c
)
&&
(
ret
==
-
EIO
)
&&
(
*
retlen
==
len
)
)
{
if
(
(
ret
==
-
EIO
)
&&
(
*
retlen
==
len
)
)
{
printk
(
KERN_WARNING
"mtd->read(0x%x bytes from 0x%llx) returned ECC error
\n
"
,
len
,
ofs
);
/*
* We have the raw data without ECC correction in the buffer, maybe
...
...
@@ -431,12 +475,13 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
*/
ret
=
0
;
}
}
else
return
c
->
mtd
->
read
(
c
->
mtd
,
ofs
,
len
,
retlen
,
buf
);
/* if no writebuffer available or write buffer empty, return */
if
(
!
c
->
wbuf_pagesize
||
!
c
->
wbuf_len
)
return
ret
;
/* if we read in a different block, return */
if
(
(
ofs
&
~
(
c
->
sector_size
-
1
))
!=
(
c
->
wbuf_ofs
&
~
(
c
->
sector_size
-
1
))
)
return
ret
;
...
...
@@ -478,7 +523,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
switch
(
c
->
mtd
->
ecctype
)
{
case
MTD_ECC_SW
:
fsdata_pos
=
(
c
->
wbuf_pagesize
==
256
)
?
NAND_JFFS2_OOB8_FSDAPOS
:
NAND_JFFS2_OOB16_FSDAPOS
;
badblock_pos
=
NAND_
JFFS2_OOB_BADB
POS
;
badblock_pos
=
NAND_
BADBLOCK_
POS
;
break
;
default:
D1
(
printk
(
KERN_WARNING
"jffs2_write_oob_empty(): Invalid ECC type
\n
"
));
...
...
@@ -486,7 +531,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
}
/* allocate a buffer for all oob data in this sector */
len
=
oob_size
*
(
c
->
sector_size
/
c
->
mtd
->
oobblock
)
;
len
=
4
*
oob_size
;
buf
=
kmalloc
(
len
,
GFP_KERNEL
);
if
(
!
buf
)
{
printk
(
KERN_NOTICE
"jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed
\n
"
);
...
...
@@ -510,7 +555,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
}
/* Special check for first two pages */
for
(
page
=
0
;
page
<
2
;
page
+=
oob_size
)
{
for
(
page
=
0
;
page
<
2
*
oob_size
;
page
+=
oob_size
)
{
/* Check for bad block marker */
if
(
buf
[
page
+
badblock_pos
]
!=
0xff
)
{
D1
(
printk
(
KERN_WARNING
"jffs2_check_oob_empty(): Bad or failed block at %08x
\n
"
,
jeb
->
offset
));
...
...
@@ -563,7 +608,7 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
case
MTD_ECC_SW
:
fsdata_pos
=
(
c
->
wbuf_pagesize
==
256
)
?
NAND_JFFS2_OOB8_FSDAPOS
:
NAND_JFFS2_OOB16_FSDAPOS
;
fsdata_len
=
(
c
->
wbuf_pagesize
==
256
)
?
NAND_JFFS2_OOB8_FSDALEN
:
NAND_JFFS2_OOB16_FSDALEN
;
badblock_pos
=
NAND_
JFFS2_OOB_BADB
POS
;
badblock_pos
=
NAND_
BADBLOCK_
POS
;
break
;
default:
D1
(
printk
(
KERN_WARNING
"jffs2_write_nand_cleanmarker(): Invalid ECC type
\n
"
));
...
...
@@ -598,9 +643,9 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
return
3
;
}
n
.
magic
=
JFFS2_MAGIC_BITMASK
;
n
.
nodetype
=
JFFS2_NODETYPE_CLEANMARKER
;
n
.
totlen
=
8
;
n
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
n
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_CLEANMARKER
)
;
n
.
totlen
=
cpu_to_je32
(
8
)
;
p
=
(
unsigned
char
*
)
&
n
;
for
(
i
=
0
;
i
<
fsdata_len
;
i
++
)
{
...
...
@@ -630,9 +675,9 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
return
-
EINVAL
;
}
n
.
magic
=
JFFS2_MAGIC_BITMASK
;
n
.
nodetype
=
JFFS2_NODETYPE_CLEANMARKER
;
n
.
totlen
=
8
;
n
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
n
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_CLEANMARKER
)
;
n
.
totlen
=
cpu_to_je32
(
8
)
;
ret
=
jffs2_flash_write_oob
(
c
,
jeb
->
offset
+
fsdata_pos
,
fsdata_len
,
&
retlen
,
(
unsigned
char
*
)
&
n
);
...
...
@@ -661,7 +706,7 @@ int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
switch
(
c
->
mtd
->
ecctype
)
{
case
MTD_ECC_SW
:
badblock_pos
=
NAND_
JFFS2_OOB_BADB
POS
;
badblock_pos
=
NAND_
BADBLOCK_
POS
;
break
;
default:
D1
(
printk
(
KERN_WARNING
"jffs2_nand_read_failcnt(): Invalid ECC type
\n
"
));
...
...
@@ -702,7 +747,7 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *
switch
(
c
->
mtd
->
ecctype
)
{
case
MTD_ECC_SW
:
pos
=
NAND_
JFFS2_OOB_BADB
POS
;
pos
=
NAND_
BADBLOCK_
POS
;
break
;
default:
D1
(
printk
(
KERN_WARNING
"jffs2_write_nand_badblock(): Invalid ECC type
\n
"
));
...
...
fs/jffs2/write.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: write.c,v 1.
56 2002/07/10 14:05:16
dwmw2 Exp $
* $Id: write.c,v 1.
60 2002/09/09 16:29:08
dwmw2 Exp $
*
*/
...
...
@@ -15,6 +15,7 @@
#include <linux/fs.h>
#include <linux/crc32.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include "nodelist.h"
...
...
@@ -34,16 +35,22 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
f
->
inocache
=
ic
;
f
->
inocache
->
nlink
=
1
;
f
->
inocache
->
nodes
=
(
struct
jffs2_raw_node_ref
*
)
f
->
inocache
;
f
->
inocache
->
ino
=
ri
->
ino
=
++
c
->
highest_ino
;
D1
(
printk
(
KERN_DEBUG
"jffs2_do_new_inode(): Assigned ino# %d
\n
"
,
ri
->
ino
));
f
->
inocache
->
ino
=
++
c
->
highest_ino
;
f
->
inocache
->
state
=
INO_STATE_PRESENT
;
ri
->
ino
=
cpu_to_je32
(
f
->
inocache
->
ino
);
D1
(
printk
(
KERN_DEBUG
"jffs2_do_new_inode(): Assigned ino# %d
\n
"
,
f
->
inocache
->
ino
));
jffs2_add_ino_cache
(
c
,
f
->
inocache
);
ri
->
magic
=
JFFS2_MAGIC_BITMASK
;
ri
->
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
->
totlen
=
PAD
(
sizeof
(
*
ri
));
ri
->
hdr_crc
=
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
->
mode
=
mode
;
f
->
highest_version
=
ri
->
version
=
1
;
ri
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
);
ri
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
);
ri
->
totlen
=
cpu_to_je32
(
PAD
(
sizeof
(
*
ri
)));
ri
->
hdr_crc
=
cpu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
));
ri
->
mode
=
cpu_to_je32
(
mode
);
f
->
highest_version
=
1
;
ri
->
version
=
cpu_to_je32
(
f
->
highest_version
);
return
0
;
}
...
...
@@ -88,7 +95,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
int
ret
;
unsigned
long
cnt
=
2
;
D1
(
if
(
ri
->
hdr_crc
!=
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
))
{
D1
(
if
(
je32_to_cpu
(
ri
->
hdr_crc
)
!=
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
))
{
printk
(
KERN_CRIT
"Eep. CRC not correct in jffs2_write_dnode()
\n
"
);
BUG
();
}
...
...
@@ -100,8 +107,8 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
writecheck
(
c
,
flash_ofs
);
if
(
ri
->
totlen
!=
sizeof
(
*
ri
)
+
datalen
)
{
printk
(
KERN_WARNING
"jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)
\n
"
,
ri
->
totlen
,
sizeof
(
*
ri
),
datalen
);
if
(
je32_to_cpu
(
ri
->
totlen
)
!=
sizeof
(
*
ri
)
+
datalen
)
{
printk
(
KERN_WARNING
"jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)
\n
"
,
je32_to_cpu
(
ri
->
totlen
)
,
sizeof
(
*
ri
),
datalen
);
}
raw
=
jffs2_alloc_raw_node_ref
();
if
(
!
raw
)
...
...
@@ -113,11 +120,11 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
return
ERR_PTR
(
-
ENOMEM
);
}
raw
->
flash_offset
=
flash_ofs
;
raw
->
totlen
=
PAD
(
ri
->
tot
len
);
raw
->
totlen
=
PAD
(
sizeof
(
*
ri
)
+
data
len
);
raw
->
next_phys
=
NULL
;
fn
->
ofs
=
ri
->
offset
;
fn
->
size
=
ri
->
dsize
;
fn
->
ofs
=
je32_to_cpu
(
ri
->
offset
)
;
fn
->
size
=
je32_to_cpu
(
ri
->
dsize
)
;
fn
->
frags
=
0
;
fn
->
raw
=
raw
;
...
...
@@ -140,7 +147,8 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
seem corrupted, in which case the scan would skip over
any node we write before the original intended end of
this node */
jffs2_add_physical_node_ref
(
c
,
raw
,
sizeof
(
*
ri
)
+
datalen
,
1
);
raw
->
flash_offset
|=
REF_OBSOLETE
;
jffs2_add_physical_node_ref
(
c
,
raw
);
jffs2_mark_node_obsolete
(
c
,
raw
);
}
else
{
printk
(
KERN_NOTICE
"Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero
\n
"
,
raw
->
flash_offset
);
...
...
@@ -154,13 +162,20 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
return
ERR_PTR
(
ret
?
ret
:-
EIO
);
}
/* Mark the space used */
jffs2_add_physical_node_ref
(
c
,
raw
,
retlen
,
0
);
if
(
datalen
==
PAGE_CACHE_SIZE
)
raw
->
flash_offset
|=
REF_PRISTINE
;
else
raw
->
flash_offset
|=
REF_NORMAL
;
jffs2_add_physical_node_ref
(
c
,
raw
);
/* Link into per-inode list */
raw
->
next_in_ino
=
f
->
inocache
->
nodes
;
f
->
inocache
->
nodes
=
raw
;
D1
(
printk
(
KERN_DEBUG
"jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x
\n
"
,
flash_ofs
,
ri
->
dsize
,
ri
->
csize
,
ri
->
node_crc
,
ri
->
data_crc
,
ri
->
totlen
));
D1
(
printk
(
KERN_DEBUG
"jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x
\n
"
,
flash_ofs
,
je32_to_cpu
(
ri
->
dsize
),
je32_to_cpu
(
ri
->
csize
),
je32_to_cpu
(
ri
->
node_crc
),
je32_to_cpu
(
ri
->
data_crc
),
je32_to_cpu
(
ri
->
totlen
)));
if
(
writelen
)
*
writelen
=
retlen
;
...
...
@@ -176,10 +191,12 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
struct
iovec
vecs
[
2
];
int
ret
;
D1
(
printk
(
KERN_DEBUG
"jffs2_write_dirent(ino #%u, name at *0x%p
\"
%s
\"
->ino #%u, name_crc 0x%08x)
\n
"
,
rd
->
pino
,
name
,
name
,
rd
->
ino
,
rd
->
name_crc
));
D1
(
printk
(
KERN_DEBUG
"jffs2_write_dirent(ino #%u, name at *0x%p
\"
%s
\"
->ino #%u, name_crc 0x%08x)
\n
"
,
je32_to_cpu
(
rd
->
pino
),
name
,
name
,
je32_to_cpu
(
rd
->
ino
),
je32_to_cpu
(
rd
->
name_crc
)));
writecheck
(
c
,
flash_ofs
);
D1
(
if
(
rd
->
hdr_crc
!=
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
))
{
D1
(
if
(
je32_to_cpu
(
rd
->
hdr_crc
)
!=
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
))
{
printk
(
KERN_CRIT
"Eep. CRC not correct in jffs2_write_dirent()
\n
"
);
BUG
();
}
...
...
@@ -201,13 +218,13 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
return
ERR_PTR
(
-
ENOMEM
);
}
raw
->
flash_offset
=
flash_ofs
;
raw
->
totlen
=
PAD
(
rd
->
tot
len
);
raw
->
totlen
=
PAD
(
sizeof
(
*
rd
)
+
name
len
);
raw
->
next_in_ino
=
f
->
inocache
->
nodes
;
f
->
inocache
->
nodes
=
raw
;
raw
->
next_phys
=
NULL
;
fd
->
version
=
rd
->
version
;
fd
->
ino
=
rd
->
ino
;
fd
->
version
=
je32_to_cpu
(
rd
->
version
)
;
fd
->
ino
=
je32_to_cpu
(
rd
->
ino
)
;
fd
->
nhash
=
full_name_hash
(
name
,
strlen
(
name
));
fd
->
type
=
rd
->
type
;
memcpy
(
fd
->
name
,
name
,
namelen
);
...
...
@@ -220,7 +237,8 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
sizeof
(
*
rd
)
+
namelen
,
flash_ofs
,
ret
,
retlen
);
/* Mark the space as dirtied */
if
(
retlen
)
{
jffs2_add_physical_node_ref
(
c
,
raw
,
sizeof
(
*
rd
)
+
namelen
,
1
);
raw
->
flash_offset
|=
REF_OBSOLETE
;
jffs2_add_physical_node_ref
(
c
,
raw
);
jffs2_mark_node_obsolete
(
c
,
raw
);
}
else
{
printk
(
KERN_NOTICE
"Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero
\n
"
,
raw
->
flash_offset
);
...
...
@@ -234,7 +252,8 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
return
ERR_PTR
(
ret
?
ret
:-
EIO
);
}
/* Mark the space used */
jffs2_add_physical_node_ref
(
c
,
raw
,
retlen
,
0
);
raw
->
flash_offset
|=
REF_PRISTINE
;
jffs2_add_physical_node_ref
(
c
,
raw
);
if
(
writelen
)
*
writelen
=
retlen
;
...
...
@@ -289,20 +308,20 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
that the comprbuf doesn't need to be kfree()d.
*/
ri
->
magic
=
JFFS2_MAGIC_BITMASK
;
ri
->
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
->
totlen
=
sizeof
(
*
ri
)
+
cdatalen
;
ri
->
hdr_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
->
ino
=
f
->
inocache
->
ino
;
ri
->
version
=
++
f
->
highest_version
;
ri
->
isize
=
max
(
ri
->
isize
,
offset
+
datalen
);
ri
->
offset
=
offset
;
ri
->
csize
=
c
datalen
;
ri
->
dsize
=
datalen
;
ri
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
->
totlen
=
cpu_to_je32
(
sizeof
(
*
ri
)
+
cdatalen
)
;
ri
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
->
ino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
ri
->
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
->
isize
=
cpu_to_je32
(
max
(
je32_to_cpu
(
ri
->
isize
),
offset
+
datalen
)
);
ri
->
offset
=
cpu_to_je32
(
offset
)
;
ri
->
csize
=
c
pu_to_je32
(
cdatalen
)
;
ri
->
dsize
=
cpu_to_je32
(
datalen
)
;
ri
->
compr
=
comprtype
;
ri
->
node_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
ri
->
data_crc
=
c
rc32
(
0
,
comprbuf
,
cdatalen
);
ri
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
)
);
ri
->
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
comprbuf
,
cdatalen
)
);
fn
=
jffs2_write_dnode
(
c
,
f
,
ri
,
comprbuf
,
cdatalen
,
phys_ofs
,
NULL
);
...
...
@@ -367,12 +386,13 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
return
ret
;
}
ri
->
data_crc
=
0
;
ri
->
node_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
ri
->
data_crc
=
cpu_to_je32
(
0
)
;
ri
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
)
);
fn
=
jffs2_write_dnode
(
c
,
f
,
ri
,
NULL
,
0
,
phys_ofs
,
&
writtenlen
);
D1
(
printk
(
KERN_DEBUG
"jffs2_do_create created file with mode 0x%x
\n
"
,
ri
->
mode
));
D1
(
printk
(
KERN_DEBUG
"jffs2_do_create created file with mode 0x%x
\n
"
,
je32_to_cpu
(
ri
->
mode
)));
if
(
IS_ERR
(
fn
))
{
D1
(
printk
(
KERN_DEBUG
"jffs2_write_dnode() failed
\n
"
));
...
...
@@ -413,19 +433,19 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
down
(
&
dir_f
->
sem
);
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
dir_f
->
inocache
->
ino
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
pino
=
cpu_to_je32
(
dir_f
->
inocache
->
ino
)
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
ri
->
ino
;
rd
->
mctime
=
ri
->
ctime
;
rd
->
nsize
=
namelen
;
rd
->
type
=
DT_REG
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
name_crc
=
c
rc32
(
0
,
name
,
namelen
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
pu_to_je32
(
crc32
(
0
,
name
,
namelen
)
);
fd
=
jffs2_write_dirent
(
c
,
dir_f
,
rd
,
name
,
namelen
,
phys_ofs
,
&
writtenlen
);
...
...
@@ -471,19 +491,19 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
down
(
&
dir_f
->
sem
);
/* Build a deletion node */
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
pino
=
dir_f
->
inocache
->
ino
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
ino
=
0
;
rd
->
mctime
=
get_seconds
(
);
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
cpu_to_je32
(
dir_f
->
inocache
->
ino
)
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
cpu_to_je32
(
0
)
;
rd
->
mctime
=
cpu_to_je32
(
get_seconds
()
);
rd
->
nsize
=
namelen
;
rd
->
type
=
DT_UNKNOWN
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
name_crc
=
c
rc32
(
0
,
name
,
namelen
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
pu_to_je32
(
crc32
(
0
,
name
,
namelen
)
);
fd
=
jffs2_write_dirent
(
c
,
dir_f
,
rd
,
name
,
namelen
,
phys_ofs
,
NULL
);
...
...
@@ -498,7 +518,6 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
/* File it. This will mark the old one obsolete. */
jffs2_add_fd_to_list
(
c
,
fd
,
&
dir_f
->
dents
);
jffs2_complete_reservation
(
c
);
up
(
&
dir_f
->
sem
);
/* dead_f is NULL if this was a rename not a real unlink */
...
...
@@ -529,6 +548,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
up
(
&
dead_f
->
sem
);
}
jffs2_complete_reservation
(
c
);
return
0
;
}
...
...
@@ -553,21 +574,21 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
down
(
&
dir_f
->
sem
);
/* Build a deletion node */
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
pino
=
dir_f
->
inocache
->
ino
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
ino
=
ino
;
rd
->
mctime
=
get_seconds
(
);
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
cpu_to_je32
(
dir_f
->
inocache
->
ino
)
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
cpu_to_je32
(
ino
)
;
rd
->
mctime
=
cpu_to_je32
(
get_seconds
()
);
rd
->
nsize
=
namelen
;
rd
->
type
=
type
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
name_crc
=
c
rc32
(
0
,
name
,
namelen
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
pu_to_je32
(
crc32
(
0
,
name
,
namelen
)
);
fd
=
jffs2_write_dirent
(
c
,
dir_f
,
rd
,
name
,
namelen
,
phys_ofs
,
NULL
);
...
...
fs/jffs2/writev.c
View file @
20fed049
...
...
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: writev.c,v 1.
2 2002/05/20 14:56:39
dwmw2 Exp $
* $Id: writev.c,v 1.
3 2002/08/08 08:35:21
dwmw2 Exp $
*
*/
...
...
@@ -28,7 +28,7 @@ static inline int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs
for
(
i
=
0
;
i
<
count
;
i
++
)
{
if
(
!
vecs
[
i
].
iov_len
)
continue
;
mtd
->
write
(
mtd
,
to
,
vecs
[
i
].
iov_len
,
&
thislen
,
vecs
[
i
].
iov_base
);
ret
=
mtd
->
write
(
mtd
,
to
,
vecs
[
i
].
iov_len
,
&
thislen
,
vecs
[
i
].
iov_base
);
totlen
+=
thislen
;
if
(
ret
||
thislen
!=
vecs
[
i
].
iov_len
)
break
;
...
...
include/linux/jffs2.h
View file @
20fed049
...
...
@@ -8,7 +8,7 @@
* For licensing information, see the file 'LICENCE' in the
* jffs2 directory.
*
* $Id: jffs2.h,v 1.2
4 2002/05/20 14:56:3
7 dwmw2 Exp $
* $Id: jffs2.h,v 1.2
5 2002/08/20 21:37:2
7 dwmw2 Exp $
*
*/
...
...
@@ -68,30 +68,65 @@
compression type */
/* These can go once we've made sure we've caught all uses without
byteswapping */
typedef
struct
{
uint32_t
v32
;
}
__attribute__
((
packed
))
jint32_t
;
typedef
struct
{
uint16_t
v16
;
}
__attribute__
((
packed
))
jint16_t
;
#define JFFS2_NATIVE_ENDIAN
#if defined(JFFS2_NATIVE_ENDIAN)
#define cpu_to_je16(x) ((jint16_t){x})
#define cpu_to_je32(x) ((jint32_t){x})
#define je16_to_cpu(x) ((x).v16)
#define je32_to_cpu(x) ((x).v32)
#elif defined(JFFS2_BIG_ENDIAN)
#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)})
#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
#define je16_to_cpu(x) (be16_to_cpu(x.v16))
#define je32_to_cpu(x) (be32_to_cpu(x.v32))
#elif defined(JFFS2_LITTLE_ENDIAN)
#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)})
#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
#define je16_to_cpu(x) (le16_to_cpu(x.v16))
#define je32_to_cpu(x) (le32_to_cpu(x.v32))
#else
#error wibble
#endif
struct
jffs2_unknown_node
{
/* All start like this */
u
int16_t
magic
;
u
int16_t
nodetype
;
u
int32_t
totlen
;
/* So we can skip over nodes we don't grok */
u
int32_t
hdr_crc
;
j
int16_t
magic
;
j
int16_t
nodetype
;
j
int32_t
totlen
;
/* So we can skip over nodes we don't grok */
j
int32_t
hdr_crc
;
}
__attribute__
((
packed
));
struct
jffs2_raw_dirent
{
u
int16_t
magic
;
u
int16_t
nodetype
;
/* == JFFS_NODETYPE_DIRENT */
u
int32_t
totlen
;
u
int32_t
hdr_crc
;
u
int32_t
pino
;
u
int32_t
version
;
u
int32_t
ino
;
/* == zero for unlink */
u
int32_t
mctime
;
j
int16_t
magic
;
j
int16_t
nodetype
;
/* == JFFS_NODETYPE_DIRENT */
j
int32_t
totlen
;
j
int32_t
hdr_crc
;
j
int32_t
pino
;
j
int32_t
version
;
j
int32_t
ino
;
/* == zero for unlink */
j
int32_t
mctime
;
uint8_t
nsize
;
uint8_t
type
;
uint8_t
unused
[
2
];
u
int32_t
node_crc
;
u
int32_t
name_crc
;
j
int32_t
node_crc
;
j
int32_t
name_crc
;
uint8_t
name
[
0
];
}
__attribute__
((
packed
));
...
...
@@ -103,27 +138,27 @@ struct jffs2_raw_dirent
*/
struct
jffs2_raw_inode
{
u
int16_t
magic
;
/* A constant magic number. */
u
int16_t
nodetype
;
/* == JFFS_NODETYPE_INODE */
u
int32_t
totlen
;
/* Total length of this node (inc data, etc.) */
u
int32_t
hdr_crc
;
u
int32_t
ino
;
/* Inode number. */
u
int32_t
version
;
/* Version number. */
u
int32_t
mode
;
/* The file's type or mode. */
u
int16_t
uid
;
/* The file's owner. */
u
int16_t
gid
;
/* The file's group. */
u
int32_t
isize
;
/* Total resultant size of this inode (used for truncations) */
u
int32_t
atime
;
/* Last access time. */
u
int32_t
mtime
;
/* Last modification time. */
u
int32_t
ctime
;
/* Change time. */
u
int32_t
offset
;
/* Where to begin to write. */
u
int32_t
csize
;
/* (Compressed) data size */
u
int32_t
dsize
;
/* Size of the node's data. (after decompression) */
j
int16_t
magic
;
/* A constant magic number. */
j
int16_t
nodetype
;
/* == JFFS_NODETYPE_INODE */
j
int32_t
totlen
;
/* Total length of this node (inc data, etc.) */
j
int32_t
hdr_crc
;
j
int32_t
ino
;
/* Inode number. */
j
int32_t
version
;
/* Version number. */
j
int32_t
mode
;
/* The file's type or mode. */
j
int16_t
uid
;
/* The file's owner. */
j
int16_t
gid
;
/* The file's group. */
j
int32_t
isize
;
/* Total resultant size of this inode (used for truncations) */
j
int32_t
atime
;
/* Last access time. */
j
int32_t
mtime
;
/* Last modification time. */
j
int32_t
ctime
;
/* Change time. */
j
int32_t
offset
;
/* Where to begin to write. */
j
int32_t
csize
;
/* (Compressed) data size */
j
int32_t
dsize
;
/* Size of the node's data. (after decompression) */
uint8_t
compr
;
/* Compression algorithm used */
uint8_t
usercompr
;
/* Compression algorithm requested by the user */
u
int16_t
flags
;
/* See JFFS2_INO_FLAG_* */
u
int32_t
data_crc
;
/* CRC for the (compressed) data. */
u
int32_t
node_crc
;
/* CRC for the raw inode (excluding data) */
j
int16_t
flags
;
/* See JFFS2_INO_FLAG_* */
j
int32_t
data_crc
;
/* CRC for the (compressed) data. */
j
int32_t
node_crc
;
/* CRC for the raw inode (excluding data) */
// uint8_t data[dsize];
}
__attribute__
((
packed
));
...
...
include/linux/jffs2_fs_i.h
View file @
20fed049
/* $Id: jffs2_fs_i.h,v 1.1
2 2002/03/06 13:59:21
dwmw2 Exp $ */
/* $Id: jffs2_fs_i.h,v 1.1
5 2002/11/12 09:42:49
dwmw2 Exp $ */
#ifndef _JFFS2_FS_I
#define _JFFS2_FS_I
#include <linux/version.h>
#include <linux/rbtree.h>
struct
jffs2_inode_info
{
/* We need an internal semaphore similar to inode->i_sem.
...
...
@@ -18,7 +19,7 @@ struct jffs2_inode_info {
uint32_t
highest_version
;
/* List of data fragments which make up the file */
struct
jffs2_node_frag
*
fraglist
;
struct
rb_root
fragtree
;
/* There may be one datanode which isn't referenced by any of the
above fragments, if it contains a metadata update but no actual
...
...
include/linux/jffs2_fs_sb.h
View file @
20fed049
/* $Id: jffs2_fs_sb.h,v 1.3
2 2002/07/23 14:35:34
dwmw2 Exp $ */
/* $Id: jffs2_fs_sb.h,v 1.3
5 2002/11/12 09:42:18
dwmw2 Exp $ */
#ifndef _JFFS2_FS_SB
#define _JFFS2_FS_SB
...
...
@@ -21,6 +21,8 @@ struct jffs2_sb_info {
struct
mtd_info
*
mtd
;
uint32_t
highest_ino
;
uint32_t
checked_ino
;
unsigned
int
flags
;
struct
task_struct
*
gc_task
;
/* GC task struct */
...
...
@@ -38,10 +40,12 @@ struct jffs2_sb_info {
uint32_t
flash_size
;
uint32_t
used_size
;
uint32_t
dirty_size
;
uint32_t
wasted_size
;
uint32_t
free_size
;
uint32_t
erasing_size
;
uint32_t
bad_size
;
uint32_t
sector_size
;
uint32_t
unchecked_size
;
uint32_t
nr_free_blocks
;
uint32_t
nr_erasing_blocks
;
...
...
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