Author: wmb Date: Sat Oct 22 05:40:39 2011 New Revision: 2636 URL: http://tracker.coreboot.org/trac/openfirmware/changeset/2636
Log: Initial checkin of barely-tested code to handle ext3/4 journals.
Added: ofw/fs/ext2fs/recovery.fth
Added: ofw/fs/ext2fs/recovery.fth ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ ofw/fs/ext2fs/recovery.fth Sat Oct 22 05:40:39 2011 (r2636) @@ -0,0 +1,362 @@ +h# c03b3998 constant jbd_magic + +struct + /l field >h_magic + /l field >h_blocktype + /l field >h_sequence +constant /journal-header + +/journal-header + /c field >h_chksum_type + /c field >h_chksum_size + 2 /c* \ Padding + 4 /l* field >h_chksum + 2 /l* field >h_commit_sec + /l field >h_commit_nsec +constant /commit-header + +/journal-header + /l field >r_count +constant /revoke-header + +struct + /l field >t_blocknr + /l field >t_flags +dup constant /tag32 + /l field >t_blocknr_high +constant /tag64 + +/journal-header + /l field >s_blocksize + /l field >s_maxlen + /l field >s_first + /l field >s_sequence + /l field >s_start + /l field >s_errno + /l field >s_feature_compat + /l field >s_feature_incompat + /l field >s_feature_ro_compat + \ We don't need the rest +drop + +0 value j-buf +0 value j-compat +0 value j-incompat +0 value j-blocksize +0 value j-first +0 value j-last +0 value j-start +0 value j-sequence +0 value tag-bytes + +0 value jsb +0 value bh +0 value obh +: free-journal ( -- ) + jsb if jsb bsize free-mem 0 to jsb then + bh if bh j-blocksize free-mem 0 to bh then + obh if obh j-blocksize free-mem 0 to obh then +; +: read-journal ( -- skip? ) + bsize alloc-mem to jsb + 8 set-inode \ 8 is the well-known inode# for the journal + jsb 0 read-file-block ( ) + + jsb >h_magic be-l@ jbd_magic <> if + free-journal true exit ( -- skip? ) + then + + jsb >h_blocktype be-l@ 3 4 between 0= if + \ Not superblock + free-journal true exit ( -- skip? ) + then + + jsb >s_start be-l@ to j-start + jsb 0= if + free-journal true exit ( -- skip? ) + then + + jsb >s_blocksize be-l@ to j-blocksize ( ) + + j-blocksize bsize <> if + ." Journal block size != filesystem block size" cr + free-journal true exit ( -- skip? ) + then + + j-blocksize alloc-mem to bh ( ) + j-blocksize alloc-mem to obh ( ) + + jsb >s_sequence be-l@ to j-sequence ( ) + jsb >s_first be-l@ to j-first ( ) + jsb >s_maxlen be-l@ to j-last ( ) + + jsb >s_feature_compat be-l@ to j-compat ( ) + jsb >s_feature_incompat be-l@ to j-incompat ( ) + + j-incompat 2 and if /tag64 else /tag32 then to tag-bytes \ 2:FEATURE_INCOMPAT_64BIT + + false ( skip? ) +; + +: +wrap ( n increment -- n' ) + + dup j-last >= if + j-last - j-first + + then +; + +0 value tagend +0 value tagp +: first-tag ( -- ) + bh j-blocksize + to tagend ( ) + bh /journal-header + to tagp ( ) +; +: +tagp ( -- end? ) + tagp >t_flags be-l@ ( flags ) + tagp tag-bytes + ( flags tagp ) + over 2 and 0= if d# 16 + then ( flags tagp ) \ 2:FLAG_SAME_UUID + to tagp ( flags ) + 8 and if ( ) \ 8:FLAG_LAST_TAG + true ( end? ) + else ( ) + tagp tagend >= ( end? ) + then ( end? ) +; +: count-tags ( -- count ) + 0 ( count ) + first-tag begin 1+ +tagp until ( count end? ) +; + +: write-jblock ( d.block# adr -- ) + -rot drop write-fs-block ( error? ) +\ j-blocksize 2swap ( adr len d.block# ) +\ j-blocksize du* ( adr len d.byte# ) +\ write-bytes + if ." Journal recovery write error" cr abort then +; + +0 value next-log-block +: next-jblock ( buf -- ) + next-log-block read-file-block ( ) + next-log-block 1 +wrap to next-log-block ( ) +; + +0 value crc32-sum +: crc32-block ( buf -- ) + crc32-sum crctab rot j-blocksize ($crc) to crc32-sum +; +: calc-chksums ( -- ) + bh crc32-block + count-tags 0 ?do + obh next-jblock obh crc32-block + loop +; + +listnode + /n 2* field >r_block# + /n field >r_sequence +nodetype: revoke-node + +list: revoke-list + +: free-revoke-list ( -- ) + begin revoke-list >next-node while ( ) + revoke-list delete-after ( node ) + revoke-node free-node ( ) + repeat ( ) +; + +: block#> ( d.block# 'node -- d.block# flag ) + >r_block# 2@ 2over d< +; + +\ node is either the found one or the insertion point +: find-revoked ( d.block# -- d.block# node found? ) + revoke-list ['] block#> find-node drop ( d.block# node ) + 3dup >r_block# 2@ d= ( d.block# node ) +; + +0 value next-commit-id + +: revoked? ( d.block# -- revoked? ) + find-revoked if ( d.block# node ) + nip nip ( node ) + >r_sequence @ ( sequence# ) + next-commit-id = ( revoked? ) + else ( d.block# node ) + 3drop false ( revoked? ) + then ( revoked? ) +; + +: set-revoke ( d.block# -- ) + find-revoked if ( d.block# node ) + nip nip ( node ) + next-commit-id over >r_sequence @ - 0>= if ( node ) + next-commit-id over >r_sequence ! ( node ) + then ( node ) + drop ( ) + else ( d.block# node ) + -rot ( node d.block# ) + revoke-node allocate-node >r ( node d.block# r: newnode ) + r@ >r_block# 2! ( node r: newnode ) + next-commit-id r@ >r_sequence ! ( node r: newnode ) + r> swap insert-after ( ) + then ( ) +; + +: replay-tag ( -- ) + obh next-jblock ( ) + + tagp >t_blocknr be-l@ ( block# ) + j-incompat 2 and if ( block# ) \ 2:FEATURE_INCOMPAT_64BIT + tagp >t_blocknr_high be-l@ ( d.block# ) + else ( block# ) + u>d ( d.block# ) + then ( d.block# ) + 2dup revoked? if ( d.block# ) + 2drop ( ) + else ( d.block# ) + tagp >t_flags be-l@ 1 and if ( d.block# ) \ 1:FLAG_ESCAPE + jbd_magic obh >data be-l! ( d.block# ) + then ( d.block# ) + obh write-jblock ( ) + then ( ) +; + +: replay-descriptor-block ( -- ) + first-tag begin replay-tag +tagp until ( ) +; + +0 value pass +: scanning? ( -- flag ) pass 0= ; +: revoking? ( -- flag ) pass 1 = ; +: replaying? ( -- flag ) pass 2 = ; + +0 value end-transaction + +: do-descriptor-block ( -- ) + replaying? if + replay-descriptor-block + else + scanning? if + j-compat 1 and if \ FEATURE_COMPAT_CHECKSUM + end-transaction 0= if + calc-chksums \ Can abort + exit \ Continues loop in pass-loop + then + then + then + next-log-block count-tags +wrap to next-log-block + then +; + +0 value j-failed-commit +: do-commit-chksum ( -- ) + bh >h_chksum be-l@ ( sum ) + end-transaction if ( sum ) + true to j-failed-commit ( sum ) + drop exit ( -- ) + then ( sum ) + + dup crc32-sum = ( sum flag ) + bh >h_chksum_type c@ 1 = and \ 1:CRC32_CHKSUM ( sum flag' ) + bh >h_chksum_size c@ 4 = and \ 4:CRC32_CHKSUM_SIZE ( sum flag' ) + if ( sum ) + drop ( ) + else ( sum ) + 0= ( flag ) + bh >h_chksum_type c@ 0= ( flag' ) + bh >h_chksum_size c@ 0= and 0= if ( flag' ) + next-commit-id to end-transaction ( ) + j-incompat 4 and if ( ) \ 4:FEATURE_INCOMPAT_ASYNC_COMMIT + next-commit-id to j-failed-commit ( ) + abort + then ( ) + then ( ) + then ( ) + -1 to crc32-sum ( ) +; +: do-commit-block ( -- ) + scanning? if + j-compat 1 and if \ FEATURE_COMPAT_CHECKSUM + do-commit-chksum + then + then + next-commit-id 1+ to next-commit-id +; + +: be-x@ ( adr -- d ) dup la1+ be-l@ swap be-l@ ; +: do-revoke-block ( -- ) + revoking? 0= if exit then + + bh /revoke-header + ( adr ) + bh >r_count be-l@ bounds ( endadr adr ) + + j-incompat 2 and if ( endadr adr ) \ 2:FEATURE_INCOMPAT_64BIT + ?do i be-x@ set-revoke 8 +loop ( ) + else + ?do i be-l@ u>d set-revoke 4 +loop ( ) + then +; + +: pass-loop ( -- ) + begin + scanning? 0= if + next-commit-id end-transaction - 0>= if exit then + then + bh next-jblock ( ) + bh >h_magic be-l@ jbd_magic <> if ( ) + exit ( -- ) + then ( ) + bh >h_sequence be-l@ next-commit-id <> if ( adr ) + exit ( -- ) + then ( ) + bh >h_blocktype be-l@ case ( ) + 1 of do-descriptor-block endof ( ) + 2 of do-commit-block endof ( ) + 5 of do-revoke-block endof ( ) + ( default ) drop exit ( ) + endcase ( ) + again +; +: one-pass ( pass -- ) + to pass + -1 to crc32-sum + j-sequence to next-commit-id + j-start to next-log-block + pass-loop + scanning? if + end-transaction 0= if + next-commit-id to end-transaction + then + else + end-transaction next-commit-id <> abort" Recover end-transaction mismatch" + then +; +: commit-journal ( -- ) + 0 jsb >s_start be-l! + jsb 0 write-file-block + flush +; +: process-journal ( -- ) + read-journal if exit then + + 0 ['] one-pass catch if + ." Journal scan failed" cr + free-journal exit + then + + 1 ['] one-pass catch if + ." Journal revoke failed" cr + free-revoke-list free-journal exit + then + + 2 ['] one-pass catch if + ." Journal replay failed" cr + free-revoke-list free-journal exit + then + + free-revoke-list + + \ commit-journal + free-journal +;