Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 29 Jun 1997 08:59:25 +1000
From:      Bruce Evans <bde@zeta.org.au>
To:        fs@freebsd.org
Subject:   fix for triple indirect block allocation
Message-ID:  <199706282259.IAA13203@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
For ufs on systems with 32-bit ints, triple indirect blocks only worked for
block sizes of 4K, since MNINDIR(ump)^3 overflows for larger block sizes
( (8192/4)^3 = 2^33 ).  This fix is large mainly because it rearranges the
code to avoid doing unnecessary 64-bit caclulations.  Please review it.

There are some abitrary limits that prevent creation of files larger than
a measly 512GB:

- in newfs/mkfs.c, rev.1.6 hacks fs_maxfilesize down to 512GB.  Lite2
  fixed this in another way.
- in ffs_vfsops.c, ffs_oldcompatfs() also reduces fs_maxfilesize to
  512GB for the pre-4.4 filesystem case.  I think it should reduce it
  to 2GB-1 instead, since old filesystems may need to be run under
  old or foreign systems that don't support 64 bit offsets.
- in ffs_vfsops.c, ffs_mountfs reduces fs_maxfilesize to
  0x40000000ULL * fs_bsize - 1.  This is the Lite2 way.  I think it has
  an off by one error and the correct limit is
  0x80000000ULL * fs_bsize - 1.  This still leaves negative block numbers
  free for metadata.  For the default fs_bsize of 8K, this gives a limit
  of 16TB-1.  This is not arbitrary.  It is fundamental that ufs
  block numbers are 32 bits.  The code is XXX'ed, but I think that is
  because the limit should be set properly in newfs and checked by fsck.
  Note that the magic numbers here are only indirectly related to the
  filesystem size and i/o offset limit of 1TB-1.  Filesystem blocks are
  16 times larger than DEV_BSIZE by default, and this gives a limit of
  about times larger.  Sparse files can be much larger than the filesystems
  containing them.  It takes only 512 real blocks for a sparse file of
  size 16TB-1 with 1 nonzero block at the end.

Bruce

diff -c2 ufs_bmap.c~ ufs_bmap.c
*** ufs_bmap.c~	Tue Mar 11 05:18:32 1997
--- ufs_bmap.c	Sun Jun 29 07:33:10 1997
***************
*** 251,257 ****
  	int *nump;
  {
! 	long metalbn, realbn;
  	struct ufsmount *ump;
! 	int blockcnt, i, numlevels, off;
  
  	ump = VFSTOUFS(vp->v_mount);
--- 249,256 ----
  	int *nump;
  {
! 	long blockcnt, metalbn, realbn;
  	struct ufsmount *ump;
! 	int i, numlevels, off;
! 	int64_t qblockcnt;
  
  	ump = VFSTOUFS(vp->v_mount);
***************
*** 270,274 ****
  	 * Determine the number of levels of indirection.  After this loop
  	 * is done, blockcnt indicates the number of data blocks possible
! 	 * at the given level of indirection, and NIADDR - i is the number
  	 * of levels of indirection needed to locate the requested block.
  	 */
--- 269,273 ----
  	 * Determine the number of levels of indirection.  After this loop
  	 * is done, blockcnt indicates the number of data blocks possible
! 	 * at the previous level of indirection, and NIADDR - i is the number
  	 * of levels of indirection needed to locate the requested block.
  	 */
***************
*** 276,282 ****
  		if (i == 0)
  			return (EFBIG);
! 		blockcnt *= MNINDIR(ump);
! 		if (bn < blockcnt)
  			break;
  	}
  
--- 275,287 ----
  		if (i == 0)
  			return (EFBIG);
! 		/*
! 		 * Use int64_t's here to avoid overflow for triple indirect
! 		 * blocks when longs have 32 bits and the block size is more
! 		 * than 4K.
! 		 */
! 		qblockcnt = (int64_t)blockcnt * MNINDIR(ump);
! 		if (bn < qblockcnt)
  			break;
+ 		blockcnt = qblockcnt;
  	}
  
***************
*** 302,306 ****
  			break;
  
- 		blockcnt /= MNINDIR(ump);
  		off = (bn / blockcnt) % MNINDIR(ump);
  
--- 307,310 ----
***************
*** 312,315 ****
--- 316,320 ----
  
  		metalbn -= -1 + off * blockcnt;
+ 		blockcnt /= MNINDIR(ump);
  	}
  	if (nump)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199706282259.IAA13203>