11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
31da177e4SLinus Torvalds */
41da177e4SLinus Torvalds
51da177e4SLinus Torvalds /*
61da177e4SLinus Torvalds * Written by Alexander Zarochentcev.
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * The kernel part of the (on-line) reiserfs resizer.
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/mm.h>
131da177e4SLinus Torvalds #include <linux/vmalloc.h>
141da177e4SLinus Torvalds #include <linux/string.h>
151da177e4SLinus Torvalds #include <linux/errno.h>
16f466c6fdSAl Viro #include "reiserfs.h"
171da177e4SLinus Torvalds #include <linux/buffer_head.h>
181da177e4SLinus Torvalds
reiserfs_resize(struct super_block * s,unsigned long block_count_new)191da177e4SLinus Torvalds int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
201da177e4SLinus Torvalds {
211da177e4SLinus Torvalds int err = 0;
221da177e4SLinus Torvalds struct reiserfs_super_block *sb;
231da177e4SLinus Torvalds struct reiserfs_bitmap_info *bitmap;
240b3dc17bSJeff Mahoney struct reiserfs_bitmap_info *info;
251da177e4SLinus Torvalds struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s);
261da177e4SLinus Torvalds struct buffer_head *bh;
271da177e4SLinus Torvalds struct reiserfs_transaction_handle th;
281da177e4SLinus Torvalds unsigned int bmap_nr_new, bmap_nr;
291da177e4SLinus Torvalds unsigned int block_r_new, block_r;
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds struct reiserfs_list_bitmap *jb;
321da177e4SLinus Torvalds struct reiserfs_list_bitmap jbitmap[JOURNAL_NUM_BITMAPS];
331da177e4SLinus Torvalds
341da177e4SLinus Torvalds unsigned long int block_count, free_blocks;
351da177e4SLinus Torvalds int i;
361da177e4SLinus Torvalds int copy_size;
37278f6679SJeff Mahoney int depth;
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds sb = SB_DISK_SUPER_BLOCK(s);
401da177e4SLinus Torvalds
411da177e4SLinus Torvalds if (SB_BLOCK_COUNT(s) >= block_count_new) {
421da177e4SLinus Torvalds printk("can\'t shrink filesystem on-line\n");
431da177e4SLinus Torvalds return -EINVAL;
441da177e4SLinus Torvalds }
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds /* check the device size */
47278f6679SJeff Mahoney depth = reiserfs_write_unlock_nested(s);
481da177e4SLinus Torvalds bh = sb_bread(s, block_count_new - 1);
49278f6679SJeff Mahoney reiserfs_write_lock_nested(s, depth);
501da177e4SLinus Torvalds if (!bh) {
511da177e4SLinus Torvalds printk("reiserfs_resize: can\'t read last block\n");
521da177e4SLinus Torvalds return -EINVAL;
531da177e4SLinus Torvalds }
541da177e4SLinus Torvalds bforget(bh);
551da177e4SLinus Torvalds
56098297b2SJeff Mahoney /*
57098297b2SJeff Mahoney * old disk layout detection; those partitions can be mounted, but
58098297b2SJeff Mahoney * cannot be resized
59098297b2SJeff Mahoney */
601da177e4SLinus Torvalds if (SB_BUFFER_WITH_SB(s)->b_blocknr * SB_BUFFER_WITH_SB(s)->b_size
611da177e4SLinus Torvalds != REISERFS_DISK_OFFSET_IN_BYTES) {
62bd4c625cSLinus Torvalds printk
63bd4c625cSLinus Torvalds ("reiserfs_resize: unable to resize a reiserfs without distributed bitmap (fs version < 3.5.12)\n");
641da177e4SLinus Torvalds return -ENOTSUPP;
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds /* count used bits in last bitmap block */
68cb680c1bSJeff Mahoney block_r = SB_BLOCK_COUNT(s) -
69cb680c1bSJeff Mahoney (reiserfs_bmap_count(s) - 1) * s->s_blocksize * 8;
701da177e4SLinus Torvalds
711da177e4SLinus Torvalds /* count bitmap blocks in new fs */
721da177e4SLinus Torvalds bmap_nr_new = block_count_new / (s->s_blocksize * 8);
731da177e4SLinus Torvalds block_r_new = block_count_new - bmap_nr_new * s->s_blocksize * 8;
741da177e4SLinus Torvalds if (block_r_new)
751da177e4SLinus Torvalds bmap_nr_new++;
761da177e4SLinus Torvalds else
771da177e4SLinus Torvalds block_r_new = s->s_blocksize * 8;
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds /* save old values */
801da177e4SLinus Torvalds block_count = SB_BLOCK_COUNT(s);
81cb680c1bSJeff Mahoney bmap_nr = reiserfs_bmap_count(s);
821da177e4SLinus Torvalds
831da177e4SLinus Torvalds /* resizing of reiserfs bitmaps (journal and real), if needed */
841da177e4SLinus Torvalds if (bmap_nr_new > bmap_nr) {
851da177e4SLinus Torvalds /* reallocate journal bitmaps */
861da177e4SLinus Torvalds if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) {
87bd4c625cSLinus Torvalds printk
88bd4c625cSLinus Torvalds ("reiserfs_resize: unable to allocate memory for journal bitmaps\n");
891da177e4SLinus Torvalds return -ENOMEM;
901da177e4SLinus Torvalds }
91098297b2SJeff Mahoney /*
92098297b2SJeff Mahoney * the new journal bitmaps are zero filled, now we copy i
93098297b2SJeff Mahoney * the bitmap node pointers from the old journal bitmap
94098297b2SJeff Mahoney * structs, and then transfer the new data structures
95098297b2SJeff Mahoney * into the journal struct.
96098297b2SJeff Mahoney *
97098297b2SJeff Mahoney * using the copy_size var below allows this code to work for
98098297b2SJeff Mahoney * both shrinking and expanding the FS.
991da177e4SLinus Torvalds */
100*e03d3b1bSJiangshan Yi copy_size = min(bmap_nr_new, bmap_nr);
101bd4c625cSLinus Torvalds copy_size =
102bd4c625cSLinus Torvalds copy_size * sizeof(struct reiserfs_list_bitmap_node *);
1031da177e4SLinus Torvalds for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {
1041da177e4SLinus Torvalds struct reiserfs_bitmap_node **node_tmp;
1051da177e4SLinus Torvalds jb = SB_JOURNAL(s)->j_list_bitmap + i;
1061da177e4SLinus Torvalds memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size);
1071da177e4SLinus Torvalds
108098297b2SJeff Mahoney /*
109098297b2SJeff Mahoney * just in case vfree schedules on us, copy the new
110098297b2SJeff Mahoney * pointer into the journal struct before freeing the
111098297b2SJeff Mahoney * old one
1121da177e4SLinus Torvalds */
1131da177e4SLinus Torvalds node_tmp = jb->bitmaps;
1141da177e4SLinus Torvalds jb->bitmaps = jbitmap[i].bitmaps;
1151da177e4SLinus Torvalds vfree(node_tmp);
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds
118098297b2SJeff Mahoney /*
119098297b2SJeff Mahoney * allocate additional bitmap blocks, reallocate
120098297b2SJeff Mahoney * array of bitmap block pointers
121098297b2SJeff Mahoney */
122bd4c625cSLinus Torvalds bitmap =
123fad953ceSKees Cook vzalloc(array_size(bmap_nr_new,
124fad953ceSKees Cook sizeof(struct reiserfs_bitmap_info)));
1251da177e4SLinus Torvalds if (!bitmap) {
126098297b2SJeff Mahoney /*
127098297b2SJeff Mahoney * Journal bitmaps are still supersized, but the
128098297b2SJeff Mahoney * memory isn't leaked, so I guess it's ok
129098297b2SJeff Mahoney */
1301da177e4SLinus Torvalds printk("reiserfs_resize: unable to allocate memory.\n");
1311da177e4SLinus Torvalds return -ENOMEM;
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds for (i = 0; i < bmap_nr; i++)
1341da177e4SLinus Torvalds bitmap[i] = old_bitmap[i];
1351da177e4SLinus Torvalds
136098297b2SJeff Mahoney /*
137098297b2SJeff Mahoney * This doesn't go through the journal, but it doesn't have to.
138098297b2SJeff Mahoney * The changes are still atomic: We're synced up when the
139098297b2SJeff Mahoney * journal transaction begins, and the new bitmaps don't
140098297b2SJeff Mahoney * matter if the transaction fails.
141098297b2SJeff Mahoney */
1421da177e4SLinus Torvalds for (i = bmap_nr; i < bmap_nr_new; i++) {
143278f6679SJeff Mahoney int depth;
144098297b2SJeff Mahoney /*
145098297b2SJeff Mahoney * don't use read_bitmap_block since it will cache
146098297b2SJeff Mahoney * the uninitialized bitmap
147098297b2SJeff Mahoney */
148278f6679SJeff Mahoney depth = reiserfs_write_unlock_nested(s);
1495065227bSJeff Mahoney bh = sb_bread(s, i * s->s_blocksize * 8);
150278f6679SJeff Mahoney reiserfs_write_lock_nested(s, depth);
1512d3466a3SDmitriy Monakhov if (!bh) {
1522d3466a3SDmitriy Monakhov vfree(bitmap);
1532d3466a3SDmitriy Monakhov return -EIO;
1542d3466a3SDmitriy Monakhov }
1550b3dc17bSJeff Mahoney memset(bh->b_data, 0, sb_blocksize(sb));
1560c2fd1bfSAkinobu Mita reiserfs_set_le_bit(0, bh->b_data);
1576f01046bSJeff Mahoney reiserfs_cache_bitmap_metadata(s, bh, bitmap + i);
1581da177e4SLinus Torvalds
1590b3dc17bSJeff Mahoney set_buffer_uptodate(bh);
1600b3dc17bSJeff Mahoney mark_buffer_dirty(bh);
161278f6679SJeff Mahoney depth = reiserfs_write_unlock_nested(s);
1620b3dc17bSJeff Mahoney sync_dirty_buffer(bh);
163278f6679SJeff Mahoney reiserfs_write_lock_nested(s, depth);
164098297b2SJeff Mahoney /* update bitmap_info stuff */
1651da177e4SLinus Torvalds bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
1660b3dc17bSJeff Mahoney brelse(bh);
1671da177e4SLinus Torvalds }
1681da177e4SLinus Torvalds /* free old bitmap blocks array */
1691da177e4SLinus Torvalds SB_AP_BITMAP(s) = bitmap;
1701da177e4SLinus Torvalds vfree(old_bitmap);
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds
173098297b2SJeff Mahoney /*
174098297b2SJeff Mahoney * begin transaction, if there was an error, it's fine. Yes, we have
1751da177e4SLinus Torvalds * incorrect bitmaps now, but none of it is ever going to touch the
176098297b2SJeff Mahoney * disk anyway.
177098297b2SJeff Mahoney */
1781da177e4SLinus Torvalds err = journal_begin(&th, s, 10);
1791da177e4SLinus Torvalds if (err)
1801da177e4SLinus Torvalds return err;
1811da177e4SLinus Torvalds
1820b3dc17bSJeff Mahoney /* Extend old last bitmap block - new blocks have been made available */
1830b3dc17bSJeff Mahoney info = SB_AP_BITMAP(s) + bmap_nr - 1;
1845065227bSJeff Mahoney bh = reiserfs_read_bitmap_block(s, bmap_nr - 1);
1855065227bSJeff Mahoney if (!bh) {
18658d85426SJeff Mahoney int jerr = journal_end(&th);
1875065227bSJeff Mahoney if (jerr)
1885065227bSJeff Mahoney return jerr;
1895065227bSJeff Mahoney return -EIO;
1905065227bSJeff Mahoney }
1910b3dc17bSJeff Mahoney
1920b3dc17bSJeff Mahoney reiserfs_prepare_for_journal(s, bh, 1);
1931da177e4SLinus Torvalds for (i = block_r; i < s->s_blocksize * 8; i++)
1940c2fd1bfSAkinobu Mita reiserfs_clear_le_bit(i, bh->b_data);
1950b3dc17bSJeff Mahoney info->free_count += s->s_blocksize * 8 - block_r;
1961da177e4SLinus Torvalds
19709f1b80bSJeff Mahoney journal_mark_dirty(&th, bh);
1980b3dc17bSJeff Mahoney brelse(bh);
1991da177e4SLinus Torvalds
2000b3dc17bSJeff Mahoney /* Correct new last bitmap block - It may not be full */
2010b3dc17bSJeff Mahoney info = SB_AP_BITMAP(s) + bmap_nr_new - 1;
2025065227bSJeff Mahoney bh = reiserfs_read_bitmap_block(s, bmap_nr_new - 1);
2035065227bSJeff Mahoney if (!bh) {
20458d85426SJeff Mahoney int jerr = journal_end(&th);
2055065227bSJeff Mahoney if (jerr)
2065065227bSJeff Mahoney return jerr;
2075065227bSJeff Mahoney return -EIO;
2085065227bSJeff Mahoney }
2090b3dc17bSJeff Mahoney
2100b3dc17bSJeff Mahoney reiserfs_prepare_for_journal(s, bh, 1);
2111da177e4SLinus Torvalds for (i = block_r_new; i < s->s_blocksize * 8; i++)
2120c2fd1bfSAkinobu Mita reiserfs_set_le_bit(i, bh->b_data);
21309f1b80bSJeff Mahoney journal_mark_dirty(&th, bh);
2140b3dc17bSJeff Mahoney brelse(bh);
2151da177e4SLinus Torvalds
2160b3dc17bSJeff Mahoney info->free_count -= s->s_blocksize * 8 - block_r_new;
2171da177e4SLinus Torvalds /* update super */
2181da177e4SLinus Torvalds reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
2191da177e4SLinus Torvalds free_blocks = SB_FREE_BLOCKS(s);
220bd4c625cSLinus Torvalds PUT_SB_FREE_BLOCKS(s,
221bd4c625cSLinus Torvalds free_blocks + (block_count_new - block_count -
222bd4c625cSLinus Torvalds (bmap_nr_new - bmap_nr)));
2231da177e4SLinus Torvalds PUT_SB_BLOCK_COUNT(s, block_count_new);
224cb680c1bSJeff Mahoney PUT_SB_BMAP_NR(s, bmap_would_wrap(bmap_nr_new) ? : bmap_nr_new);
2251da177e4SLinus Torvalds
22609f1b80bSJeff Mahoney journal_mark_dirty(&th, SB_BUFFER_WITH_SB(s));
2271da177e4SLinus Torvalds
2281da177e4SLinus Torvalds SB_JOURNAL(s)->j_must_wait = 1;
22958d85426SJeff Mahoney return journal_end(&th);
2301da177e4SLinus Torvalds }
231