xref: /minix3/minix/fs/ext2/super.c (revision 92601f58cb467e2964d15a32a639bd9ef2910055)
1433d6423SLionel Sambuc /* This file manages the super block structure.
2433d6423SLionel Sambuc  *
3433d6423SLionel Sambuc  * The entry points into this file are
4433d6423SLionel Sambuc  *   get_super:       search the 'superblock' table for a device
5433d6423SLionel Sambuc  *   read_super:      read a superblock
6433d6423SLionel Sambuc  *
7433d6423SLionel Sambuc  * Created (MFS based):
8433d6423SLionel Sambuc  *   February 2010 (Evgeniy Ivanov)
9433d6423SLionel Sambuc  */
10433d6423SLionel Sambuc 
11433d6423SLionel Sambuc #include "fs.h"
12433d6423SLionel Sambuc #include <string.h>
13433d6423SLionel Sambuc #include <stdlib.h>
14433d6423SLionel Sambuc #include <assert.h>
15433d6423SLionel Sambuc #include <minix/com.h>
16433d6423SLionel Sambuc #include <minix/u64.h>
17433d6423SLionel Sambuc #include <minix/bdev.h>
18433d6423SLionel Sambuc #include <machine/param.h>
19433d6423SLionel Sambuc #include <machine/vmparam.h>
20*92601f58SDavid van Moolenbroek #include <sys/mman.h>
21433d6423SLionel Sambuc #include "buf.h"
22433d6423SLionel Sambuc #include "inode.h"
23433d6423SLionel Sambuc #include "super.h"
24433d6423SLionel Sambuc #include "const.h"
25433d6423SLionel Sambuc 
26433d6423SLionel Sambuc static off_t ext2_max_size(int block_size);
27433d6423SLionel Sambuc static u32_t ext2_count_dirs(struct super_block *sp);
28433d6423SLionel Sambuc 
29433d6423SLionel Sambuc static void super_copy(register struct super_block *dest, register
30433d6423SLionel Sambuc 	struct super_block *source);
31433d6423SLionel Sambuc static void copy_group_descriptors(register struct group_desc
32433d6423SLionel Sambuc 	*dest_array, register struct group_desc *source_array, unsigned int
33433d6423SLionel Sambuc 	ngroups);
34433d6423SLionel Sambuc 
35433d6423SLionel Sambuc static off_t super_block_offset;
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc /*===========================================================================*
39433d6423SLionel Sambuc  *                              get_super                                    *
40433d6423SLionel Sambuc  *===========================================================================*/
get_super(dev_t dev)41433d6423SLionel Sambuc struct super_block *get_super(
42433d6423SLionel Sambuc   dev_t dev           /* device number whose super_block is sought */
43433d6423SLionel Sambuc )
44433d6423SLionel Sambuc {
45433d6423SLionel Sambuc   if (dev == NO_DEV)
46433d6423SLionel Sambuc 	panic("request for super_block of NO_DEV");
47433d6423SLionel Sambuc   if (superblock->s_dev != dev)
48433d6423SLionel Sambuc 	panic("wrong superblock: 0x%x", (int) dev);
49433d6423SLionel Sambuc 
50433d6423SLionel Sambuc   return(superblock);
51433d6423SLionel Sambuc }
52433d6423SLionel Sambuc 
53433d6423SLionel Sambuc 
54433d6423SLionel Sambuc /*===========================================================================*
55433d6423SLionel Sambuc  *                              get_block_size                               *
56433d6423SLionel Sambuc  *===========================================================================*/
get_block_size(dev_t dev)57433d6423SLionel Sambuc unsigned int get_block_size(dev_t dev)
58433d6423SLionel Sambuc {
59433d6423SLionel Sambuc   if (dev == NO_DEV)
60433d6423SLionel Sambuc 	panic("request for block size of NO_DEV");
61433d6423SLionel Sambuc   return(lmfs_fs_block_size());
62433d6423SLionel Sambuc }
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc static struct group_desc *ondisk_group_descs;
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc /*===========================================================================*
67433d6423SLionel Sambuc  *                              read_super                                   *
68433d6423SLionel Sambuc  *===========================================================================*/
read_super(sp)69433d6423SLionel Sambuc int read_super(sp)
70433d6423SLionel Sambuc register struct super_block *sp; /* pointer to a superblock */
71433d6423SLionel Sambuc {
72433d6423SLionel Sambuc   /* Read a superblock. */
73433d6423SLionel Sambuc   dev_t dev;
74433d6423SLionel Sambuc   int r;
75433d6423SLionel Sambuc   /* group descriptors, sp->s_group_desc points to this. */
76433d6423SLionel Sambuc   static struct group_desc *group_descs;
77433d6423SLionel Sambuc   block_t gd_size; /* group descriptors table size in blocks */
78*92601f58SDavid van Moolenbroek   u64_t gdt_position;
79*92601f58SDavid van Moolenbroek   size_t off, chunk;
80433d6423SLionel Sambuc 
81*92601f58SDavid van Moolenbroek   ondisk_superblock = (struct super_block *)mmap(NULL, SUPER_SIZE_D,
82*92601f58SDavid van Moolenbroek 	PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
83*92601f58SDavid van Moolenbroek   if (ondisk_superblock == MAP_FAILED)
84*92601f58SDavid van Moolenbroek 	panic("can't allocate buffer for super block");
85433d6423SLionel Sambuc 
86433d6423SLionel Sambuc   dev = sp->s_dev;              /* save device (will be overwritten by copy) */
87433d6423SLionel Sambuc   if (dev == NO_DEV)
88433d6423SLionel Sambuc 	panic("request for super_block of NO_DEV");
89433d6423SLionel Sambuc 
90433d6423SLionel Sambuc   if (opt.block_with_super == 0) {
91433d6423SLionel Sambuc 	super_block_offset = SUPER_BLOCK_BYTES;
92433d6423SLionel Sambuc   } else {
93433d6423SLionel Sambuc 	/* The block number here uses 1k units */
94433d6423SLionel Sambuc 	super_block_offset = opt.block_with_super * 1024;
95433d6423SLionel Sambuc   }
96433d6423SLionel Sambuc 
97*92601f58SDavid van Moolenbroek   r = bdev_read(dev, super_block_offset, (char*) ondisk_superblock,
98*92601f58SDavid van Moolenbroek 	SUPER_SIZE_D, BDEV_NOFLAGS);
99433d6423SLionel Sambuc 
100*92601f58SDavid van Moolenbroek   if (r != SUPER_SIZE_D)
101433d6423SLionel Sambuc 	return(EINVAL);
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc   super_copy(sp, ondisk_superblock);
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc   sp->s_dev = NO_DEV;           /* restore later */
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc   if (sp->s_magic != SUPER_MAGIC)
108433d6423SLionel Sambuc 	return(EINVAL);
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc   sp->s_block_size = 1024*(1<<sp->s_log_block_size);
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc   if (sp->s_block_size < PAGE_SIZE) {
113433d6423SLionel Sambuc 	printf("data block size (%u) is invalid\n", sp->s_block_size);
114433d6423SLionel Sambuc 	return(EINVAL);
115433d6423SLionel Sambuc   }
116433d6423SLionel Sambuc 
117433d6423SLionel Sambuc   if ((sp->s_block_size % 512) != 0)
118433d6423SLionel Sambuc 	return(EINVAL);
119433d6423SLionel Sambuc 
120433d6423SLionel Sambuc   if (SUPER_SIZE_D > sp->s_block_size)
121433d6423SLionel Sambuc 	return(EINVAL);
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc   /* Variable added for convinience (i_blocks counts 512-byte blocks). */
124433d6423SLionel Sambuc   sp->s_sectors_in_block = sp->s_block_size / 512;
125433d6423SLionel Sambuc 
126433d6423SLionel Sambuc   /* TODO: this code is for revision 1 (but bw compatible with 0)
127433d6423SLionel Sambuc    * inode must be power of 2 and smaller, than block size.
128433d6423SLionel Sambuc    */
129433d6423SLionel Sambuc   if ((EXT2_INODE_SIZE(sp) & (EXT2_INODE_SIZE(sp) - 1)) != 0
130433d6423SLionel Sambuc       || EXT2_INODE_SIZE(sp) > sp->s_block_size) {
131433d6423SLionel Sambuc 	printf("superblock->s_inode_size is incorrect...\n");
132433d6423SLionel Sambuc 	return(EINVAL);
133433d6423SLionel Sambuc   }
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc   sp->s_blocksize_bits = sp->s_log_block_size + 10;
136433d6423SLionel Sambuc   sp->s_max_size = ext2_max_size(sp->s_block_size);
137433d6423SLionel Sambuc   sp->s_inodes_per_block = sp->s_block_size / EXT2_INODE_SIZE(sp);
138433d6423SLionel Sambuc   if (sp->s_inodes_per_block == 0 || sp->s_inodes_per_group == 0) {
139433d6423SLionel Sambuc 	printf("either inodes_per_block or inodes_per_group count is 0\n");
140433d6423SLionel Sambuc 	return(EINVAL);
141433d6423SLionel Sambuc   }
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc   sp->s_itb_per_group = sp->s_inodes_per_group / sp->s_inodes_per_block;
144433d6423SLionel Sambuc   sp->s_desc_per_block = sp->s_block_size / sizeof(struct group_desc);
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc   sp->s_groups_count = ((sp->s_blocks_count - sp->s_first_data_block - 1)
147433d6423SLionel Sambuc 				/ sp->s_blocks_per_group) + 1;
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc   /* ceil(groups_count/desc_per_block) */
150433d6423SLionel Sambuc   sp->s_gdb_count = (sp->s_groups_count + sp->s_desc_per_block - 1)
151433d6423SLionel Sambuc 			/ sp->s_desc_per_block;
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc   gd_size = sp->s_gdb_count * sp->s_block_size;
154433d6423SLionel Sambuc 
155d1abad94SBen Gras   if(!(group_descs = malloc(gd_size * sizeof(struct group_desc))))
156d1abad94SBen Gras 	panic("can't allocate group desc array");
157*92601f58SDavid van Moolenbroek   ondisk_group_descs = mmap(NULL, gd_size * sizeof(struct group_desc),
158*92601f58SDavid van Moolenbroek 	PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
159*92601f58SDavid van Moolenbroek   if (ondisk_group_descs == MAP_FAILED)
160d1abad94SBen Gras 	panic("can't allocate group desc array");
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc   /* s_first_data_block (block number, where superblock is stored)
163433d6423SLionel Sambuc    * is 1 for 1Kb blocks and 0 for larger blocks.
164433d6423SLionel Sambuc    * For fs with 1024-byte blocks first 1024 bytes (block0) used by MBR,
165433d6423SLionel Sambuc    * and block1 stores superblock. When block size is larger, block0 stores
166433d6423SLionel Sambuc    * both MBR and superblock, but gdt lives in next block anyway.
167433d6423SLionel Sambuc    * If sb=N was specified, then gdt is stored in N+1 block, the block number
168433d6423SLionel Sambuc    * here uses 1k units.
169433d6423SLionel Sambuc    *
170433d6423SLionel Sambuc    */
171433d6423SLionel Sambuc   if (opt.block_with_super == 0) {
172433d6423SLionel Sambuc 	gdt_position = (sp->s_first_data_block + 1) * sp->s_block_size;
173433d6423SLionel Sambuc   } else {
174433d6423SLionel Sambuc 	gdt_position = (opt.block_with_super + 1) * 1024;
175433d6423SLionel Sambuc   }
176433d6423SLionel Sambuc 
177*92601f58SDavid van Moolenbroek   /* The driver requires contiguous memory chunks, so use page granularity. */
178*92601f58SDavid van Moolenbroek   for (off = 0; off < gd_size; off += chunk) {
179*92601f58SDavid van Moolenbroek 	chunk = gd_size - off;
180*92601f58SDavid van Moolenbroek 	if (chunk > PAGE_SIZE)
181*92601f58SDavid van Moolenbroek 		chunk = PAGE_SIZE;
182*92601f58SDavid van Moolenbroek 
183*92601f58SDavid van Moolenbroek 	r = bdev_read(dev, gdt_position + off,
184*92601f58SDavid van Moolenbroek 	    (char *)ondisk_group_descs + off, chunk, BDEV_NOFLAGS);
185*92601f58SDavid van Moolenbroek 	if (r != (ssize_t)chunk) {
186433d6423SLionel Sambuc 		printf("Can not read group descriptors\n");
187433d6423SLionel Sambuc 		return(EINVAL);
188433d6423SLionel Sambuc 	}
189*92601f58SDavid van Moolenbroek   }
190433d6423SLionel Sambuc 
191433d6423SLionel Sambuc   /* TODO: check descriptors we just read */
192433d6423SLionel Sambuc 
193433d6423SLionel Sambuc   copy_group_descriptors(group_descs, ondisk_group_descs, sp->s_groups_count);
194433d6423SLionel Sambuc   sp->s_group_desc = group_descs;
195433d6423SLionel Sambuc 
196433d6423SLionel Sambuc   /* Make a few basic checks to see if super block looks reasonable. */
197433d6423SLionel Sambuc   if (sp->s_inodes_count < 1 || sp->s_blocks_count < 1) {
198433d6423SLionel Sambuc 	printf("not enough inodes or data blocks, \n");
199433d6423SLionel Sambuc 	return(EINVAL);
200433d6423SLionel Sambuc   }
201433d6423SLionel Sambuc 
202433d6423SLionel Sambuc   sp->s_dirs_counter = ext2_count_dirs(sp);
203433d6423SLionel Sambuc 
204433d6423SLionel Sambuc   /* Start block search from this block.
205433d6423SLionel Sambuc    * We skip superblock (1 block), group descriptors blocks (sp->s_gdb_count)
206433d6423SLionel Sambuc    * block and inode bitmaps (2 blocks) and inode table.
207433d6423SLionel Sambuc    */
208433d6423SLionel Sambuc   sp->s_bsearch = sp->s_first_data_block + 1 + sp->s_gdb_count + 2
209433d6423SLionel Sambuc 			+ sp->s_itb_per_group;
210433d6423SLionel Sambuc 
211433d6423SLionel Sambuc   sp->s_igsearch = 0;
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc   sp->s_dev = dev; /* restore device number */
214433d6423SLionel Sambuc   return(OK);
215433d6423SLionel Sambuc }
216433d6423SLionel Sambuc 
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc /*===========================================================================*
219433d6423SLionel Sambuc  *                              write_super				     *
220433d6423SLionel Sambuc  *===========================================================================*/
write_super(sp)221433d6423SLionel Sambuc void write_super(sp)
222433d6423SLionel Sambuc struct super_block *sp; /* pointer to a superblock */
223433d6423SLionel Sambuc {
224433d6423SLionel Sambuc /* Write a superblock and gdt. */
225433d6423SLionel Sambuc   int r;
226433d6423SLionel Sambuc   block_t gd_size; /* group descriptors table size in blocks */
227*92601f58SDavid van Moolenbroek   u64_t gdt_position;
228*92601f58SDavid van Moolenbroek   size_t off, chunk;
229433d6423SLionel Sambuc 
230433d6423SLionel Sambuc   if (sp->s_rd_only)
231433d6423SLionel Sambuc 	panic("can't write superblock on read-only filesys.");
232433d6423SLionel Sambuc 
233433d6423SLionel Sambuc   if (sp->s_dev == NO_DEV)
234433d6423SLionel Sambuc 	panic("request to write super_block, but NO_DEV");
235433d6423SLionel Sambuc 
236433d6423SLionel Sambuc   super_copy(ondisk_superblock, sp);
237433d6423SLionel Sambuc 
238*92601f58SDavid van Moolenbroek   r = bdev_write(sp->s_dev, super_block_offset, (char *) sp, SUPER_SIZE_D,
239*92601f58SDavid van Moolenbroek 	BDEV_NOFLAGS);
240433d6423SLionel Sambuc   if (r != SUPER_SIZE_D)
241433d6423SLionel Sambuc 	printf("ext2: Warning, failed to write superblock to the disk!\n");
242433d6423SLionel Sambuc 
243433d6423SLionel Sambuc   if (group_descriptors_dirty) {
244433d6423SLionel Sambuc 	/* Locate the appropriate super_block. */
245433d6423SLionel Sambuc 	gd_size = sp->s_gdb_count * sp->s_block_size;
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc 	if (opt.block_with_super == 0) {
248433d6423SLionel Sambuc 		gdt_position = (sp->s_first_data_block + 1) * sp->s_block_size;
249433d6423SLionel Sambuc 	} else {
250433d6423SLionel Sambuc 		gdt_position = (opt.block_with_super + 1) * 1024;
251433d6423SLionel Sambuc 	}
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc         copy_group_descriptors(ondisk_group_descs, sp->s_group_desc,
254433d6423SLionel Sambuc 			       sp->s_groups_count);
255433d6423SLionel Sambuc 
256*92601f58SDavid van Moolenbroek 	/* As above. Yes, lame. */
257*92601f58SDavid van Moolenbroek 	for (off = 0; off < gd_size; off += chunk) {
258*92601f58SDavid van Moolenbroek 		chunk = gd_size - off;
259*92601f58SDavid van Moolenbroek 		if (chunk > PAGE_SIZE)
260*92601f58SDavid van Moolenbroek 			chunk = PAGE_SIZE;
261*92601f58SDavid van Moolenbroek 
262*92601f58SDavid van Moolenbroek 		r = bdev_write(sp->s_dev, gdt_position + off,
263*92601f58SDavid van Moolenbroek 		    (char *)ondisk_group_descs + off, chunk, BDEV_NOFLAGS);
264*92601f58SDavid van Moolenbroek 		if (r != (ssize_t)chunk) {
265433d6423SLionel Sambuc 			printf("Can not write group descriptors\n");
266433d6423SLionel Sambuc 		}
267*92601f58SDavid van Moolenbroek 	}
268*92601f58SDavid van Moolenbroek 
269433d6423SLionel Sambuc 	group_descriptors_dirty = 0;
270433d6423SLionel Sambuc   }
271433d6423SLionel Sambuc }
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc 
274433d6423SLionel Sambuc /*===========================================================================*
275433d6423SLionel Sambuc  *                              get_group_desc                               *
276433d6423SLionel Sambuc  *===========================================================================*/
get_group_desc(unsigned int bnum)277433d6423SLionel Sambuc struct group_desc* get_group_desc(unsigned int bnum)
278433d6423SLionel Sambuc {
279433d6423SLionel Sambuc   if (bnum >= superblock->s_groups_count) {
280433d6423SLionel Sambuc 	printf("ext2, get_group_desc: wrong bnum (%d) requested\n", bnum);
281433d6423SLionel Sambuc 	return NULL;
282433d6423SLionel Sambuc   }
283433d6423SLionel Sambuc   return &superblock->s_group_desc[bnum];
284433d6423SLionel Sambuc }
285433d6423SLionel Sambuc 
286433d6423SLionel Sambuc 
ext2_count_dirs(struct super_block * sp)287433d6423SLionel Sambuc static u32_t ext2_count_dirs(struct super_block *sp)
288433d6423SLionel Sambuc {
289433d6423SLionel Sambuc   u32_t count = 0;
290433d6423SLionel Sambuc   unsigned int i;
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc   for (i = 0; i < sp->s_groups_count; i++) {
293433d6423SLionel Sambuc 	struct group_desc *desc = get_group_desc(i);
294433d6423SLionel Sambuc 	if (!desc)
295433d6423SLionel Sambuc 		continue; /* TODO: fail? */
296433d6423SLionel Sambuc 	count += desc->used_dirs_count;
297433d6423SLionel Sambuc   }
298433d6423SLionel Sambuc   return count;
299433d6423SLionel Sambuc }
300433d6423SLionel Sambuc 
301433d6423SLionel Sambuc 
302433d6423SLionel Sambuc /*===========================================================================*
303433d6423SLionel Sambuc  *                              ext2_max_size                                *
304433d6423SLionel Sambuc  *===========================================================================*/
305433d6423SLionel Sambuc /* There are several things, which affect max filesize:
306433d6423SLionel Sambuc  * - inode.i_blocks (512-byte blocks) is limited to (2^32 - 1).
307433d6423SLionel Sambuc  * - number of addressed direct, single, double and triple indirect blocks.
308433d6423SLionel Sambuc  * Number of addressed blocks depends on block_size only, thus unlike in
309433d6423SLionel Sambuc  * linux (ext2_max_size) we do not make calculations, but use constants
310433d6423SLionel Sambuc  * for different block sizes. Calculations (gcc code) are commented.
311433d6423SLionel Sambuc  * Note: linux ext2_max_size makes calculated based on shifting, not
312433d6423SLionel Sambuc  * arithmetics.
313433d6423SLionel Sambuc  * (!!!)Note: constants hardly tight to EXT2_NDIR_BLOCKS, but I doubt its value
314433d6423SLionel Sambuc  * will be changed someday. So if it's changed, then just recalculate constatns.
315433d6423SLionel Sambuc  * Anyway this function is safe for any change.
316433d6423SLionel Sambuc  * Note: there is also limitation from VFS (to LONG_MAX, i.e. 2GB).
317433d6423SLionel Sambuc  */
ext2_max_size(int block_size)318433d6423SLionel Sambuc static off_t ext2_max_size(int block_size)
319433d6423SLionel Sambuc {
320433d6423SLionel Sambuc   /* 12 is EXT2_NDIR_BLOCKS used in calculations. */
321433d6423SLionel Sambuc   if (EXT2_NDIR_BLOCKS != 12)
322433d6423SLionel Sambuc 	panic("ext2_max_size needs modification!");
323433d6423SLionel Sambuc   switch(block_size) {
324433d6423SLionel Sambuc 	case 1024: return LONG_MAX; /* actually 17247252480 */
325433d6423SLionel Sambuc 	case 2048: return LONG_MAX; /* 275415851008 */
326433d6423SLionel Sambuc 	case 4096: return LONG_MAX; /* 2194719883264 */
327433d6423SLionel Sambuc 	default: {
328433d6423SLionel Sambuc 		ext2_debug("ext2_max_size: Unsupported block_size! \
329433d6423SLionel Sambuc 				Assuming bs is 1024 bytes\n");
330433d6423SLionel Sambuc 		return 67383296L;
331433d6423SLionel Sambuc 	}
332433d6423SLionel Sambuc   }
333433d6423SLionel Sambuc #if 0
334433d6423SLionel Sambuc   long addr_in_block = block_size/4; /* 4 bytes per addr */
335433d6423SLionel Sambuc   long sectors_in_block = block_size/512;
336433d6423SLionel Sambuc   long long meta_blocks; /* single, double and triple indirect blocks */
337433d6423SLionel Sambuc   unsigned long long out_range_s; /* max blocks addressed by inode */
338433d6423SLionel Sambuc   unsigned long long max_bytes;
339433d6423SLionel Sambuc   unsigned long long upper_limit;
340433d6423SLionel Sambuc 
341433d6423SLionel Sambuc   /* 1 indirect block, 1 + addr_in_block dindirect and 1 + addr_in_block +
342433d6423SLionel Sambuc    * + addr_in_block*addr_in_block triple indirect blocks */
343433d6423SLionel Sambuc   meta_blocks = 2*addr_in_block + addr_in_block*addr_in_block + 3;
344433d6423SLionel Sambuc   out_range_s = EXT2_NDIR_BLOCKS + addr_in_block + addr_in_block * addr_in_block
345433d6423SLionel Sambuc                 + addr_in_block * addr_in_block * addr_in_block;
346433d6423SLionel Sambuc   max_bytes = out_range_s * block_size;
347433d6423SLionel Sambuc 
348433d6423SLionel Sambuc   upper_limit = (1LL << 32) - 1; /* max 512-byte blocks by i_blocks */
349433d6423SLionel Sambuc   upper_limit /= sectors_in_block; /* total block_size blocks */
350433d6423SLionel Sambuc   upper_limit -= meta_blocks; /* total data blocks */
351433d6423SLionel Sambuc   upper_limit *= (long long)block_size; /* max size in bytes */
352433d6423SLionel Sambuc 
353433d6423SLionel Sambuc   if (max_bytes > upper_limit)
354433d6423SLionel Sambuc 	max_bytes = upper_limit;
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc   /* Limit s_max_size to LONG_MAX */
357433d6423SLionel Sambuc   if (max_bytes > LONG_MAX)
358433d6423SLionel Sambuc 	max_bytes = LONG_MAX;
359433d6423SLionel Sambuc 
360433d6423SLionel Sambuc   return max_bytes;
361433d6423SLionel Sambuc #endif
362433d6423SLionel Sambuc }
363433d6423SLionel Sambuc 
364433d6423SLionel Sambuc 
365433d6423SLionel Sambuc /*===========================================================================*
366433d6423SLionel Sambuc  *				super_copy				     *
367433d6423SLionel Sambuc  *===========================================================================*/
super_copy(register struct super_block * dest,register struct super_block * source)368433d6423SLionel Sambuc static void super_copy(
369433d6423SLionel Sambuc   register struct super_block *dest,
370433d6423SLionel Sambuc   register struct super_block *source
371433d6423SLionel Sambuc )
372433d6423SLionel Sambuc /* Note: we don't convert stuff, used in ext3. */
373433d6423SLionel Sambuc {
374433d6423SLionel Sambuc /* Copy super_block to the in-core table, swapping bytes if need be. */
375433d6423SLionel Sambuc   if (le_CPU) {
376433d6423SLionel Sambuc 	/* Just use memcpy */
377433d6423SLionel Sambuc 	memcpy(dest, source, SUPER_SIZE_D);
378433d6423SLionel Sambuc 	return;
379433d6423SLionel Sambuc   }
380433d6423SLionel Sambuc   dest->s_inodes_count = conv4(le_CPU, source->s_inodes_count);
381433d6423SLionel Sambuc   dest->s_blocks_count = conv4(le_CPU, source->s_blocks_count);
382433d6423SLionel Sambuc   dest->s_r_blocks_count = conv4(le_CPU, source->s_r_blocks_count);
383433d6423SLionel Sambuc   dest->s_free_blocks_count = conv4(le_CPU, source->s_free_blocks_count);
384433d6423SLionel Sambuc   dest->s_free_inodes_count = conv4(le_CPU, source->s_free_inodes_count);
385433d6423SLionel Sambuc   dest->s_first_data_block = conv4(le_CPU, source->s_first_data_block);
386433d6423SLionel Sambuc   dest->s_log_block_size = conv4(le_CPU, source->s_log_block_size);
387433d6423SLionel Sambuc   dest->s_log_frag_size = conv4(le_CPU, source->s_log_frag_size);
388433d6423SLionel Sambuc   dest->s_blocks_per_group = conv4(le_CPU, source->s_blocks_per_group);
389433d6423SLionel Sambuc   dest->s_frags_per_group = conv4(le_CPU, source->s_frags_per_group);
390433d6423SLionel Sambuc   dest->s_inodes_per_group = conv4(le_CPU, source->s_inodes_per_group);
391433d6423SLionel Sambuc   dest->s_mtime = conv4(le_CPU, source->s_mtime);
392433d6423SLionel Sambuc   dest->s_wtime = conv4(le_CPU, source->s_wtime);
393433d6423SLionel Sambuc   dest->s_mnt_count = conv2(le_CPU, source->s_mnt_count);
394433d6423SLionel Sambuc   dest->s_max_mnt_count = conv2(le_CPU, source->s_max_mnt_count);
395433d6423SLionel Sambuc   dest->s_magic = conv2(le_CPU, source->s_magic);
396433d6423SLionel Sambuc   dest->s_state = conv2(le_CPU, source->s_state);
397433d6423SLionel Sambuc   dest->s_errors = conv2(le_CPU, source->s_errors);
398433d6423SLionel Sambuc   dest->s_minor_rev_level = conv2(le_CPU, source->s_minor_rev_level);
399433d6423SLionel Sambuc   dest->s_lastcheck = conv4(le_CPU, source->s_lastcheck);
400433d6423SLionel Sambuc   dest->s_checkinterval = conv4(le_CPU, source->s_checkinterval);
401433d6423SLionel Sambuc   dest->s_creator_os = conv4(le_CPU, source->s_creator_os);
402433d6423SLionel Sambuc   dest->s_rev_level = conv4(le_CPU, source->s_rev_level);
403433d6423SLionel Sambuc   dest->s_def_resuid = conv2(le_CPU, source->s_def_resuid);
404433d6423SLionel Sambuc   dest->s_def_resgid = conv2(le_CPU, source->s_def_resgid);
405433d6423SLionel Sambuc   dest->s_first_ino = conv4(le_CPU, source->s_first_ino);
406433d6423SLionel Sambuc   dest->s_inode_size = conv2(le_CPU, source->s_inode_size);
407433d6423SLionel Sambuc   dest->s_block_group_nr = conv2(le_CPU, source->s_block_group_nr);
408433d6423SLionel Sambuc   dest->s_feature_compat = conv4(le_CPU, source->s_feature_compat);
409433d6423SLionel Sambuc   dest->s_feature_incompat = conv4(le_CPU, source->s_feature_incompat);
410433d6423SLionel Sambuc   dest->s_feature_ro_compat = conv4(le_CPU, source->s_feature_ro_compat);
411433d6423SLionel Sambuc   memcpy(dest->s_uuid, source->s_uuid, sizeof(dest->s_uuid));
412433d6423SLionel Sambuc   memcpy(dest->s_volume_name, source->s_volume_name,
413433d6423SLionel Sambuc 	 sizeof(dest->s_volume_name));
414433d6423SLionel Sambuc   memcpy(dest->s_last_mounted, source->s_last_mounted,
415433d6423SLionel Sambuc 	 sizeof(dest->s_last_mounted));
416433d6423SLionel Sambuc   dest->s_algorithm_usage_bitmap =
417433d6423SLionel Sambuc 			conv4(le_CPU, source->s_algorithm_usage_bitmap);
418433d6423SLionel Sambuc   dest->s_prealloc_blocks = source->s_prealloc_blocks;
419433d6423SLionel Sambuc   dest->s_prealloc_dir_blocks = source->s_prealloc_dir_blocks;
420433d6423SLionel Sambuc   dest->s_padding1 = conv2(le_CPU, source->s_padding1);
421433d6423SLionel Sambuc }
422433d6423SLionel Sambuc 
423433d6423SLionel Sambuc 
424433d6423SLionel Sambuc /*===========================================================================*
425433d6423SLionel Sambuc  *				gd_copy 				     *
426433d6423SLionel Sambuc  *===========================================================================*/
gd_copy(register struct group_desc * dest,register struct group_desc * source)427433d6423SLionel Sambuc static void gd_copy(
428433d6423SLionel Sambuc   register struct group_desc *dest,
429433d6423SLionel Sambuc   register struct group_desc *source
430433d6423SLionel Sambuc )
431433d6423SLionel Sambuc {
432433d6423SLionel Sambuc   /* Copy super_block to the in-core table, swapping bytes if need be. */
433433d6423SLionel Sambuc   if (le_CPU) {
434433d6423SLionel Sambuc 	/* Just use memcpy */
435433d6423SLionel Sambuc 	memcpy(dest, source, sizeof(struct group_desc));
436433d6423SLionel Sambuc 	return;
437433d6423SLionel Sambuc   }
438433d6423SLionel Sambuc   dest->block_bitmap = conv4(le_CPU, source->block_bitmap);
439433d6423SLionel Sambuc   dest->inode_bitmap = conv4(le_CPU, source->inode_bitmap);
440433d6423SLionel Sambuc   dest->inode_table = conv4(le_CPU, source->inode_table);
441433d6423SLionel Sambuc   dest->free_blocks_count = conv2(le_CPU, source->free_blocks_count);
442433d6423SLionel Sambuc   dest->free_inodes_count = conv2(le_CPU, source->free_inodes_count);
443433d6423SLionel Sambuc   dest->used_dirs_count = conv2(le_CPU, source->used_dirs_count);
444433d6423SLionel Sambuc }
445433d6423SLionel Sambuc 
446433d6423SLionel Sambuc 
447433d6423SLionel Sambuc /*===========================================================================*
448433d6423SLionel Sambuc  *			copy_group_descriptors  			     *
449433d6423SLionel Sambuc  *===========================================================================*/
copy_group_descriptors(register struct group_desc * dest_array,register struct group_desc * source_array,unsigned int ngroups)450433d6423SLionel Sambuc static void copy_group_descriptors(
451433d6423SLionel Sambuc   register struct group_desc *dest_array,
452433d6423SLionel Sambuc   register struct group_desc *source_array,
453433d6423SLionel Sambuc   unsigned int ngroups
454433d6423SLionel Sambuc )
455433d6423SLionel Sambuc {
456433d6423SLionel Sambuc   unsigned int i;
457433d6423SLionel Sambuc   for (i = 0; i < ngroups; i++)
458433d6423SLionel Sambuc 	gd_copy(&dest_array[i], &source_array[i]);
459433d6423SLionel Sambuc }
460