162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci/* 662306a36Sopenharmony_ci * Written by Alexander Zarochentcev. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * The kernel part of the (on-line) reiserfs resizer. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/mm.h> 1362306a36Sopenharmony_ci#include <linux/vmalloc.h> 1462306a36Sopenharmony_ci#include <linux/string.h> 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci#include "reiserfs.h" 1762306a36Sopenharmony_ci#include <linux/buffer_head.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciint reiserfs_resize(struct super_block *s, unsigned long block_count_new) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci int err = 0; 2262306a36Sopenharmony_ci struct reiserfs_super_block *sb; 2362306a36Sopenharmony_ci struct reiserfs_bitmap_info *bitmap; 2462306a36Sopenharmony_ci struct reiserfs_bitmap_info *info; 2562306a36Sopenharmony_ci struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s); 2662306a36Sopenharmony_ci struct buffer_head *bh; 2762306a36Sopenharmony_ci struct reiserfs_transaction_handle th; 2862306a36Sopenharmony_ci unsigned int bmap_nr_new, bmap_nr; 2962306a36Sopenharmony_ci unsigned int block_r_new, block_r; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci struct reiserfs_list_bitmap *jb; 3262306a36Sopenharmony_ci struct reiserfs_list_bitmap jbitmap[JOURNAL_NUM_BITMAPS]; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci unsigned long int block_count, free_blocks; 3562306a36Sopenharmony_ci int i; 3662306a36Sopenharmony_ci int copy_size; 3762306a36Sopenharmony_ci int depth; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci sb = SB_DISK_SUPER_BLOCK(s); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (SB_BLOCK_COUNT(s) >= block_count_new) { 4262306a36Sopenharmony_ci printk("can\'t shrink filesystem on-line\n"); 4362306a36Sopenharmony_ci return -EINVAL; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* check the device size */ 4762306a36Sopenharmony_ci depth = reiserfs_write_unlock_nested(s); 4862306a36Sopenharmony_ci bh = sb_bread(s, block_count_new - 1); 4962306a36Sopenharmony_ci reiserfs_write_lock_nested(s, depth); 5062306a36Sopenharmony_ci if (!bh) { 5162306a36Sopenharmony_ci printk("reiserfs_resize: can\'t read last block\n"); 5262306a36Sopenharmony_ci return -EINVAL; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci bforget(bh); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* 5762306a36Sopenharmony_ci * old disk layout detection; those partitions can be mounted, but 5862306a36Sopenharmony_ci * cannot be resized 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci if (SB_BUFFER_WITH_SB(s)->b_blocknr * SB_BUFFER_WITH_SB(s)->b_size 6162306a36Sopenharmony_ci != REISERFS_DISK_OFFSET_IN_BYTES) { 6262306a36Sopenharmony_ci printk 6362306a36Sopenharmony_ci ("reiserfs_resize: unable to resize a reiserfs without distributed bitmap (fs version < 3.5.12)\n"); 6462306a36Sopenharmony_ci return -ENOTSUPP; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* count used bits in last bitmap block */ 6862306a36Sopenharmony_ci block_r = SB_BLOCK_COUNT(s) - 6962306a36Sopenharmony_ci (reiserfs_bmap_count(s) - 1) * s->s_blocksize * 8; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* count bitmap blocks in new fs */ 7262306a36Sopenharmony_ci bmap_nr_new = block_count_new / (s->s_blocksize * 8); 7362306a36Sopenharmony_ci block_r_new = block_count_new - bmap_nr_new * s->s_blocksize * 8; 7462306a36Sopenharmony_ci if (block_r_new) 7562306a36Sopenharmony_ci bmap_nr_new++; 7662306a36Sopenharmony_ci else 7762306a36Sopenharmony_ci block_r_new = s->s_blocksize * 8; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* save old values */ 8062306a36Sopenharmony_ci block_count = SB_BLOCK_COUNT(s); 8162306a36Sopenharmony_ci bmap_nr = reiserfs_bmap_count(s); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* resizing of reiserfs bitmaps (journal and real), if needed */ 8462306a36Sopenharmony_ci if (bmap_nr_new > bmap_nr) { 8562306a36Sopenharmony_ci /* reallocate journal bitmaps */ 8662306a36Sopenharmony_ci if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) { 8762306a36Sopenharmony_ci printk 8862306a36Sopenharmony_ci ("reiserfs_resize: unable to allocate memory for journal bitmaps\n"); 8962306a36Sopenharmony_ci return -ENOMEM; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * the new journal bitmaps are zero filled, now we copy i 9362306a36Sopenharmony_ci * the bitmap node pointers from the old journal bitmap 9462306a36Sopenharmony_ci * structs, and then transfer the new data structures 9562306a36Sopenharmony_ci * into the journal struct. 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * using the copy_size var below allows this code to work for 9862306a36Sopenharmony_ci * both shrinking and expanding the FS. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci copy_size = min(bmap_nr_new, bmap_nr); 10162306a36Sopenharmony_ci copy_size = 10262306a36Sopenharmony_ci copy_size * sizeof(struct reiserfs_list_bitmap_node *); 10362306a36Sopenharmony_ci for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) { 10462306a36Sopenharmony_ci struct reiserfs_bitmap_node **node_tmp; 10562306a36Sopenharmony_ci jb = SB_JOURNAL(s)->j_list_bitmap + i; 10662306a36Sopenharmony_ci memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* 10962306a36Sopenharmony_ci * just in case vfree schedules on us, copy the new 11062306a36Sopenharmony_ci * pointer into the journal struct before freeing the 11162306a36Sopenharmony_ci * old one 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci node_tmp = jb->bitmaps; 11462306a36Sopenharmony_ci jb->bitmaps = jbitmap[i].bitmaps; 11562306a36Sopenharmony_ci vfree(node_tmp); 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* 11962306a36Sopenharmony_ci * allocate additional bitmap blocks, reallocate 12062306a36Sopenharmony_ci * array of bitmap block pointers 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci bitmap = 12362306a36Sopenharmony_ci vzalloc(array_size(bmap_nr_new, 12462306a36Sopenharmony_ci sizeof(struct reiserfs_bitmap_info))); 12562306a36Sopenharmony_ci if (!bitmap) { 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * Journal bitmaps are still supersized, but the 12862306a36Sopenharmony_ci * memory isn't leaked, so I guess it's ok 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci printk("reiserfs_resize: unable to allocate memory.\n"); 13162306a36Sopenharmony_ci return -ENOMEM; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci for (i = 0; i < bmap_nr; i++) 13462306a36Sopenharmony_ci bitmap[i] = old_bitmap[i]; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * This doesn't go through the journal, but it doesn't have to. 13862306a36Sopenharmony_ci * The changes are still atomic: We're synced up when the 13962306a36Sopenharmony_ci * journal transaction begins, and the new bitmaps don't 14062306a36Sopenharmony_ci * matter if the transaction fails. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci for (i = bmap_nr; i < bmap_nr_new; i++) { 14362306a36Sopenharmony_ci int depth; 14462306a36Sopenharmony_ci /* 14562306a36Sopenharmony_ci * don't use read_bitmap_block since it will cache 14662306a36Sopenharmony_ci * the uninitialized bitmap 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci depth = reiserfs_write_unlock_nested(s); 14962306a36Sopenharmony_ci bh = sb_bread(s, i * s->s_blocksize * 8); 15062306a36Sopenharmony_ci reiserfs_write_lock_nested(s, depth); 15162306a36Sopenharmony_ci if (!bh) { 15262306a36Sopenharmony_ci vfree(bitmap); 15362306a36Sopenharmony_ci return -EIO; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci memset(bh->b_data, 0, sb_blocksize(sb)); 15662306a36Sopenharmony_ci reiserfs_set_le_bit(0, bh->b_data); 15762306a36Sopenharmony_ci reiserfs_cache_bitmap_metadata(s, bh, bitmap + i); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci set_buffer_uptodate(bh); 16062306a36Sopenharmony_ci mark_buffer_dirty(bh); 16162306a36Sopenharmony_ci depth = reiserfs_write_unlock_nested(s); 16262306a36Sopenharmony_ci sync_dirty_buffer(bh); 16362306a36Sopenharmony_ci reiserfs_write_lock_nested(s, depth); 16462306a36Sopenharmony_ci /* update bitmap_info stuff */ 16562306a36Sopenharmony_ci bitmap[i].free_count = sb_blocksize(sb) * 8 - 1; 16662306a36Sopenharmony_ci brelse(bh); 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci /* free old bitmap blocks array */ 16962306a36Sopenharmony_ci SB_AP_BITMAP(s) = bitmap; 17062306a36Sopenharmony_ci vfree(old_bitmap); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* 17462306a36Sopenharmony_ci * begin transaction, if there was an error, it's fine. Yes, we have 17562306a36Sopenharmony_ci * incorrect bitmaps now, but none of it is ever going to touch the 17662306a36Sopenharmony_ci * disk anyway. 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci err = journal_begin(&th, s, 10); 17962306a36Sopenharmony_ci if (err) 18062306a36Sopenharmony_ci return err; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Extend old last bitmap block - new blocks have been made available */ 18362306a36Sopenharmony_ci info = SB_AP_BITMAP(s) + bmap_nr - 1; 18462306a36Sopenharmony_ci bh = reiserfs_read_bitmap_block(s, bmap_nr - 1); 18562306a36Sopenharmony_ci if (!bh) { 18662306a36Sopenharmony_ci int jerr = journal_end(&th); 18762306a36Sopenharmony_ci if (jerr) 18862306a36Sopenharmony_ci return jerr; 18962306a36Sopenharmony_ci return -EIO; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci reiserfs_prepare_for_journal(s, bh, 1); 19362306a36Sopenharmony_ci for (i = block_r; i < s->s_blocksize * 8; i++) 19462306a36Sopenharmony_ci reiserfs_clear_le_bit(i, bh->b_data); 19562306a36Sopenharmony_ci info->free_count += s->s_blocksize * 8 - block_r; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci journal_mark_dirty(&th, bh); 19862306a36Sopenharmony_ci brelse(bh); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Correct new last bitmap block - It may not be full */ 20162306a36Sopenharmony_ci info = SB_AP_BITMAP(s) + bmap_nr_new - 1; 20262306a36Sopenharmony_ci bh = reiserfs_read_bitmap_block(s, bmap_nr_new - 1); 20362306a36Sopenharmony_ci if (!bh) { 20462306a36Sopenharmony_ci int jerr = journal_end(&th); 20562306a36Sopenharmony_ci if (jerr) 20662306a36Sopenharmony_ci return jerr; 20762306a36Sopenharmony_ci return -EIO; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci reiserfs_prepare_for_journal(s, bh, 1); 21162306a36Sopenharmony_ci for (i = block_r_new; i < s->s_blocksize * 8; i++) 21262306a36Sopenharmony_ci reiserfs_set_le_bit(i, bh->b_data); 21362306a36Sopenharmony_ci journal_mark_dirty(&th, bh); 21462306a36Sopenharmony_ci brelse(bh); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci info->free_count -= s->s_blocksize * 8 - block_r_new; 21762306a36Sopenharmony_ci /* update super */ 21862306a36Sopenharmony_ci reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); 21962306a36Sopenharmony_ci free_blocks = SB_FREE_BLOCKS(s); 22062306a36Sopenharmony_ci PUT_SB_FREE_BLOCKS(s, 22162306a36Sopenharmony_ci free_blocks + (block_count_new - block_count - 22262306a36Sopenharmony_ci (bmap_nr_new - bmap_nr))); 22362306a36Sopenharmony_ci PUT_SB_BLOCK_COUNT(s, block_count_new); 22462306a36Sopenharmony_ci PUT_SB_BMAP_NR(s, bmap_would_wrap(bmap_nr_new) ? : bmap_nr_new); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s)); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci SB_JOURNAL(s)->j_must_wait = 1; 22962306a36Sopenharmony_ci return journal_end(&th); 23062306a36Sopenharmony_ci} 231