diff -rup linux-2.4.8/fs/reiserfs/bitmap.c linux-2.4.8-bb/fs/reiserfs/bitmap.c --- linux-2.4.8/fs/reiserfs/bitmap.c Wed May 2 14:04:15 2001 +++ linux-2.4.8-bb/fs/reiserfs/bitmap.c Wed Aug 22 13:55:24 2001 @@ -716,3 +716,118 @@ void reiserfs_discard_all_prealloc (stru } } #endif + + +#if defined( REISERFS_HANDLE_BADBLOCKS ) +int mark_in_use_on_user_behalf( struct reiserfs_transaction_handle *th, + unsigned long blocknr, int used ) +{ +#if !defined( SUPPORT_OLD_FORMAT ) +#define first_block ( REISERFS_DISK_OFFSET_IN_BYTES / block_size ) +#else +#define first_block ( REISERFS_OLD_DISK_OFFSET_IN_BYTES / block_size ) +#endif + + struct super_block *super; + int block_size; + int result; + + super = th -> t_super; +#if !defined( SUPPORT_OLD_FORMAT ) + block_size = super -> s_blocksize; +#else + block_size = REISERFS_OLD_BLOCKSIZE; +#endif + + result = -EINVAL; + if( blocknr >= le32_to_cpu( super -> u.reiserfs_sb.s_rs -> s_block_count ) ) + { + REISERFS_LOG( "mark-used-too-far", + "Attempt to mark block beyond file-system: " + "0x%lx >= 0x%lx", + blocknr, + le32_to_cpu( super -> u.reiserfs_sb.s_rs -> s_block_count ) + ); + } + else if( ( blocknr >= reiserfs_get_journal_block( super ) ) && + ( blocknr < ( reiserfs_get_journal_block( super ) + + JOURNAL_BLOCK_COUNT ) ) ) + { + REISERFS_LOG( "mark-journal-used", + "Attempt to mark journal block in use is futile: " + "0x%lx in [0x%lx, 0x%lx)", + blocknr, + reiserfs_get_journal_block( super ), + reiserfs_get_journal_block( super ) + JOURNAL_BLOCK_COUNT ); + } + else if( blocknr <= first_block ) + { + REISERFS_LOG( "mark-boot-used", + "Attempt to mark one of first 0x%lx blocks in use is futile", + ( unsigned long ) first_block ); + } +#if defined( CONFIG_REISERFS_CHECK ) + else if( !is_reusable( super, blocknr, used ? 0 : 1 ) ) + { + REISERFS_LOG( "mark-reusable-used", "is_reusable() barfs on block 0x%lx", blocknr ); + } +#endif + else + { + int bitmap_block; + int offset; + + bitmap_block = blocknr / ( block_size << 3 ); + offset = blocknr % ( block_size << 3 ); + + /* REISERFS_LOG( "trace", */ + /* "bitmap_block: %x, offset: %x", bitmap_block, offset ); */ + + reiserfs_prepare_for_journal( super, + SB_AP_BITMAP( super )[ bitmap_block ], 1 ); + if( ( used && + reiserfs_test_and_set_le_bit + ( offset, + SB_AP_BITMAP( super )[ bitmap_block ] -> b_data ) != 0 ) || + ( !used && reiserfs_test_and_clear_le_bit + ( offset, + SB_AP_BITMAP( super )[ bitmap_block ] -> b_data ) == 0 ) ) + { + REISERFS_LOG( "already-marked", "block 0x%lx already %s", blocknr, + used ? "in use" : "free" ); + reiserfs_restore_prepared_buffer + ( super, + SB_AP_BITMAP( super )[ bitmap_block ] ); + result = -EBUSY; + } + else + { + used = ( used ? -1 : +1 ); + journal_mark_dirty( th, super, + SB_AP_BITMAP( super )[ bitmap_block ] ); + reiserfs_prepare_for_journal( super, SB_BUFFER_WITH_SB( super ), 1 ); + super -> u.reiserfs_sb.s_rs -> s_free_blocks = + cpu_to_le32( SB_FREE_BLOCKS( super ) + used ); + if( le32_to_cpu( super -> + u.reiserfs_sb.s_rs -> s_marked_in_use ) < 0xffff ) + { + super -> u.reiserfs_sb.s_rs -> s_marked_in_use = + cpu_to_le32 + ( le32_to_cpu + ( super -> u.reiserfs_sb.s_rs -> s_marked_in_use ) - + used ); + } + else + { + REISERFS_LOG( "too-many-marked", "already have 0xffff of `bad' blocks" ); + } + journal_mark_dirty( th, super, SB_BUFFER_WITH_SB( super ) ); + super -> s_dirt = 1; + result = 0; + } + } + return result; +} +/* REISERFS_HANDLE_BADBLOCKS */ +#endif + diff -rup linux-2.4.8/fs/reiserfs/ioctl.c linux-2.4.8-bb/fs/reiserfs/ioctl.c --- linux-2.4.8/fs/reiserfs/ioctl.c Wed May 2 14:03:23 2001 +++ linux-2.4.8-bb/fs/reiserfs/ioctl.c Wed Aug 22 13:55:24 2001 @@ -22,7 +22,9 @@ ** supported commands: ** 1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect ** and prevent packing file (argument arg has to be non-zero) -** 2) That's all for a while ... +** 2) REISERFS_IOC_USED - arg is block number to be marked used in the bitmap. +** Used for bad-block handling. +** 3) That's all for a while ... */ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) @@ -31,7 +33,49 @@ int reiserfs_ioctl (struct inode * inode case REISERFS_IOC_UNPACK: if (arg) return reiserfs_unpack (inode, filp); + break; +#if defined( REISERFS_HANDLE_BADBLOCKS ) + case REISERFS_IOC_USED: + case REISERFS_IOC_FREE: + case REISERFS_IOC_BADCNT: + { + if( !capable( CAP_SYS_ADMIN ) ) + { + return -EPERM; + } + else + { + struct reiserfs_transaction_handle th; + int result; + int token; + /* we can put into transaction two blocks: bitmap + block and super-block. */ + journal_begin( &th, inode -> i_sb, 2 ); + token = push_journal_writer( "REISERFS_IOC_USED" ); + if( cmd == REISERFS_IOC_BADCNT ) + { + reiserfs_prepare_for_journal + ( inode -> i_sb, SB_BUFFER_WITH_SB( inode -> i_sb ), 1 ); + inode -> i_sb -> u.reiserfs_sb.s_rs -> s_marked_in_use = + cpu_to_le32( ( __u32 ) arg ); + journal_mark_dirty( &th, inode -> i_sb, + SB_BUFFER_WITH_SB( inode -> i_sb ) ); + inode -> i_sb -> s_dirt = 1; + result = 0; + } + else + { + result = mark_in_use_on_user_behalf + ( &th, arg, ( cmd == REISERFS_IOC_USED ) ? 1 : 0 ); + } + pop_journal_writer( token ) ; + journal_end( &th, inode -> i_sb, 2 ); + return result; + } + } +/* REISERFS_HANDLE_BADBLOCKS */ +#endif default: return -ENOTTY; } diff -rup linux-2.4.8/include/linux/reiserfs_fs.h linux-2.4.8-bb/include/linux/reiserfs_fs.h --- linux-2.4.8/include/linux/reiserfs_fs.h Mon Aug 13 15:31:43 2001 +++ linux-2.4.8-bb/include/linux/reiserfs_fs.h Wed Aug 22 13:55:24 2001 @@ -68,6 +68,9 @@ #define USE_INODE_GENERATION_COUNTER +/* handle bad blocks by marking them used in the bitmap */ +#define REISERFS_HANDLE_BADBLOCKS + #ifdef __KERNEL__ /* #define REISERFS_CHECK */ @@ -98,6 +101,13 @@ */ #define REISERFS_DEBUG_CODE 5 /* extra messages to help find/debug errors */ +/* macro for debugging output */ +#define REISERFS_LOG( maintainer, format, args... ) \ + do { \ + printk( "reiserfs: %s-%i %s:%s: " format "\n", \ + ( maintainer ), __LINE__, __func__, __FILE__ , ##args ); \ + } while( 0 ) + /* * Disk Data Structures */ @@ -1618,6 +1628,19 @@ int reiserfs_remove_page_from_flush_list int reiserfs_allocate_list_bitmaps(struct super_block *s, struct reiserfs_list_bitmap *, int) ; +#if defined( REISERFS_HANDLE_BADBLOCKS ) +/** mark `blocknr' as being in use in bitmap, associated with + super-block in `th'. This is supposed to be called from special + ioctl() to handle bad blocks. Checks that `blocknr' is not in + journal area or before superblock. + + If `used' is not 0, mark it used, otherwise, mark it free. + + Returns 0 on sucess and (-errno) on error. */ +int mark_in_use_on_user_behalf( struct reiserfs_transaction_handle *th, + unsigned long blocknr, int used ); +#endif + /* why is this kerplunked right here? */ static inline int reiserfs_buffer_prepared(struct buffer_head *bh) { if (bh && test_bit(BH_JPrepared, &bh->b_state)) @@ -2053,6 +2076,11 @@ int reiserfs_unpack (struct inode * inod /* ioctl's command */ #define REISERFS_IOC_UNPACK _IOW(0xCD,1,long) +#if defined( REISERFS_HANDLE_BADBLOCKS ) +#define REISERFS_IOC_USED _IOW(0xCD,2,long) +#define REISERFS_IOC_FREE _IOW(0xCD,3,long) +#define REISERFS_IOC_BADCNT _IOW(0xCD,4,long) +#endif #endif /* _LINUX_REISER_FS_H */ diff -rup linux-2.4.8/include/linux/reiserfs_fs_sb.h linux-2.4.8-bb/include/linux/reiserfs_fs_sb.h --- linux-2.4.8/include/linux/reiserfs_fs_sb.h Wed Aug 1 17:21:13 2001 +++ linux-2.4.8-bb/include/linux/reiserfs_fs_sb.h Wed Aug 22 14:00:53 2001 @@ -25,11 +25,11 @@ struct reiserfs_super_block { - __u32 s_block_count; - __u32 s_free_blocks; /* free blocks count */ - __u32 s_root_block; /* root block number */ - __u32 s_journal_block; /* journal block number */ - __u32 s_journal_dev; /* journal device number */ + /* 0 */ __u32 s_block_count; + /* 4 */ __u32 s_free_blocks; /* free blocks count */ + /* 8 */ __u32 s_root_block; /* root block number */ + /* 12 */ __u32 s_journal_block; /* journal block number */ + /* 16 */ __u32 s_journal_dev; /* journal device number */ /* Since journal size is currently a #define in a header file, if ** someone creates a disk with a 16MB journal and moves it to a @@ -59,7 +59,7 @@ struct reiserfs_super_block 16 bytes long mostly unused. We don't need to save bytes in the superblock. -Hans */ - __u16 s_reserved; + __u16 s_marked_in_use; __u32 s_inode_generation; char s_unused[124] ; /* zero filled by mkreiserfs */ } __attribute__ ((__packed__)); @@ -87,7 +87,8 @@ struct reiserfs_super_block_v1 char s_magic[16]; /* reiserfs magic string indicates that file system is reiserfs */ __u16 s_tree_height; /* height of disk tree */ __u16 s_bmap_nr; /* amount of bitmap blocks needed to address each block of file system */ - __u32 s_reserved; + __u16 s_reserved; + __u16 s_marked_in_use; } __attribute__ ((__packed__)); #define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1)) Only in linux-2.4.8-bb: linux