2009-03-30 22:02:44 +04:00
/*
2005-04-17 02:20:36 +04:00
* Copyright 2000 by Hans Reiser , licensing governed by reiserfs / README
*/
2005-07-13 07:21:28 +04:00
2009-03-30 22:02:44 +04:00
/*
2005-04-17 02:20:36 +04:00
* Written by Alexander Zarochentcev .
*
* The kernel part of the ( on - line ) reiserfs resizer .
*/
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/vmalloc.h>
# include <linux/string.h>
# include <linux/errno.h>
2012-03-17 09:16:43 +04:00
# include "reiserfs.h"
2005-04-17 02:20:36 +04:00
# include <linux/buffer_head.h>
2005-07-13 07:21:28 +04:00
int reiserfs_resize ( struct super_block * s , unsigned long block_count_new )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
int err = 0 ;
struct reiserfs_super_block * sb ;
struct reiserfs_bitmap_info * bitmap ;
2006-10-01 10:28:42 +04:00
struct reiserfs_bitmap_info * info ;
2005-04-17 02:20:36 +04:00
struct reiserfs_bitmap_info * old_bitmap = SB_AP_BITMAP ( s ) ;
2005-07-13 07:21:28 +04:00
struct buffer_head * bh ;
2005-04-17 02:20:36 +04:00
struct reiserfs_transaction_handle th ;
unsigned int bmap_nr_new , bmap_nr ;
unsigned int block_r_new , block_r ;
2005-07-13 07:21:28 +04:00
struct reiserfs_list_bitmap * jb ;
2005-04-17 02:20:36 +04:00
struct reiserfs_list_bitmap jbitmap [ JOURNAL_NUM_BITMAPS ] ;
2005-07-13 07:21:28 +04:00
2005-04-17 02:20:36 +04:00
unsigned long int block_count , free_blocks ;
int i ;
2005-07-13 07:21:28 +04:00
int copy_size ;
2013-08-09 01:34:46 +04:00
int depth ;
2005-04-17 02:20:36 +04:00
sb = SB_DISK_SUPER_BLOCK ( s ) ;
if ( SB_BLOCK_COUNT ( s ) > = block_count_new ) {
printk ( " can \' t shrink filesystem on-line \n " ) ;
return - EINVAL ;
}
/* check the device size */
2013-08-09 01:34:46 +04:00
depth = reiserfs_write_unlock_nested ( s ) ;
2005-04-17 02:20:36 +04:00
bh = sb_bread ( s , block_count_new - 1 ) ;
2013-08-09 01:34:46 +04:00
reiserfs_write_lock_nested ( s , depth ) ;
2005-04-17 02:20:36 +04:00
if ( ! bh ) {
printk ( " reiserfs_resize: can \' t read last block \n " ) ;
return - EINVAL ;
2005-07-13 07:21:28 +04:00
}
2005-04-17 02:20:36 +04:00
bforget ( bh ) ;
2014-04-23 18:00:36 +04:00
/*
* old disk layout detection ; those partitions can be mounted , but
* cannot be resized
*/
2005-07-13 07:21:28 +04:00
if ( SB_BUFFER_WITH_SB ( s ) - > b_blocknr * SB_BUFFER_WITH_SB ( s ) - > b_size
! = REISERFS_DISK_OFFSET_IN_BYTES ) {
printk
( " reiserfs_resize: unable to resize a reiserfs without distributed bitmap (fs version < 3.5.12) \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENOTSUPP ;
}
2005-07-13 07:21:28 +04:00
2005-04-17 02:20:36 +04:00
/* count used bits in last bitmap block */
2007-10-19 10:39:27 +04:00
block_r = SB_BLOCK_COUNT ( s ) -
( reiserfs_bmap_count ( s ) - 1 ) * s - > s_blocksize * 8 ;
2005-07-13 07:21:28 +04:00
2005-04-17 02:20:36 +04:00
/* count bitmap blocks in new fs */
2005-07-13 07:21:28 +04:00
bmap_nr_new = block_count_new / ( s - > s_blocksize * 8 ) ;
2005-04-17 02:20:36 +04:00
block_r_new = block_count_new - bmap_nr_new * s - > s_blocksize * 8 ;
2005-07-13 07:21:28 +04:00
if ( block_r_new )
2005-04-17 02:20:36 +04:00
bmap_nr_new + + ;
else
block_r_new = s - > s_blocksize * 8 ;
/* save old values */
block_count = SB_BLOCK_COUNT ( s ) ;
2007-10-19 10:39:27 +04:00
bmap_nr = reiserfs_bmap_count ( s ) ;
2005-04-17 02:20:36 +04:00
/* resizing of reiserfs bitmaps (journal and real), if needed */
2005-07-13 07:21:28 +04:00
if ( bmap_nr_new > bmap_nr ) {
/* reallocate journal bitmaps */
if ( reiserfs_allocate_list_bitmaps ( s , jbitmap , bmap_nr_new ) < 0 ) {
printk
( " reiserfs_resize: unable to allocate memory for journal bitmaps \n " ) ;
return - ENOMEM ;
}
2014-04-23 18:00:36 +04:00
/*
* the new journal bitmaps are zero filled , now we copy i
* the bitmap node pointers from the old journal bitmap
* structs , and then transfer the new data structures
* into the journal struct .
*
* using the copy_size var below allows this code to work for
* both shrinking and expanding the FS .
2005-07-13 07:21:28 +04:00
*/
copy_size = bmap_nr_new < bmap_nr ? bmap_nr_new : bmap_nr ;
copy_size =
copy_size * sizeof ( struct reiserfs_list_bitmap_node * ) ;
for ( i = 0 ; i < JOURNAL_NUM_BITMAPS ; i + + ) {
struct reiserfs_bitmap_node * * node_tmp ;
jb = SB_JOURNAL ( s ) - > j_list_bitmap + i ;
memcpy ( jbitmap [ i ] . bitmaps , jb - > bitmaps , copy_size ) ;
2014-04-23 18:00:36 +04:00
/*
* just in case vfree schedules on us , copy the new
* pointer into the journal struct before freeing the
* old one
2005-07-13 07:21:28 +04:00
*/
node_tmp = jb - > bitmaps ;
jb - > bitmaps = jbitmap [ i ] . bitmaps ;
vfree ( node_tmp ) ;
}
2014-04-23 18:00:36 +04:00
/*
* allocate additional bitmap blocks , reallocate
* array of bitmap block pointers
*/
2005-07-13 07:21:28 +04:00
bitmap =
2011-05-28 21:36:33 +04:00
vzalloc ( sizeof ( struct reiserfs_bitmap_info ) * bmap_nr_new ) ;
2005-07-13 07:21:28 +04:00
if ( ! bitmap ) {
2014-04-23 18:00:36 +04:00
/*
* Journal bitmaps are still supersized , but the
* memory isn ' t leaked , so I guess it ' s ok
*/
2005-07-13 07:21:28 +04:00
printk ( " reiserfs_resize: unable to allocate memory. \n " ) ;
return - ENOMEM ;
}
for ( i = 0 ; i < bmap_nr ; i + + )
bitmap [ i ] = old_bitmap [ i ] ;
2014-04-23 18:00:36 +04:00
/*
* This doesn ' t go through the journal , but it doesn ' t have to .
* The changes are still atomic : We ' re synced up when the
* journal transaction begins , and the new bitmaps don ' t
* matter if the transaction fails .
*/
2005-07-13 07:21:28 +04:00
for ( i = bmap_nr ; i < bmap_nr_new ; i + + ) {
2013-08-09 01:34:46 +04:00
int depth ;
2014-04-23 18:00:36 +04:00
/*
* don ' t use read_bitmap_block since it will cache
* the uninitialized bitmap
*/
2013-08-09 01:34:46 +04:00
depth = reiserfs_write_unlock_nested ( s ) ;
2006-10-01 10:28:44 +04:00
bh = sb_bread ( s , i * s - > s_blocksize * 8 ) ;
2013-08-09 01:34:46 +04:00
reiserfs_write_lock_nested ( s , depth ) ;
2007-05-08 11:24:37 +04:00
if ( ! bh ) {
vfree ( bitmap ) ;
return - EIO ;
}
2006-10-01 10:28:42 +04:00
memset ( bh - > b_data , 0 , sb_blocksize ( sb ) ) ;
2011-07-26 04:13:37 +04:00
reiserfs_set_le_bit ( 0 , bh - > b_data ) ;
2006-10-01 10:28:43 +04:00
reiserfs_cache_bitmap_metadata ( s , bh , bitmap + i ) ;
2006-10-01 10:28:42 +04:00
set_buffer_uptodate ( bh ) ;
mark_buffer_dirty ( bh ) ;
2013-08-09 01:34:46 +04:00
depth = reiserfs_write_unlock_nested ( s ) ;
2006-10-01 10:28:42 +04:00
sync_dirty_buffer ( bh ) ;
2013-08-09 01:34:46 +04:00
reiserfs_write_lock_nested ( s , depth ) ;
2014-04-23 18:00:36 +04:00
/* update bitmap_info stuff */
2005-07-13 07:21:28 +04:00
bitmap [ i ] . free_count = sb_blocksize ( sb ) * 8 - 1 ;
2006-10-01 10:28:42 +04:00
brelse ( bh ) ;
2005-07-13 07:21:28 +04:00
}
/* free old bitmap blocks array */
SB_AP_BITMAP ( s ) = bitmap ;
vfree ( old_bitmap ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:36 +04:00
/*
* begin transaction , if there was an error , it ' s fine . Yes , we have
2005-04-17 02:20:36 +04:00
* incorrect bitmaps now , but none of it is ever going to touch the
2014-04-23 18:00:36 +04:00
* disk anyway .
*/
2005-04-17 02:20:36 +04:00
err = journal_begin ( & th , s , 10 ) ;
if ( err )
2005-07-13 07:21:28 +04:00
return err ;
2005-04-17 02:20:36 +04:00
2006-10-01 10:28:42 +04:00
/* Extend old last bitmap block - new blocks have been made available */
info = SB_AP_BITMAP ( s ) + bmap_nr - 1 ;
2006-10-01 10:28:44 +04:00
bh = reiserfs_read_bitmap_block ( s , bmap_nr - 1 ) ;
if ( ! bh ) {
2014-04-23 18:00:38 +04:00
int jerr = journal_end ( & th ) ;
2006-10-01 10:28:44 +04:00
if ( jerr )
return jerr ;
return - EIO ;
}
2006-10-01 10:28:42 +04:00
reiserfs_prepare_for_journal ( s , bh , 1 ) ;
2005-04-17 02:20:36 +04:00
for ( i = block_r ; i < s - > s_blocksize * 8 ; i + + )
2011-07-26 04:13:37 +04:00
reiserfs_clear_le_bit ( i , bh - > b_data ) ;
2006-10-01 10:28:42 +04:00
info - > free_count + = s - > s_blocksize * 8 - block_r ;
2014-04-23 18:00:39 +04:00
journal_mark_dirty ( & th , bh ) ;
2006-10-01 10:28:42 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
2006-10-01 10:28:42 +04:00
/* Correct new last bitmap block - It may not be full */
info = SB_AP_BITMAP ( s ) + bmap_nr_new - 1 ;
2006-10-01 10:28:44 +04:00
bh = reiserfs_read_bitmap_block ( s , bmap_nr_new - 1 ) ;
if ( ! bh ) {
2014-04-23 18:00:38 +04:00
int jerr = journal_end ( & th ) ;
2006-10-01 10:28:44 +04:00
if ( jerr )
return jerr ;
return - EIO ;
}
2005-04-17 02:20:36 +04:00
2006-10-01 10:28:42 +04:00
reiserfs_prepare_for_journal ( s , bh , 1 ) ;
2005-04-17 02:20:36 +04:00
for ( i = block_r_new ; i < s - > s_blocksize * 8 ; i + + )
2011-07-26 04:13:37 +04:00
reiserfs_set_le_bit ( i , bh - > b_data ) ;
2014-04-23 18:00:39 +04:00
journal_mark_dirty ( & th , bh ) ;
2006-10-01 10:28:42 +04:00
brelse ( bh ) ;
2005-07-13 07:21:28 +04:00
2006-10-01 10:28:42 +04:00
info - > free_count - = s - > s_blocksize * 8 - block_r_new ;
2005-07-13 07:21:28 +04:00
/* update super */
reiserfs_prepare_for_journal ( s , SB_BUFFER_WITH_SB ( s ) , 1 ) ;
2005-04-17 02:20:36 +04:00
free_blocks = SB_FREE_BLOCKS ( s ) ;
2005-07-13 07:21:28 +04:00
PUT_SB_FREE_BLOCKS ( s ,
free_blocks + ( block_count_new - block_count -
( bmap_nr_new - bmap_nr ) ) ) ;
2005-04-17 02:20:36 +04:00
PUT_SB_BLOCK_COUNT ( s , block_count_new ) ;
2007-10-19 10:39:27 +04:00
PUT_SB_BMAP_NR ( s , bmap_would_wrap ( bmap_nr_new ) ? : bmap_nr_new ) ;
2005-04-17 02:20:36 +04:00
2014-04-23 18:00:39 +04:00
journal_mark_dirty ( & th , SB_BUFFER_WITH_SB ( s ) ) ;
2005-07-13 07:21:28 +04:00
2005-04-17 02:20:36 +04:00
SB_JOURNAL ( s ) - > j_must_wait = 1 ;
2014-04-23 18:00:38 +04:00
return journal_end ( & th ) ;
2005-04-17 02:20:36 +04:00
}