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