diff -uNr linux-2.4.22.orig/fs/Config.in linux-2.4.22/fs/Config.in --- linux-2.4.22.orig/fs/Config.in 2003-10-02 18:37:44.000000000 +0400 +++ linux-2.4.22/fs/Config.in 2003-10-02 18:51:04.000000000 +0400 @@ -13,6 +13,7 @@ tristate 'Reiserfs support' CONFIG_REISERFS_FS dep_mbool ' Enable reiserfs debug mode' CONFIG_REISERFS_CHECK $CONFIG_REISERFS_FS dep_mbool ' Stats in /proc/fs/reiserfs' CONFIG_REISERFS_PROC_INFO $CONFIG_REISERFS_FS +dep_mbool ' Allow badblock marking on live fs' CONFIG_REISERFS_BADBLOCKS $CONFIG_REISERFS_FS dep_tristate 'ADFS file system support (EXPERIMENTAL)' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL dep_mbool ' ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW $CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL diff -uNr linux-2.4.22.orig/fs/reiserfs/Makefile linux-2.4.22/fs/reiserfs/Makefile --- linux-2.4.22.orig/fs/reiserfs/Makefile 2003-10-02 18:37:44.000000000 +0400 +++ linux-2.4.22/fs/reiserfs/Makefile 2003-10-02 18:51:04.000000000 +0400 @@ -13,6 +13,8 @@ obj-m := $(O_TARGET) +obj-$(CONFIG_REISERFS_BADBLOCKS) += badblocks.o + # gcc -O2 (the kernel default) is overaggressive on ppc32 when many inline # functions are used. This causes the compiler to advance the stack # pointer out of the available stack space, corrupting kernel space, diff -uNr linux-2.4.22.orig/fs/reiserfs/badblocks.c linux-2.4.22/fs/reiserfs/badblocks.c --- linux-2.4.22.orig/fs/reiserfs/badblocks.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.4.22/fs/reiserfs/badblocks.c 2003-10-02 19:07:02.000000000 +0400 @@ -0,0 +1,263 @@ +/* + * Copyright 2002, 2003 by Hans Reiser, licensing governed by reiserfs/README + */ + +#include +#include +#include + + +static int handle_badblocks_add(unsigned long blocknr, struct super_block *super) +{ + struct reiserfs_transaction_handle th; + struct cpu_key badblocks_key; + struct item_head badblocks_ih; + int retval; + unsigned int block_ondisk; // Should it be 32 bit, as we only have 32bit + // blocknumbers in on-disk format? + INITIALIZE_PATH (path); + int windex; + int bitmap_block, offset; + + lock_kernel(); + // check that block is not busy yet here. + bitmap_block = blocknr / ( super->s_blocksize << 3 ); + offset = blocknr % ( super->s_blocksize << 3 ); + if ( reiserfs_test_le_bit( offset, + SB_AP_BITMAP( super )[ bitmap_block ].bh -> b_data )) { + /* Block is already busy, so it cannot be marked as bad + while filesystem is online */ + unlock_kernel(); + return -EBUSY; + } + + /* Construct a key of object to which we bind bad blocks */ + badblocks_key.version = KEY_FORMAT_3_5; + badblocks_key.on_disk_key.k_dir_id = 1; + badblocks_key.on_disk_key.k_objectid = MAX_KEY_OBJECTID; + set_cpu_key_k_offset (&badblocks_key, -1); //MAX_KEY_OFFSET); + set_cpu_key_k_type (&badblocks_key, TYPE_INDIRECT); + badblocks_key.key_length = 3; + + windex = push_journal_writer("handle_badblocks_add") ; + /* One extra block for bitmap corresponding to the bad block */ + journal_begin(&th, super, JOURNAL_PER_BALANCE_CNT + 1) ; + + // Mark block as used + reiserfs_prepare_for_journal( super, + SB_AP_BITMAP( super )[ bitmap_block ].bh, 1 ); + if ( reiserfs_test_and_set_le_bit( offset, + SB_AP_BITMAP( super )[ bitmap_block ].bh -> b_data ) ) { + /* Sigh, block became busy while we made our preparation, + abandon our furtile attempts, then */ + reiserfs_restore_prepared_buffer( super, + SB_AP_BITMAP( super )[ bitmap_block ].bh ); + retval = -EBUSY; + goto finish; + } + // Update superblock free blocks statistics + reiserfs_prepare_for_journal( super, SB_BUFFER_WITH_SB( super ), 1 ); + PUT_SB_FREE_BLOCKS( super, SB_FREE_BLOCKS(super) - 1 ); + /* Note that we postpone marking journal dirty until all + following operations will succeed */ + + block_ondisk = cpu_to_le32 ( blocknr ); + + /* Now let's see if there is such object already */ + retval = search_for_position_by_key (super, &badblocks_key, &path); + + if ( retval == FILE_NOT_FOUND) { + /* No such object, so we need to create it */ + make_le_item_head (&badblocks_ih, &badblocks_key, + badblocks_key.version, 1, TYPE_INDIRECT, + UNFM_P_SIZE, 0/*free space*/); + retval = reiserfs_insert_item (&th, &path, &badblocks_key, + &badblocks_ih, + (char *)&block_ondisk); + } else if ( retval == POSITION_NOT_FOUND ) { + struct item_head *ih = get_ih (&path); + + set_cpu_key_k_offset (&badblocks_key, path.pos_in_item * super->s_blocksize + le_ih_k_offset(ih)); + retval = reiserfs_paste_into_item (&th, &path, &badblocks_key, (char *)&block_ondisk, UNFM_P_SIZE); + } else { + reiserfs_warning(super, "Existing object, but no indirect item" + " while adding bad block? Confused and" + " giving up\n"); + } + pathrelse(&path); + if ( retval ) { + // Well, pasting failed for some reason, it means we + // must reject our changes to bitmap + + reiserfs_restore_prepared_buffer( super, + SB_AP_BITMAP( super )[ bitmap_block ].bh ); + reiserfs_restore_prepared_buffer( super, + SB_BUFFER_WITH_SB( super ) ); + } else { + journal_mark_dirty( &th, super, SB_AP_BITMAP( super )[ bitmap_block ].bh ); + journal_mark_dirty( &th, super, SB_BUFFER_WITH_SB( super ) ); + } + +finish: + journal_end(&th, super, JOURNAL_PER_BALANCE_CNT + 1) ; + pop_journal_writer(windex); + unlock_kernel(); + reiserfs_check_path(&path) ; + return retval; +} + +static int handle_badblocks_remove(unsigned long blocknr, struct super_block *super) +{ + struct reiserfs_transaction_handle th; + struct cpu_key badblocks_key; + int retval; + unsigned int block_ondisk; // Should it be 32 bit, as we only have 32bit + // blocknumbers in on-disk format? + INITIALIZE_PATH (path); + int windex; + int bitmap_block, offset; + + lock_kernel(); + // check that block is not free yet here. + bitmap_block = blocknr / ( super->s_blocksize << 3 ); + offset = blocknr % ( super->s_blocksize << 3 ); + if ( !reiserfs_test_le_bit( offset, + SB_AP_BITMAP( super )[ bitmap_block ].bh -> b_data )) { + /* Block is already free */ + unlock_kernel(); + return -EBUSY; + } + + /* Construct a key of object to which we bind bad blocks */ + badblocks_key.version = KEY_FORMAT_3_5; + badblocks_key.on_disk_key.k_dir_id = 1; + badblocks_key.on_disk_key.k_objectid = MAX_KEY_OBJECTID; + set_cpu_key_k_offset (&badblocks_key, 1); + set_cpu_key_k_type (&badblocks_key, TYPE_INDIRECT); + badblocks_key.key_length = 3; + + windex = push_journal_writer("handle_badblocks_remove") ; + /* One extra block for bitmap corresponding to the bad block */ + journal_begin(&th, super, JOURNAL_PER_BALANCE_CNT + 1) ; + + + block_ondisk = cpu_to_le32 ( blocknr ); + + /* Now let's see if there is such object already */ + retval = search_for_position_by_key (super, &badblocks_key, &path); + +// Probably only while loop alone can be left as result won't change. + if ( retval == FILE_NOT_FOUND) { + /* No such object, so there is no accounted bad blocks at all */ + retval = -ENODATA; + goto finish; + } else if ( retval == POSITION_FOUND ) { + int cut_offset = 1, fs_gen, i; + struct item_head *ih; + __u32 * item; +research: + while ( retval == POSITION_FOUND ) { + + ih = get_ih (&path); + item = get_item (&path); + for ( i=0; i < I_UNFM_NUM (ih) ; i++) { + if ( get_block_num(item, i) == blocknr) + break; + } + cut_offset += i * super->s_blocksize; + set_cpu_key_k_offset ( &badblocks_key, cut_offset); + if ( i != I_UNFM_NUM (ih)) + break; // found block number in the list. + retval = search_for_position_by_key (super, &badblocks_key, &path); + } + if ( retval != POSITION_FOUND ) { + /* Block was not found in the list, so abandon + the operation */ + retval = -ENODATA; + goto finish; + } + fs_gen = get_generation ( super ); + reiserfs_prepare_for_journal(super, get_last_bh(&path), 1); + if ( fs_changed (fs_gen, super) && item_moved (ih, &path)) { + reiserfs_restore_prepared_buffer(super, get_last_bh(&path)); + retval = search_for_position_by_key (super, &badblocks_key, &path); + goto research; + } + + /* Now we have correct offset, since block may be + in the middle of indirect item and there is no code + to cut stuff from the middle of a file, we simply put + a zero instead of old block number. + Right now we rely on fsck to clean up the stuff. */ + put_block_num(item, path.pos_in_item+i, 0); + journal_mark_dirty (&th, super, get_last_bh(&path)); + retval = 0; + } else { + reiserfs_warning(super, "Something strange is going on" + " while removing bad block? Confused and" + " giving up\n"); + } + // Mark block as free + if ( !retval ) { + reiserfs_prepare_for_journal( super, + SB_AP_BITMAP( super )[ bitmap_block ].bh, 1 ); + if ( !reiserfs_test_and_clear_le_bit( offset, + SB_AP_BITMAP( super )[ bitmap_block ].bh -> b_data ) ) { + /* Sigh, block became free while we made our preparation, + abandon our futile attempts, then */ + reiserfs_restore_prepared_buffer( super, + SB_AP_BITMAP( super )[ bitmap_block ].bh ); + retval = -EBUSY; + goto finish; + } + // Update superblock free blocks statistics + reiserfs_prepare_for_journal( super, SB_BUFFER_WITH_SB( super ), 1 ); + PUT_SB_FREE_BLOCKS( super, SB_FREE_BLOCKS(super) + 1 ); + journal_mark_dirty( &th, super, SB_AP_BITMAP( super )[ bitmap_block ].bh ); + journal_mark_dirty( &th, super, SB_BUFFER_WITH_SB( super ) ); + } + +finish: + pathrelse(&path); + journal_end(&th, super, JOURNAL_PER_BALANCE_CNT + 1) ; + pop_journal_writer(windex); + unlock_kernel(); + reiserfs_check_path(&path) ; + return retval; +} + + +int reiserfs_handle_badblocks_ioctl (int cmd, unsigned long blocknr, struct super_block *super) +{ + + if (cmd == REISERFS_IOC_BADCNT) { + printk("Not yet implemented\n"); + return -ENOTTY; + } + + if ( blocknr >= le32_to_cpu( super -> u.reiserfs_sb.s_rs -> s_v1.s_block_count )) { + return -EINVAL; // attempt to mark a block beyond FS. + } + if ( ( blocknr >= SB_ONDISK_JOURNAL_1st_BLOCK( super ) ) + && ( blocknr < ( SB_ONDISK_JOURNAL_1st_BLOCK( super ) + + JOURNAL_BLOCK_COUNT ) ) ) { + return -EINVAL; // attempt to mark bad block inside of journal area. + } + +#ifdef CONFIG_REISERFS_CHECK + if ( !is_reusable( super, blocknr, 2 ) ) { + // we do want only consistency checks, so we pass illegal single + // bit value of 2. + return -EINVAL; + } +#endif + if ( cmd == REISERFS_IOC_MARKBAD ) + return handle_badblocks_add( blocknr, super); + + if ( cmd == REISERFS_IOC_UNMARKBAD ) + return handle_badblocks_remove( blocknr, super); + + reiserfs_warning(super, "Invalid ioctl value for badblocks handler\n"); + + return -ENOTTY; +} diff -uNr linux-2.4.22.orig/fs/reiserfs/ioctl.c linux-2.4.22/fs/reiserfs/ioctl.c --- linux-2.4.22.orig/fs/reiserfs/ioctl.c 2003-10-02 18:37:44.000000000 +0400 +++ linux-2.4.22/fs/reiserfs/ioctl.c 2003-10-02 18:51:04.000000000 +0400 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README + * Copyright 2000-2003 by Hans Reiser, licensing governed by reiserfs/README */ #include @@ -81,6 +81,15 @@ inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); return 0; +#if defined( CONFIG_REISERFS_BADBLOCKS ) + case REISERFS_IOC_MARKBAD: + case REISERFS_IOC_UNMARKBAD: + case REISERFS_IOC_BADCNT: + if( !capable( CAP_SYS_ADMIN ) ) + return -EPERM; + else + return reiserfs_handle_badblocks_ioctl( cmd, arg, inode->i_sb ); +#endif default: return -ENOTTY; } diff -uNr linux-2.4.22.orig/fs/reiserfs/stree.c linux-2.4.22/fs/reiserfs/stree.c --- linux-2.4.22.orig/fs/reiserfs/stree.c 2003-10-02 18:37:44.000000000 +0400 +++ linux-2.4.22/fs/reiserfs/stree.c 2003-10-02 18:51:04.000000000 +0400 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README + * Copyright 2000-2003 by Hans Reiser, licensing governed by reiserfs/README */ /* @@ -849,6 +849,7 @@ n_blk_size = p_s_sb->s_blocksize; if (comp_short_keys (&(p_le_ih->ih_key), p_cpu_key)) { + PATH_LAST_POSITION(p_s_search_path)++; return FILE_NOT_FOUND; } diff -uNr linux-2.4.22.orig/include/linux/reiserfs_fs.h linux-2.4.22/include/linux/reiserfs_fs.h --- linux-2.4.22.orig/include/linux/reiserfs_fs.h 2003-10-02 18:37:53.000000000 +0400 +++ linux-2.4.22/include/linux/reiserfs_fs.h 2003-10-02 19:08:16.000000000 +0400 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2002 Hans Reiser, see reiserfs/README for licensing and copyright details + * Copyright 1996-2003 Hans Reiser, see reiserfs/README for licensing and copyright details */ /* this file has an amazingly stupid @@ -2067,6 +2067,9 @@ void make_empty_node (struct buffer_info *); struct buffer_head * get_FEB (struct tree_balance *); +/* badblocks.c */ +int reiserfs_handle_badblocks_ioctl (int cmd, unsigned long blocknr, struct super_block *super); + /* bitmap.c */ /* structure contains hints for block allocator, and it is a container for @@ -2188,6 +2191,10 @@ #define REISERFS_IOC_SETFLAGS EXT2_IOC_SETFLAGS #define REISERFS_IOC_GETVERSION EXT2_IOC_GETVERSION #define REISERFS_IOC_SETVERSION EXT2_IOC_SETVERSION +#define REISERFS_IOC_MARKBAD _IOW(0xCD,2,long) +#define REISERFS_IOC_UNMARKBAD _IOW(0xCD,3,long) +#define REISERFS_IOC_BADCNT _IOW(0xCD,4,long) + #endif /* _LINUX_REISER_FS_H */ .