xref: /openbmc/linux/fs/reiserfs/resize.c (revision e03d3b1b)
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