xref: /openbmc/linux/fs/jfs/resize.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1  // SPDX-License-Identifier: GPL-2.0-or-later
2  /*
3   *   Copyright (C) International Business Machines  Corp., 2000-2004
4  */
5  
6  #include <linux/fs.h>
7  #include <linux/buffer_head.h>
8  #include <linux/quotaops.h>
9  #include <linux/blkdev.h>
10  #include "jfs_incore.h"
11  #include "jfs_filsys.h"
12  #include "jfs_metapage.h"
13  #include "jfs_dinode.h"
14  #include "jfs_imap.h"
15  #include "jfs_dmap.h"
16  #include "jfs_superblock.h"
17  #include "jfs_txnmgr.h"
18  #include "jfs_debug.h"
19  
20  #define BITSPERPAGE	(PSIZE << 3)
21  #define L2MEGABYTE	20
22  #define MEGABYTE	(1 << L2MEGABYTE)
23  #define MEGABYTE32	(MEGABYTE << 5)
24  
25  /* convert block number to bmap file page number */
26  #define BLKTODMAPN(b)\
27  	(((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1)
28  
29  /*
30   *	jfs_extendfs()
31   *
32   * function: extend file system;
33   *
34   *   |-------------------------------|----------|----------|
35   *   file system space               fsck       inline log
36   *                                   workspace  space
37   *
38   * input:
39   *	new LVSize: in LV blocks (required)
40   *	new LogSize: in LV blocks (optional)
41   *	new FSSize: in LV blocks (optional)
42   *
43   * new configuration:
44   * 1. set new LogSize as specified or default from new LVSize;
45   * 2. compute new FSCKSize from new LVSize;
46   * 3. set new FSSize as MIN(FSSize, LVSize-(LogSize+FSCKSize)) where
47   *    assert(new FSSize >= old FSSize),
48   *    i.e., file system must not be shrunk;
49   */
jfs_extendfs(struct super_block * sb,s64 newLVSize,int newLogSize)50  int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
51  {
52  	int rc = 0;
53  	struct jfs_sb_info *sbi = JFS_SBI(sb);
54  	struct inode *ipbmap = sbi->ipbmap;
55  	struct inode *ipbmap2;
56  	struct inode *ipimap = sbi->ipimap;
57  	struct jfs_log *log = sbi->log;
58  	struct bmap *bmp = sbi->bmap;
59  	s64 newLogAddress, newFSCKAddress;
60  	int newFSCKSize;
61  	s64 newMapSize = 0, mapSize;
62  	s64 XAddress, XSize, nblocks, xoff, xaddr, t64;
63  	s64 oldLVSize;
64  	s64 newFSSize;
65  	s64 VolumeSize;
66  	int newNpages = 0, nPages, newPage, xlen, t32;
67  	int tid;
68  	int log_formatted = 0;
69  	struct inode *iplist[1];
70  	struct jfs_superblock *j_sb, *j_sb2;
71  	s64 old_agsize;
72  	int agsizechanged = 0;
73  	struct buffer_head *bh, *bh2;
74  
75  	/* If the volume hasn't grown, get out now */
76  
77  	if (sbi->mntflag & JFS_INLINELOG)
78  		oldLVSize = addressPXD(&sbi->logpxd) + lengthPXD(&sbi->logpxd);
79  	else
80  		oldLVSize = addressPXD(&sbi->fsckpxd) +
81  		    lengthPXD(&sbi->fsckpxd);
82  
83  	if (oldLVSize >= newLVSize) {
84  		printk(KERN_WARNING
85  		       "jfs_extendfs: volume hasn't grown, returning\n");
86  		goto out;
87  	}
88  
89  	VolumeSize = sb_bdev_nr_blocks(sb);
90  	if (VolumeSize) {
91  		if (newLVSize > VolumeSize) {
92  			printk(KERN_WARNING "jfs_extendfs: invalid size\n");
93  			rc = -EINVAL;
94  			goto out;
95  		}
96  	} else {
97  		/* check the device */
98  		bh = sb_bread(sb, newLVSize - 1);
99  		if (!bh) {
100  			printk(KERN_WARNING "jfs_extendfs: invalid size\n");
101  			rc = -EINVAL;
102  			goto out;
103  		}
104  		bforget(bh);
105  	}
106  
107  	/* Can't extend write-protected drive */
108  
109  	if (isReadOnly(ipbmap)) {
110  		printk(KERN_WARNING "jfs_extendfs: read-only file system\n");
111  		rc = -EROFS;
112  		goto out;
113  	}
114  
115  	/*
116  	 *	reconfigure LV spaces
117  	 *	---------------------
118  	 *
119  	 * validate new size, or, if not specified, determine new size
120  	 */
121  
122  	/*
123  	 * reconfigure inline log space:
124  	 */
125  	if ((sbi->mntflag & JFS_INLINELOG)) {
126  		if (newLogSize == 0) {
127  			/*
128  			 * no size specified: default to 1/256 of aggregate
129  			 * size; rounded up to a megabyte boundary;
130  			 */
131  			newLogSize = newLVSize >> 8;
132  			t32 = (1 << (20 - sbi->l2bsize)) - 1;
133  			newLogSize = (newLogSize + t32) & ~t32;
134  			newLogSize =
135  			    min(newLogSize, MEGABYTE32 >> sbi->l2bsize);
136  		} else {
137  			/*
138  			 * convert the newLogSize to fs blocks.
139  			 *
140  			 * Since this is given in megabytes, it will always be
141  			 * an even number of pages.
142  			 */
143  			newLogSize = (newLogSize * MEGABYTE) >> sbi->l2bsize;
144  		}
145  
146  	} else
147  		newLogSize = 0;
148  
149  	newLogAddress = newLVSize - newLogSize;
150  
151  	/*
152  	 * reconfigure fsck work space:
153  	 *
154  	 * configure it to the end of the logical volume regardless of
155  	 * whether file system extends to the end of the aggregate;
156  	 * Need enough 4k pages to cover:
157  	 *  - 1 bit per block in aggregate rounded up to BPERDMAP boundary
158  	 *  - 1 extra page to handle control page and intermediate level pages
159  	 *  - 50 extra pages for the chkdsk service log
160  	 */
161  	t64 = ((newLVSize - newLogSize + BPERDMAP - 1) >> L2BPERDMAP)
162  	    << L2BPERDMAP;
163  	t32 = DIV_ROUND_UP(t64, BITSPERPAGE) + 1 + 50;
164  	newFSCKSize = t32 << sbi->l2nbperpage;
165  	newFSCKAddress = newLogAddress - newFSCKSize;
166  
167  	/*
168  	 * compute new file system space;
169  	 */
170  	newFSSize = newLVSize - newLogSize - newFSCKSize;
171  
172  	/* file system cannot be shrunk */
173  	if (newFSSize < bmp->db_mapsize) {
174  		rc = -EINVAL;
175  		goto out;
176  	}
177  
178  	/*
179  	 * If we're expanding enough that the inline log does not overlap
180  	 * the old one, we can format the new log before we quiesce the
181  	 * filesystem.
182  	 */
183  	if ((sbi->mntflag & JFS_INLINELOG) && (newLogAddress > oldLVSize)) {
184  		if ((rc = lmLogFormat(log, newLogAddress, newLogSize)))
185  			goto out;
186  		log_formatted = 1;
187  	}
188  	/*
189  	 *	quiesce file system
190  	 *
191  	 * (prepare to move the inline log and to prevent map update)
192  	 *
193  	 * block any new transactions and wait for completion of
194  	 * all wip transactions and flush modified pages s.t.
195  	 * on-disk file system is in consistent state and
196  	 * log is not required for recovery.
197  	 */
198  	txQuiesce(sb);
199  
200  	/* Reset size of direct inode */
201  	sbi->direct_inode->i_size = bdev_nr_bytes(sb->s_bdev);
202  
203  	if (sbi->mntflag & JFS_INLINELOG) {
204  		/*
205  		 * deactivate old inline log
206  		 */
207  		lmLogShutdown(log);
208  
209  		/*
210  		 * mark on-disk super block for fs in transition;
211  		 *
212  		 * update on-disk superblock for the new space configuration
213  		 * of inline log space and fsck work space descriptors:
214  		 * N.B. FS descriptor is NOT updated;
215  		 *
216  		 * crash recovery:
217  		 * logredo(): if FM_EXTENDFS, return to fsck() for cleanup;
218  		 * fsck(): if FM_EXTENDFS, reformat inline log and fsck
219  		 * workspace from superblock inline log descriptor and fsck
220  		 * workspace descriptor;
221  		 */
222  
223  		/* read in superblock */
224  		if ((rc = readSuper(sb, &bh)))
225  			goto error_out;
226  		j_sb = (struct jfs_superblock *)bh->b_data;
227  
228  		/* mark extendfs() in progress */
229  		j_sb->s_state |= cpu_to_le32(FM_EXTENDFS);
230  		j_sb->s_xsize = cpu_to_le64(newFSSize);
231  		PXDaddress(&j_sb->s_xfsckpxd, newFSCKAddress);
232  		PXDlength(&j_sb->s_xfsckpxd, newFSCKSize);
233  		PXDaddress(&j_sb->s_xlogpxd, newLogAddress);
234  		PXDlength(&j_sb->s_xlogpxd, newLogSize);
235  
236  		/* synchronously update superblock */
237  		mark_buffer_dirty(bh);
238  		sync_dirty_buffer(bh);
239  		brelse(bh);
240  
241  		/*
242  		 * format new inline log synchronously;
243  		 *
244  		 * crash recovery: if log move in progress,
245  		 * reformat log and exit success;
246  		 */
247  		if (!log_formatted)
248  			if ((rc = lmLogFormat(log, newLogAddress, newLogSize)))
249  				goto error_out;
250  
251  		/*
252  		 * activate new log
253  		 */
254  		log->base = newLogAddress;
255  		log->size = newLogSize >> (L2LOGPSIZE - sb->s_blocksize_bits);
256  		if ((rc = lmLogInit(log)))
257  			goto error_out;
258  	}
259  
260  	/*
261  	 *	extend block allocation map
262  	 *	---------------------------
263  	 *
264  	 * extendfs() for new extension, retry after crash recovery;
265  	 *
266  	 * note: both logredo() and fsck() rebuild map from
267  	 * the bitmap and configuration parameter from superblock
268  	 * (disregarding all other control information in the map);
269  	 *
270  	 * superblock:
271  	 *  s_size: aggregate size in physical blocks;
272  	 */
273  	/*
274  	 *	compute the new block allocation map configuration
275  	 *
276  	 * map dinode:
277  	 *  di_size: map file size in byte;
278  	 *  di_nblocks: number of blocks allocated for map file;
279  	 *  di_mapsize: number of blocks in aggregate (covered by map);
280  	 * map control page:
281  	 *  db_mapsize: number of blocks in aggregate (covered by map);
282  	 */
283  	newMapSize = newFSSize;
284  	/* number of data pages of new bmap file:
285  	 * roundup new size to full dmap page boundary and
286  	 * add 1 extra dmap page for next extendfs()
287  	 */
288  	t64 = (newMapSize - 1) + BPERDMAP;
289  	newNpages = BLKTODMAPN(t64) + 1;
290  
291  	/*
292  	 *	extend map from current map (WITHOUT growing mapfile)
293  	 *
294  	 * map new extension with unmapped part of the last partial
295  	 * dmap page, if applicable, and extra page(s) allocated
296  	 * at end of bmap by mkfs() or previous extendfs();
297  	 */
298        extendBmap:
299  	/* compute number of blocks requested to extend */
300  	mapSize = bmp->db_mapsize;
301  	XAddress = mapSize;	/* eXtension Address */
302  	XSize = newMapSize - mapSize;	/* eXtension Size */
303  	old_agsize = bmp->db_agsize;	/* We need to know if this changes */
304  
305  	/* compute number of blocks that can be extended by current mapfile */
306  	t64 = dbMapFileSizeToMapSize(ipbmap);
307  	if (mapSize > t64) {
308  		printk(KERN_ERR "jfs_extendfs: mapSize (0x%Lx) > t64 (0x%Lx)\n",
309  		       (long long) mapSize, (long long) t64);
310  		rc = -EIO;
311  		goto error_out;
312  	}
313  	nblocks = min(t64 - mapSize, XSize);
314  
315  	/*
316  	 * update map pages for new extension:
317  	 *
318  	 * update/init dmap and bubble up the control hierarchy
319  	 * incrementally fold up dmaps into upper levels;
320  	 * update bmap control page;
321  	 */
322  	if ((rc = dbExtendFS(ipbmap, XAddress, nblocks)))
323  		goto error_out;
324  
325  	agsizechanged |= (bmp->db_agsize != old_agsize);
326  
327  	/*
328  	 * the map now has extended to cover additional nblocks:
329  	 * dn_mapsize = oldMapsize + nblocks;
330  	 */
331  	/* ipbmap->i_mapsize += nblocks; */
332  	XSize -= nblocks;
333  
334  	/*
335  	 *	grow map file to cover remaining extension
336  	 *	and/or one extra dmap page for next extendfs();
337  	 *
338  	 * allocate new map pages and its backing blocks, and
339  	 * update map file xtree
340  	 */
341  	/* compute number of data pages of current bmap file */
342  	nPages = ipbmap->i_size >> L2PSIZE;
343  
344  	/* need to grow map file ? */
345  	if (nPages == newNpages)
346  		goto finalizeBmap;
347  
348  	/*
349  	 * grow bmap file for the new map pages required:
350  	 *
351  	 * allocate growth at the start of newly extended region;
352  	 * bmap file only grows sequentially, i.e., both data pages
353  	 * and possibly xtree index pages may grow in append mode,
354  	 * s.t. logredo() can reconstruct pre-extension state
355  	 * by washing away bmap file of pages outside s_size boundary;
356  	 */
357  	/*
358  	 * journal map file growth as if a regular file growth:
359  	 * (note: bmap is created with di_mode = IFJOURNAL|IFREG);
360  	 *
361  	 * journaling of bmap file growth is not required since
362  	 * logredo() do/can not use log records of bmap file growth
363  	 * but it provides careful write semantics, pmap update, etc.;
364  	 */
365  	/* synchronous write of data pages: bmap data pages are
366  	 * cached in meta-data cache, and not written out
367  	 * by txCommit();
368  	 */
369  	rc = filemap_fdatawait(ipbmap->i_mapping);
370  	if (rc)
371  		goto error_out;
372  
373  	rc = filemap_write_and_wait(ipbmap->i_mapping);
374  	if (rc)
375  		goto error_out;
376  
377  	diWriteSpecial(ipbmap, 0);
378  
379  	newPage = nPages;	/* first new page number */
380  	xoff = newPage << sbi->l2nbperpage;
381  	xlen = (newNpages - nPages) << sbi->l2nbperpage;
382  	xlen = min(xlen, (int) nblocks) & ~(sbi->nbperpage - 1);
383  	xaddr = XAddress;
384  
385  	tid = txBegin(sb, COMMIT_FORCE);
386  
387  	if ((rc = xtAppend(tid, ipbmap, 0, xoff, nblocks, &xlen, &xaddr, 0))) {
388  		txEnd(tid);
389  		goto error_out;
390  	}
391  	/* update bmap file size */
392  	ipbmap->i_size += xlen << sbi->l2bsize;
393  	inode_add_bytes(ipbmap, xlen << sbi->l2bsize);
394  
395  	iplist[0] = ipbmap;
396  	rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
397  
398  	txEnd(tid);
399  
400  	if (rc)
401  		goto error_out;
402  
403  	/*
404  	 * map file has been grown now to cover extension to further out;
405  	 * di_size = new map file size;
406  	 *
407  	 * if huge extension, the previous extension based on previous
408  	 * map file size may not have been sufficient to cover whole extension
409  	 * (it could have been used up for new map pages),
410  	 * but the newly grown map file now covers lot bigger new free space
411  	 * available for further extension of map;
412  	 */
413  	/* any more blocks to extend ? */
414  	if (XSize)
415  		goto extendBmap;
416  
417        finalizeBmap:
418  	/* finalize bmap */
419  	dbFinalizeBmap(ipbmap);
420  
421  	/*
422  	 *	update inode allocation map
423  	 *	---------------------------
424  	 *
425  	 * move iag lists from old to new iag;
426  	 * agstart field is not updated for logredo() to reconstruct
427  	 * iag lists if system crash occurs.
428  	 * (computation of ag number from agstart based on agsize
429  	 * will correctly identify the new ag);
430  	 */
431  	/* if new AG size the same as old AG size, done! */
432  	if (agsizechanged) {
433  		if ((rc = diExtendFS(ipimap, ipbmap)))
434  			goto error_out;
435  
436  		/* finalize imap */
437  		if ((rc = diSync(ipimap)))
438  			goto error_out;
439  	}
440  
441  	/*
442  	 *	finalize
443  	 *	--------
444  	 *
445  	 * extension is committed when on-disk super block is
446  	 * updated with new descriptors: logredo will recover
447  	 * crash before it to pre-extension state;
448  	 */
449  
450  	/* sync log to skip log replay of bmap file growth transaction; */
451  	/* lmLogSync(log, 1); */
452  
453  	/*
454  	 * synchronous write bmap global control page;
455  	 * for crash before completion of write
456  	 * logredo() will recover to pre-extendfs state;
457  	 * for crash after completion of write,
458  	 * logredo() will recover post-extendfs state;
459  	 */
460  	if ((rc = dbSync(ipbmap)))
461  		goto error_out;
462  
463  	/*
464  	 * copy primary bmap inode to secondary bmap inode
465  	 */
466  
467  	ipbmap2 = diReadSpecial(sb, BMAP_I, 1);
468  	if (ipbmap2 == NULL) {
469  		printk(KERN_ERR "jfs_extendfs: diReadSpecial(bmap) failed\n");
470  		goto error_out;
471  	}
472  	memcpy(&JFS_IP(ipbmap2)->i_xtroot, &JFS_IP(ipbmap)->i_xtroot, 288);
473  	ipbmap2->i_size = ipbmap->i_size;
474  	ipbmap2->i_blocks = ipbmap->i_blocks;
475  
476  	diWriteSpecial(ipbmap2, 1);
477  	diFreeSpecial(ipbmap2);
478  
479  	/*
480  	 *	update superblock
481  	 */
482  	if ((rc = readSuper(sb, &bh)))
483  		goto error_out;
484  	j_sb = (struct jfs_superblock *)bh->b_data;
485  
486  	/* mark extendfs() completion */
487  	j_sb->s_state &= cpu_to_le32(~FM_EXTENDFS);
488  	j_sb->s_size = cpu_to_le64(bmp->db_mapsize <<
489  				   le16_to_cpu(j_sb->s_l2bfactor));
490  	j_sb->s_agsize = cpu_to_le32(bmp->db_agsize);
491  
492  	/* update inline log space descriptor */
493  	if (sbi->mntflag & JFS_INLINELOG) {
494  		PXDaddress(&(j_sb->s_logpxd), newLogAddress);
495  		PXDlength(&(j_sb->s_logpxd), newLogSize);
496  	}
497  
498  	/* record log's mount serial number */
499  	j_sb->s_logserial = cpu_to_le32(log->serial);
500  
501  	/* update fsck work space descriptor */
502  	PXDaddress(&(j_sb->s_fsckpxd), newFSCKAddress);
503  	PXDlength(&(j_sb->s_fsckpxd), newFSCKSize);
504  	j_sb->s_fscklog = 1;
505  	/* sb->s_fsckloglen remains the same */
506  
507  	/* Update secondary superblock */
508  	bh2 = sb_bread(sb, SUPER2_OFF >> sb->s_blocksize_bits);
509  	if (bh2) {
510  		j_sb2 = (struct jfs_superblock *)bh2->b_data;
511  		memcpy(j_sb2, j_sb, sizeof (struct jfs_superblock));
512  
513  		mark_buffer_dirty(bh);
514  		sync_dirty_buffer(bh2);
515  		brelse(bh2);
516  	}
517  
518  	/* write primary superblock */
519  	mark_buffer_dirty(bh);
520  	sync_dirty_buffer(bh);
521  	brelse(bh);
522  
523  	goto resume;
524  
525        error_out:
526  	jfs_error(sb, "\n");
527  
528        resume:
529  	/*
530  	 *	resume file system transactions
531  	 */
532  	txResume(sb);
533  
534        out:
535  	return rc;
536  }
537