18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README 38c2ecf20Sopenharmony_ci */ 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci/* 68c2ecf20Sopenharmony_ci * Written by Alexander Zarochentcev. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * The kernel part of the (on-line) reiserfs resizer. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/mm.h> 138c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include "reiserfs.h" 178c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciint reiserfs_resize(struct super_block *s, unsigned long block_count_new) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci int err = 0; 228c2ecf20Sopenharmony_ci struct reiserfs_super_block *sb; 238c2ecf20Sopenharmony_ci struct reiserfs_bitmap_info *bitmap; 248c2ecf20Sopenharmony_ci struct reiserfs_bitmap_info *info; 258c2ecf20Sopenharmony_ci struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s); 268c2ecf20Sopenharmony_ci struct buffer_head *bh; 278c2ecf20Sopenharmony_ci struct reiserfs_transaction_handle th; 288c2ecf20Sopenharmony_ci unsigned int bmap_nr_new, bmap_nr; 298c2ecf20Sopenharmony_ci unsigned int block_r_new, block_r; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci struct reiserfs_list_bitmap *jb; 328c2ecf20Sopenharmony_ci struct reiserfs_list_bitmap jbitmap[JOURNAL_NUM_BITMAPS]; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci unsigned long int block_count, free_blocks; 358c2ecf20Sopenharmony_ci int i; 368c2ecf20Sopenharmony_ci int copy_size; 378c2ecf20Sopenharmony_ci int depth; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci sb = SB_DISK_SUPER_BLOCK(s); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (SB_BLOCK_COUNT(s) >= block_count_new) { 428c2ecf20Sopenharmony_ci printk("can\'t shrink filesystem on-line\n"); 438c2ecf20Sopenharmony_ci return -EINVAL; 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* check the device size */ 478c2ecf20Sopenharmony_ci depth = reiserfs_write_unlock_nested(s); 488c2ecf20Sopenharmony_ci bh = sb_bread(s, block_count_new - 1); 498c2ecf20Sopenharmony_ci reiserfs_write_lock_nested(s, depth); 508c2ecf20Sopenharmony_ci if (!bh) { 518c2ecf20Sopenharmony_ci printk("reiserfs_resize: can\'t read last block\n"); 528c2ecf20Sopenharmony_ci return -EINVAL; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci bforget(bh); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* 578c2ecf20Sopenharmony_ci * old disk layout detection; those partitions can be mounted, but 588c2ecf20Sopenharmony_ci * cannot be resized 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci if (SB_BUFFER_WITH_SB(s)->b_blocknr * SB_BUFFER_WITH_SB(s)->b_size 618c2ecf20Sopenharmony_ci != REISERFS_DISK_OFFSET_IN_BYTES) { 628c2ecf20Sopenharmony_ci printk 638c2ecf20Sopenharmony_ci ("reiserfs_resize: unable to resize a reiserfs without distributed bitmap (fs version < 3.5.12)\n"); 648c2ecf20Sopenharmony_ci return -ENOTSUPP; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* count used bits in last bitmap block */ 688c2ecf20Sopenharmony_ci block_r = SB_BLOCK_COUNT(s) - 698c2ecf20Sopenharmony_ci (reiserfs_bmap_count(s) - 1) * s->s_blocksize * 8; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* count bitmap blocks in new fs */ 728c2ecf20Sopenharmony_ci bmap_nr_new = block_count_new / (s->s_blocksize * 8); 738c2ecf20Sopenharmony_ci block_r_new = block_count_new - bmap_nr_new * s->s_blocksize * 8; 748c2ecf20Sopenharmony_ci if (block_r_new) 758c2ecf20Sopenharmony_ci bmap_nr_new++; 768c2ecf20Sopenharmony_ci else 778c2ecf20Sopenharmony_ci block_r_new = s->s_blocksize * 8; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* save old values */ 808c2ecf20Sopenharmony_ci block_count = SB_BLOCK_COUNT(s); 818c2ecf20Sopenharmony_ci bmap_nr = reiserfs_bmap_count(s); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* resizing of reiserfs bitmaps (journal and real), if needed */ 848c2ecf20Sopenharmony_ci if (bmap_nr_new > bmap_nr) { 858c2ecf20Sopenharmony_ci /* reallocate journal bitmaps */ 868c2ecf20Sopenharmony_ci if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) { 878c2ecf20Sopenharmony_ci printk 888c2ecf20Sopenharmony_ci ("reiserfs_resize: unable to allocate memory for journal bitmaps\n"); 898c2ecf20Sopenharmony_ci return -ENOMEM; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci /* 928c2ecf20Sopenharmony_ci * the new journal bitmaps are zero filled, now we copy i 938c2ecf20Sopenharmony_ci * the bitmap node pointers from the old journal bitmap 948c2ecf20Sopenharmony_ci * structs, and then transfer the new data structures 958c2ecf20Sopenharmony_ci * into the journal struct. 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * using the copy_size var below allows this code to work for 988c2ecf20Sopenharmony_ci * both shrinking and expanding the FS. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci copy_size = bmap_nr_new < bmap_nr ? bmap_nr_new : bmap_nr; 1018c2ecf20Sopenharmony_ci copy_size = 1028c2ecf20Sopenharmony_ci copy_size * sizeof(struct reiserfs_list_bitmap_node *); 1038c2ecf20Sopenharmony_ci for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) { 1048c2ecf20Sopenharmony_ci struct reiserfs_bitmap_node **node_tmp; 1058c2ecf20Sopenharmony_ci jb = SB_JOURNAL(s)->j_list_bitmap + i; 1068c2ecf20Sopenharmony_ci memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* 1098c2ecf20Sopenharmony_ci * just in case vfree schedules on us, copy the new 1108c2ecf20Sopenharmony_ci * pointer into the journal struct before freeing the 1118c2ecf20Sopenharmony_ci * old one 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci node_tmp = jb->bitmaps; 1148c2ecf20Sopenharmony_ci jb->bitmaps = jbitmap[i].bitmaps; 1158c2ecf20Sopenharmony_ci vfree(node_tmp); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* 1198c2ecf20Sopenharmony_ci * allocate additional bitmap blocks, reallocate 1208c2ecf20Sopenharmony_ci * array of bitmap block pointers 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci bitmap = 1238c2ecf20Sopenharmony_ci vzalloc(array_size(bmap_nr_new, 1248c2ecf20Sopenharmony_ci sizeof(struct reiserfs_bitmap_info))); 1258c2ecf20Sopenharmony_ci if (!bitmap) { 1268c2ecf20Sopenharmony_ci /* 1278c2ecf20Sopenharmony_ci * Journal bitmaps are still supersized, but the 1288c2ecf20Sopenharmony_ci * memory isn't leaked, so I guess it's ok 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci printk("reiserfs_resize: unable to allocate memory.\n"); 1318c2ecf20Sopenharmony_ci return -ENOMEM; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci for (i = 0; i < bmap_nr; i++) 1348c2ecf20Sopenharmony_ci bitmap[i] = old_bitmap[i]; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * This doesn't go through the journal, but it doesn't have to. 1388c2ecf20Sopenharmony_ci * The changes are still atomic: We're synced up when the 1398c2ecf20Sopenharmony_ci * journal transaction begins, and the new bitmaps don't 1408c2ecf20Sopenharmony_ci * matter if the transaction fails. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci for (i = bmap_nr; i < bmap_nr_new; i++) { 1438c2ecf20Sopenharmony_ci int depth; 1448c2ecf20Sopenharmony_ci /* 1458c2ecf20Sopenharmony_ci * don't use read_bitmap_block since it will cache 1468c2ecf20Sopenharmony_ci * the uninitialized bitmap 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_ci depth = reiserfs_write_unlock_nested(s); 1498c2ecf20Sopenharmony_ci bh = sb_bread(s, i * s->s_blocksize * 8); 1508c2ecf20Sopenharmony_ci reiserfs_write_lock_nested(s, depth); 1518c2ecf20Sopenharmony_ci if (!bh) { 1528c2ecf20Sopenharmony_ci vfree(bitmap); 1538c2ecf20Sopenharmony_ci return -EIO; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci memset(bh->b_data, 0, sb_blocksize(sb)); 1568c2ecf20Sopenharmony_ci reiserfs_set_le_bit(0, bh->b_data); 1578c2ecf20Sopenharmony_ci reiserfs_cache_bitmap_metadata(s, bh, bitmap + i); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci set_buffer_uptodate(bh); 1608c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 1618c2ecf20Sopenharmony_ci depth = reiserfs_write_unlock_nested(s); 1628c2ecf20Sopenharmony_ci sync_dirty_buffer(bh); 1638c2ecf20Sopenharmony_ci reiserfs_write_lock_nested(s, depth); 1648c2ecf20Sopenharmony_ci /* update bitmap_info stuff */ 1658c2ecf20Sopenharmony_ci bitmap[i].free_count = sb_blocksize(sb) * 8 - 1; 1668c2ecf20Sopenharmony_ci brelse(bh); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci /* free old bitmap blocks array */ 1698c2ecf20Sopenharmony_ci SB_AP_BITMAP(s) = bitmap; 1708c2ecf20Sopenharmony_ci vfree(old_bitmap); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* 1748c2ecf20Sopenharmony_ci * begin transaction, if there was an error, it's fine. Yes, we have 1758c2ecf20Sopenharmony_ci * incorrect bitmaps now, but none of it is ever going to touch the 1768c2ecf20Sopenharmony_ci * disk anyway. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci err = journal_begin(&th, s, 10); 1798c2ecf20Sopenharmony_ci if (err) 1808c2ecf20Sopenharmony_ci return err; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Extend old last bitmap block - new blocks have been made available */ 1838c2ecf20Sopenharmony_ci info = SB_AP_BITMAP(s) + bmap_nr - 1; 1848c2ecf20Sopenharmony_ci bh = reiserfs_read_bitmap_block(s, bmap_nr - 1); 1858c2ecf20Sopenharmony_ci if (!bh) { 1868c2ecf20Sopenharmony_ci int jerr = journal_end(&th); 1878c2ecf20Sopenharmony_ci if (jerr) 1888c2ecf20Sopenharmony_ci return jerr; 1898c2ecf20Sopenharmony_ci return -EIO; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci reiserfs_prepare_for_journal(s, bh, 1); 1938c2ecf20Sopenharmony_ci for (i = block_r; i < s->s_blocksize * 8; i++) 1948c2ecf20Sopenharmony_ci reiserfs_clear_le_bit(i, bh->b_data); 1958c2ecf20Sopenharmony_ci info->free_count += s->s_blocksize * 8 - block_r; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci journal_mark_dirty(&th, bh); 1988c2ecf20Sopenharmony_ci brelse(bh); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* Correct new last bitmap block - It may not be full */ 2018c2ecf20Sopenharmony_ci info = SB_AP_BITMAP(s) + bmap_nr_new - 1; 2028c2ecf20Sopenharmony_ci bh = reiserfs_read_bitmap_block(s, bmap_nr_new - 1); 2038c2ecf20Sopenharmony_ci if (!bh) { 2048c2ecf20Sopenharmony_ci int jerr = journal_end(&th); 2058c2ecf20Sopenharmony_ci if (jerr) 2068c2ecf20Sopenharmony_ci return jerr; 2078c2ecf20Sopenharmony_ci return -EIO; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci reiserfs_prepare_for_journal(s, bh, 1); 2118c2ecf20Sopenharmony_ci for (i = block_r_new; i < s->s_blocksize * 8; i++) 2128c2ecf20Sopenharmony_ci reiserfs_set_le_bit(i, bh->b_data); 2138c2ecf20Sopenharmony_ci journal_mark_dirty(&th, bh); 2148c2ecf20Sopenharmony_ci brelse(bh); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci info->free_count -= s->s_blocksize * 8 - block_r_new; 2178c2ecf20Sopenharmony_ci /* update super */ 2188c2ecf20Sopenharmony_ci reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); 2198c2ecf20Sopenharmony_ci free_blocks = SB_FREE_BLOCKS(s); 2208c2ecf20Sopenharmony_ci PUT_SB_FREE_BLOCKS(s, 2218c2ecf20Sopenharmony_ci free_blocks + (block_count_new - block_count - 2228c2ecf20Sopenharmony_ci (bmap_nr_new - bmap_nr))); 2238c2ecf20Sopenharmony_ci PUT_SB_BLOCK_COUNT(s, block_count_new); 2248c2ecf20Sopenharmony_ci PUT_SB_BMAP_NR(s, bmap_would_wrap(bmap_nr_new) ? : bmap_nr_new); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s)); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci SB_JOURNAL(s)->j_must_wait = 1; 2298c2ecf20Sopenharmony_ci return journal_end(&th); 2308c2ecf20Sopenharmony_ci} 231