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