Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
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
...
@@ -531,8 +531,8 @@ config JFFS2_FS
levelling, compression and support for hard links. You cannot use
levelling, compression and support for hard links. You cannot use
this on normal block devices, only on 'MTD' devices.
this on normal block devices, only on 'MTD' devices.
Further information
should be made available soon at
Further information
on the design and implementation of JFFS2 is
<http://sources.redhat.com/jffs2/>.
available at
<http://sources.redhat.com/jffs2/>.
config JFFS2_FS_DEBUG
config JFFS2_FS_DEBUG
int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)"
int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)"
...
@@ -554,6 +554,19 @@ config JFFS2_FS_DEBUG
...
@@ -554,6 +554,19 @@ config JFFS2_FS_DEBUG
config JFFS2_FS_NAND
config JFFS2_FS_NAND
bool "JFFS2 support for NAND flash (EXPERIMENTAL)"
bool "JFFS2 support for NAND flash (EXPERIMENTAL)"
depends on JFFS2_FS && 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
config CRAMFS
tristate "Compressed ROM file system support"
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()?
- disable compression in commit_write()?
- fine-tune the allocation / GC thresholds
- fine-tune the allocation / GC thresholds
...
@@ -23,22 +23,18 @@ $Id: TODO,v 1.9 2002/07/11 10:39:04 dwmw2 Exp $
...
@@ -23,22 +23,18 @@ $Id: TODO,v 1.9 2002/07/11 10:39:04 dwmw2 Exp $
- Optimisations:
- Optimisations:
- Stop GC from decompressing and immediately recompressing nodes which could
- 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
- 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 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
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
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
_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
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
- 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
the full dirent, we only need to go to the flash in lookup() when we think we've
got a match, and in readdir().
got a match, and in readdir().
- Doubly-linked next_in_ino list to allow us to free obsoleted raw_node_refs immediately?
- 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
- Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into
jffs2_mark_node_obsolete(). Can all callers work it out?
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
- Remove size from jffs2_raw_node_frag.
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.
fs/jffs2/background.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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)
...
@@ -83,6 +83,7 @@ static int jffs2_garbage_collect_thread(void *_c)
struct
jffs2_sb_info
*
c
=
_c
;
struct
jffs2_sb_info
*
c
=
_c
;
daemonize
();
daemonize
();
c
->
gc_task
=
current
;
c
->
gc_task
=
current
;
up
(
&
c
->
gc_thread_start
);
up
(
&
c
->
gc_thread_start
);
...
@@ -91,10 +92,10 @@ static int jffs2_garbage_collect_thread(void *_c)
...
@@ -91,10 +92,10 @@ static int jffs2_garbage_collect_thread(void *_c)
set_user_nice
(
current
,
10
);
set_user_nice
(
current
,
10
);
for
(;;)
{
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
));
siginitsetinv
(
&
current
->
blocked
,
sigmask
(
SIGHUP
)
|
sigmask
(
SIGKILL
)
|
sigmask
(
SIGSTOP
)
|
sigmask
(
SIGCONT
));
recalc_sigpending
();
recalc_sigpending
();
spin_unlock_irq
(
&
current
->
sig
->
sig
lock
);
spin_unlock_irq
(
&
current
_sig_
lock
);
if
(
!
thread_should_wake
(
c
))
{
if
(
!
thread_should_wake
(
c
))
{
set_current_state
(
TASK_INTERRUPTIBLE
);
set_current_state
(
TASK_INTERRUPTIBLE
);
...
@@ -112,11 +113,11 @@ static int jffs2_garbage_collect_thread(void *_c)
...
@@ -112,11 +113,11 @@ static int jffs2_garbage_collect_thread(void *_c)
*/
*/
while
(
signal_pending
(
current
))
{
while
(
signal_pending
(
current
))
{
siginfo_t
info
;
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
);
signr
=
dequeue_signal
(
&
current
->
blocked
,
&
info
);
spin_unlock_irq
(
&
current
->
sig
->
sig
lock
);
spin_unlock_irq
(
&
current_sig_
lock
);
switch
(
signr
)
{
switch
(
signr
)
{
case
SIGSTOP
:
case
SIGSTOP
:
...
@@ -137,14 +138,13 @@ static int jffs2_garbage_collect_thread(void *_c)
...
@@ -137,14 +138,13 @@ static int jffs2_garbage_collect_thread(void *_c)
break
;
break
;
default:
default:
D1
(
printk
(
KERN_DEBUG
"jffs2_garbage_collect_thread(): signal %ld received
\n
"
,
signr
));
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. */
/* 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
));
siginitsetinv
(
&
current
->
blocked
,
sigmask
(
SIGKILL
)
|
sigmask
(
SIGSTOP
)
|
sigmask
(
SIGCONT
));
recalc_sigpending
();
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
"
));
D1
(
printk
(
KERN_DEBUG
"jffs2_garbage_collect_thread(): pass
\n
"
));
jffs2_garbage_collect_pass
(
c
);
jffs2_garbage_collect_pass
(
c
);
...
@@ -153,23 +153,20 @@ static int jffs2_garbage_collect_thread(void *_c)
...
@@ -153,23 +153,20 @@ static int jffs2_garbage_collect_thread(void *_c)
static
int
thread_should_wake
(
struct
jffs2_sb_info
*
c
)
static
int
thread_should_wake
(
struct
jffs2_sb_info
*
c
)
{
{
uint32_t
gcnodeofs
=
0
;
int
ret
=
0
;
int
ret
;
/* Don't count any progress we've already made through the gcblock
if
(
c
->
unchecked_size
)
{
as dirty space, for the purposes of this calculation */
D1
(
printk
(
KERN_DEBUG
"thread_should_wake(): unchecked_size %d, checked_ino #%d
\n
"
,
if
(
c
->
gcblock
&&
c
->
gcblock
->
gc_node
)
c
->
unchecked_size
,
c
->
checked_ino
));
gcnodeofs
=
c
->
gcblock
->
gc_node
->
flash_offset
&
~
3
&
(
c
->
sector_size
-
1
);
return
1
;
}
if
(
c
->
nr_free_blocks
+
c
->
nr_erasing_blocks
<
JFFS2_RESERVED_BLOCKS_GCTRIGGER
&&
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
;
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
"
,
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
,
c
->
nr_free_blocks
,
c
->
nr_erasing_blocks
,
c
->
dirty_size
,
ret
?
"yes"
:
"no"
));
c
->
dirty_size
-
gcnodeofs
,
ret
?
"yes"
:
"no"
));
return
ret
;
return
ret
;
}
}
fs/jffs2/build.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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)
...
@@ -43,8 +43,9 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
return
ret
;
return
ret
;
D1
(
printk
(
KERN_DEBUG
"Scanned flash completely
\n
"
));
D1
(
printk
(
KERN_DEBUG
"Scanned flash completely
\n
"
));
/* Now build the data map for each inode, marking obsoleted nodes
D1
(
jffs2_dump_block_lists
(
c
));
as such, and also increase nlink of any children. */
/* Now scan the directory tree, increasing nlink according to every dirent found. */
for_each_inode
(
i
,
c
,
ic
)
{
for_each_inode
(
i
,
c
,
ic
)
{
D1
(
printk
(
KERN_DEBUG
"Pass 1: ino #%u
\n
"
,
ic
->
ino
));
D1
(
printk
(
KERN_DEBUG
"Pass 1: ino #%u
\n
"
,
ic
->
ino
));
ret
=
jffs2_build_inode_pass1
(
c
,
ic
);
ret
=
jffs2_build_inode_pass1
(
c
,
ic
);
...
@@ -52,8 +53,10 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
...
@@ -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
));
D1
(
printk
(
KERN_WARNING
"Eep. jffs2_build_inode_pass1 for ino %d returned %d
\n
"
,
ic
->
ino
,
ret
));
return
ret
;
return
ret
;
}
}
cond_resched
();
}
}
D1
(
printk
(
KERN_DEBUG
"Pass 1 complete
\n
"
));
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
/* Next, scan for inodes with nlink == 0 and remove them. If
they were directories, then decrement the nlink of their
they were directories, then decrement the nlink of their
...
@@ -68,6 +71,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
...
@@ -68,6 +71,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
if
(
ic
->
nlink
)
if
(
ic
->
nlink
)
continue
;
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
);
ret
=
jffs2_build_remove_unlinked_inode
(
c
,
ic
);
if
(
ret
)
if
(
ret
)
break
;
break
;
...
@@ -75,30 +80,29 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
...
@@ -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
and furthermore that it had children and their nlink has now
gone to zero too. So we have to restart the scan. */
gone to zero too. So we have to restart the scan. */
}
}
D1
(
jffs2_dump_block_lists
(
c
));
cond_resched
();
}
while
(
ret
==
-
EAGAIN
);
}
while
(
ret
==
-
EAGAIN
);
D1
(
printk
(
KERN_DEBUG
"Pass 2 complete
\n
"
));
D1
(
printk
(
KERN_DEBUG
"Pass 2 complete
\n
"
));
/* Finally, we can scan again and free the dirent nodes and scan_info structs */
/* Finally, we can scan again and free the dirent nodes and scan_info structs */
for_each_inode
(
i
,
c
,
ic
)
{
for_each_inode
(
i
,
c
,
ic
)
{
struct
jffs2_scan_info
*
scan
=
ic
->
scan
;
struct
jffs2_full_dirent
*
fd
;
struct
jffs2_full_dirent
*
fd
;
D1
(
printk
(
KERN_DEBUG
"Pass 3: ino #%u, ic %p, nodes %p
\n
"
,
ic
->
ino
,
ic
,
ic
->
nodes
));
D1
(
printk
(
KERN_DEBUG
"Pass 3: ino #%u, ic %p, nodes %p
\n
"
,
ic
->
ino
,
ic
,
ic
->
nodes
));
if
(
!
scan
)
{
if
(
ic
->
nlink
)
{
while
(
ic
->
scan_dents
)
{
D1
(
printk
(
KERN_WARNING
"Why no scan struct for ino #%u which has nlink %d?
\n
"
,
ic
->
ino
,
ic
->
nlink
));
fd
=
ic
->
scan_dents
;
}
ic
->
scan_dents
=
fd
->
next
;
continue
;
}
ic
->
scan
=
NULL
;
while
(
scan
->
dents
)
{
fd
=
scan
->
dents
;
scan
->
dents
=
fd
->
next
;
jffs2_free_full_dirent
(
fd
);
jffs2_free_full_dirent
(
fd
);
}
}
kfree
(
scan
);
ic
->
scan_dents
=
NULL
;
cond_resched
();
}
}
D1
(
printk
(
KERN_DEBUG
"Pass 3 complete
\n
"
));
D1
(
printk
(
KERN_DEBUG
"Pass 3 complete
\n
"
));
D1
(
jffs2_dump_block_lists
(
c
));
/* Rotate the lists by some number to ensure wear levelling */
/* Rotate the lists by some number to ensure wear levelling */
jffs2_rotate_lists
(
c
);
jffs2_rotate_lists
(
c
);
...
@@ -108,83 +112,21 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *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
)
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_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
));
D1
(
printk
(
KERN_DEBUG
"jffs2_build_inode building inode #%u
\n
"
,
ic
->
ino
));
if
(
ic
->
ino
>
c
->
highest_ino
)
if
(
ic
->
ino
>
c
->
highest_ino
)
c
->
highest_ino
=
ic
->
ino
;
c
->
highest_ino
=
ic
->
ino
;
if
(
!
ic
->
scan
->
tmpnodes
&&
ic
->
ino
!=
1
)
{
/* For each child, increase nlink */
D1
(
printk
(
KERN_DEBUG
"jffs2_build_inode: ino #%u has no data nodes!
\n
"
,
ic
->
ino
));
for
(
fd
=
ic
->
scan_dents
;
fd
;
fd
=
fd
->
next
)
{
}
/* 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
)
{
struct
jffs2_inode_cache
*
child_ic
;
struct
jffs2_inode_cache
*
child_ic
;
if
(
!
fd
->
ino
)
if
(
!
fd
->
ino
)
continue
;
continue
;
/* XXX: Can get high latency here with huge directories */
child_ic
=
jffs2_get_ino_cache
(
c
,
fd
->
ino
);
child_ic
=
jffs2_get_ino_cache
(
c
,
fd
->
ino
);
if
(
!
child_ic
)
{
if
(
!
child_ic
)
{
printk
(
KERN_NOTICE
"Eep. Child
\"
%s
\"
(ino #%u) of dir ino #%u doesn't exist!
\n
"
,
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
...
@@ -212,26 +154,33 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
struct
jffs2_full_dirent
*
fd
;
struct
jffs2_full_dirent
*
fd
;
int
ret
=
0
;
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
));
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
)
{
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
);
jffs2_mark_node_obsolete
(
c
,
raw
);
}
}
if
(
ic
->
scan
->
dents
)
{
if
(
ic
->
scan_dents
)
{
printk
(
KERN_NOTICE
"Inode #%u was a directory with children - removing those too...
\n
"
,
ic
->
ino
);
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
;
struct
jffs2_inode_cache
*
child_ic
;
fd
=
ic
->
scan
->
dents
;
fd
=
ic
->
scan_dents
;
ic
->
scan
->
dents
=
fd
->
next
;
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
"
,
D1
(
printk
(
KERN_DEBUG
"Removing child
\"
%s
\"
, ino #%u
\n
"
,
fd
->
name
,
fd
->
ino
));
fd
->
name
,
fd
->
ino
));
...
@@ -239,6 +188,7 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
...
@@ -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
);
child_ic
=
jffs2_get_ino_cache
(
c
,
fd
->
ino
);
if
(
!
child_ic
)
{
if
(
!
child_ic
)
{
printk
(
KERN_NOTICE
"Cannot remove child
\"
%s
\"
, ino #%u, because it doesn't exist
\n
"
,
fd
->
name
,
fd
->
ino
);
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
;
continue
;
}
}
jffs2_free_full_dirent
(
fd
);
jffs2_free_full_dirent
(
fd
);
...
@@ -246,8 +196,6 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
...
@@ -246,8 +196,6 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
}
}
ret
=
-
EAGAIN
;
ret
=
-
EAGAIN
;
}
}
kfree
(
ic
->
scan
);
ic
->
scan
=
NULL
;
/*
/*
We don't delete the inocache from the hash list and free it yet.
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)
...
@@ -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
].
offset
=
i
*
c
->
sector_size
;
c
->
blocks
[
i
].
free_size
=
c
->
sector_size
;
c
->
blocks
[
i
].
free_size
=
c
->
sector_size
;
c
->
blocks
[
i
].
dirty_size
=
0
;
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
].
used_size
=
0
;
c
->
blocks
[
i
].
first_node
=
NULL
;
c
->
blocks
[
i
].
first_node
=
NULL
;
c
->
blocks
[
i
].
last_node
=
NULL
;
c
->
blocks
[
i
].
last_node
=
NULL
;
...
...
fs/jffs2/dir.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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)
...
@@ -211,7 +211,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode)
return
ret
;
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
;
dir_i
->
i_mtime
.
tv_nsec
=
dir_i
->
i_ctime
.
tv_nsec
=
0
;
jffs2_free_raw_inode
(
ri
);
jffs2_free_raw_inode
(
ri
);
...
@@ -234,6 +234,7 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
...
@@ -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
,
ret
=
jffs2_do_unlink
(
c
,
dir_f
,
dentry
->
d_name
.
name
,
dentry
->
d_name
.
len
,
dead_f
);
dentry
->
d_name
.
len
,
dead_f
);
if
(
dead_f
->
inocache
)
dentry
->
d_inode
->
i_nlink
=
dead_f
->
inocache
->
nlink
;
dentry
->
d_inode
->
i_nlink
=
dead_f
->
inocache
->
nlink
;
return
ret
;
return
ret
;
}
}
...
@@ -248,6 +249,10 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
...
@@ -248,6 +249,10 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
int
ret
;
int
ret
;
uint8_t
type
;
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
))
if
(
S_ISDIR
(
old_dentry
->
d_inode
->
i_mode
))
return
-
EPERM
;
return
-
EPERM
;
...
@@ -318,13 +323,14 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
...
@@ -318,13 +323,14 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
f
=
JFFS2_INODE_INFO
(
inode
);
f
=
JFFS2_INODE_INFO
(
inode
);
inode
->
i_size
=
ri
->
isize
=
ri
->
dsize
=
ri
->
csize
=
strlen
(
target
);
inode
->
i_size
=
strlen
(
target
);
ri
->
totlen
=
sizeof
(
*
ri
)
+
ri
->
dsize
;
ri
->
isize
=
ri
->
dsize
=
ri
->
csize
=
cpu_to_je32
(
inode
->
i_size
);
ri
->
hdr_crc
=
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
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
->
compr
=
JFFS2_COMPR_NONE
;
ri
->
data_crc
=
c
rc32
(
0
,
target
,
strlen
(
target
));
ri
->
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
target
,
strlen
(
target
)
));
ri
->
node_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
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
);
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
...
@@ -370,19 +376,19 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
dir_f
=
JFFS2_INODE_INFO
(
dir_i
);
dir_f
=
JFFS2_INODE_INFO
(
dir_i
);
down
(
&
dir_f
->
sem
);
down
(
&
dir_f
->
sem
);
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
dir_i
->
i_ino
;
rd
->
pino
=
cpu_to_je32
(
dir_i
->
i_ino
)
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
inode
->
i_ino
;
rd
->
ino
=
cpu_to_je32
(
inode
->
i_ino
)
;
rd
->
mctime
=
get_seconds
(
);
rd
->
mctime
=
cpu_to_je32
(
get_seconds
()
);
rd
->
nsize
=
namelen
;
rd
->
nsize
=
namelen
;
rd
->
type
=
DT_LNK
;
rd
->
type
=
DT_LNK
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
rc32
(
0
,
dentry
->
d_name
.
name
,
namelen
);
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
);
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
...
@@ -396,7 +402,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
return
PTR_ERR
(
fd
);
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_mtime
.
tv_nsec
=
dir_i
->
i_ctime
.
tv_nsec
=
0
;
jffs2_free_raw_dirent
(
rd
);
jffs2_free_raw_dirent
(
rd
);
...
@@ -461,8 +467,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
...
@@ -461,8 +467,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
f
=
JFFS2_INODE_INFO
(
inode
);
f
=
JFFS2_INODE_INFO
(
inode
);
ri
->
data_crc
=
0
;
ri
->
data_crc
=
cpu_to_je32
(
0
)
;
ri
->
node_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
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
);
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)
...
@@ -508,19 +514,19 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
dir_f
=
JFFS2_INODE_INFO
(
dir_i
);
dir_f
=
JFFS2_INODE_INFO
(
dir_i
);
down
(
&
dir_f
->
sem
);
down
(
&
dir_f
->
sem
);
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
dir_i
->
i_ino
;
rd
->
pino
=
cpu_to_je32
(
dir_i
->
i_ino
)
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
inode
->
i_ino
;
rd
->
ino
=
cpu_to_je32
(
inode
->
i_ino
)
;
rd
->
mctime
=
get_seconds
(
);
rd
->
mctime
=
cpu_to_je32
(
get_seconds
()
);
rd
->
nsize
=
namelen
;
rd
->
nsize
=
namelen
;
rd
->
type
=
DT_DIR
;
rd
->
type
=
DT_DIR
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
rc32
(
0
,
dentry
->
d_name
.
name
,
namelen
);
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
);
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)
...
@@ -534,7 +540,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
return
PTR_ERR
(
fd
);
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_mtime
.
tv_nsec
=
dir_i
->
i_ctime
.
tv_nsec
=
0
;
dir_i
->
i_nlink
++
;
dir_i
->
i_nlink
++
;
...
@@ -617,13 +623,13 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
...
@@ -617,13 +623,13 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
f
=
JFFS2_INODE_INFO
(
inode
);
f
=
JFFS2_INODE_INFO
(
inode
);
ri
->
dsize
=
ri
->
csize
=
devlen
;
ri
->
dsize
=
ri
->
csize
=
cpu_to_je32
(
devlen
)
;
ri
->
totlen
=
sizeof
(
*
ri
)
+
ri
->
csize
;
ri
->
totlen
=
cpu_to_je32
(
sizeof
(
*
ri
)
+
devlen
)
;
ri
->
hdr_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
->
compr
=
JFFS2_COMPR_NONE
;
ri
->
compr
=
JFFS2_COMPR_NONE
;
ri
->
data_crc
=
c
rc32
(
0
,
&
dev
,
devlen
);
ri
->
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
dev
,
devlen
)
);
ri
->
node_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
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
);
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
...
@@ -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
);
dir_f
=
JFFS2_INODE_INFO
(
dir_i
);
down
(
&
dir_f
->
sem
);
down
(
&
dir_f
->
sem
);
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
dir_i
->
i_ino
;
rd
->
pino
=
cpu_to_je32
(
dir_i
->
i_ino
)
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
inode
->
i_ino
;
rd
->
ino
=
cpu_to_je32
(
inode
->
i_ino
)
;
rd
->
mctime
=
get_seconds
(
);
rd
->
mctime
=
cpu_to_je32
(
get_seconds
()
);
rd
->
nsize
=
namelen
;
rd
->
nsize
=
namelen
;
/* XXX: This is ugly. */
/* XXX: This is ugly. */
rd
->
type
=
(
mode
&
S_IFMT
)
>>
12
;
rd
->
type
=
(
mode
&
S_IFMT
)
>>
12
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
rc32
(
0
,
dentry
->
d_name
.
name
,
namelen
);
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
);
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
...
@@ -698,7 +704,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
return
PTR_ERR
(
fd
);
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_mtime
.
tv_nsec
=
dir_i
->
i_ctime
.
tv_nsec
=
0
;
jffs2_free_raw_dirent
(
rd
);
jffs2_free_raw_dirent
(
rd
);
...
@@ -790,6 +796,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
...
@@ -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
);
struct
jffs2_inode_info
*
f
=
JFFS2_INODE_INFO
(
old_dentry
->
d_inode
);
down
(
&
f
->
sem
);
down
(
&
f
->
sem
);
old_dentry
->
d_inode
->
i_nlink
++
;
old_dentry
->
d_inode
->
i_nlink
++
;
if
(
f
->
inocache
)
f
->
inocache
->
nlink
++
;
f
->
inocache
->
nlink
++
;
up
(
&
f
->
sem
);
up
(
&
f
->
sem
);
...
...
fs/jffs2/erase.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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 {
...
@@ -27,6 +27,7 @@ struct erase_priv_struct {
static
void
jffs2_erase_callback
(
struct
erase_info
*
);
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_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_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
)
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)
...
@@ -81,12 +82,18 @@ void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
else
else
printk
(
KERN_WARNING
"Erase at 0x%08x failed immediately: errno %d
\n
"
,
jeb
->
offset
,
ret
);
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
);
spin_lock_bh
(
&
c
->
erase_completion_lock
);
c
->
erasing_size
-=
c
->
sector_size
;
c
->
bad_size
+=
c
->
sector_size
;
list_del
(
&
jeb
->
list
);
list_del
(
&
jeb
->
list
);
list_add
(
&
jeb
->
list
,
&
c
->
bad_list
);
list_add
(
&
jeb
->
list
,
&
c
->
bad_list
);
c
->
nr_erasing_blocks
--
;
c
->
nr_erasing_blocks
--
;
c
->
bad_size
+=
c
->
sector_size
;
c
->
erasing_size
-=
c
->
sector_size
;
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
wake_up
(
&
c
->
erase_wait
);
wake_up
(
&
c
->
erase_wait
);
}
}
...
@@ -98,12 +105,19 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
...
@@ -98,12 +105,19 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
down
(
&
c
->
erase_free_sem
);
down
(
&
c
->
erase_free_sem
);
spin_lock_bh
(
&
c
->
erase_completion_lock
);
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
);
list_del
(
&
jeb
->
list
);
c
->
erasing_size
+=
c
->
sector_size
;
c
->
erasing_size
+=
c
->
sector_size
;
c
->
free_size
-=
jeb
->
free_size
;
c
->
free_size
-=
jeb
->
free_size
;
...
@@ -116,18 +130,21 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
...
@@ -116,18 +130,21 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
jffs2_erase_block
(
c
,
jeb
);
jffs2_erase_block
(
c
,
jeb
);
}
else
{
BUG
();
}
/* Be nice */
/* Be nice */
cond_resched
();
cond_resched
();
spin_lock_bh
(
&
c
->
erase_completion_lock
);
spin_lock_bh
(
&
c
->
erase_completion_lock
);
}
}
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
D1
(
printk
(
KERN_DEBUG
"jffs2_erase_pending_blocks completed
\n
"
));
D1
(
printk
(
KERN_DEBUG
"jffs2_erase_pending_blocks completed
\n
"
));
up
(
&
c
->
erase_free_sem
);
up
(
&
c
->
erase_free_sem
);
}
}
static
void
jffs2_erase_succeeded
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
)
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
));
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
...
@@ -135,6 +152,8 @@ static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblo
list_del
(
&
jeb
->
list
);
list_del
(
&
jeb
->
list
);
list_add_tail
(
&
jeb
->
list
,
&
c
->
erase_complete_list
);
list_add_tail
(
&
jeb
->
list
,
&
c
->
erase_complete_list
);
spin_unlock
(
&
c
->
erase_completion_lock
);
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)
...
@@ -160,8 +179,6 @@ static void jffs2_erase_callback(struct erase_info *instr)
}
else
{
}
else
{
jffs2_erase_succeeded
(
priv
->
c
,
priv
->
jeb
);
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
);
kfree
(
instr
);
}
}
...
@@ -220,7 +237,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
...
@@ -220,7 +237,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
this
=
ic
->
nodes
;
this
=
ic
->
nodes
;
while
(
this
)
{
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
)
{
if
(
++
i
==
5
)
{
printk
(
"
\n
"
KERN_DEBUG
);
printk
(
"
\n
"
KERN_DEBUG
);
i
=
0
;
i
=
0
;
...
@@ -260,26 +277,22 @@ void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
...
@@ -260,26 +277,22 @@ void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
OFNI_BS_2SFFJ
(
c
)
->
s_dirt
=
1
;
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
;
struct
jffs2_raw_node_ref
*
marker_ref
=
NULL
;
unsigned
char
*
ebuf
;
unsigned
char
*
ebuf
;
size_t
retlen
;
size_t
retlen
;
int
ret
;
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
))
{
if
(
!
jffs2_cleanmarker_oob
(
c
))
{
marker_ref
=
jffs2_alloc_raw_node_ref
();
marker_ref
=
jffs2_alloc_raw_node_ref
();
if
(
!
marker_ref
)
{
if
(
!
marker_ref
)
{
printk
(
KERN_WARNING
"Failed to allocate raw node ref for clean marker
\n
"
);
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
);
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
;
return
;
}
}
}
}
...
@@ -344,37 +357,39 @@ void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
...
@@ -344,37 +357,39 @@ void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
jeb
->
free_size
=
c
->
sector_size
;
jeb
->
free_size
=
c
->
sector_size
;
jeb
->
used_size
=
0
;
jeb
->
used_size
=
0
;
jeb
->
dirty_size
=
0
;
jeb
->
dirty_size
=
0
;
jeb
->
wasted_size
=
0
;
}
else
{
}
else
{
struct
jffs2_unknown_node
marker
=
{
struct
jffs2_unknown_node
marker
=
{
.
magic
=
JFFS2_MAGIC_BITMASK
,
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
,
.
nodetype
=
JFFS2_NODETYPE_CLEANMARKER
,
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_CLEANMARKER
)
,
.
totlen
=
c
->
cleanmarker_size
.
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
)
{
if
(
ret
)
{
printk
(
KERN_WARNING
"Write clean marker to block at 0x%08x failed: %d
\n
"
,
printk
(
KERN_WARNING
"Write clean marker to block at 0x%08x failed: %d
\n
"
,
jeb
->
offset
,
ret
);
jeb
->
offset
,
ret
);
goto
bad2
;
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
"
,
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
;
goto
bad2
;
}
}
marker_ref
->
next_in_ino
=
NULL
;
marker_ref
->
next_in_ino
=
NULL
;
marker_ref
->
next_phys
=
NULL
;
marker_ref
->
next_phys
=
NULL
;
marker_ref
->
flash_offset
=
jeb
->
offset
;
marker_ref
->
flash_offset
=
jeb
->
offset
|
REF_NORMAL
;
marker_ref
->
totlen
=
PAD
(
marker
.
totlen
);
marker_ref
->
totlen
=
PAD
(
je32_to_cpu
(
marker
.
totlen
)
);
jeb
->
first_node
=
jeb
->
last_node
=
marker_ref
;
jeb
->
first_node
=
jeb
->
last_node
=
marker_ref
;
jeb
->
free_size
=
c
->
sector_size
-
marker_ref
->
totlen
;
jeb
->
free_size
=
c
->
sector_size
-
marker_ref
->
totlen
;
jeb
->
used_size
=
marker_ref
->
totlen
;
jeb
->
used_size
=
marker_ref
->
totlen
;
jeb
->
dirty_size
=
0
;
jeb
->
dirty_size
=
0
;
jeb
->
wasted_size
=
0
;
}
}
spin_lock_bh
(
&
c
->
erase_completion_lock
);
spin_lock_bh
(
&
c
->
erase_completion_lock
);
...
@@ -383,12 +398,12 @@ void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
...
@@ -383,12 +398,12 @@ void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
c
->
used_size
+=
jeb
->
used_size
;
c
->
used_size
+=
jeb
->
used_size
;
ACCT_SANITY_CHECK
(
c
,
jeb
);
ACCT_SANITY_CHECK
(
c
,
jeb
);
ACCT_PARANOIA_CHECK
(
jeb
);
D1
(
ACCT_PARANOIA_CHECK
(
jeb
)
);
list_add_tail
(
&
jeb
->
list
,
&
c
->
free_list
);
list_add_tail
(
&
jeb
->
list
,
&
c
->
free_list
);
c
->
nr_erasing_blocks
--
;
c
->
nr_erasing_blocks
--
;
c
->
nr_free_blocks
++
;
c
->
nr_free_blocks
++
;
wake_up
(
&
c
->
erase_wait
);
}
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
wake_up
(
&
c
->
erase_wait
);
}
}
fs/jffs2/file.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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)
...
@@ -139,41 +139,43 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
down
(
&
f
->
sem
);
down
(
&
f
->
sem
);
ivalid
=
iattr
->
ia_valid
;
ivalid
=
iattr
->
ia_valid
;
ri
->
magic
=
JFFS2_MAGIC_BITMASK
;
ri
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
->
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
->
totlen
=
sizeof
(
*
ri
)
+
mdatalen
;
ri
->
totlen
=
cpu_to_je32
(
sizeof
(
*
ri
)
+
mdatalen
)
;
ri
->
hdr_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
->
ino
=
inode
->
i_ino
;
ri
->
ino
=
cpu_to_je32
(
inode
->
i_ino
)
;
ri
->
version
=
++
f
->
highest_version
;
ri
->
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
->
mode
=
(
ivalid
&
ATTR_MODE
)
?
iattr
->
ia_mode
:
inode
->
i_mode
;
ri
->
uid
=
cpu_to_je16
((
ivalid
&
ATTR_UID
)
?
iattr
->
ia_uid
:
inode
->
i_uid
);
ri
->
uid
=
(
ivalid
&
ATTR_UID
)
?
iattr
->
ia_uid
:
inode
->
i_uid
;
ri
->
gid
=
cpu_to_je16
((
ivalid
&
ATTR_GID
)
?
iattr
->
ia_gid
:
inode
->
i_gid
);
ri
->
gid
=
(
ivalid
&
ATTR_GID
)
?
iattr
->
ia_gid
:
inode
->
i_gid
;
if
(
ivalid
&
ATTR_MODE
&&
ri
->
mode
&
S_ISGID
&&
if
(
ivalid
&
ATTR_MODE
)
!
in_group_p
(
ri
->
gid
)
&&
!
capable
(
CAP_FSETID
))
if
(
iattr
->
ia_mode
&
S_ISGID
&&
ri
->
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
->
isize
=
cpu_to_je32
((
ivalid
&
ATTR_SIZE
)
?
iattr
->
ia_size
:
inode
->
i_size
);
ri
->
csize
=
ri
->
dsize
=
mdatalen
;
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
;
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 */
/* It's an extension. Make it a hole node */
ri
->
compr
=
JFFS2_COMPR_ZERO
;
ri
->
compr
=
JFFS2_COMPR_ZERO
;
ri
->
dsize
=
ri
->
isize
-
inode
->
i_size
;
ri
->
dsize
=
cpu_to_je32
(
iattr
->
ia_size
-
inode
->
i_size
)
;
ri
->
offset
=
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
)
if
(
mdatalen
)
ri
->
data_crc
=
c
rc32
(
0
,
mdata
,
mdatalen
);
ri
->
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
mdata
,
mdatalen
)
);
else
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
);
new_metadata
=
jffs2_write_dnode
(
c
,
f
,
ri
,
mdata
,
mdatalen
,
phys_ofs
,
NULL
);
if
(
S_ISLNK
(
inode
->
i_mode
))
if
(
S_ISLNK
(
inode
->
i_mode
))
...
@@ -186,27 +188,27 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
...
@@ -186,27 +188,27 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
return
PTR_ERR
(
new_metadata
);
return
PTR_ERR
(
new_metadata
);
}
}
/* It worked. Update the inode */
/* It worked. Update the inode */
inode
->
i_atime
.
tv_sec
=
ri
->
atime
;
inode
->
i_atime
=
je32_to_cpu
(
ri
->
atime
.
tv_sec
)
;
inode
->
i_ctime
.
tv_sec
=
ri
->
ctime
;
inode
->
i_ctime
=
je32_to_cpu
(
ri
->
ctime
.
tv_sec
)
;
inode
->
i_mtime
.
tv_sec
=
ri
->
mtime
;
inode
->
i_mtime
=
je32_to_cpu
(
ri
->
mtime
.
tv_sec
)
;
inode
->
i_atime
.
tv_nsec
=
inode
->
i_atime
.
tv_nsec
=
inode
->
i_ctime
.
tv_nsec
=
inode
->
i_ctime
.
tv_nsec
=
inode
->
i_mtime
.
tv_nsec
=
0
;
inode
->
i_mtime
.
tv_nsec
=
0
;
inode
->
i_mode
=
ri
->
mode
;
inode
->
i_mode
=
je32_to_cpu
(
ri
->
mode
)
;
inode
->
i_uid
=
ri
->
uid
;
inode
->
i_uid
=
je16_to_cpu
(
ri
->
uid
)
;
inode
->
i_gid
=
ri
->
gid
;
inode
->
i_gid
=
je16_to_cpu
(
ri
->
gid
)
;
old_metadata
=
f
->
metadata
;
old_metadata
=
f
->
metadata
;
if
(
i
node
->
i_size
>
ri
->
i
size
)
{
if
(
i
valid
&
ATTR_SIZE
&&
inode
->
i_size
>
iattr
->
ia_
size
)
{
vmtruncate
(
inode
,
ri
->
i
size
);
vmtruncate
(
inode
,
iattr
->
ia_
size
);
jffs2_truncate_fraglist
(
c
,
&
f
->
frag
list
,
ri
->
i
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
);
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
;
f
->
metadata
=
NULL
;
}
else
{
}
else
{
f
->
metadata
=
new_metadata
;
f
->
metadata
=
new_metadata
;
...
@@ -281,7 +283,6 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
...
@@ -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
;
uint32_t
pageofs
=
pg
->
index
<<
PAGE_CACHE_SHIFT
;
int
ret
=
0
;
int
ret
=
0
;
down
(
&
f
->
sem
);
D1
(
printk
(
KERN_DEBUG
"jffs2_prepare_write()
\n
"
));
D1
(
printk
(
KERN_DEBUG
"jffs2_prepare_write()
\n
"
));
if
(
pageofs
>
inode
->
i_size
)
{
if
(
pageofs
>
inode
->
i_size
)
{
...
@@ -295,30 +296,30 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
...
@@ -295,30 +296,30 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
(
unsigned
int
)
inode
->
i_size
,
pageofs
));
(
unsigned
int
)
inode
->
i_size
,
pageofs
));
ret
=
jffs2_reserve_space
(
c
,
sizeof
(
ri
),
&
phys_ofs
,
&
alloc_len
,
ALLOC_NORMAL
);
ret
=
jffs2_reserve_space
(
c
,
sizeof
(
ri
),
&
phys_ofs
,
&
alloc_len
,
ALLOC_NORMAL
);
if
(
ret
)
{
if
(
ret
)
up
(
&
f
->
sem
);
return
ret
;
return
ret
;
}
down
(
&
f
->
sem
);
memset
(
&
ri
,
0
,
sizeof
(
ri
));
memset
(
&
ri
,
0
,
sizeof
(
ri
));
ri
.
magic
=
JFFS2_MAGIC_BITMASK
;
ri
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
.
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
.
totlen
=
sizeof
(
ri
);
ri
.
totlen
=
cpu_to_je32
(
sizeof
(
ri
)
);
ri
.
hdr_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
.
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
.
ino
=
f
->
inocache
->
ino
;
ri
.
ino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
ri
.
version
=
++
f
->
highest_version
;
ri
.
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
.
mode
=
inode
->
i_mode
;
ri
.
mode
=
cpu_to_je32
(
inode
->
i_mode
)
;
ri
.
uid
=
inode
->
i_uid
;
ri
.
uid
=
cpu_to_je16
(
inode
->
i_uid
)
;
ri
.
gid
=
inode
->
i_gid
;
ri
.
gid
=
cpu_to_je16
(
inode
->
i_gid
)
;
ri
.
isize
=
max
((
uint32_t
)
inode
->
i_size
,
pageofs
);
ri
.
isize
=
cpu_to_je32
(
max
((
uint32_t
)
inode
->
i_size
,
pageofs
)
);
ri
.
atime
=
ri
.
ctime
=
ri
.
mtime
=
get_seconds
(
);
ri
.
atime
=
ri
.
ctime
=
ri
.
mtime
=
cpu_to_je32
(
get_seconds
()
);
ri
.
offset
=
inode
->
i_size
;
ri
.
offset
=
cpu_to_je32
(
inode
->
i_size
)
;
ri
.
dsize
=
pageofs
-
inode
->
i_size
;
ri
.
dsize
=
cpu_to_je32
(
pageofs
-
inode
->
i_size
)
;
ri
.
csize
=
0
;
ri
.
csize
=
cpu_to_je32
(
0
)
;
ri
.
compr
=
JFFS2_COMPR_ZERO
;
ri
.
compr
=
JFFS2_COMPR_ZERO
;
ri
.
node_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
);
ri
.
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
)
);
ri
.
data_crc
=
0
;
ri
.
data_crc
=
cpu_to_je32
(
0
)
;
fn
=
jffs2_write_dnode
(
c
,
f
,
&
ri
,
NULL
,
0
,
phys_ofs
,
NULL
);
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
...
@@ -344,14 +345,16 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
}
}
jffs2_complete_reservation
(
c
);
jffs2_complete_reservation
(
c
);
inode
->
i_size
=
pageofs
;
inode
->
i_size
=
pageofs
;
up
(
&
f
->
sem
);
}
}
/* Read in the page if it wasn't already present, unless it's a whole page */
/* Read in the page if it wasn't already present */
if
(
!
PageUptodate
(
pg
)
&&
(
start
||
end
<
PAGE_CACHE_SIZE
))
{
if
(
!
PageUptodate
(
pg
)
&&
(
start
||
end
<
PAGE_SIZE
))
down
(
&
f
->
sem
);
ret
=
jffs2_do_readpage_nolock
(
inode
,
pg
);
ret
=
jffs2_do_readpage_nolock
(
inode
,
pg
);
D1
(
printk
(
KERN_DEBUG
"end prepare_write()
\n
"
));
up
(
&
f
->
sem
);
up
(
&
f
->
sem
);
}
D1
(
printk
(
KERN_DEBUG
"end prepare_write(). pg->flags %lx
\n
"
,
pg
->
flags
));
return
ret
;
return
ret
;
}
}
...
@@ -367,8 +370,16 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
...
@@ -367,8 +370,16 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
int
ret
=
0
;
int
ret
=
0
;
uint32_t
writtenlen
=
0
;
uint32_t
writtenlen
=
0
;
D1
(
printk
(
KERN_DEBUG
"jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d
\n
"
,
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
));
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
();
ri
=
jffs2_alloc_raw_inode
();
...
@@ -378,16 +389,21 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
...
@@ -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 */
/* Set the fields that the generic jffs2_write_inode_range() code can't find */
ri
->
ino
=
inode
->
i_ino
;
ri
->
ino
=
cpu_to_je32
(
inode
->
i_ino
);
ri
->
mode
=
inode
->
i_mode
;
ri
->
mode
=
cpu_to_je32
(
inode
->
i_mode
);
ri
->
uid
=
inode
->
i_uid
;
ri
->
uid
=
cpu_to_je16
(
inode
->
i_uid
);
ri
->
gid
=
inode
->
i_gid
;
ri
->
gid
=
cpu_to_je16
(
inode
->
i_gid
);
ri
->
isize
=
(
uint32_t
)
inode
->
i_size
;
ri
->
isize
=
cpu_to_je32
((
uint32_t
)
inode
->
i_size
);
ri
->
atime
=
ri
->
ctime
=
ri
->
mtime
=
get_seconds
();
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
);
kmap
(
pg
);
ret
=
jffs2_write_inode_range
(
c
,
f
,
ri
,
page_address
(
pg
)
+
start
,
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
);
kunmap
(
pg
);
if
(
ret
)
{
if
(
ret
)
{
...
@@ -400,7 +416,7 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
...
@@ -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_size
=
(
pg
->
index
<<
PAGE_CACHE_SHIFT
)
+
start
+
writtenlen
;
inode
->
i_blocks
=
(
inode
->
i_size
+
511
)
>>
9
;
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
;
inode
->
i_ctime
.
tv_nsec
=
inode
->
i_mtime
.
tv_nsec
=
0
;
}
}
}
}
...
...
fs/jffs2/fs.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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)
...
@@ -86,13 +86,13 @@ void jffs2_read_inode (struct inode *inode)
up
(
&
f
->
sem
);
up
(
&
f
->
sem
);
return
;
return
;
}
}
inode
->
i_mode
=
latest_node
.
mode
;
inode
->
i_mode
=
je32_to_cpu
(
latest_node
.
mode
)
;
inode
->
i_uid
=
latest_node
.
uid
;
inode
->
i_uid
=
je16_to_cpu
(
latest_node
.
uid
)
;
inode
->
i_gid
=
latest_node
.
gid
;
inode
->
i_gid
=
je16_to_cpu
(
latest_node
.
gid
)
;
inode
->
i_size
=
latest_node
.
isize
;
inode
->
i_size
=
je32_to_cpu
(
latest_node
.
isize
)
;
inode
->
i_atime
.
tv_sec
=
latest_node
.
atime
;
inode
->
i_atime
=
je32_to_cpu
(
latest_node
.
atime
)
;
inode
->
i_mtime
.
tv_sec
=
latest_node
.
mtime
;
inode
->
i_mtime
=
je32_to_cpu
(
latest_node
.
mtime
)
;
inode
->
i_ctime
.
tv_sec
=
latest_node
.
ctime
;
inode
->
i_ctime
=
je32_to_cpu
(
latest_node
.
ctime
)
;
inode
->
i_atime
.
tv_nsec
=
inode
->
i_atime
.
tv_nsec
=
inode
->
i_mtime
.
tv_nsec
=
inode
->
i_mtime
.
tv_nsec
=
inode
->
i_ctime
.
tv_nsec
=
0
;
inode
->
i_ctime
.
tv_nsec
=
0
;
...
@@ -192,19 +192,9 @@ void jffs2_write_super (struct super_block *sb)
...
@@ -192,19 +192,9 @@ void jffs2_write_super (struct super_block *sb)
if
(
sb
->
s_flags
&
MS_RDONLY
)
if
(
sb
->
s_flags
&
MS_RDONLY
)
return
;
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_garbage_collect_trigger
(
c
);
jffs2_erase_pending_blocks
(
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
...
@@ -232,16 +222,16 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
memset
(
ri
,
0
,
sizeof
(
*
ri
));
memset
(
ri
,
0
,
sizeof
(
*
ri
));
/* Set OS-specific defaults for new inodes */
/* 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
)
{
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
))
if
(
S_ISDIR
(
mode
))
ri
->
mode
|=
S_ISGID
;
mode
|=
S_ISGID
;
}
else
{
}
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
);
ret
=
jffs2_do_new_inode
(
c
,
f
,
mode
,
ri
);
if
(
ret
)
{
if
(
ret
)
{
make_bad_inode
(
inode
);
make_bad_inode
(
inode
);
...
@@ -249,12 +239,14 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
...
@@ -249,12 +239,14 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
return
ERR_PTR
(
ret
);
return
ERR_PTR
(
ret
);
}
}
inode
->
i_nlink
=
1
;
inode
->
i_nlink
=
1
;
inode
->
i_ino
=
ri
->
ino
;
inode
->
i_ino
=
je32_to_cpu
(
ri
->
ino
);
inode
->
i_mode
=
ri
->
mode
;
inode
->
i_mode
=
je32_to_cpu
(
ri
->
mode
);
inode
->
i_gid
=
ri
->
gid
;
inode
->
i_gid
=
je16_to_cpu
(
ri
->
gid
);
inode
->
i_uid
=
ri
->
uid
;
inode
->
i_uid
=
je16_to_cpu
(
ri
->
uid
);
inode
->
i_atime
=
inode
->
i_ctime
=
inode
->
i_mtime
=
inode
->
i_atime
.
tv_nsec
=
inode
->
i_ctime
.
tv_nsec
=
inode
->
i_mtime
.
tv_nsec
=
0
;
ri
->
atime
=
ri
->
mtime
=
ri
->
ctime
=
get_seconds
();
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_blksize
=
PAGE_SIZE
;
inode
->
i_blocks
=
0
;
inode
->
i_blocks
=
0
;
inode
->
i_size
=
0
;
inode
->
i_size
=
0
;
...
@@ -305,9 +297,10 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
...
@@ -305,9 +297,10 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
if
(
!
c
->
wbuf
)
if
(
!
c
->
wbuf
)
return
-
ENOMEM
;
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
);
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
);
init_timer
(
&
c
->
wbuf_timer
);
c
->
wbuf_timer
.
function
=
jffs2_wbuf_timeout
;
c
->
wbuf_timer
.
function
=
jffs2_wbuf_timeout
;
c
->
wbuf_timer
.
data
=
(
unsigned
long
)
c
;
c
->
wbuf_timer
.
data
=
(
unsigned
long
)
c
;
...
...
fs/jffs2/gc.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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 @@
...
@@ -17,6 +17,7 @@
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/pagemap.h>
#include <linux/pagemap.h>
#include <linux/crc32.h>
#include <linux/crc32.h>
#include <linux/compiler.h>
#include "nodelist.h"
#include "nodelist.h"
static
int
jffs2_garbage_collect_metadata
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
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)
...
@@ -87,6 +88,15 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
BUG
();
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
));
D1
(
jffs2_dump_block_lists
(
c
));
return
ret
;
return
ret
;
}
}
...
@@ -113,6 +123,49 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
...
@@ -113,6 +123,49 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
spin_lock_bh
(
&
c
->
erase_completion_lock
);
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 */
/* First, work out which block we're garbage-collecting */
jeb
=
c
->
gcblock
;
jeb
=
c
->
gcblock
;
...
@@ -128,15 +181,17 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
...
@@ -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
(
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
)
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
;
goto
eraseit
;
}
raw
=
jeb
->
gc_node
;
raw
=
jeb
->
gc_node
;
while
(
r
aw
->
flash_offset
&
1
)
{
while
(
r
ef_obsolete
(
raw
)
)
{
D1
(
printk
(
KERN_DEBUG
"Node at 0x%08x is obsolete... skipping
\n
"
,
r
aw
->
flash_offset
&~
3
));
D1
(
printk
(
KERN_DEBUG
"Node at 0x%08x is obsolete... skipping
\n
"
,
r
ef_offset
(
raw
)
));
jeb
->
gc_node
=
raw
=
raw
->
next_phys
;
jeb
->
gc_node
=
raw
=
raw
->
next_phys
;
if
(
!
raw
)
{
if
(
!
raw
)
{
printk
(
KERN_WARNING
"eep. End of raw list while still supposedly nodes to GC
\n
"
);
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)
...
@@ -147,13 +202,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
BUG
();
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
)
{
if
(
!
raw
->
next_in_ino
)
{
/* Inode-less node. Clean marker, snapshot or something like that */
/* Inode-less node. Clean marker, snapshot or something like that */
/* FIXME: If it's something that needs to be copied, including something
/* 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 */
we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
jffs2_mark_node_obsolete
(
c
,
raw
);
jffs2_mark_node_obsolete
(
c
,
raw
);
up
(
&
c
->
alloc_sem
);
goto
eraseit_lock
;
goto
eraseit_lock
;
}
}
...
@@ -162,14 +218,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
...
@@ -162,14 +218,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
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
);
inode
=
iget
(
OFNI_BS_2SFFJ
(
c
),
inum
);
if
(
is_bad_inode
(
inode
))
{
if
(
is_bad_inode
(
inode
))
{
printk
(
KERN_NOTICE
"Eep. read_inode() failed for ino #%u
\n
"
,
inum
);
printk
(
KERN_NOTICE
"Eep. read_inode() failed for ino #%u
\n
"
,
inum
);
/* NB. This will happen again. We need to do something appropriate here. */
/* NB. This will happen again. We need to do something appropriate here. */
iput
(
inode
);
up
(
&
c
->
alloc_sem
);
up
(
&
c
->
alloc_sem
);
iput
(
inode
);
return
-
EIO
;
return
-
EIO
;
}
}
...
@@ -179,7 +235,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
...
@@ -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
/* Now we have the lock for this inode. Check that it's still the one at the head
of the list. */
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
"
));
D1
(
printk
(
KERN_DEBUG
"node to be GC'd was obsoleted in the meantime.
\n
"
));
/* They'll call again */
/* They'll call again */
goto
upnout
;
goto
upnout
;
...
@@ -191,10 +247,25 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
...
@@ -191,10 +247,25 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
goto
upnout
;
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
)
{
if
(
frag
->
node
&&
frag
->
node
->
raw
==
raw
)
{
fn
=
frag
->
node
;
fn
=
frag
->
node
;
end
=
frag
->
ofs
+
frag
->
size
;
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
++
)
if
(
!
nrfrags
++
)
start
=
frag
->
ofs
;
start
=
frag
->
ofs
;
if
(
nrfrags
==
frag
->
node
->
frags
)
if
(
nrfrags
==
frag
->
node
->
frags
)
...
@@ -225,8 +296,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
...
@@ -225,8 +296,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
ret
=
jffs2_garbage_collect_deletion_dirent
(
c
,
jeb
,
f
,
fd
);
ret
=
jffs2_garbage_collect_deletion_dirent
(
c
,
jeb
,
f
,
fd
);
}
else
{
}
else
{
printk
(
KERN_WARNING
"Raw node at 0x%08x wasn't in node lists for ino #%u
\n
"
,
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
);
r
ef_offset
(
raw
)
,
f
->
inocache
->
ino
);
if
(
r
aw
->
flash_offset
&
1
)
{
if
(
r
ef_obsolete
(
raw
)
)
{
printk
(
KERN_WARNING
"But it's obsolete so we don't mind too much
\n
"
);
printk
(
KERN_WARNING
"But it's obsolete so we don't mind too much
\n
"
);
}
else
{
}
else
{
ret
=
-
EIO
;
ret
=
-
EIO
;
...
@@ -234,6 +305,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
...
@@ -234,6 +305,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
}
}
upnout:
upnout:
up
(
&
f
->
sem
);
up
(
&
f
->
sem
);
up
(
&
c
->
alloc_sem
);
iput
(
inode
);
iput
(
inode
);
eraseit_lock:
eraseit_lock:
...
@@ -250,7 +322,6 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
...
@@ -250,7 +322,6 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
jffs2_erase_pending_trigger
(
c
);
jffs2_erase_pending_trigger
(
c
);
}
}
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
up
(
&
c
->
alloc_sem
);
return
ret
;
return
ret
;
}
}
...
@@ -299,26 +370,26 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
...
@@ -299,26 +370,26 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
}
}
memset
(
&
ri
,
0
,
sizeof
(
ri
));
memset
(
&
ri
,
0
,
sizeof
(
ri
));
ri
.
magic
=
JFFS2_MAGIC_BITMASK
;
ri
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
.
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
.
totlen
=
sizeof
(
ri
)
+
mdatalen
;
ri
.
totlen
=
cpu_to_je32
(
sizeof
(
ri
)
+
mdatalen
)
;
ri
.
hdr_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
.
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
.
ino
=
f
->
inocache
->
ino
;
ri
.
ino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
ri
.
version
=
++
f
->
highest_version
;
ri
.
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
.
mode
=
JFFS2_F_I_MODE
(
f
);
ri
.
mode
=
cpu_to_je32
(
JFFS2_F_I_MODE
(
f
)
);
ri
.
uid
=
JFFS2_F_I_UID
(
f
);
ri
.
uid
=
cpu_to_je16
(
JFFS2_F_I_UID
(
f
)
);
ri
.
gid
=
JFFS2_F_I_GID
(
f
);
ri
.
gid
=
cpu_to_je16
(
JFFS2_F_I_GID
(
f
)
);
ri
.
isize
=
JFFS2_F_I_SIZE
(
f
);
ri
.
isize
=
cpu_to_je32
(
JFFS2_F_I_SIZE
(
f
)
);
ri
.
atime
=
JFFS2_F_I_ATIME
(
f
);
ri
.
atime
=
cpu_to_je32
(
JFFS2_F_I_ATIME
(
f
)
);
ri
.
ctime
=
JFFS2_F_I_CTIME
(
f
);
ri
.
ctime
=
cpu_to_je32
(
JFFS2_F_I_CTIME
(
f
)
);
ri
.
mtime
=
JFFS2_F_I_MTIME
(
f
);
ri
.
mtime
=
cpu_to_je32
(
JFFS2_F_I_MTIME
(
f
)
);
ri
.
offset
=
0
;
ri
.
offset
=
cpu_to_je32
(
0
)
;
ri
.
csize
=
mdatalen
;
ri
.
csize
=
cpu_to_je32
(
mdatalen
)
;
ri
.
dsize
=
mdatalen
;
ri
.
dsize
=
cpu_to_je32
(
mdatalen
)
;
ri
.
compr
=
JFFS2_COMPR_NONE
;
ri
.
compr
=
JFFS2_COMPR_NONE
;
ri
.
node_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
);
ri
.
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
)
);
ri
.
data_crc
=
c
rc32
(
0
,
mdata
,
mdatalen
);
ri
.
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
mdata
,
mdatalen
)
);
new_fn
=
jffs2_write_dnode
(
c
,
f
,
&
ri
,
mdata
,
mdatalen
,
phys_ofs
,
NULL
);
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
...
@@ -344,19 +415,19 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er
uint32_t
alloclen
,
phys_ofs
;
uint32_t
alloclen
,
phys_ofs
;
int
ret
;
int
ret
;
rd
.
magic
=
JFFS2_MAGIC_BITMASK
;
rd
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
.
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
.
nsize
=
strlen
(
fd
->
name
);
rd
.
nsize
=
strlen
(
fd
->
name
);
rd
.
totlen
=
sizeof
(
rd
)
+
rd
.
nsize
;
rd
.
totlen
=
cpu_to_je32
(
sizeof
(
rd
)
+
rd
.
nsize
)
;
rd
.
hdr_crc
=
c
rc32
(
0
,
&
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
.
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
.
pino
=
f
->
inocache
->
ino
;
rd
.
pino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
rd
.
version
=
++
f
->
highest_version
;
rd
.
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
rd
.
ino
=
fd
->
ino
;
rd
.
ino
=
cpu_to_je32
(
fd
->
ino
)
;
rd
.
mctime
=
max
(
JFFS2_F_I_MTIME
(
f
),
JFFS2_F_I_CTIME
(
f
));
rd
.
mctime
=
cpu_to_je32
(
max
(
JFFS2_F_I_MTIME
(
f
),
JFFS2_F_I_CTIME
(
f
)
));
rd
.
type
=
fd
->
type
;
rd
.
type
=
fd
->
type
;
rd
.
node_crc
=
c
rc32
(
0
,
&
rd
,
sizeof
(
rd
)
-
8
);
rd
.
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
rd
,
sizeof
(
rd
)
-
8
)
);
rd
.
name_crc
=
c
rc32
(
0
,
fd
->
name
,
rd
.
nsize
);
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
);
ret
=
jffs2_reserve_space_gc
(
c
,
sizeof
(
rd
)
+
rd
.
nsize
,
&
phys_ofs
,
&
alloclen
);
if
(
ret
)
{
if
(
ret
)
{
...
@@ -401,7 +472,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
...
@@ -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
)
{
for
(
raw
=
f
->
inocache
->
nodes
;
raw
!=
(
void
*
)
f
->
inocache
;
raw
=
raw
->
next_in_ino
)
{
/* We only care about obsolete ones */
/* We only care about obsolete ones */
if
(
!
(
r
aw
->
flash_offset
&
1
))
if
(
!
(
r
ef_obsolete
(
raw
)
))
continue
;
continue
;
/* Doesn't matter if there's one in the same erase block. We're going to
/* 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
...
@@ -411,40 +482,40 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
continue
;
continue
;
/* This is an obsolete node belonging to the same directory */
/* 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
)
{
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
);
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 continu
n
e to obsolete it. Continue */
/* If we can't read it, we don't need to continue to obsolete it. Continue */
continue
;
continue
;
}
}
if
(
retlen
!=
sizeof
(
struct
jffs2_unknown_node
))
{
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
"
,
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
;
continue
;
}
}
if
(
rd
.
nodetype
!=
JFFS2_NODETYPE_DIRENT
||
if
(
je16_to_cpu
(
rd
.
nodetype
)
!=
JFFS2_NODETYPE_DIRENT
||
PAD
(
rd
.
totlen
)
!=
PAD
(
sizeof
(
rd
)
+
name_len
))
PAD
(
je32_to_cpu
(
rd
.
totlen
)
)
!=
PAD
(
sizeof
(
rd
)
+
name_len
))
continue
;
continue
;
/* OK, it's a dirent node, it's the right length. We have to take a
/* OK, it's a dirent node, it's the right length. We have to take a
closer look at it... */
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
)
{
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 */
/* If we can't read it, we don't need to continune to obsolete it. Continue */
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
"
,
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
;
continue
;
}
}
/* If the name CRC doesn't match, skip */
/* If the name CRC doesn't match, skip */
if
(
rd
.
name_crc
!=
name_crc
)
if
(
je32_to_cpu
(
rd
.
name_crc
)
!=
name_crc
)
continue
;
continue
;
/* If the name length doesn't match, or it's another deletion dirent, skip */
/* 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
;
continue
;
/* OK, check the actual name now */
/* OK, check the actual name now */
...
@@ -456,15 +527,15 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
...
@@ -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 */
/* 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
)
{
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 */
/* If we can't read it, we don't need to continune to obsolete it. Continue */
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
"
,
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
;
continue
;
}
}
if
(
memcmp
(
namebuf
+
1
,
fd
->
name
,
name_len
))
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
...
@@ -524,59 +595,62 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
uint32_t
crc
;
uint32_t
crc
;
/* It's partially obsoleted by a later write. So we have to
/* It's partially obsoleted by a later write. So we have to
write it out again with the _same_ version as before */
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
)
{
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
;
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
"
,
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
;
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
"
,
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
;
return
-
EIO
;
}
}
crc
=
crc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
);
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
"
,
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 */
/* 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
"
,
printk
(
KERN_WARNING
"Data in the range 0x%08x to 0x%08x of inode #%u will be lost
\n
"
,
start
,
end
,
f
->
inocache
->
ino
);
start
,
end
,
f
->
inocache
->
ino
);
goto
fill
;
goto
fill
;
}
}
if
(
ri
.
compr
!=
JFFS2_COMPR_ZERO
)
{
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
"
,
printk
(
KERN_WARNING
"Data in the range 0x%08x to 0x%08x of inode #%u will be lost
\n
"
,
start
,
end
,
f
->
inocache
->
ino
);
start
,
end
,
f
->
inocache
->
ino
);
goto
fill
;
goto
fill
;
}
}
}
else
{
}
else
{
fill:
fill:
ri
.
magic
=
JFFS2_MAGIC_BITMASK
;
ri
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
.
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
.
totlen
=
sizeof
(
ri
);
ri
.
totlen
=
cpu_to_je32
(
sizeof
(
ri
)
);
ri
.
hdr_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
.
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
.
ino
=
f
->
inocache
->
ino
;
ri
.
ino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
ri
.
version
=
++
f
->
highest_version
;
ri
.
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
.
offset
=
start
;
ri
.
offset
=
cpu_to_je32
(
start
)
;
ri
.
dsize
=
end
-
start
;
ri
.
dsize
=
cpu_to_je32
(
end
-
start
)
;
ri
.
csize
=
0
;
ri
.
csize
=
cpu_to_je32
(
0
)
;
ri
.
compr
=
JFFS2_COMPR_ZERO
;
ri
.
compr
=
JFFS2_COMPR_ZERO
;
}
}
ri
.
mode
=
JFFS2_F_I_MODE
(
f
);
ri
.
mode
=
cpu_to_je32
(
JFFS2_F_I_MODE
(
f
)
);
ri
.
uid
=
JFFS2_F_I_UID
(
f
);
ri
.
uid
=
cpu_to_je16
(
JFFS2_F_I_UID
(
f
)
);
ri
.
gid
=
JFFS2_F_I_GID
(
f
);
ri
.
gid
=
cpu_to_je16
(
JFFS2_F_I_GID
(
f
)
);
ri
.
isize
=
JFFS2_F_I_SIZE
(
f
);
ri
.
isize
=
cpu_to_je32
(
JFFS2_F_I_SIZE
(
f
)
);
ri
.
atime
=
JFFS2_F_I_ATIME
(
f
);
ri
.
atime
=
cpu_to_je32
(
JFFS2_F_I_ATIME
(
f
)
);
ri
.
ctime
=
JFFS2_F_I_CTIME
(
f
);
ri
.
ctime
=
cpu_to_je32
(
JFFS2_F_I_CTIME
(
f
)
);
ri
.
mtime
=
JFFS2_F_I_MTIME
(
f
);
ri
.
mtime
=
cpu_to_je32
(
JFFS2_F_I_MTIME
(
f
)
);
ri
.
data_crc
=
0
;
ri
.
data_crc
=
cpu_to_je32
(
0
)
;
ri
.
node_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
);
ri
.
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
)
);
ret
=
jffs2_reserve_space_gc
(
c
,
sizeof
(
ri
),
&
phys_ofs
,
&
alloclen
);
ret
=
jffs2_reserve_space_gc
(
c
,
sizeof
(
ri
),
&
phys_ofs
,
&
alloclen
);
if
(
ret
)
{
if
(
ret
)
{
...
@@ -590,7 +664,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
...
@@ -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
));
printk
(
KERN_WARNING
"Error writing new hole node: %ld
\n
"
,
PTR_ERR
(
new_fn
));
return
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
);
jffs2_add_full_dnode_to_inode
(
c
,
f
,
new_fn
);
if
(
f
->
metadata
)
{
if
(
f
->
metadata
)
{
jffs2_mark_node_obsolete
(
c
,
f
->
metadata
->
raw
);
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
...
@@ -608,10 +682,12 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
*/
*/
D1
(
if
(
unlikely
(
fn
->
frags
<=
1
))
{
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
"
,
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
)
if
(
frag
->
ofs
>
fn
->
size
+
fn
->
ofs
)
break
;
break
;
if
(
frag
->
node
==
fn
)
{
if
(
frag
->
node
==
fn
)
{
...
@@ -655,7 +731,6 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
...
@@ -655,7 +731,6 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
orig_end
=
end
;
orig_end
=
end
;
/* If we're looking at the last node in the block we're
/* If we're looking at the last node in the block we're
garbage-collecting, we allow ourselves to merge as if the
garbage-collecting, we allow ourselves to merge as if the
block was already erasing. We're likely to be GC'ing a
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
...
@@ -722,26 +797,26 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
}
else
{
}
else
{
datalen
=
cdatalen
;
datalen
=
cdatalen
;
}
}
ri
.
magic
=
JFFS2_MAGIC_BITMASK
;
ri
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
.
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
.
totlen
=
sizeof
(
ri
)
+
cdatalen
;
ri
.
totlen
=
cpu_to_je32
(
sizeof
(
ri
)
+
cdatalen
)
;
ri
.
hdr_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
.
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
.
ino
=
f
->
inocache
->
ino
;
ri
.
ino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
ri
.
version
=
++
f
->
highest_version
;
ri
.
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
.
mode
=
JFFS2_F_I_MODE
(
f
);
ri
.
mode
=
cpu_to_je32
(
JFFS2_F_I_MODE
(
f
)
);
ri
.
uid
=
JFFS2_F_I_UID
(
f
);
ri
.
uid
=
cpu_to_je16
(
JFFS2_F_I_UID
(
f
)
);
ri
.
gid
=
JFFS2_F_I_GID
(
f
);
ri
.
gid
=
cpu_to_je16
(
JFFS2_F_I_GID
(
f
)
);
ri
.
isize
=
JFFS2_F_I_SIZE
(
f
);
ri
.
isize
=
cpu_to_je32
(
JFFS2_F_I_SIZE
(
f
)
);
ri
.
atime
=
JFFS2_F_I_ATIME
(
f
);
ri
.
atime
=
cpu_to_je32
(
JFFS2_F_I_ATIME
(
f
)
);
ri
.
ctime
=
JFFS2_F_I_CTIME
(
f
);
ri
.
ctime
=
cpu_to_je32
(
JFFS2_F_I_CTIME
(
f
)
);
ri
.
mtime
=
JFFS2_F_I_MTIME
(
f
);
ri
.
mtime
=
cpu_to_je32
(
JFFS2_F_I_MTIME
(
f
)
);
ri
.
offset
=
offset
;
ri
.
offset
=
cpu_to_je32
(
offset
)
;
ri
.
csize
=
c
datalen
;
ri
.
csize
=
c
pu_to_je32
(
cdatalen
)
;
ri
.
dsize
=
datalen
;
ri
.
dsize
=
cpu_to_je32
(
datalen
)
;
ri
.
compr
=
comprtype
;
ri
.
compr
=
comprtype
;
ri
.
node_crc
=
c
rc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
);
ri
.
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
&
ri
,
sizeof
(
ri
)
-
8
)
);
ri
.
data_crc
=
c
rc32
(
0
,
writebuf
,
cdatalen
);
ri
.
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
writebuf
,
cdatalen
)
);
new_fn
=
jffs2_write_dnode
(
c
,
f
,
&
ri
,
writebuf
,
cdatalen
,
phys_ofs
,
NULL
);
new_fn
=
jffs2_write_dnode
(
c
,
f
,
&
ri
,
writebuf
,
cdatalen
,
phys_ofs
,
NULL
);
...
...
fs/jffs2/nodelist.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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 @@
...
@@ -15,6 +15,9 @@
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/rbtree.h>
#include <linux/crc32.h>
#include <linux/slab.h>
#include "nodelist.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
)
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
...
@@ -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
)
{
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 */
/* 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 */
/* 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
;
continue
;
}
}
/* We can hold a pointer to a non-obsolete node without the spinlock,
/* 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
...
@@ -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 */
they're in gets erased */
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
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
)
{
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
;
goto
free_out
;
}
}
...
@@ -140,20 +146,24 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
...
@@ -140,20 +146,24 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
goto
free_out
;
goto
free_out
;
}
}
switch
(
node
.
u
.
nodetype
)
{
switch
(
je16_to_cpu
(
node
.
u
.
nodetype
)
)
{
case
JFFS2_NODETYPE_DIRENT
:
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
))
{
if
(
retlen
<
sizeof
(
node
.
d
))
{
printk
(
KERN_WARNING
"short read in get_inode_nodes()
\n
"
);
printk
(
KERN_WARNING
"short read in get_inode_nodes()
\n
"
);
err
=
-
EIO
;
err
=
-
EIO
;
goto
free_out
;
goto
free_out
;
}
}
if
(
node
.
d
.
version
>
*
highest_version
)
if
(
je32_to_cpu
(
node
.
d
.
version
)
>
*
highest_version
)
*
highest_version
=
node
.
d
.
version
;
*
highest_version
=
je32_to_cpu
(
node
.
d
.
version
)
;
if
(
ref
->
flash_offset
&
1
)
{
if
(
ref
_obsolete
(
ref
)
)
{
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
printk
(
KERN_ERR
"Dirent node at 0x%08x became obsolete while we weren't looking
\n
"
,
printk
(
KERN_ERR
"Dirent node at 0x%08x became obsolete while we weren't looking
\n
"
,
ref
->
flash_offset
&
~
3
);
ref
_offset
(
ref
)
);
BUG
();
BUG
();
}
}
fd
=
jffs2_alloc_full_dirent
(
node
.
d
.
nsize
+
1
);
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
...
@@ -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
);
memset
(
fd
,
0
,
sizeof
(
struct
jffs2_full_dirent
)
+
node
.
d
.
nsize
+
1
);
fd
->
raw
=
ref
;
fd
->
raw
=
ref
;
fd
->
version
=
node
.
d
.
version
;
fd
->
version
=
je32_to_cpu
(
node
.
d
.
version
)
;
fd
->
ino
=
node
.
d
.
ino
;
fd
->
ino
=
je32_to_cpu
(
node
.
d
.
ino
)
;
fd
->
type
=
node
.
d
.
type
;
fd
->
type
=
node
.
d
.
type
;
/* Pick out the mctime of the latest dirent */
/* Pick out the mctime of the latest dirent */
if
(
fd
->
version
>
*
mctime_ver
)
{
if
(
fd
->
version
>
*
mctime_ver
)
{
*
mctime_ver
=
fd
->
version
;
*
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
/* 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
...
@@ -183,9 +193,10 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
from the flash?
from the flash?
*/
*/
if
(
node
.
d
.
nsize
+
sizeof
(
struct
jffs2_raw_dirent
)
>
retlen
)
{
if
(
node
.
d
.
nsize
+
sizeof
(
struct
jffs2_raw_dirent
)
>
retlen
)
{
/* FIXME: point() */
int
already
=
retlen
-
sizeof
(
struct
jffs2_raw_dirent
);
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
]);
node
.
d
.
nsize
-
already
,
&
retlen
,
&
fd
->
name
[
already
]);
if
(
!
err
&&
retlen
!=
node
.
d
.
nsize
-
already
)
if
(
!
err
&&
retlen
!=
node
.
d
.
nsize
-
already
)
err
=
-
EIO
;
err
=
-
EIO
;
...
@@ -206,22 +217,75 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
...
@@ -206,22 +217,75 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
break
;
break
;
case
JFFS2_NODETYPE_INODE
:
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
))
{
if
(
retlen
<
sizeof
(
node
.
i
))
{
printk
(
KERN_WARNING
"read too short for dnode
\n
"
);
printk
(
KERN_WARNING
"read too short for dnode
\n
"
);
err
=
-
EIO
;
err
=
-
EIO
;
goto
free_out
;
goto
free_out
;
}
}
if
(
node
.
d
.
version
>
*
highest_version
)
if
(
je32_to_cpu
(
node
.
i
.
version
)
>
*
highest_version
)
*
highest_version
=
node
.
i
.
version
;
*
highest_version
=
je32_to_cpu
(
node
.
i
.
version
)
;
D1
(
printk
(
KERN_DEBUG
"version %d, highest_version now %d
\n
"
,
node
.
d
.
version
,
*
highest_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 */
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
printk
(
KERN_ERR
"Inode node at 0x%08x became obsolete while we weren't looking
\n
"
,
printk
(
KERN_ERR
"Inode node at 0x%08x became obsolete while we weren't looking
\n
"
,
ref
->
flash_offset
&
~
3
);
ref
_offset
(
ref
)
);
BUG
();
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
();
tn
=
jffs2_alloc_tmp_dnode_info
();
if
(
!
tn
)
{
if
(
!
tn
)
{
D1
(
printk
(
KERN_DEBUG
"alloc tn failed
\n
"
));
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
...
@@ -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
);
jffs2_free_tmp_dnode_info
(
tn
);
goto
free_out
;
goto
free_out
;
}
}
tn
->
version
=
node
.
i
.
version
;
tn
->
version
=
je32_to_cpu
(
node
.
i
.
version
)
;
tn
->
fn
->
ofs
=
node
.
i
.
offset
;
tn
->
fn
->
ofs
=
je32_to_cpu
(
node
.
i
.
offset
)
;
/* There was a bug where we wrote hole nodes out with
/* There was a bug where we wrote hole nodes out with
csize/dsize swapped. Deal with it */
csize/dsize swapped. Deal with it */
if
(
node
.
i
.
compr
==
JFFS2_COMPR_ZERO
&&
!
node
.
i
.
dsize
&&
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
=
node
.
i
.
csize
;
tn
->
fn
->
size
=
je32_to_cpu
(
node
.
i
.
csize
)
;
else
// normal case...
else
// normal case...
tn
->
fn
->
size
=
node
.
i
.
dsize
;
tn
->
fn
->
size
=
je32_to_cpu
(
node
.
i
.
dsize
)
;
tn
->
fn
->
raw
=
ref
;
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
);
jffs2_add_tn_to_list
(
tn
,
&
ret_tn
);
break
;
break
;
default:
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
:
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
;
break
;
case
JFFS2_FEATURE_ROCOMPAT
:
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
;
break
;
case
JFFS2_FEATURE_RWCOMPAT_COPY
:
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
;
break
;
case
JFFS2_FEATURE_RWCOMPAT_DELETE
:
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
;
break
;
}
}
}
}
spin_lock_bh
(
&
c
->
erase_completion_lock
);
spin_lock_bh
(
&
c
->
erase_completion_lock
);
...
@@ -369,3 +465,126 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c)
...
@@ -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 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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
...
@@ -53,16 +53,22 @@ struct jffs2_raw_node_ref
for this inode instead. The inode_cache will have NULL in the first
for this inode instead. The inode_cache will have NULL in the first
word so you know when you've got there :) */
word so you know when you've got there :) */
struct
jffs2_raw_node_ref
*
next_phys
;
struct
jffs2_raw_node_ref
*
next_phys
;
// uint32_t ino;
uint32_t
flash_offset
;
uint32_t
flash_offset
;
uint32_t
totlen
;
uint32_t
totlen
;
// uint16_t nodetype;
/* flash_offset & 3 always has to be zero, because nodes are
/* flash_offset & 3 always has to be zero, because nodes are
always aligned at 4 bytes. So we have a couple of extra bits
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
to play with. So we set the least significant bit to 1 to
signify that the node is obsoleted by later nodes.
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 {
...
@@ -83,14 +89,20 @@ struct jffs2_raw_node_ref_list {
a pointer to the first physical node which is part of this inode, too.
a pointer to the first physical node which is part of this inode, too.
*/
*/
struct
jffs2_inode_cache
{
struct
jffs2_inode_cache
{
struct
jffs2_
scan_info
*
scan
;
/* Used during scan to hold
struct
jffs2_
full_dirent
*
scan_dents
;
/* Used during scan to hold
temporary lists of
node
s, and later must be set to
temporary lists of
dirent
s, and later must be set to
NULL to mark the end of the raw_node_ref->next_in_ino
NULL to mark the end of the raw_node_ref->next_in_ino
chain. */
chain. */
struct
jffs2_inode_cache
*
next
;
struct
jffs2_inode_cache
*
next
;
struct
jffs2_raw_node_ref
*
nodes
;
struct
jffs2_raw_node_ref
*
nodes
;
uint32_t
ino
;
uint32_t
ino
;
int
nlink
;
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
#define INOCACHE_HASHSIZE 128
...
@@ -146,7 +158,7 @@ struct jffs2_full_dirent
...
@@ -146,7 +158,7 @@ struct jffs2_full_dirent
*/
*/
struct
jffs2_node_frag
struct
jffs2_node_frag
{
{
struct
jffs2_node_frag
*
next
;
struct
rb_node
rb
;
struct
jffs2_full_dnode
*
node
;
/* NULL for holes */
struct
jffs2_full_dnode
*
node
;
/* NULL for holes */
uint32_t
size
;
uint32_t
size
;
uint32_t
ofs
;
/* Don't really need this, but optimisation */
uint32_t
ofs
;
/* Don't really need this, but optimisation */
...
@@ -158,8 +170,10 @@ struct jffs2_eraseblock
...
@@ -158,8 +170,10 @@ struct jffs2_eraseblock
int
bad_count
;
int
bad_count
;
uint32_t
offset
;
/* of this block in the MTD */
uint32_t
offset
;
/* of this block in the MTD */
uint32_t
unchecked_size
;
uint32_t
used_size
;
uint32_t
used_size
;
uint32_t
dirty_size
;
uint32_t
dirty_size
;
uint32_t
wasted_size
;
uint32_t
free_size
;
/* Note that sector_size - free_size
uint32_t
free_size
;
/* Note that sector_size - free_size
is the address of the first free space */
is the address of the first free space */
struct
jffs2_raw_node_ref
*
first_node
;
struct
jffs2_raw_node_ref
*
first_node
;
...
@@ -177,25 +191,28 @@ struct jffs2_eraseblock
...
@@ -177,25 +191,28 @@ struct jffs2_eraseblock
};
};
#define ACCT_SANITY_CHECK(c, jeb) do { \
#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 "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", \
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, c->sector_size); \
jeb->free_size, jeb->dirty_size, jeb->used_size,
jeb->wasted_size, jeb->unchecked_size,
c->sector_size); \
BUG(); \
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 "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", \
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->flash_size); \
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(); \
BUG(); \
} \
} \
} while(0)
} while(0)
#define ACCT_PARANOIA_CHECK(jeb) do { \
#define ACCT_PARANOIA_CHECK(jeb) do { \
uint32_t my_used_size = 0; \
uint32_t my_used_size = 0; \
uint32_t my_unchecked_size = 0; \
struct jffs2_raw_node_ref *ref2 = jeb->first_node; \
struct jffs2_raw_node_ref *ref2 = jeb->first_node; \
while (ref2) { \
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; \
my_used_size += ref2->totlen; \
ref2 = ref2->next_phys; \
ref2 = ref2->next_phys; \
} \
} \
...
@@ -203,6 +220,10 @@ struct jffs2_eraseblock
...
@@ -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); \
printk(KERN_NOTICE "Calculated used size %08x != stored used size %08x\n", my_used_size, jeb->used_size); \
BUG(); \
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)
} while(0)
#define ALLOC_NORMAL 0
/* Normal allocation */
#define ALLOC_NORMAL 0
/* Normal allocation */
...
@@ -211,7 +232,7 @@ struct jffs2_eraseblock
...
@@ -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_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_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_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_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 */
#define JFFS2_RESERVED_BLOCKS_GCMERGE (JFFS2_RESERVED_BLOCKS_BASE)
/* ... merge pages when garbage collecting */
...
@@ -220,6 +241,9 @@ struct jffs2_eraseblock
...
@@ -220,6 +241,9 @@ struct jffs2_eraseblock
/* How much dirty space before it goes on the very_dirty_list */
/* How much dirty space before it goes on the very_dirty_list */
#define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2))
#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)
#define PAD(x) (((x)+3)&~3)
static
inline
int
jffs2_raw_ref_to_inum
(
struct
jffs2_raw_node_ref
*
raw
)
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)
...
@@ -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
;
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 */
/* nodelist.c */
D1
(
void
jffs2_print_frag_list
(
struct
jffs2_inode_info
*
f
));
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
);
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
...
@@ -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_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_ino_caches
(
struct
jffs2_sb_info
*
c
);
void
jffs2_free_raw_node_refs
(
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 */
/* 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
(
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_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_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_mark_node_obsolete
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_raw_node_ref
*
raw
);
void
jffs2_dump_block_lists
(
struct
jffs2_sb_info
*
c
);
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
...
@@ -266,8 +314,8 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
/* readinode.c */
/* readinode.c */
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
);
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
);
int
jffs2_add_full_dnode_to_inode
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_inode_info
*
f
,
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
,
int
jffs2_do_read_inode
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_inode_info
*
f
,
uint32_t
ino
,
struct
jffs2_raw_inode
*
latest_node
);
uint32_t
ino
,
struct
jffs2_raw_inode
*
latest_node
);
...
@@ -320,7 +368,6 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c);
...
@@ -320,7 +368,6 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c);
/* erase.c */
/* erase.c */
void
jffs2_erase_block
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
);
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_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
);
void
jffs2_erase_pending_trigger
(
struct
jffs2_sb_info
*
c
);
#ifdef CONFIG_JFFS2_FS_NAND
#ifdef CONFIG_JFFS2_FS_NAND
...
...
fs/jffs2/nodemgmt.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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
...
@@ -62,14 +62,17 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
int
ret
;
int
ret
;
up
(
&
c
->
alloc_sem
);
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
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
return
-
ENOSPC
;
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
,
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
->
free_size
+
c
->
dirty_size
+
c
->
used_size
+
c
->
erasing_size
+
c
->
bad_size
,
c
->
flash_size
));
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
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
ret
=
jffs2_garbage_collect_pass
(
c
);
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
...
@@ -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
);
spin_lock_bh
(
&
c
->
erase_completion_lock
);
/* We know nobody's going to have changed nextblock. Just continue */
/* 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
;
c
->
free_size
-=
jeb
->
free_size
;
jeb
->
dirty
_size
+=
jeb
->
free_size
;
jeb
->
wasted
_size
+=
jeb
->
free_size
;
jeb
->
free_size
=
0
;
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
))
{
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
"
,
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
));
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
...
@@ -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
));
jeb
->
offset
,
jeb
->
free_size
,
jeb
->
dirty_size
,
jeb
->
used_size
));
list_add_tail
(
&
jeb
->
list
,
&
c
->
dirty_list
);
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
;
c
->
nextblock
=
jeb
=
NULL
;
}
}
...
@@ -225,7 +240,7 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
...
@@ -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
);
*
ofs
=
jeb
->
offset
+
(
c
->
sector_size
-
jeb
->
free_size
);
*
len
=
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
)
{
!
jeb
->
first_node
->
next_in_ino
)
{
/* Only node in it beforehand was a CLEANMARKER node (we think).
/* Only node in it beforehand was a CLEANMARKER node (we think).
So mark it obsolete now that there's going to be another node
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
...
@@ -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.
* 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
;
struct
jffs2_eraseblock
*
jeb
;
uint32_t
len
=
new
->
totlen
;
len
=
PAD
(
len
);
jeb
=
&
c
->
blocks
[
new
->
flash_offset
/
c
->
sector_size
];
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 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
"
);
printk
(
KERN_WARNING
"argh. node added in wrong place
\n
"
);
jffs2_free_raw_node_ref
(
new
);
jffs2_free_raw_node_ref
(
new
);
return
-
EINVAL
;
return
-
EINVAL
;
...
@@ -279,8 +294,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
...
@@ -279,8 +294,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
jeb
->
free_size
-=
len
;
jeb
->
free_size
-=
len
;
c
->
free_size
-=
len
;
c
->
free_size
-=
len
;
if
(
dirty
)
{
if
(
ref_obsolete
(
new
))
{
new
->
flash_offset
|=
1
;
jeb
->
dirty_size
+=
len
;
jeb
->
dirty_size
+=
len
;
c
->
dirty_size
+=
len
;
c
->
dirty_size
+=
len
;
}
else
{
}
else
{
...
@@ -303,7 +317,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
...
@@ -303,7 +317,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
c
->
nextblock
=
NULL
;
c
->
nextblock
=
NULL
;
}
}
ACCT_SANITY_CHECK
(
c
,
jeb
);
ACCT_SANITY_CHECK
(
c
,
jeb
);
ACCT_PARANOIA_CHECK
(
jeb
);
D1
(
ACCT_PARANOIA_CHECK
(
jeb
)
);
spin_unlock_bh
(
&
c
->
erase_completion_lock
);
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
...
@@ -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
"
);
printk
(
KERN_NOTICE
"EEEEEK. jffs2_mark_node_obsolete called with NULL node
\n
"
);
return
;
return
;
}
}
if
(
ref
->
flash_offset
&
1
)
{
if
(
ref
_obsolete
(
ref
)
)
{
D1
(
printk
(
KERN_DEBUG
"jffs2_mark_node_obsolete called with already obsolete node at 0x%08x
\n
"
,
ref
->
flash_offset
&~
3
));
D1
(
printk
(
KERN_DEBUG
"jffs2_mark_node_obsolete called with already obsolete node at 0x%08x
\n
"
,
ref
_offset
(
ref
)
));
return
;
return
;
}
}
blocknr
=
ref
->
flash_offset
/
c
->
sector_size
;
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
...
@@ -340,22 +354,45 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
BUG
();
BUG
();
}
}
jeb
=
&
c
->
blocks
[
blocknr
];
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
"
,
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
);
ref
->
totlen
,
blocknr
,
ref
->
flash_offset
,
jeb
->
used_size
);
BUG
();
BUG
();
}
})
D1
(
printk
(
KERN_DEBUG
"Obsoleting node at 0x%08x of len %x: "
,
ref_offset
(
ref
),
ref
->
totlen
));
spin_lock_bh
(
&
c
->
erase_completion_lock
);
jeb
->
used_size
-=
ref
->
totlen
;
jeb
->
used_size
-=
ref
->
totlen
;
jeb
->
dirty_size
+=
ref
->
totlen
;
c
->
used_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_SANITY_CHECK
(
c
,
jeb
);
ACCT_PARANOIA_CHECK
(
jeb
);
D1
(
ACCT_PARANOIA_CHECK
(
jeb
)
);
if
(
c
->
flags
&
JFFS2_SB_FLAG_MOUNTING
)
{
if
(
c
->
flags
&
JFFS2_SB_FLAG_MOUNTING
)
{
/* Mount in progress. Don't muck about with the block
/* 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
...
@@ -369,7 +406,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
if
(
jeb
==
c
->
nextblock
)
{
if
(
jeb
==
c
->
nextblock
)
{
D2
(
printk
(
KERN_DEBUG
"Not moving nextblock 0x%08x to dirty/erase_pending list
\n
"
,
jeb
->
offset
));
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
)
{
if
(
jeb
==
c
->
gcblock
)
{
D1
(
printk
(
KERN_DEBUG
"gcblock at 0x%08x completely dirtied. Clearing gcblock...
\n
"
,
jeb
->
offset
));
D1
(
printk
(
KERN_DEBUG
"gcblock at 0x%08x completely dirtied. Clearing gcblock...
\n
"
,
jeb
->
offset
));
c
->
gcblock
=
NULL
;
c
->
gcblock
=
NULL
;
...
@@ -417,7 +454,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
...
@@ -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
"
));
D1
(
printk
(
KERN_DEBUG
"Done OK
\n
"
));
}
else
if
(
jeb
==
c
->
gcblock
)
{
}
else
if
(
jeb
==
c
->
gcblock
)
{
D2
(
printk
(
KERN_DEBUG
"Not moving gcblock 0x%08x to dirty_list
\n
"
,
jeb
->
offset
));
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
));
D1
(
printk
(
KERN_DEBUG
"Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...
\n
"
,
jeb
->
offset
));
list_del
(
&
jeb
->
list
);
list_del
(
&
jeb
->
list
);
D1
(
printk
(
KERN_DEBUG
"...and adding to dirty_list
\n
"
));
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
...
@@ -428,6 +465,9 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
list_del
(
&
jeb
->
list
);
list_del
(
&
jeb
->
list
);
D1
(
printk
(
KERN_DEBUG
"...and adding to very_dirty_list
\n
"
));
D1
(
printk
(
KERN_DEBUG
"...and adding to very_dirty_list
\n
"
));
list_add_tail
(
&
jeb
->
list
,
&
c
->
very_dirty_list
);
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
);
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
...
@@ -437,32 +477,33 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
if
(
jffs2_is_readonly
(
c
))
if
(
jffs2_is_readonly
(
c
))
return
;
return
;
D1
(
printk
(
KERN_DEBUG
"obliterating obsoleted node at 0x%08x
\n
"
,
ref
->
flash_offset
&~
3
));
D1
(
printk
(
KERN_DEBUG
"obliterating obsoleted node at 0x%08x
\n
"
,
ref
_offset
(
ref
)
));
ret
=
jffs2_flash_read
(
c
,
ref
->
flash_offset
&~
3
,
sizeof
(
n
),
&
retlen
,
(
char
*
)
&
n
);
ret
=
jffs2_flash_read
(
c
,
ref
_offset
(
ref
)
,
sizeof
(
n
),
&
retlen
,
(
char
*
)
&
n
);
if
(
ret
)
{
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
;
return
;
}
}
if
(
retlen
!=
sizeof
(
n
))
{
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
;
return
;
}
}
if
(
PAD
(
n
.
totlen
)
!=
PAD
(
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
"
,
n
.
totlen
,
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
;
return
;
}
}
if
(
!
(
n
.
nodetype
&
JFFS2_NODE_ACCURATE
))
{
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
->
flash_offset
&~
3
,
n
.
nodetype
));
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
;
return
;
}
}
n
.
nodetype
&=
~
JFFS2_NODE_ACCURATE
;
/* XXX FIXME: This is ugly now */
ret
=
jffs2_flash_write
(
c
,
ref
->
flash_offset
&~
3
,
sizeof
(
n
),
&
retlen
,
(
char
*
)
&
n
);
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
)
{
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
;
return
;
}
}
if
(
retlen
!=
sizeof
(
n
))
{
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
;
return
;
}
}
}
}
...
@@ -470,10 +511,14 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
...
@@ -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
#if CONFIG_JFFS2_FS_DEBUG > 0
void
jffs2_dump_block_lists
(
struct
jffs2_sb_info
*
c
)
void
jffs2_dump_block_lists
(
struct
jffs2_sb_info
*
c
)
{
{
printk
(
KERN_DEBUG
"jffs2_dump_block_lists:
\n
"
);
printk
(
KERN_DEBUG
"jffs2_dump_block_lists:
\n
"
);
printk
(
KERN_DEBUG
"flash_size: %08x
\n
"
,
c
->
flash_size
);
printk
(
KERN_DEBUG
"flash_size: %08x
\n
"
,
c
->
flash_size
);
printk
(
KERN_DEBUG
"used_size: %08x
\n
"
,
c
->
used_size
);
printk
(
KERN_DEBUG
"used_size: %08x
\n
"
,
c
->
used_size
);
printk
(
KERN_DEBUG
"dirty_size: %08x
\n
"
,
c
->
dirty_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
"free_size: %08x
\n
"
,
c
->
free_size
);
printk
(
KERN_DEBUG
"erasing_size: %08x
\n
"
,
c
->
erasing_size
);
printk
(
KERN_DEBUG
"erasing_size: %08x
\n
"
,
c
->
erasing_size
);
printk
(
KERN_DEBUG
"bad_size: %08x
\n
"
,
c
->
bad_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)
...
@@ -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
);
printk
(
KERN_DEBUG
"jffs2_reserved_blocks size: %08x
\n
"
,
c
->
sector_size
*
JFFS2_RESERVED_BLOCKS_WRITE
);
if
(
c
->
nextblock
)
{
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
{
}
else
{
printk
(
KERN_DEBUG
"nextblock: NULL
\n
"
);
printk
(
KERN_DEBUG
"nextblock: NULL
\n
"
);
}
}
if
(
c
->
gcblock
)
{
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
{
}
else
{
printk
(
KERN_DEBUG
"gcblock: NULL
\n
"
);
printk
(
KERN_DEBUG
"gcblock: NULL
\n
"
);
}
}
...
@@ -494,31 +541,50 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
...
@@ -494,31 +541,50 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
printk
(
KERN_DEBUG
"clean_list: empty
\n
"
);
printk
(
KERN_DEBUG
"clean_list: empty
\n
"
);
}
else
{
}
else
{
struct
list_head
*
this
;
struct
list_head
*
this
;
int
numblocks
=
0
;
uint32_t
dirty
=
0
;
list_for_each
(
this
,
&
c
->
clean_list
)
{
list_for_each
(
this
,
&
c
->
clean_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
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
))
{
if
(
list_empty
(
&
c
->
very_dirty_list
))
{
printk
(
KERN_DEBUG
"very_dirty_list: empty
\n
"
);
printk
(
KERN_DEBUG
"very_dirty_list: empty
\n
"
);
}
else
{
}
else
{
struct
list_head
*
this
;
struct
list_head
*
this
;
int
numblocks
=
0
;
uint32_t
dirty
=
0
;
list_for_each
(
this
,
&
c
->
very_dirty_list
)
{
list_for_each
(
this
,
&
c
->
very_dirty_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
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
))
{
if
(
list_empty
(
&
c
->
dirty_list
))
{
printk
(
KERN_DEBUG
"dirty_list: empty
\n
"
);
printk
(
KERN_DEBUG
"dirty_list: empty
\n
"
);
}
else
{
}
else
{
struct
list_head
*
this
;
struct
list_head
*
this
;
int
numblocks
=
0
;
uint32_t
dirty
=
0
;
list_for_each
(
this
,
&
c
->
dirty_list
)
{
list_for_each
(
this
,
&
c
->
dirty_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
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
))
{
if
(
list_empty
(
&
c
->
erasable_list
))
{
printk
(
KERN_DEBUG
"erasable_list: empty
\n
"
);
printk
(
KERN_DEBUG
"erasable_list: empty
\n
"
);
...
@@ -527,7 +593,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
...
@@ -527,7 +593,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
erasable_list
)
{
list_for_each
(
this
,
&
c
->
erasable_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
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
))
{
if
(
list_empty
(
&
c
->
erasing_list
))
{
...
@@ -537,7 +604,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
...
@@ -537,7 +604,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
erasing_list
)
{
list_for_each
(
this
,
&
c
->
erasing_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
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
))
{
if
(
list_empty
(
&
c
->
erase_pending_list
))
{
...
@@ -547,7 +615,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
...
@@ -547,7 +615,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
erase_pending_list
)
{
list_for_each
(
this
,
&
c
->
erase_pending_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
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
))
{
if
(
list_empty
(
&
c
->
erasable_pending_wbuf_list
))
{
...
@@ -557,7 +626,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
...
@@ -557,7 +626,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
erasable_pending_wbuf_list
)
{
list_for_each
(
this
,
&
c
->
erasable_pending_wbuf_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
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
))
{
if
(
list_empty
(
&
c
->
free_list
))
{
...
@@ -567,7 +637,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
...
@@ -567,7 +637,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
free_list
)
{
list_for_each
(
this
,
&
c
->
free_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
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
))
{
if
(
list_empty
(
&
c
->
bad_list
))
{
...
@@ -577,7 +648,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
...
@@ -577,7 +648,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
bad_list
)
{
list_for_each
(
this
,
&
c
->
bad_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
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
))
{
if
(
list_empty
(
&
c
->
bad_used_list
))
{
...
@@ -587,7 +659,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
...
@@ -587,7 +659,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each
(
this
,
&
c
->
bad_used_list
)
{
list_for_each
(
this
,
&
c
->
bad_used_list
)
{
struct
jffs2_eraseblock
*
jeb
=
list_entry
(
this
,
struct
jffs2_eraseblock
,
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 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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 @@
...
@@ -49,11 +49,19 @@
#define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
#define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
#endif
#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
)
static
inline
void
jffs2_init_inode_info
(
struct
jffs2_inode_info
*
f
)
{
{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
f
->
highest_version
=
0
;
f
->
highest_version
=
0
;
f
->
frag
list
=
NULL
;
f
->
frag
tree
=
RB_ROOT
;
f
->
metadata
=
NULL
;
f
->
metadata
=
NULL
;
f
->
dents
=
NULL
;
f
->
dents
=
NULL
;
f
->
flags
=
0
;
f
->
flags
=
0
;
...
...
fs/jffs2/read.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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
...
@@ -31,35 +31,41 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
if
(
!
ri
)
if
(
!
ri
)
return
-
ENOMEM
;
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
)
{
if
(
ret
)
{
jffs2_free_raw_inode
(
ri
);
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
;
return
ret
;
}
}
if
(
readlen
!=
sizeof
(
*
ri
))
{
if
(
readlen
!=
sizeof
(
*
ri
))
{
jffs2_free_raw_inode
(
ri
);
jffs2_free_raw_inode
(
ri
);
printk
(
KERN_WARNING
"Short read from 0x%08x: wanted 0x%x bytes, got 0x%x
\n
"
,
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
;
return
-
EIO
;
}
}
crc
=
crc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
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
));
D1
(
printk
(
KERN_DEBUG
"Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p
\n
"
,
if
(
crc
!=
ri
->
node_crc
)
{
ref_offset
(
fd
->
raw
),
je32_to_cpu
(
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
);
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
;
ret
=
-
EIO
;
goto
out_ri
;
goto
out_ri
;
}
}
/* There was a bug where we wrote hole nodes out with csize/dsize
/* There was a bug where we wrote hole nodes out with csize/dsize
swapped. Deal with it */
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
->
dsize
=
ri
->
csize
;
ri
->
csize
=
0
;
ri
->
csize
=
cpu_to_je32
(
0
)
;
}
}
D1
(
if
(
ofs
+
len
>
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
,
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
;
ret
=
-
EINVAL
;
goto
out_ri
;
goto
out_ri
;
});
});
...
@@ -76,18 +82,18 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
...
@@ -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 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
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
;
readbuf
=
buf
;
}
else
{
}
else
{
readbuf
=
kmalloc
(
ri
->
csize
,
GFP_KERNEL
);
readbuf
=
kmalloc
(
je32_to_cpu
(
ri
->
csize
)
,
GFP_KERNEL
);
if
(
!
readbuf
)
{
if
(
!
readbuf
)
{
ret
=
-
ENOMEM
;
ret
=
-
ENOMEM
;
goto
out_ri
;
goto
out_ri
;
}
}
}
}
if
(
ri
->
compr
!=
JFFS2_COMPR_NONE
)
{
if
(
ri
->
compr
!=
JFFS2_COMPR_NONE
)
{
if
(
len
<
ri
->
dsize
)
{
if
(
len
<
je32_to_cpu
(
ri
->
dsize
)
)
{
decomprbuf
=
kmalloc
(
ri
->
dsize
,
GFP_KERNEL
);
decomprbuf
=
kmalloc
(
je32_to_cpu
(
ri
->
dsize
)
,
GFP_KERNEL
);
if
(
!
decomprbuf
)
{
if
(
!
decomprbuf
)
{
ret
=
-
ENOMEM
;
ret
=
-
ENOMEM
;
goto
out_readbuf
;
goto
out_readbuf
;
...
@@ -99,31 +105,35 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
...
@@ -99,31 +105,35 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
decomprbuf
=
readbuf
;
decomprbuf
=
readbuf
;
}
}
D2
(
printk
(
KERN_DEBUG
"Read %d bytes to %p
\n
"
,
ri
->
csize
,
readbuf
));
D2
(
printk
(
KERN_DEBUG
"Read %d bytes to %p
\n
"
,
je32_to_cpu
(
ri
->
csize
),
ret
=
jffs2_flash_read
(
c
,
(
fd
->
raw
->
flash_offset
&~
3
)
+
sizeof
(
*
ri
),
ri
->
csize
,
&
readlen
,
readbuf
);
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
;
ret
=
-
EIO
;
if
(
ret
)
if
(
ret
)
goto
out_decomprbuf
;
goto
out_decomprbuf
;
crc
=
crc32
(
0
,
readbuf
,
ri
->
csize
);
crc
=
crc32
(
0
,
readbuf
,
je32_to_cpu
(
ri
->
csize
));
if
(
crc
!=
ri
->
data_crc
)
{
if
(
crc
!=
je32_to_cpu
(
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
);
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
;
ret
=
-
EIO
;
goto
out_decomprbuf
;
goto
out_decomprbuf
;
}
}
D2
(
printk
(
KERN_DEBUG
"Data CRC matches calculated CRC %08x
\n
"
,
crc
));
D2
(
printk
(
KERN_DEBUG
"Data CRC matches calculated CRC %08x
\n
"
,
crc
));
if
(
ri
->
compr
!=
JFFS2_COMPR_NONE
)
{
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
));
D2
(
printk
(
KERN_DEBUG
"Decompress %d bytes from %p to %d bytes at %p
\n
"
,
ret
=
jffs2_decompress
(
ri
->
compr
,
readbuf
,
decomprbuf
,
ri
->
csize
,
ri
->
dsize
);
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
)
{
if
(
ret
)
{
printk
(
KERN_WARNING
"Error: jffs2_decompress returned %d
\n
"
,
ret
);
printk
(
KERN_WARNING
"Error: jffs2_decompress returned %d
\n
"
,
ret
);
goto
out_decomprbuf
;
goto
out_decomprbuf
;
}
}
}
}
if
(
len
<
ri
->
dsize
)
{
if
(
len
<
je32_to_cpu
(
ri
->
dsize
)
)
{
memcpy
(
buf
,
decomprbuf
+
ofs
,
len
);
memcpy
(
buf
,
decomprbuf
+
ofs
,
len
);
}
}
out_decomprbuf:
out_decomprbuf:
...
@@ -142,16 +152,14 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
...
@@ -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
)
unsigned
char
*
buf
,
uint32_t
offset
,
uint32_t
len
)
{
{
uint32_t
end
=
offset
+
len
;
uint32_t
end
=
offset
+
len
;
struct
jffs2_node_frag
*
frag
=
f
->
fraglist
;
struct
jffs2_node_frag
*
frag
;
int
ret
;
int
ret
;
D1
(
printk
(
KERN_DEBUG
"jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x
\n
"
,
D1
(
printk
(
KERN_DEBUG
"jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x
\n
"
,
f
->
inocache
->
ino
,
offset
,
offset
+
len
));
f
->
inocache
->
ino
,
offset
,
offset
+
len
));
while
(
frag
&&
frag
->
ofs
+
frag
->
size
<=
offset
)
{
frag
=
jffs2_lookup_node_frag
(
&
f
->
fragtree
,
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
;
}
/* XXX FIXME: Where a single physical node actually shows up in two
/* XXX FIXME: Where a single physical node actually shows up in two
frags, we read it twice. Don't do that. */
frags, we read it twice. Don't do that. */
/* Now we're pointing at the first frag which overlaps our page */
/* 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,
...
@@ -181,25 +189,29 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
memset
(
buf
,
0
,
holeend
-
offset
);
memset
(
buf
,
0
,
holeend
-
offset
);
buf
+=
holeend
-
offset
;
buf
+=
holeend
-
offset
;
offset
=
holeend
;
offset
=
holeend
;
frag
=
frag
->
next
;
frag
=
frag
_next
(
frag
)
;
continue
;
continue
;
}
else
{
}
else
{
uint32_t
readlen
;
uint32_t
readlen
;
readlen
=
min
(
frag
->
size
,
end
-
offset
);
uint32_t
fragofs
;
/* offset within the frag to start reading */
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
);
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
"
));
D2
(
printk
(
KERN_DEBUG
"node read done
\n
"
));
if
(
ret
)
{
if
(
ret
)
{
D1
(
printk
(
KERN_DEBUG
"jffs2_read_inode_range error %d
\n
"
,
ret
));
D1
(
printk
(
KERN_DEBUG
"jffs2_read_inode_range error %d
\n
"
,
ret
));
memset
(
buf
,
0
,
frag
->
size
);
memset
(
buf
,
0
,
readlen
);
return
ret
;
return
ret
;
}
}
}
buf
+=
readlen
;
buf
+=
frag
->
size
;
offset
+=
readlen
;
offset
+=
frag
->
size
;
frag
=
frag_next
(
frag
);
frag
=
frag
->
next
;
D2
(
printk
(
KERN_DEBUG
"node read was OK. Looping
\n
"
));
D2
(
printk
(
KERN_DEBUG
"node read was OK. Looping
\n
"
));
}
}
}
return
0
;
return
0
;
}
}
...
...
fs/jffs2/readinode.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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 @@
...
@@ -15,24 +15,43 @@
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/crc32.h>
#include <linux/crc32.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include "nodelist.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
)
{
while
(
this
)
{
if
(
this
->
node
)
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
else
printk
(
KERN_DEBUG
"frag %04x-%04x: hole (*%p->%p)
\n
"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
,
this
,
this
->
next
);
printk
(
KERN_DEBUG
"frag %04x-%04x: hole (*%p). left (%p} right (%p), parent (%p)
\n
"
,
this
->
ofs
,
this
=
this
->
next
;
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
)
{
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
...
@@ -45,7 +64,7 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in
int
ret
;
int
ret
;
D1
(
printk
(
KERN_DEBUG
"jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)
\n
"
,
f
->
inocache
->
ino
,
f
,
fn
));
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
));
D2
(
jffs2_print_frag_list
(
f
));
return
ret
;
return
ret
;
...
@@ -58,13 +77,14 @@ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_
...
@@ -58,13 +77,14 @@ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_
if
(
!
this
->
node
->
frags
)
{
if
(
!
this
->
node
->
frags
)
{
/* The node has no valid frags left. It's totally obsoleted */
/* 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
"
,
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_mark_node_obsolete
(
c
,
this
->
node
->
raw
);
jffs2_free_full_dnode
(
this
->
node
);
jffs2_free_full_dnode
(
this
->
node
);
}
else
{
}
else
{
D2
(
printk
(
KERN_DEBUG
"
Not marking old node @0x%08x (0x%04x-0x%04x) obsolete
. frags is %d
\n
"
,
D2
(
printk
(
KERN_DEBUG
"
Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL
. frags is %d
\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
,
this
->
node
->
frags
));
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_
...
@@ -72,26 +92,23 @@ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_
}
}
/* Doesn't set inode->i_size */
/* 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
;
struct
jffs2_node_frag
*
this
,
**
prev
,
*
old
;
struct
jffs2_node_frag
*
newfrag
;
struct
jffs2_node_frag
*
newfrag
,
*
newfrag2
;
uint32_t
lastend
;
uint32_t
lastend
=
0
;
newfrag
=
jffs2_alloc_node_frag
();
newfrag
=
jffs2_alloc_node_frag
();
if
(
!
newfrag
)
{
if
(
!
newfrag
)
{
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
D2
(
if
(
fn
->
raw
)
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
);
printk
(
KERN_
WARNING
"dwmw2 is stupid. j_a_f_d_t_f should never happen with ->raw == NULL
\n
"
);
else
BUG
();
printk
(
KERN_DEBUG
"adding hole node %04x-%04x on flash, newfrag *%p
\n
"
,
fn
->
ofs
,
fn
->
ofs
+
fn
->
size
,
newfrag
));
}
prev
=
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
));
this
=
*
list
;
if
(
!
fn
->
size
)
{
if
(
!
fn
->
size
)
{
jffs2_free_node_frag
(
newfrag
);
jffs2_free_node_frag
(
newfrag
);
...
@@ -102,21 +119,33 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_
...
@@ -102,21 +119,33 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_
newfrag
->
size
=
fn
->
size
;
newfrag
->
size
=
fn
->
size
;
newfrag
->
node
=
fn
;
newfrag
->
node
=
fn
;
newfrag
->
node
->
frags
=
1
;
newfrag
->
node
->
frags
=
1
;
newfrag
->
next
=
(
void
*
)
0xdeadbeef
;
/* Skip all the nodes which are completed before this one starts */
/* Skip all the nodes which are completed before this one starts */
while
(
this
&&
fn
->
ofs
>=
this
->
ofs
+
this
->
size
)
{
this
=
jffs2_lookup_node_frag
(
list
,
fn
->
ofs
);
lastend
=
this
->
ofs
+
this
->
size
;
D2
(
printk
(
KERN_DEBUG
"j_a_f_d_t_f: skipping frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)
\n
"
,
if
(
this
)
{
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: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)
\n
"
,
prev
=
&
this
->
next
;
this
->
ofs
,
this
->
ofs
+
this
->
size
,
this
->
node
?
(
ref_offset
(
this
->
node
->
raw
))
:
0xffffffff
,
this
));
this
=
this
->
next
;
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 */
/* See if we ran off the end of the list */
if
(
!
thi
s
)
{
if
(
lastend
<=
newfrag
->
of
s
)
{
/* We did */
/* 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
)
{
if
(
lastend
<
fn
->
ofs
)
{
/* ... and we need to put a hole in before the new node */
/* ... and we need to put a hole in before the new node */
struct
jffs2_node_frag
*
holefrag
=
jffs2_alloc_node_frag
();
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_
...
@@ -124,96 +153,162 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_
return
-
ENOMEM
;
return
-
ENOMEM
;
holefrag
->
ofs
=
lastend
;
holefrag
->
ofs
=
lastend
;
holefrag
->
size
=
fn
->
ofs
-
lastend
;
holefrag
->
size
=
fn
->
ofs
-
lastend
;
holefrag
->
next
=
NULL
;
holefrag
->
node
=
NULL
;
holefrag
->
node
=
NULL
;
*
prev
=
holefrag
;
if
(
this
)
{
prev
=
&
holefrag
->
next
;
/* 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
;
rb_insert_color
(
&
newfrag
->
rb
,
list
);
*
prev
=
newfrag
;
return
0
;
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
"
,
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
?
(
this
->
node
->
raw
->
flash_offset
&~
3
)
:
0xffffffff
,
this
,
this
->
next
));
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,
/* OK. 'this' is pointing at the first frag that
newfrag
->ofs at least partially obsoletes,
* - i.e.
fn->ofs < this->ofs+this->size && fn
->ofs >= this->ofs
* - 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 */
/* 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 */
/* The new node splits 'this' frag into two */
newfrag2
=
jffs2_alloc_node_frag
();
struct
jffs2_node_frag
*
newfrag2
=
jffs2_alloc_node_frag
();
if
(
!
newfrag2
)
{
if
(
!
newfrag2
)
{
jffs2_free_node_frag
(
newfrag
);
jffs2_free_node_frag
(
newfrag
);
return
-
ENOMEM
;
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
)
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
else
printk
(
"hole
\n
"
);
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
->
size
=
(
this
->
ofs
+
this
->
size
)
-
newfrag2
->
ofs
;
newfrag2
->
next
=
this
->
next
;
newfrag2
->
node
=
this
->
node
;
newfrag2
->
node
=
this
->
node
;
if
(
this
->
node
)
if
(
this
->
node
)
this
->
node
->
frags
++
;
this
->
node
->
frags
++
;
newfrag
->
next
=
newfrag2
;
this
->
next
=
newfrag
;
/* Adjust size of original 'this' */
this
->
size
=
newfrag
->
ofs
-
this
->
ofs
;
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
;
return
0
;
}
}
/* New node just reduces 'this' frag in size, doesn't split it */
/* New node just reduces 'this' frag in size, doesn't split it */
this
->
size
=
fn
->
ofs
-
this
->
ofs
;
this
->
size
=
newfrag
->
ofs
-
this
->
ofs
;
newfrag
->
next
=
this
->
next
;
this
->
next
=
newfrag
;
/* Again, we know it lives down here in the tree */
this
=
newfrag
->
next
;
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
{
}
else
{
D2
(
printk
(
KERN_DEBUG
"Inserting newfrag (*%p) in before 'this' (*%p)
\n
"
,
newfrag
,
this
));
this
->
ofs
+=
newfrag
->
size
;
*
prev
=
newfrag
;
this
->
size
-=
newfrag
->
size
;
newfrag
->
next
=
this
;
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
)
{
while
(
(
this
=
frag_next
(
newfrag
))
&&
newfrag
->
ofs
+
newfrag
->
size
>=
this
->
ofs
+
this
->
size
)
{
/* 'this' frag is obsoleted. */
/* 'this' frag is obsoleted
completely
. */
old
=
this
;
D2
(
printk
(
KERN_DEBUG
"Obsoleting node frag %p (%x-%x) and removing from tree
\n
"
,
this
,
this
->
ofs
,
this
->
ofs
+
this
->
size
))
;
this
=
old
->
next
;
rb_erase
(
&
this
->
rb
,
list
)
;
jffs2_obsolete_node_frag
(
c
,
old
);
jffs2_obsolete_node_frag
(
c
,
this
);
}
}
/* Now we're pointing at the first frag which isn't totally obsoleted by
/* Now we're pointing at the first frag which isn't totally obsoleted by
the new frag */
the new frag */
newfrag
->
next
=
this
;
if
(
!
this
||
newfrag
->
ofs
+
newfrag
->
size
==
this
->
ofs
)
{
if
(
!
this
||
newfrag
->
ofs
+
newfrag
->
size
==
this
->
ofs
)
{
return
0
;
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
->
size
=
(
this
->
ofs
+
this
->
size
)
-
(
newfrag
->
ofs
+
newfrag
->
size
);
this
->
ofs
=
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
;
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
));
D1
(
printk
(
KERN_DEBUG
"Truncating fraglist to 0x%08x bytes
\n
"
,
size
));
while
(
*
list
)
{
/* We know frag->ofs <= size. That's what lookup does for us */
if
((
*
list
)
->
ofs
>=
size
)
{
if
(
frag
&&
frag
->
ofs
!=
size
)
{
struct
jffs2_node_frag
*
this
=
*
list
;
if
(
frag
->
ofs
+
frag
->
size
>=
size
)
{
*
list
=
this
->
next
;
D1
(
printk
(
KERN_DEBUG
"Truncating frag 0x%08x-0x%08x
\n
"
,
frag
->
ofs
,
frag
->
ofs
+
frag
->
size
));
D1
(
printk
(
KERN_DEBUG
"Removing frag 0x%08x-0x%08x
\n
"
,
this
->
ofs
,
this
->
ofs
+
this
->
size
));
frag
->
size
=
size
-
frag
->
ofs
;
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
;
}
}
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,
...
@@ -271,7 +366,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
fn
=
tn
->
fn
;
fn
=
tn
->
fn
;
if
(
f
->
metadata
&&
tn
->
version
>
mdata_ver
)
{
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_mark_node_obsolete
(
c
,
f
->
metadata
->
raw
);
jffs2_free_full_dnode
(
f
->
metadata
);
jffs2_free_full_dnode
(
f
->
metadata
);
f
->
metadata
=
NULL
;
f
->
metadata
=
NULL
;
...
@@ -283,7 +378,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
...
@@ -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
);
jffs2_add_full_dnode_to_inode
(
c
,
f
,
fn
);
}
else
{
}
else
{
/* Zero-sized node at end of version list. Just a metadata update */
/* 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
;
f
->
metadata
=
fn
;
mdata_ver
=
tn
->
version
;
mdata_ver
=
tn
->
version
;
}
}
...
@@ -299,16 +394,16 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
...
@@ -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
"
);
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
->
mode
=
cpu_to_je32
(
S_IFDIR
|
S_IRUGO
|
S_IWUSR
|
S_IXUGO
)
;
latest_node
->
version
=
0
;
latest_node
->
version
=
cpu_to_je32
(
0
)
;
latest_node
->
atime
=
latest_node
->
ctime
=
latest_node
->
mtime
=
0
;
latest_node
->
atime
=
latest_node
->
ctime
=
latest_node
->
mtime
=
cpu_to_je32
(
0
)
;
latest_node
->
isize
=
0
;
latest_node
->
isize
=
cpu_to_je32
(
0
)
;
latest_node
->
gid
=
0
;
latest_node
->
gid
=
cpu_to_je16
(
0
)
;
latest_node
->
uid
=
0
;
latest_node
->
uid
=
cpu_to_je16
(
0
)
;
return
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
))
{
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
"
,
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
));
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,
...
@@ -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
);
crc
=
crc32
(
0
,
latest_node
,
sizeof
(
*
latest_node
)
-
8
);
if
(
crc
!=
latest_node
->
node_crc
)
{
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
,
fn
->
raw
->
flash_offset
&
~
3
);
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
);
up
(
&
f
->
sem
);
jffs2_do_clear_inode
(
c
,
f
);
jffs2_do_clear_inode
(
c
,
f
);
return
-
EIO
;
return
-
EIO
;
}
}
switch
(
latest_node
->
mode
&
S_IFMT
)
{
switch
(
je32_to_cpu
(
latest_node
->
mode
)
&
S_IFMT
)
{
case
S_IFDIR
:
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
/* The times in the latest_node are actually older than
mctime in the latest dirent. Cheat. */
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
;
break
;
case
S_IFREG
:
case
S_IFREG
:
/* If it was a regular file, truncate it to the latest node's isize */
/* 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
;
break
;
case
S_IFLNK
:
case
S_IFLNK
:
...
@@ -346,7 +441,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
...
@@ -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
Remove this when dwmw2 comes to his senses and stops
symlinks from being an entirely gratuitous special
symlinks from being an entirely gratuitous special
case. */
case. */
if
(
!
latest_node
->
isize
)
if
(
!
je32_to_cpu
(
latest_node
->
isize
)
)
latest_node
->
isize
=
latest_node
->
dsize
;
latest_node
->
isize
=
latest_node
->
dsize
;
/* fall through... */
/* fall through... */
...
@@ -355,82 +450,79 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
...
@@ -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
/* Xertain inode types should have only one data node, and it's
kept as the metadata node */
kept as the metadata node */
if
(
f
->
metadata
)
{
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
);
up
(
&
f
->
sem
);
jffs2_do_clear_inode
(
c
,
f
);
jffs2_do_clear_inode
(
c
,
f
);
return
-
EIO
;
return
-
EIO
;
}
}
if
(
!
f
->
fraglist
)
{
if
(
!
f
rag_first
(
&
f
->
fragtree
)
)
{
printk
(
KERN_WARNING
"Argh. Special inode #%u with mode 0%o has no fragments
\n
"
,
ino
,
latest_node
->
mode
);
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
);
up
(
&
f
->
sem
);
jffs2_do_clear_inode
(
c
,
f
);
jffs2_do_clear_inode
(
c
,
f
);
return
-
EIO
;
return
-
EIO
;
}
}
/* ASSERT: f->fraglist != NULL */
/* ASSERT: f->fraglist != NULL */
if
(
f
->
fraglist
->
next
)
{
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
,
latest_node
->
mode
);
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 */
/* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
up
(
&
f
->
sem
);
up
(
&
f
->
sem
);
jffs2_do_clear_inode
(
c
,
f
);
jffs2_do_clear_inode
(
c
,
f
);
return
-
EIO
;
return
-
EIO
;
}
}
/* OK. We're happy */
/* OK. We're happy */
f
->
metadata
=
f
->
fraglist
->
node
;
f
->
metadata
=
f
rag_first
(
&
f
->
fragtree
)
->
node
;
jffs2_free_node_frag
(
f
->
fraglist
);
jffs2_free_node_frag
(
f
rag_first
(
&
f
->
fragtree
)
);
f
->
frag
list
=
NULL
;
f
->
frag
tree
=
RB_ROOT
;
break
;
break
;
}
}
f
->
inocache
->
state
=
INO_STATE_PRESENT
;
return
0
;
return
0
;
}
}
void
jffs2_do_clear_inode
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_inode_info
*
f
)
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
;
struct
jffs2_full_dirent
*
fd
,
*
fds
;
/* I don't think we care about the potential race due to reading this
/* If it's a deleted inode, grab the alloc_sem to keep the
without f->sem. It can never get undeleted. */
(maybe temporary) BUG() in jffs2_mark_node_obsolete()
int
deleted
=
f
->
inocache
&&
!
f
->
inocache
->
nlink
;
from triggering */
if
(
!
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
(
&
c
->
alloc_sem
);
down
(
&
f
->
sem
);
down
(
&
f
->
sem
);
frags
=
f
->
fraglist
;
fds
=
f
->
dents
;
if
(
f
->
metadata
)
{
if
(
f
->
metadata
)
{
if
(
!
f
->
inocache
->
nlink
)
if
(
deleted
)
jffs2_mark_node_obsolete
(
c
,
f
->
metadata
->
raw
);
jffs2_mark_node_obsolete
(
c
,
f
->
metadata
->
raw
);
jffs2_free_full_dnode
(
f
->
metadata
);
jffs2_free_full_dnode
(
f
->
metadata
);
}
}
while
(
frags
)
{
jffs2_kill_fragtree
(
&
f
->
fragtree
,
deleted
?
c
:
NULL
);
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
));
if
(
frag
->
node
&&
!
(
--
frag
->
node
->
frags
))
{
fds
=
f
->
dents
;
/* 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
);
jffs2_free_full_dnode
(
frag
->
node
);
}
jffs2_free_node_frag
(
frag
);
}
while
(
fds
)
{
while
(
fds
)
{
fd
=
fds
;
fd
=
fds
;
fds
=
fd
->
next
;
fds
=
fd
->
next
;
jffs2_free_full_dirent
(
fd
);
jffs2_free_full_dirent
(
fd
);
}
}
/* Urgh. Is there a nicer way to do this? */
if
(
f
->
inocache
)
if
(
!
f
->
inocache
->
nlink
)
{
f
->
inocache
->
state
=
INO_STATE_CHECKEDABSENT
;
up
(
&
f
->
sem
);
up
(
&
f
->
sem
);
if
(
deleted
)
up
(
&
c
->
alloc_sem
);
up
(
&
c
->
alloc_sem
);
}
else
{
up
(
&
f
->
sem
);
}
}
}
fs/jffs2/scan.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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>
#include <linux/kernel.h>
...
@@ -15,8 +15,10 @@
...
@@ -15,8 +15,10 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/mtd.h>
#include <linux/pagemap.h>
#include <linux/pagemap.h>
#include <linux/crc32.h>
#include <linux/crc32.h>
#include <linux/compiler.h>
#include "nodelist.h"
#include "nodelist.h"
#define EMPTY_SCAN_SIZE 1024
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->dirty_size += _x; \
c->free_size -= _x; c->dirty_size += _x; \
...
@@ -26,6 +28,10 @@
...
@@ -26,6 +28,10 @@
c->free_size -= _x; c->used_size += _x; \
c->free_size -= _x; c->used_size += _x; \
jeb->free_size -= _x ; jeb->used_size += _x; \
jeb->free_size -= _x ; jeb->used_size += _x; \
}while(0)
}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 { \
#define noisy_printk(noise, args...) do { \
if (*(noise)) { \
if (*(noise)) { \
...
@@ -39,15 +45,17 @@
...
@@ -39,15 +45,17 @@
static
uint32_t
pseudo_random
;
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.
/* 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
* Returning an error will abort the mount - bad checksums etc. should just mark the space
* as dirty.
* 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
,
static
int
jffs2_scan_inode_node
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
,
uint32_t
*
ofs
);
struct
jffs2_raw_inode
*
ri
,
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_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_ALLFF 0
#define BLK_STATE_CLEAN 1
#define BLK_STATE_CLEAN 1
...
@@ -60,15 +68,44 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
...
@@ -60,15 +68,44 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
{
{
int
i
,
ret
;
int
i
,
ret
;
uint32_t
empty_blocks
=
0
,
bad_blocks
=
0
;
uint32_t
empty_blocks
=
0
,
bad_blocks
=
0
;
unsigned
char
*
flashbuf
=
NULL
;
uint32_t
buf_size
=
0
;
size_t
pointlen
;
if
(
!
c
->
blocks
)
{
if
(
!
c
->
blocks
)
{
printk
(
KERN_WARNING
"EEEK! c->blocks is NULL!
\n
"
);
printk
(
KERN_WARNING
"EEEK! c->blocks is NULL!
\n
"
);
return
-
EINVAL
;
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
++
)
{
for
(
i
=
0
;
i
<
c
->
nr_blocks
;
i
++
)
{
struct
jffs2_eraseblock
*
jeb
=
&
c
->
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
)
if
(
ret
<
0
)
return
ret
;
return
ret
;
...
@@ -120,6 +157,11 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
...
@@ -120,6 +157,11 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
(
!
c
->
nextblock
||
c
->
nextblock
->
free_size
<
jeb
->
free_size
))
{
(
!
c
->
nextblock
||
c
->
nextblock
->
free_size
<
jeb
->
free_size
))
{
/* Better candidate for the next writes to go to */
/* Better candidate for the next writes to go to */
if
(
c
->
nextblock
)
{
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
))
{
if
(
VERYDIRTY
(
c
,
c
->
nextblock
->
dirty_size
))
{
list_add
(
&
c
->
nextblock
->
list
,
&
c
->
very_dirty_list
);
list_add
(
&
c
->
nextblock
->
list
,
&
c
->
very_dirty_list
);
}
else
{
}
else
{
...
@@ -128,6 +170,11 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
...
@@ -128,6 +170,11 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
}
}
c
->
nextblock
=
jeb
;
c
->
nextblock
=
jeb
;
}
else
{
}
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
))
{
if
(
VERYDIRTY
(
c
,
jeb
->
dirty_size
))
{
list_add
(
&
jeb
->
list
,
&
c
->
very_dirty_list
);
list_add
(
&
jeb
->
list
,
&
c
->
very_dirty_list
);
}
else
{
}
else
{
...
@@ -157,6 +204,14 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
...
@@ -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
(
!
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
/* If we're going to start writing into a block which already
contains data, and the end of the data isn't page-aligned,
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)
...
@@ -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
"
,
D1
(
printk
(
KERN_DEBUG
"jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment
\n
"
,
skip
));
skip
));
c
->
nextblock
->
dirty
_size
+=
skip
;
c
->
nextblock
->
wasted
_size
+=
skip
;
c
->
dirty
_size
+=
skip
;
c
->
wasted
_size
+=
skip
;
c
->
nextblock
->
free_size
-=
skip
;
c
->
nextblock
->
free_size
-=
skip
;
c
->
free_size
-=
skip
;
c
->
free_size
-=
skip
;
...
@@ -180,17 +235,47 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
...
@@ -180,17 +235,47 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
}
}
jffs2_erase_pending_trigger
(
c
);
jffs2_erase_pending_trigger
(
c
);
}
}
if
(
buf_size
)
kfree
(
flashbuf
);
else
c
->
mtd
->
unpoint
(
c
->
mtd
,
flashbuf
);
return
0
;
return
0
;
}
}
static
int
jffs2_scan_eraseblock
(
struct
jffs2_sb_info
*
c
,
struct
jffs2_eraseblock
*
jeb
)
{
static
int
jffs2_fill_scan_buf
(
struct
jffs2_sb_info
*
c
,
unsigned
char
*
buf
,
struct
jffs2_unknown_node
node
;
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
ofs
,
prevofs
;
uint32_t
hdr_crc
,
nodetype
;
uint32_t
hdr_crc
,
buf_ofs
,
buf_len
;
int
err
;
int
err
;
int
noise
=
0
;
int
noise
=
0
;
int
wasempty
=
0
;
uint32_t
empty_start
=
0
;
#ifdef CONFIG_JFFS2_FS_NAND
#ifdef CONFIG_JFFS2_FS_NAND
int
cleanmarkerfound
=
0
;
int
cleanmarkerfound
=
0
;
#endif
#endif
ofs
=
jeb
->
offset
;
ofs
=
jeb
->
offset
;
...
@@ -214,16 +299,30 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
...
@@ -214,16 +299,30 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
}
}
}
}
#endif
#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
)
if
(
err
)
return
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
#ifdef CONFIG_JFFS2_FS_NAND
if
(
jffs2_cleanmarker_oob
(
c
))
{
if
(
jffs2_cleanmarker_oob
(
c
))
{
/* scan oob, take care of cleanmarker */
/* scan oob, take care of cleanmarker */
int
ret
=
jffs2_check_oob_empty
(
c
,
jeb
,
cleanmarkerfound
);
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
)
{
switch
(
ret
)
{
case
0
:
return
cleanmarkerfound
?
BLK_STATE_CLEANMARKER
:
BLK_STATE_ALLFF
;
case
0
:
return
cleanmarkerfound
?
BLK_STATE_CLEANMARKER
:
BLK_STATE_ALLFF
;
case
1
:
return
BLK_STATE_ALLDIRTY
;
case
1
:
return
BLK_STATE_ALLDIRTY
;
...
@@ -236,12 +335,20 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
...
@@ -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
));
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 */
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
;
noise
=
10
;
while
(
ofs
<
jeb
->
offset
+
c
->
sector_size
)
{
while
(
ofs
<
jeb
->
offset
+
c
->
sector_size
)
{
size_t
retlen
;
ACCT_PARANOIA_CHECK
(
jeb
);
D1
(
ACCT_PARANOIA_CHECK
(
jeb
)
);
cond_resched
();
cond_resched
();
...
@@ -258,109 +365,173 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
...
@@ -258,109 +365,173 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
}
}
prevofs
=
ofs
;
prevofs
=
ofs
;
if
(
jeb
->
offset
+
c
->
sector_size
<
ofs
+
sizeof
(
node
))
{
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
)));
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
);
DIRTY_SPACE
((
jeb
->
offset
+
c
->
sector_size
)
-
ofs
);
break
;
break
;
}
}
err
=
jffs2_flash_read
(
c
,
ofs
,
sizeof
(
node
),
&
retlen
,
(
char
*
)
&
node
);
if
(
buf_ofs
+
buf_len
<
ofs
+
sizeof
(
*
node
))
{
if
(
err
)
{
buf_len
=
min_t
(
uint32_t
,
buf_size
,
jeb
->
offset
+
c
->
sector_size
-
ofs
);
D1
(
printk
(
KERN_WARNING
"mtd->read(0x%x bytes from 0x%x) returned %d
\n
"
,
sizeof
(
node
),
ofs
,
err
));
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
;
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
));
node
=
(
struct
jffs2_unknown_node
*
)
&
buf
[
ofs
-
buf_ofs
];
DIRTY_SPACE
(
retlen
);
ofs
+=
retlen
;
if
(
*
(
uint32_t
*
)(
&
buf
[
ofs
-
buf_ofs
])
==
0xffffffff
)
{
continue
;
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
)
{
if
(
buf_ofs
==
jeb
->
offset
&&
jeb
->
used_size
==
PAD
(
c
->
cleanmarker_size
)
&&
D1
(
printk
(
KERN_DEBUG
"Found empty flash at 0x%x
\n
"
,
ofs
));
!
jeb
->
first_node
->
next_in_ino
&&
!
jeb
->
dirty_size
)
err
=
jffs2_scan_empty
(
c
,
jeb
,
&
ofs
,
&
noise
);
return
BLK_STATE_CLEANMARKER
;
if
(
err
)
return
err
;
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
;
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
);
printk
(
KERN_WARNING
"Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?
\n
"
,
ofs
);
DIRTY_SPACE
(
4
);
DIRTY_SPACE
(
4
);
ofs
+=
4
;
ofs
+=
4
;
continue
;
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
));
D1
(
printk
(
KERN_DEBUG
"Empty bitmask at 0x%08x
\n
"
,
ofs
));
DIRTY_SPACE
(
4
);
DIRTY_SPACE
(
4
);
ofs
+=
4
;
ofs
+=
4
;
continue
;
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
"Old JFFS2 bitmask found at 0x%08x
\n
"
,
ofs
);
printk
(
KERN_WARNING
"You cannot use older JFFS2 filesystems with newer kernels
\n
"
);
printk
(
KERN_WARNING
"You cannot use older JFFS2 filesystems with newer kernels
\n
"
);
DIRTY_SPACE
(
4
);
DIRTY_SPACE
(
4
);
ofs
+=
4
;
ofs
+=
4
;
continue
;
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 */
/* 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
);
DIRTY_SPACE
(
4
);
ofs
+=
4
;
ofs
+=
4
;
continue
;
continue
;
}
}
/* We seem to have a node of sorts. Check the CRC */
/* We seem to have a node of sorts. Check the CRC */
nodetype
=
node
.
nodetype
;
crcnode
.
magic
=
node
->
magic
;
node
.
nodetype
|=
JFFS2_NODE_ACCURATE
;
crcnode
.
nodetype
=
cpu_to_je16
(
je16_to_cpu
(
node
->
nodetype
)
|
JFFS2_NODE_ACCURATE
);
hdr_crc
=
crc32
(
0
,
&
node
,
sizeof
(
node
)
-
4
);
crcnode
.
totlen
=
node
->
totlen
;
node
.
nodetype
=
nodetype
;
hdr_crc
=
crc32
(
0
,
&
crcnode
,
sizeof
(
crcnode
)
-
4
);
if
(
hdr_crc
!=
node
.
hdr_crc
)
{
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
"
,
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
);
DIRTY_SPACE
(
4
);
ofs
+=
4
;
ofs
+=
4
;
continue
;
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. */
/* 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
"
,
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
"
);
printk
(
KERN_WARNING
"Perhaps the file system was created with the wrong erase size?
\n
"
);
DIRTY_SPACE
(
4
);
DIRTY_SPACE
(
4
);
ofs
+=
4
;
ofs
+=
4
;
continue
;
continue
;
}
}
if
(
!
(
node
.
nodetype
&
JFFS2_NODE_ACCURATE
))
{
if
(
!
(
je16_to_cpu
(
node
->
nodetype
)
&
JFFS2_NODE_ACCURATE
))
{
/* Wheee. This is an obsoleted node */
/* Wheee. This is an obsoleted node */
D2
(
printk
(
KERN_DEBUG
"Node at 0x%08x is obsolete. Skipping
\n
"
,
ofs
));
D2
(
printk
(
KERN_DEBUG
"Node at 0x%08x is obsolete. Skipping
\n
"
,
ofs
));
DIRTY_SPACE
(
PAD
(
node
.
totlen
));
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
node
->
totlen
)
));
ofs
+=
PAD
(
node
.
totlen
);
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
)
);
continue
;
continue
;
}
}
switch
(
node
.
nodetype
)
{
switch
(
je16_to_cpu
(
node
->
nodetype
)
)
{
case
JFFS2_NODETYPE_INODE
:
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
;
if
(
err
)
return
err
;
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
));
break
;
break
;
case
JFFS2_NODETYPE_DIRENT
:
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
;
if
(
err
)
return
err
;
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
));
break
;
break
;
case
JFFS2_NODETYPE_CLEANMARKER
:
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
"
,
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
)));
DIRTY_SPACE
(
PAD
(
sizeof
(
struct
jffs2_unknown_node
)));
ofs
+=
PAD
(
sizeof
(
struct
jffs2_unknown_node
));
}
else
if
(
jeb
->
first_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
);
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
)));
DIRTY_SPACE
(
PAD
(
sizeof
(
struct
jffs2_unknown_node
)));
ofs
+=
PAD
(
sizeof
(
struct
jffs2_unknown_node
));
ofs
+=
PAD
(
sizeof
(
struct
jffs2_unknown_node
));
continue
;
}
else
{
}
else
{
struct
jffs2_raw_node_ref
*
marker_ref
=
jffs2_alloc_raw_node_ref
();
struct
jffs2_raw_node_ref
*
marker_ref
=
jffs2_alloc_raw_node_ref
();
if
(
!
marker_ref
)
{
if
(
!
marker_ref
)
{
...
@@ -369,45 +540,45 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
...
@@ -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_in_ino
=
NULL
;
marker_ref
->
next_phys
=
NULL
;
marker_ref
->
next_phys
=
NULL
;
marker_ref
->
flash_offset
=
ofs
;
marker_ref
->
flash_offset
=
ofs
|
REF_NORMAL
;
marker_ref
->
totlen
=
sizeof
(
struct
jffs2_unknown_node
)
;
marker_ref
->
totlen
=
c
->
cleanmarker_size
;
jeb
->
first_node
=
jeb
->
last_node
=
marker_ref
;
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
;
break
;
case
JFFS2_NODETYPE_PADDING
:
case
JFFS2_NODETYPE_PADDING
:
DIRTY_SPACE
(
PAD
(
node
.
totlen
));
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
node
->
totlen
)
));
ofs
+=
PAD
(
node
.
totlen
);
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
)
);
break
;
break
;
default:
default:
switch
(
node
.
nodetype
&
JFFS2_COMPAT_MASK
)
{
switch
(
je16_to_cpu
(
node
->
nodetype
)
&
JFFS2_COMPAT_MASK
)
{
case
JFFS2_FEATURE_ROCOMPAT
:
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
;
c
->
flags
|=
JFFS2_SB_FLAG_RO
;
if
(
!
(
jffs2_is_readonly
(
c
)))
if
(
!
(
jffs2_is_readonly
(
c
)))
return
-
EROFS
;
return
-
EROFS
;
DIRTY_SPACE
(
PAD
(
node
.
totlen
));
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
node
->
totlen
)
));
ofs
+=
PAD
(
node
.
totlen
);
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
)
);
break
;
break
;
case
JFFS2_FEATURE_INCOMPAT
:
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
;
return
-
EINVAL
;
case
JFFS2_FEATURE_RWCOMPAT_DELETE
:
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
));
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
(
node
.
totlen
));
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
node
->
totlen
)
));
ofs
+=
PAD
(
node
.
totlen
);
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
)
);
break
;
break
;
case
JFFS2_FEATURE_RWCOMPAT_COPY
:
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
));
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
(
node
.
totlen
));
USED_SPACE
(
PAD
(
je32_to_cpu
(
node
->
totlen
)
));
ofs
+=
PAD
(
node
.
totlen
);
ofs
+=
PAD
(
je32_to_cpu
(
node
->
totlen
)
);
break
;
break
;
}
}
}
}
...
@@ -417,64 +588,30 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
...
@@ -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
,
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
));
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
)
!
jeb
->
first_node
->
next_in_ino
&&
!
jeb
->
dirty_size
)
return
BLK_STATE_CLEANMARKER
;
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
;
return
BLK_STATE_CLEAN
;
else
if
(
jeb
->
us
ed_size
)
}
else
if
(
jeb
->
used_size
||
jeb
->
uncheck
ed_size
)
return
BLK_STATE_PARTDIRTY
;
return
BLK_STATE_PARTDIRTY
;
else
else
return
BLK_STATE_ALLDIRTY
;
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
)
static
struct
jffs2_inode_cache
*
jffs2_scan_make_ino_cache
(
struct
jffs2_sb_info
*
c
,
uint32_t
ino
)
{
{
struct
jffs2_inode_cache
*
ic
;
struct
jffs2_inode_cache
*
ic
;
...
@@ -489,13 +626,7 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
...
@@ -489,13 +626,7 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
return
NULL
;
return
NULL
;
}
}
memset
(
ic
,
0
,
sizeof
(
*
ic
));
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
->
ino
=
ino
;
ic
->
nodes
=
(
void
*
)
ic
;
ic
->
nodes
=
(
void
*
)
ic
;
jffs2_add_ino_cache
(
c
,
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
...
@@ -504,116 +635,58 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
return
ic
;
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_raw_node_ref
*
raw
;
struct
jffs2_full_dnode
*
fn
;
struct
jffs2_tmp_dnode_info
*
tn
,
**
tn_list
;
struct
jffs2_inode_cache
*
ic
;
struct
jffs2_inode_cache
*
ic
;
struct
jffs2_raw_inode
ri
;
uint32_t
ino
=
je32_to_cpu
(
ri
->
ino
);
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
));
ret
=
jffs2_flash_read
(
c
,
*
ofs
,
sizeof
(
ri
),
&
retlen
,
(
char
*
)
&
ri
);
D1
(
printk
(
KERN_DEBUG
"jffs2_scan_inode_node(): Node at 0x%08x
\n
"
,
ofs
));
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
;
}
if
(
ri
.
csize
)
{
/* We do very little here now. Just check the ino# to which we should attribute
/* Check data CRC too */
this node; we can do all the CRC checking etc. later. There's a tradeoff here --
unsigned
char
*
dbuf
;
we used to scan the flash once only, reading everything we want from it into
uint32_t
crc
;
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
();
raw
=
jffs2_alloc_raw_node_ref
();
if
(
!
raw
)
{
if
(
!
raw
)
{
printk
(
KERN_NOTICE
"jffs2_scan_inode_node(): allocation of node reference failed
\n
"
);
printk
(
KERN_NOTICE
"jffs2_scan_inode_node(): allocation of node reference failed
\n
"
);
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
tn
=
jffs2_alloc_tmp_dnode_info
();
if
(
!
tn
)
{
ic
=
jffs2_get_ino_cache
(
c
,
ino
);
jffs2_free_raw_node_ref
(
raw
);
if
(
!
ic
)
{
return
-
ENOMEM
;
/* 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
fn
=
jffs2_alloc_full_dnode
();
case */
if
(
!
fn
)
{
uint32_t
crc
=
crc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
jffs2_free_tmp_dnode_info
(
tn
);
jffs2_free_raw_node_ref
(
raw
);
if
(
crc
!=
je32_to_cpu
(
ri
->
node_crc
))
{
return
-
ENOMEM
;
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
)
{
if
(
!
ic
)
{
jffs2_free_full_dnode
(
fn
);
jffs2_free_tmp_dnode_info
(
tn
);
jffs2_free_raw_node_ref
(
raw
);
jffs2_free_raw_node_ref
(
raw
);
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
}
/* Wheee. It worked */
/* Build the data structures and file them for later */
raw
->
flash_offset
=
ofs
|
REF_UNCHECKED
;
raw
->
flash_offset
=
*
ofs
;
raw
->
totlen
=
PAD
(
je32_to_cpu
(
ri
->
totlen
));
raw
->
totlen
=
PAD
(
ri
.
totlen
);
raw
->
next_phys
=
NULL
;
raw
->
next_phys
=
NULL
;
raw
->
next_in_ino
=
ic
->
nodes
;
raw
->
next_in_ino
=
ic
->
nodes
;
ic
->
nodes
=
raw
;
ic
->
nodes
=
raw
;
if
(
!
jeb
->
first_node
)
if
(
!
jeb
->
first_node
)
jeb
->
first_node
=
raw
;
jeb
->
first_node
=
raw
;
...
@@ -622,146 +695,56 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
...
@@ -622,146 +695,56 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
jeb
->
last_node
=
raw
;
jeb
->
last_node
=
raw
;
D1
(
printk
(
KERN_DEBUG
"Node is ino #%u, version %d. Range 0x%x-0x%x
\n
"
,
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
));
je32_to_cpu
(
ri
->
ino
),
je32_to_cpu
(
ri
->
version
),
je32_to_cpu
(
ri
->
offset
),
pseudo_random
+=
ri
.
version
;
je32_to_cpu
(
ri
->
offset
)
+
je32_to_cpu
(
ri
->
dsize
)));
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
);
/* Make sure the one we just added is the _last_ in the list
pseudo_random
+=
je32_to_cpu
(
ri
->
version
);
with this version number, so the older ones get obsoleted */
while
(
tn
->
next
&&
tn
->
next
->
version
==
tn
->
version
)
{
D1
(
printk
(
KERN_DEBUG
"Shifting new node at 0x%08x after other node at 0x%08x for version %d in list
\n
"
,
UNCHECKED_SPACE
(
PAD
(
je32_to_cpu
(
ri
->
totlen
)));
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
);
return
0
;
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_raw_node_ref
*
raw
;
struct
jffs2_full_dirent
*
fd
;
struct
jffs2_full_dirent
*
fd
;
struct
jffs2_inode_cache
*
ic
;
struct
jffs2_inode_cache
*
ic
;
struct
jffs2_raw_dirent
rd
;
uint16_t
oldnodetype
;
int
ret
;
uint32_t
crc
;
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
);
/* We don't get here unless the node is still valid, so we don't have to
if
(
ret
)
{
mask in the ACCURATE bit any more. */
printk
(
KERN_NOTICE
"jffs2_scan_dirent_node(): Read error at 0x%08x: %d
\n
"
,
*
ofs
,
ret
);
crc
=
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
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
;
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
"
,
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
);
ofs
,
je32_to_cpu
(
rd
->
node_crc
),
crc
);
/* FIXME: Why do we believe totlen? */
/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
DIRTY_SPACE
(
4
);
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
rd
->
totlen
)));
*
ofs
+=
4
;
return
0
;
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
)
{
if
(
!
fd
)
{
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
ret
=
jffs2_flash_read
(
c
,
*
ofs
+
sizeof
(
rd
),
rd
.
nsize
,
&
retlen
,
&
fd
->
name
[
0
]);
memcpy
(
&
fd
->
name
,
rd
->
name
,
rd
->
nsize
);
if
(
ret
)
{
fd
->
name
[
rd
->
nsize
]
=
0
;
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
;
}
crc
=
crc32
(
0
,
fd
->
name
,
rd
.
nsize
);
crc
=
crc32
(
0
,
fd
->
name
,
rd
->
nsize
);
if
(
crc
!=
rd
.
name_crc
)
{
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
"
,
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
);
ofs
,
je32_to_cpu
(
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
,
je32_to_cpu
(
rd
->
ino
)));
D1
(
printk
(
KERN_NOTICE
"Name for which CRC failed is (now) '%s', ino #%d
\n
"
,
fd
->
name
,
rd
.
ino
));
jffs2_free_full_dirent
(
fd
);
jffs2_free_full_dirent
(
fd
);
/* FIXME: Why do we believe totlen? */
/* FIXME: Why do we believe totlen? */
DIRTY_SPACE
(
PAD
(
rd
.
totlen
));
/* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */
*
ofs
+=
PAD
(
rd
.
totlen
);
DIRTY_SPACE
(
PAD
(
je32_to_cpu
(
rd
->
totlen
))
);
return
0
;
return
0
;
}
}
raw
=
jffs2_alloc_raw_node_ref
();
raw
=
jffs2_alloc_raw_node_ref
();
...
@@ -770,15 +753,15 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
...
@@ -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
"
);
printk
(
KERN_NOTICE
"jffs2_scan_dirent_node(): allocation of node reference failed
\n
"
);
return
-
ENOMEM
;
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
)
{
if
(
!
ic
)
{
jffs2_free_full_dirent
(
fd
);
jffs2_free_full_dirent
(
fd
);
jffs2_free_raw_node_ref
(
raw
);
jffs2_free_raw_node_ref
(
raw
);
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
raw
->
totlen
=
PAD
(
rd
.
totlen
);
raw
->
totlen
=
PAD
(
je32_to_cpu
(
rd
->
totlen
)
);
raw
->
flash_offset
=
*
ofs
;
raw
->
flash_offset
=
ofs
|
REF_PRISTINE
;
raw
->
next_phys
=
NULL
;
raw
->
next_phys
=
NULL
;
raw
->
next_in_ino
=
ic
->
nodes
;
raw
->
next_in_ino
=
ic
->
nodes
;
ic
->
nodes
=
raw
;
ic
->
nodes
=
raw
;
...
@@ -788,22 +771,15 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
...
@@ -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
->
next_phys
=
raw
;
jeb
->
last_node
=
raw
;
jeb
->
last_node
=
raw
;
if
(
rd
.
nodetype
&
JFFS2_NODE_ACCURATE
)
{
fd
->
raw
=
raw
;
fd
->
raw
=
raw
;
fd
->
next
=
NULL
;
fd
->
next
=
NULL
;
fd
->
version
=
rd
.
version
;
fd
->
version
=
je32_to_cpu
(
rd
->
version
);
fd
->
ino
=
rd
.
ino
;
fd
->
ino
=
je32_to_cpu
(
rd
->
ino
);
fd
->
name
[
rd
.
nsize
]
=
0
;
fd
->
nhash
=
full_name_hash
(
fd
->
name
,
rd
->
nsize
);
fd
->
nhash
=
full_name_hash
(
fd
->
name
,
rd
.
nsize
);
fd
->
type
=
rd
->
type
;
fd
->
type
=
rd
.
type
;
USED_SPACE
(
PAD
(
je32_to_cpu
(
rd
->
totlen
)));
USED_SPACE
(
PAD
(
rd
.
totlen
));
jffs2_add_fd_to_list
(
c
,
fd
,
&
ic
->
scan_dents
);
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
);
return
0
;
return
0
;
}
}
...
...
fs/jffs2/super.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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 @@
...
@@ -7,8 +7,9 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* For licensing information, see the file 'LICENCE' in this directory.
*
*
* $Id: wbuf.c,v 1.12 2002/05/20 14:56:39 dwmw2 Exp $
* $Id: wbuf.c,v 1.20 2002/11/12 11:33:02 dwmw2 Exp $
* -- with the NAND definitions added back pending MTD update for 2.5.
* + some of the dependencies on later MTD NAND code temporarily reverted.
*
*/
*/
#include <linux/kernel.h>
#include <linux/kernel.h>
...
@@ -16,17 +17,22 @@
...
@@ -16,17 +17,22 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/crc32.h>
#include <linux/crc32.h>
#include <linux/mtd/nand.h>
#include "nodelist.h"
#include "nodelist.h"
/* FIXME duplicated defines in wbuf.c and nand.c
/* FIXME duplicated defines in wbuf.c and nand.c
* Constants for out of band layout
* 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_OOB_BADBPOS 5
#define NAND_JFFS2_OOB8_FSDAPOS 6
#define NAND_JFFS2_OOB8_FSDAPOS 6
#define NAND_JFFS2_OOB16_FSDAPOS 8
#define NAND_JFFS2_OOB16_FSDAPOS 8
#define NAND_JFFS2_OOB8_FSDALEN 2
#define NAND_JFFS2_OOB8_FSDALEN 2
#define NAND_JFFS2_OOB16_FSDALEN 8
#define NAND_JFFS2_OOB16_FSDALEN 8
#endif
/* max. erase failures before we mark a block bad */
/* max. erase failures before we mark a block bad */
#define MAX_ERASE_FAILURES 5
#define MAX_ERASE_FAILURES 5
...
@@ -89,17 +95,39 @@ void jffs2_wbuf_process (void *data)
...
@@ -89,17 +95,39 @@ void jffs2_wbuf_process (void *data)
D1
(
printk
(
KERN_DEBUG
"jffs2_wbuf_process() entered
\n
"
));
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
"
));
D1
(
printk
(
KERN_DEBUG
"jffs2_wbuf_process() alloc_sem got
\n
"
));
if
(
!
c
->
nextblock
||
(
c
->
nextblock
->
free_size
<
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
)))
if
(
!
c
->
nextblock
)
{
jffs2_flush_wbuf
(
c
,
1
);
/* pad only */
D1
(
printk
(
KERN_DEBUG
"jffs2_wbuf_process(): nextblock NULL, nothing to do
\n
"
));
else
if
(
c
->
wbuf_len
)
{
jffs2_flush_wbuf
(
c
,
2
);
/* pad and adjust nextblock */
printk
(
KERN_WARNING
"jffs2_wbuf_process(): c->wbuf_len is 0x%03x but nextblock is NULL!
\n
"
,
c
->
wbuf_len
);
up
(
&
c
->
alloc_sem
);
up
(
&
c
->
alloc_sem
);
}
else
{
BUG
();
D1
(
printk
(
KERN_DEBUG
"jffs2_wbuf_process() alloc_sem already occupied
\n
"
));
}
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)
...
@@ -113,6 +141,11 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
int
ret
;
int
ret
;
size_t
retlen
;
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
))
{
if
(
!
down_trylock
(
&
c
->
alloc_sem
))
{
up
(
&
c
->
alloc_sem
);
up
(
&
c
->
alloc_sem
);
printk
(
KERN_CRIT
"jffs2_flush_wbuf() called with alloc_sem not locked!
\n
"
);
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)
...
@@ -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
)
{
if
(
c
->
wbuf_len
+
sizeof
(
struct
jffs2_unknown_node
)
<
c
->
wbuf_pagesize
)
{
struct
jffs2_unknown_node
*
padnode
=
(
void
*
)(
c
->
wbuf
+
c
->
wbuf_len
);
struct
jffs2_unknown_node
*
padnode
=
(
void
*
)(
c
->
wbuf
+
c
->
wbuf_len
);
padnode
->
magic
=
JFFS2_MAGIC_BITMASK
;
padnode
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
padnode
->
nodetype
=
JFFS2_NODETYPE_PADDING
;
padnode
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_PADDING
)
;
padnode
->
totlen
=
c
->
wbuf_pagesize
-
c
->
wbuf_len
;
padnode
->
totlen
=
c
pu_to_je32
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
)
;
padnode
->
hdr_crc
=
c
rc32
(
0
,
padnode
,
sizeof
(
*
padnode
)
-
4
);
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
/* 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)
...
@@ -175,10 +208,20 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
spin_lock_bh
(
&
c
->
erase_completion_lock
);
spin_lock_bh
(
&
c
->
erase_completion_lock
);
if
(
!
c
->
nextblock
)
if
(
!
c
->
nextblock
)
BUG
();
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
();
BUG
();
}
c
->
nextblock
->
free_size
-=
(
c
->
wbuf_pagesize
-
c
->
wbuf_len
);
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
);
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
...
@@ -415,9 +458,10 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
int
ret
;
int
ret
;
/* Read flash */
/* Read flash */
if
(
!
jffs2_can_mark_obsolete
(
c
))
{
ret
=
c
->
mtd
->
read
(
c
->
mtd
,
ofs
,
len
,
retlen
,
buf
);
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
);
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
* 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
...
@@ -431,12 +475,13 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
*/
*/
ret
=
0
;
ret
=
0
;
}
}
}
else
return
c
->
mtd
->
read
(
c
->
mtd
,
ofs
,
len
,
retlen
,
buf
);
/* if no writebuffer available or write buffer empty, return */
/* if no writebuffer available or write buffer empty, return */
if
(
!
c
->
wbuf_pagesize
||
!
c
->
wbuf_len
)
if
(
!
c
->
wbuf_pagesize
||
!
c
->
wbuf_len
)
return
ret
;
return
ret
;
/* if we read in a different block, return */
/* if we read in a different block, return */
if
(
(
ofs
&
~
(
c
->
sector_size
-
1
))
!=
(
c
->
wbuf_ofs
&
~
(
c
->
sector_size
-
1
))
)
if
(
(
ofs
&
~
(
c
->
sector_size
-
1
))
!=
(
c
->
wbuf_ofs
&
~
(
c
->
sector_size
-
1
))
)
return
ret
;
return
ret
;
...
@@ -478,7 +523,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
...
@@ -478,7 +523,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
switch
(
c
->
mtd
->
ecctype
)
{
switch
(
c
->
mtd
->
ecctype
)
{
case
MTD_ECC_SW
:
case
MTD_ECC_SW
:
fsdata_pos
=
(
c
->
wbuf_pagesize
==
256
)
?
NAND_JFFS2_OOB8_FSDAPOS
:
NAND_JFFS2_OOB16_FSDAPOS
;
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
;
break
;
default:
default:
D1
(
printk
(
KERN_WARNING
"jffs2_write_oob_empty(): Invalid ECC type
\n
"
));
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
...
@@ -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 */
/* 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
);
buf
=
kmalloc
(
len
,
GFP_KERNEL
);
if
(
!
buf
)
{
if
(
!
buf
)
{
printk
(
KERN_NOTICE
"jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed
\n
"
);
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
...
@@ -510,7 +555,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
}
}
/* Special check for first two pages */
/* 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 */
/* Check for bad block marker */
if
(
buf
[
page
+
badblock_pos
]
!=
0xff
)
{
if
(
buf
[
page
+
badblock_pos
]
!=
0xff
)
{
D1
(
printk
(
KERN_WARNING
"jffs2_check_oob_empty(): Bad or failed block at %08x
\n
"
,
jeb
->
offset
));
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
...
@@ -563,7 +608,7 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
case
MTD_ECC_SW
:
case
MTD_ECC_SW
:
fsdata_pos
=
(
c
->
wbuf_pagesize
==
256
)
?
NAND_JFFS2_OOB8_FSDAPOS
:
NAND_JFFS2_OOB16_FSDAPOS
;
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
;
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
;
break
;
default:
default:
D1
(
printk
(
KERN_WARNING
"jffs2_write_nand_cleanmarker(): Invalid ECC type
\n
"
));
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
...
@@ -598,9 +643,9 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
return
3
;
return
3
;
}
}
n
.
magic
=
JFFS2_MAGIC_BITMASK
;
n
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
n
.
nodetype
=
JFFS2_NODETYPE_CLEANMARKER
;
n
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_CLEANMARKER
)
;
n
.
totlen
=
8
;
n
.
totlen
=
cpu_to_je32
(
8
)
;
p
=
(
unsigned
char
*
)
&
n
;
p
=
(
unsigned
char
*
)
&
n
;
for
(
i
=
0
;
i
<
fsdata_len
;
i
++
)
{
for
(
i
=
0
;
i
<
fsdata_len
;
i
++
)
{
...
@@ -630,9 +675,9 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
...
@@ -630,9 +675,9 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
return
-
EINVAL
;
return
-
EINVAL
;
}
}
n
.
magic
=
JFFS2_MAGIC_BITMASK
;
n
.
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
n
.
nodetype
=
JFFS2_NODETYPE_CLEANMARKER
;
n
.
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_CLEANMARKER
)
;
n
.
totlen
=
8
;
n
.
totlen
=
cpu_to_je32
(
8
)
;
ret
=
jffs2_flash_write_oob
(
c
,
jeb
->
offset
+
fsdata_pos
,
fsdata_len
,
&
retlen
,
(
unsigned
char
*
)
&
n
);
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
...
@@ -661,7 +706,7 @@ int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
switch
(
c
->
mtd
->
ecctype
)
{
switch
(
c
->
mtd
->
ecctype
)
{
case
MTD_ECC_SW
:
case
MTD_ECC_SW
:
badblock_pos
=
NAND_
JFFS2_OOB_BADB
POS
;
badblock_pos
=
NAND_
BADBLOCK_
POS
;
break
;
break
;
default:
default:
D1
(
printk
(
KERN_WARNING
"jffs2_nand_read_failcnt(): Invalid ECC type
\n
"
));
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 *
...
@@ -702,7 +747,7 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *
switch
(
c
->
mtd
->
ecctype
)
{
switch
(
c
->
mtd
->
ecctype
)
{
case
MTD_ECC_SW
:
case
MTD_ECC_SW
:
pos
=
NAND_
JFFS2_OOB_BADB
POS
;
pos
=
NAND_
BADBLOCK_
POS
;
break
;
break
;
default:
default:
D1
(
printk
(
KERN_WARNING
"jffs2_write_nand_badblock(): Invalid ECC type
\n
"
));
D1
(
printk
(
KERN_WARNING
"jffs2_write_nand_badblock(): Invalid ECC type
\n
"
));
...
...
fs/jffs2/write.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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 @@
...
@@ -15,6 +15,7 @@
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/crc32.h>
#include <linux/crc32.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/mtd.h>
#include "nodelist.h"
#include "nodelist.h"
...
@@ -34,16 +35,22 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
...
@@ -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
=
ic
;
f
->
inocache
->
nlink
=
1
;
f
->
inocache
->
nlink
=
1
;
f
->
inocache
->
nodes
=
(
struct
jffs2_raw_node_ref
*
)
f
->
inocache
;
f
->
inocache
->
nodes
=
(
struct
jffs2_raw_node_ref
*
)
f
->
inocache
;
f
->
inocache
->
ino
=
ri
->
ino
=
++
c
->
highest_ino
;
f
->
inocache
->
ino
=
++
c
->
highest_ino
;
D1
(
printk
(
KERN_DEBUG
"jffs2_do_new_inode(): Assigned ino# %d
\n
"
,
ri
->
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
);
jffs2_add_ino_cache
(
c
,
f
->
inocache
);
ri
->
magic
=
JFFS2_MAGIC_BITMASK
;
ri
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
);
ri
->
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
);
ri
->
totlen
=
PAD
(
sizeof
(
*
ri
));
ri
->
totlen
=
cpu_to_je32
(
PAD
(
sizeof
(
*
ri
)));
ri
->
hdr_crc
=
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
->
hdr_crc
=
cpu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
));
ri
->
mode
=
mode
;
ri
->
mode
=
cpu_to_je32
(
mode
);
f
->
highest_version
=
ri
->
version
=
1
;
f
->
highest_version
=
1
;
ri
->
version
=
cpu_to_je32
(
f
->
highest_version
);
return
0
;
return
0
;
}
}
...
@@ -88,7 +95,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
...
@@ -88,7 +95,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
int
ret
;
int
ret
;
unsigned
long
cnt
=
2
;
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
"
);
printk
(
KERN_CRIT
"Eep. CRC not correct in jffs2_write_dnode()
\n
"
);
BUG
();
BUG
();
}
}
...
@@ -100,8 +107,8 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
...
@@ -100,8 +107,8 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
writecheck
(
c
,
flash_ofs
);
writecheck
(
c
,
flash_ofs
);
if
(
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
"
,
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
();
raw
=
jffs2_alloc_raw_node_ref
();
if
(
!
raw
)
if
(
!
raw
)
...
@@ -113,11 +120,11 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
...
@@ -113,11 +120,11 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
return
ERR_PTR
(
-
ENOMEM
);
return
ERR_PTR
(
-
ENOMEM
);
}
}
raw
->
flash_offset
=
flash_ofs
;
raw
->
flash_offset
=
flash_ofs
;
raw
->
totlen
=
PAD
(
ri
->
tot
len
);
raw
->
totlen
=
PAD
(
sizeof
(
*
ri
)
+
data
len
);
raw
->
next_phys
=
NULL
;
raw
->
next_phys
=
NULL
;
fn
->
ofs
=
ri
->
offset
;
fn
->
ofs
=
je32_to_cpu
(
ri
->
offset
)
;
fn
->
size
=
ri
->
dsize
;
fn
->
size
=
je32_to_cpu
(
ri
->
dsize
)
;
fn
->
frags
=
0
;
fn
->
frags
=
0
;
fn
->
raw
=
raw
;
fn
->
raw
=
raw
;
...
@@ -140,7 +147,8 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
...
@@ -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
seem corrupted, in which case the scan would skip over
any node we write before the original intended end of
any node we write before the original intended end of
this node */
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
);
jffs2_mark_node_obsolete
(
c
,
raw
);
}
else
{
}
else
{
printk
(
KERN_NOTICE
"Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero
\n
"
,
raw
->
flash_offset
);
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
...
@@ -154,13 +162,20 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
return
ERR_PTR
(
ret
?
ret
:-
EIO
);
return
ERR_PTR
(
ret
?
ret
:-
EIO
);
}
}
/* Mark the space used */
/* 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 */
/* Link into per-inode list */
raw
->
next_in_ino
=
f
->
inocache
->
nodes
;
raw
->
next_in_ino
=
f
->
inocache
->
nodes
;
f
->
inocache
->
nodes
=
raw
;
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
)
if
(
writelen
)
*
writelen
=
retlen
;
*
writelen
=
retlen
;
...
@@ -176,10 +191,12 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
...
@@ -176,10 +191,12 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
struct
iovec
vecs
[
2
];
struct
iovec
vecs
[
2
];
int
ret
;
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
);
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
"
);
printk
(
KERN_CRIT
"Eep. CRC not correct in jffs2_write_dirent()
\n
"
);
BUG
();
BUG
();
}
}
...
@@ -201,13 +218,13 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
...
@@ -201,13 +218,13 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
return
ERR_PTR
(
-
ENOMEM
);
return
ERR_PTR
(
-
ENOMEM
);
}
}
raw
->
flash_offset
=
flash_ofs
;
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
;
raw
->
next_in_ino
=
f
->
inocache
->
nodes
;
f
->
inocache
->
nodes
=
raw
;
f
->
inocache
->
nodes
=
raw
;
raw
->
next_phys
=
NULL
;
raw
->
next_phys
=
NULL
;
fd
->
version
=
rd
->
version
;
fd
->
version
=
je32_to_cpu
(
rd
->
version
)
;
fd
->
ino
=
rd
->
ino
;
fd
->
ino
=
je32_to_cpu
(
rd
->
ino
)
;
fd
->
nhash
=
full_name_hash
(
name
,
strlen
(
name
));
fd
->
nhash
=
full_name_hash
(
name
,
strlen
(
name
));
fd
->
type
=
rd
->
type
;
fd
->
type
=
rd
->
type
;
memcpy
(
fd
->
name
,
name
,
namelen
);
memcpy
(
fd
->
name
,
name
,
namelen
);
...
@@ -220,7 +237,8 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
...
@@ -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
);
sizeof
(
*
rd
)
+
namelen
,
flash_ofs
,
ret
,
retlen
);
/* Mark the space as dirtied */
/* Mark the space as dirtied */
if
(
retlen
)
{
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
);
jffs2_mark_node_obsolete
(
c
,
raw
);
}
else
{
}
else
{
printk
(
KERN_NOTICE
"Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero
\n
"
,
raw
->
flash_offset
);
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
...
@@ -234,7 +252,8 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
return
ERR_PTR
(
ret
?
ret
:-
EIO
);
return
ERR_PTR
(
ret
?
ret
:-
EIO
);
}
}
/* Mark the space used */
/* 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
)
if
(
writelen
)
*
writelen
=
retlen
;
*
writelen
=
retlen
;
...
@@ -289,20 +308,20 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
...
@@ -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.
that the comprbuf doesn't need to be kfree()d.
*/
*/
ri
->
magic
=
JFFS2_MAGIC_BITMASK
;
ri
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
ri
->
nodetype
=
JFFS2_NODETYPE_INODE
;
ri
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_INODE
)
;
ri
->
totlen
=
sizeof
(
*
ri
)
+
cdatalen
;
ri
->
totlen
=
cpu_to_je32
(
sizeof
(
*
ri
)
+
cdatalen
)
;
ri
->
hdr_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
ri
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
ri
->
ino
=
f
->
inocache
->
ino
;
ri
->
ino
=
cpu_to_je32
(
f
->
inocache
->
ino
)
;
ri
->
version
=
++
f
->
highest_version
;
ri
->
version
=
cpu_to_je32
(
++
f
->
highest_version
)
;
ri
->
isize
=
max
(
ri
->
isize
,
offset
+
datalen
);
ri
->
isize
=
cpu_to_je32
(
max
(
je32_to_cpu
(
ri
->
isize
),
offset
+
datalen
)
);
ri
->
offset
=
offset
;
ri
->
offset
=
cpu_to_je32
(
offset
)
;
ri
->
csize
=
c
datalen
;
ri
->
csize
=
c
pu_to_je32
(
cdatalen
)
;
ri
->
dsize
=
datalen
;
ri
->
dsize
=
cpu_to_je32
(
datalen
)
;
ri
->
compr
=
comprtype
;
ri
->
compr
=
comprtype
;
ri
->
node_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
ri
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
)
);
ri
->
data_crc
=
c
rc32
(
0
,
comprbuf
,
cdatalen
);
ri
->
data_crc
=
c
pu_to_je32
(
crc32
(
0
,
comprbuf
,
cdatalen
)
);
fn
=
jffs2_write_dnode
(
c
,
f
,
ri
,
comprbuf
,
cdatalen
,
phys_ofs
,
NULL
);
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
...
@@ -367,12 +386,13 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
return
ret
;
return
ret
;
}
}
ri
->
data_crc
=
0
;
ri
->
data_crc
=
cpu_to_je32
(
0
)
;
ri
->
node_crc
=
c
rc32
(
0
,
ri
,
sizeof
(
*
ri
)
-
8
);
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
);
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
))
{
if
(
IS_ERR
(
fn
))
{
D1
(
printk
(
KERN_DEBUG
"jffs2_write_dnode() failed
\n
"
));
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
...
@@ -413,19 +433,19 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
down
(
&
dir_f
->
sem
);
down
(
&
dir_f
->
sem
);
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
dir_f
->
inocache
->
ino
;
rd
->
pino
=
cpu_to_je32
(
dir_f
->
inocache
->
ino
)
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
ri
->
ino
;
rd
->
ino
=
ri
->
ino
;
rd
->
mctime
=
ri
->
ctime
;
rd
->
mctime
=
ri
->
ctime
;
rd
->
nsize
=
namelen
;
rd
->
nsize
=
namelen
;
rd
->
type
=
DT_REG
;
rd
->
type
=
DT_REG
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
rc32
(
0
,
name
,
namelen
);
rd
->
name_crc
=
c
pu_to_je32
(
crc32
(
0
,
name
,
namelen
)
);
fd
=
jffs2_write_dirent
(
c
,
dir_f
,
rd
,
name
,
namelen
,
phys_ofs
,
&
writtenlen
);
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,
...
@@ -471,19 +491,19 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
down
(
&
dir_f
->
sem
);
down
(
&
dir_f
->
sem
);
/* Build a deletion node */
/* Build a deletion node */
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
dir_f
->
inocache
->
ino
;
rd
->
pino
=
cpu_to_je32
(
dir_f
->
inocache
->
ino
)
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
0
;
rd
->
ino
=
cpu_to_je32
(
0
)
;
rd
->
mctime
=
get_seconds
(
);
rd
->
mctime
=
cpu_to_je32
(
get_seconds
()
);
rd
->
nsize
=
namelen
;
rd
->
nsize
=
namelen
;
rd
->
type
=
DT_UNKNOWN
;
rd
->
type
=
DT_UNKNOWN
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
rc32
(
0
,
name
,
namelen
);
rd
->
name_crc
=
c
pu_to_je32
(
crc32
(
0
,
name
,
namelen
)
);
fd
=
jffs2_write_dirent
(
c
,
dir_f
,
rd
,
name
,
namelen
,
phys_ofs
,
NULL
);
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,
...
@@ -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. */
/* File it. This will mark the old one obsolete. */
jffs2_add_fd_to_list
(
c
,
fd
,
&
dir_f
->
dents
);
jffs2_add_fd_to_list
(
c
,
fd
,
&
dir_f
->
dents
);
jffs2_complete_reservation
(
c
);
up
(
&
dir_f
->
sem
);
up
(
&
dir_f
->
sem
);
/* dead_f is NULL if this was a rename not a real unlink */
/* 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,
...
@@ -529,6 +548,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
up
(
&
dead_f
->
sem
);
up
(
&
dead_f
->
sem
);
}
}
jffs2_complete_reservation
(
c
);
return
0
;
return
0
;
}
}
...
@@ -553,21 +574,21 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
...
@@ -553,21 +574,21 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
down
(
&
dir_f
->
sem
);
down
(
&
dir_f
->
sem
);
/* Build a deletion node */
/* Build a deletion node */
rd
->
magic
=
JFFS2_MAGIC_BITMASK
;
rd
->
magic
=
cpu_to_je16
(
JFFS2_MAGIC_BITMASK
)
;
rd
->
nodetype
=
JFFS2_NODETYPE_DIRENT
;
rd
->
nodetype
=
cpu_to_je16
(
JFFS2_NODETYPE_DIRENT
)
;
rd
->
totlen
=
sizeof
(
*
rd
)
+
namelen
;
rd
->
totlen
=
cpu_to_je32
(
sizeof
(
*
rd
)
+
namelen
)
;
rd
->
hdr_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
);
rd
->
hdr_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
struct
jffs2_unknown_node
)
-
4
)
);
rd
->
pino
=
dir_f
->
inocache
->
ino
;
rd
->
pino
=
cpu_to_je32
(
dir_f
->
inocache
->
ino
)
;
rd
->
version
=
++
dir_f
->
highest_version
;
rd
->
version
=
cpu_to_je32
(
++
dir_f
->
highest_version
)
;
rd
->
ino
=
ino
;
rd
->
ino
=
cpu_to_je32
(
ino
)
;
rd
->
mctime
=
get_seconds
(
);
rd
->
mctime
=
cpu_to_je32
(
get_seconds
()
);
rd
->
nsize
=
namelen
;
rd
->
nsize
=
namelen
;
rd
->
type
=
type
;
rd
->
type
=
type
;
rd
->
node_crc
=
c
rc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
);
rd
->
node_crc
=
c
pu_to_je32
(
crc32
(
0
,
rd
,
sizeof
(
*
rd
)
-
8
)
);
rd
->
name_crc
=
c
rc32
(
0
,
name
,
namelen
);
rd
->
name_crc
=
c
pu_to_je32
(
crc32
(
0
,
name
,
namelen
)
);
fd
=
jffs2_write_dirent
(
c
,
dir_f
,
rd
,
name
,
namelen
,
phys_ofs
,
NULL
);
fd
=
jffs2_write_dirent
(
c
,
dir_f
,
rd
,
name
,
namelen
,
phys_ofs
,
NULL
);
...
...
fs/jffs2/writev.c
View file @
20fed049
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
* For licensing information, see the file 'LICENCE' in this directory.
* 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
...
@@ -28,7 +28,7 @@ static inline int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs
for
(
i
=
0
;
i
<
count
;
i
++
)
{
for
(
i
=
0
;
i
<
count
;
i
++
)
{
if
(
!
vecs
[
i
].
iov_len
)
if
(
!
vecs
[
i
].
iov_len
)
continue
;
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
;
totlen
+=
thislen
;
if
(
ret
||
thislen
!=
vecs
[
i
].
iov_len
)
if
(
ret
||
thislen
!=
vecs
[
i
].
iov_len
)
break
;
break
;
...
...
include/linux/jffs2.h
View file @
20fed049
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
* For licensing information, see the file 'LICENCE' in the
* For licensing information, see the file 'LICENCE' in the
* jffs2 directory.
* 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 @@
...
@@ -68,30 +68,65 @@
compression type */
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
struct
jffs2_unknown_node
{
{
/* All start like this */
/* All start like this */
u
int16_t
magic
;
j
int16_t
magic
;
u
int16_t
nodetype
;
j
int16_t
nodetype
;
u
int32_t
totlen
;
/* So we can skip over nodes we don't grok */
j
int32_t
totlen
;
/* So we can skip over nodes we don't grok */
u
int32_t
hdr_crc
;
j
int32_t
hdr_crc
;
}
__attribute__
((
packed
));
}
__attribute__
((
packed
));
struct
jffs2_raw_dirent
struct
jffs2_raw_dirent
{
{
u
int16_t
magic
;
j
int16_t
magic
;
u
int16_t
nodetype
;
/* == JFFS_NODETYPE_DIRENT */
j
int16_t
nodetype
;
/* == JFFS_NODETYPE_DIRENT */
u
int32_t
totlen
;
j
int32_t
totlen
;
u
int32_t
hdr_crc
;
j
int32_t
hdr_crc
;
u
int32_t
pino
;
j
int32_t
pino
;
u
int32_t
version
;
j
int32_t
version
;
u
int32_t
ino
;
/* == zero for unlink */
j
int32_t
ino
;
/* == zero for unlink */
u
int32_t
mctime
;
j
int32_t
mctime
;
uint8_t
nsize
;
uint8_t
nsize
;
uint8_t
type
;
uint8_t
type
;
uint8_t
unused
[
2
];
uint8_t
unused
[
2
];
u
int32_t
node_crc
;
j
int32_t
node_crc
;
u
int32_t
name_crc
;
j
int32_t
name_crc
;
uint8_t
name
[
0
];
uint8_t
name
[
0
];
}
__attribute__
((
packed
));
}
__attribute__
((
packed
));
...
@@ -103,27 +138,27 @@ struct jffs2_raw_dirent
...
@@ -103,27 +138,27 @@ struct jffs2_raw_dirent
*/
*/
struct
jffs2_raw_inode
struct
jffs2_raw_inode
{
{
u
int16_t
magic
;
/* A constant magic number. */
j
int16_t
magic
;
/* A constant magic number. */
u
int16_t
nodetype
;
/* == JFFS_NODETYPE_INODE */
j
int16_t
nodetype
;
/* == JFFS_NODETYPE_INODE */
u
int32_t
totlen
;
/* Total length of this node (inc data, etc.) */
j
int32_t
totlen
;
/* Total length of this node (inc data, etc.) */
u
int32_t
hdr_crc
;
j
int32_t
hdr_crc
;
u
int32_t
ino
;
/* Inode number. */
j
int32_t
ino
;
/* Inode number. */
u
int32_t
version
;
/* Version number. */
j
int32_t
version
;
/* Version number. */
u
int32_t
mode
;
/* The file's type or mode. */
j
int32_t
mode
;
/* The file's type or mode. */
u
int16_t
uid
;
/* The file's owner. */
j
int16_t
uid
;
/* The file's owner. */
u
int16_t
gid
;
/* The file's group. */
j
int16_t
gid
;
/* The file's group. */
u
int32_t
isize
;
/* Total resultant size of this inode (used for truncations) */
j
int32_t
isize
;
/* Total resultant size of this inode (used for truncations) */
u
int32_t
atime
;
/* Last access time. */
j
int32_t
atime
;
/* Last access time. */
u
int32_t
mtime
;
/* Last modification time. */
j
int32_t
mtime
;
/* Last modification time. */
u
int32_t
ctime
;
/* Change time. */
j
int32_t
ctime
;
/* Change time. */
u
int32_t
offset
;
/* Where to begin to write. */
j
int32_t
offset
;
/* Where to begin to write. */
u
int32_t
csize
;
/* (Compressed) data size */
j
int32_t
csize
;
/* (Compressed) data size */
u
int32_t
dsize
;
/* Size of the node's data. (after decompression) */
j
int32_t
dsize
;
/* Size of the node's data. (after decompression) */
uint8_t
compr
;
/* Compression algorithm used */
uint8_t
compr
;
/* Compression algorithm used */
uint8_t
usercompr
;
/* Compression algorithm requested by the user */
uint8_t
usercompr
;
/* Compression algorithm requested by the user */
u
int16_t
flags
;
/* See JFFS2_INO_FLAG_* */
j
int16_t
flags
;
/* See JFFS2_INO_FLAG_* */
u
int32_t
data_crc
;
/* CRC for the (compressed) data. */
j
int32_t
data_crc
;
/* CRC for the (compressed) data. */
u
int32_t
node_crc
;
/* CRC for the raw inode (excluding data) */
j
int32_t
node_crc
;
/* CRC for the raw inode (excluding data) */
// uint8_t data[dsize];
// uint8_t data[dsize];
}
__attribute__
((
packed
));
}
__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
#ifndef _JFFS2_FS_I
#define _JFFS2_FS_I
#define _JFFS2_FS_I
#include <linux/version.h>
#include <linux/version.h>
#include <linux/rbtree.h>
struct
jffs2_inode_info
{
struct
jffs2_inode_info
{
/* We need an internal semaphore similar to inode->i_sem.
/* We need an internal semaphore similar to inode->i_sem.
...
@@ -18,7 +19,7 @@ struct jffs2_inode_info {
...
@@ -18,7 +19,7 @@ struct jffs2_inode_info {
uint32_t
highest_version
;
uint32_t
highest_version
;
/* List of data fragments which make up the file */
/* 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
/* There may be one datanode which isn't referenced by any of the
above fragments, if it contains a metadata update but no actual
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
#ifndef _JFFS2_FS_SB
#define _JFFS2_FS_SB
#define _JFFS2_FS_SB
...
@@ -21,6 +21,8 @@ struct jffs2_sb_info {
...
@@ -21,6 +21,8 @@ struct jffs2_sb_info {
struct
mtd_info
*
mtd
;
struct
mtd_info
*
mtd
;
uint32_t
highest_ino
;
uint32_t
highest_ino
;
uint32_t
checked_ino
;
unsigned
int
flags
;
unsigned
int
flags
;
struct
task_struct
*
gc_task
;
/* GC task struct */
struct
task_struct
*
gc_task
;
/* GC task struct */
...
@@ -38,10 +40,12 @@ struct jffs2_sb_info {
...
@@ -38,10 +40,12 @@ struct jffs2_sb_info {
uint32_t
flash_size
;
uint32_t
flash_size
;
uint32_t
used_size
;
uint32_t
used_size
;
uint32_t
dirty_size
;
uint32_t
dirty_size
;
uint32_t
wasted_size
;
uint32_t
free_size
;
uint32_t
free_size
;
uint32_t
erasing_size
;
uint32_t
erasing_size
;
uint32_t
bad_size
;
uint32_t
bad_size
;
uint32_t
sector_size
;
uint32_t
sector_size
;
uint32_t
unchecked_size
;
uint32_t
nr_free_blocks
;
uint32_t
nr_free_blocks
;
uint32_t
nr_erasing_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