This fix corrects a problem in the file system that treats large

inode numbers as negative rather than unsigned. For a default
(16K block) file system, this bug began to show up at a file system
size above about 16Tb.

To fully handle this problem, newfs must be updated to ensure that
it will never create a filesystem with more than 2^32 inodes. That
patch will be forthcoming soon.

Reported by: Scott Burns, John Kilburg, Bruce Evans
Followup by: Jeff Roberson
PR:          133980
MFC after:   2 weeks
This commit is contained in:
Kirk McKusick 2010-02-10 20:10:35 +00:00
parent b132183383
commit e870d1e6f9
2 changed files with 64 additions and 58 deletions

View File

@ -93,24 +93,25 @@ __FBSDID("$FreeBSD$");
#include <ufs/ffs/fs.h>
#include <ufs/ffs/ffs_extern.h>
typedef ufs2_daddr_t allocfcn_t(struct inode *ip, int cg, ufs2_daddr_t bpref,
typedef ufs2_daddr_t allocfcn_t(struct inode *ip, u_int cg, ufs2_daddr_t bpref,
int size);
static ufs2_daddr_t ffs_alloccg(struct inode *, int, ufs2_daddr_t, int);
static ufs2_daddr_t ffs_alloccg(struct inode *, u_int, ufs2_daddr_t, int);
static ufs2_daddr_t
ffs_alloccgblk(struct inode *, struct buf *, ufs2_daddr_t);
#ifdef INVARIANTS
static int ffs_checkblk(struct inode *, ufs2_daddr_t, long);
#endif
static ufs2_daddr_t ffs_clusteralloc(struct inode *, int, ufs2_daddr_t, int);
static ufs2_daddr_t ffs_clusteralloc(struct inode *, u_int, ufs2_daddr_t, int);
static void ffs_clusteracct(struct ufsmount *, struct fs *, struct cg *,
ufs1_daddr_t, int);
static ino_t ffs_dirpref(struct inode *);
static ufs2_daddr_t ffs_fragextend(struct inode *, int, ufs2_daddr_t, int, int);
static ufs2_daddr_t ffs_fragextend(struct inode *, u_int, ufs2_daddr_t,
int, int);
static void ffs_fserr(struct fs *, ino_t, char *);
static ufs2_daddr_t ffs_hashalloc
(struct inode *, int, ufs2_daddr_t, int, allocfcn_t *);
static ufs2_daddr_t ffs_nodealloccg(struct inode *, int, ufs2_daddr_t, int);
(struct inode *, u_int, ufs2_daddr_t, int, allocfcn_t *);
static ufs2_daddr_t ffs_nodealloccg(struct inode *, u_int, ufs2_daddr_t, int);
static ufs1_daddr_t ffs_mapsearch(struct fs *, struct cg *, ufs2_daddr_t, int);
static int ffs_reallocblks_ufs1(struct vop_reallocblks_args *);
static int ffs_reallocblks_ufs2(struct vop_reallocblks_args *);
@ -145,7 +146,7 @@ ffs_alloc(ip, lbn, bpref, size, flags, cred, bnp)
struct fs *fs;
struct ufsmount *ump;
ufs2_daddr_t bno;
int cg, reclaimed;
u_int cg, reclaimed;
static struct timeval lastfail;
static int curfail;
int64_t delta;
@ -248,7 +249,8 @@ ffs_realloccg(ip, lbprev, bprev, bpref, osize, nsize, flags, cred, bpp)
struct fs *fs;
struct buf *bp;
struct ufsmount *ump;
int cg, request, error, reclaimed;
u_int cg, request, reclaimed;
int error;
ufs2_daddr_t bno;
static struct timeval lastfail;
static int curfail;
@ -933,7 +935,8 @@ ffs_valloc(pvp, mode, cred, vpp)
struct timespec ts;
struct ufsmount *ump;
ino_t ino, ipref;
int cg, error, error1;
u_int cg;
int error, error1;
static struct timeval lastfail;
static int curfail;
@ -1043,11 +1046,11 @@ ffs_dirpref(pip)
struct inode *pip;
{
struct fs *fs;
int cg, prefcg, dirsize, cgsize;
int avgifree, avgbfree, avgndir, curdirsize;
int minifree, minbfree, maxndir;
int mincg, minndir;
int maxcontigdirs;
u_int cg, prefcg, dirsize, cgsize;
u_int avgifree, avgbfree, avgndir, curdirsize;
u_int minifree, minbfree, maxndir;
u_int mincg, minndir;
u_int maxcontigdirs;
mtx_assert(UFS_MTX(pip->i_ump), MA_OWNED);
fs = pip->i_fs;
@ -1171,8 +1174,8 @@ ffs_blkpref_ufs1(ip, lbn, indx, bap)
ufs1_daddr_t *bap;
{
struct fs *fs;
int cg;
int avgbfree, startcg;
u_int cg;
u_int avgbfree, startcg;
mtx_assert(UFS_MTX(ip->i_ump), MA_OWNED);
fs = ip->i_fs;
@ -1221,8 +1224,8 @@ ffs_blkpref_ufs2(ip, lbn, indx, bap)
ufs2_daddr_t *bap;
{
struct fs *fs;
int cg;
int avgbfree, startcg;
u_int cg;
u_int avgbfree, startcg;
mtx_assert(UFS_MTX(ip->i_ump), MA_OWNED);
fs = ip->i_fs;
@ -1275,14 +1278,14 @@ ffs_blkpref_ufs2(ip, lbn, indx, bap)
static ufs2_daddr_t
ffs_hashalloc(ip, cg, pref, size, allocator)
struct inode *ip;
int cg;
u_int cg;
ufs2_daddr_t pref;
int size; /* size for data blocks, mode for inodes */
allocfcn_t *allocator;
{
struct fs *fs;
ufs2_daddr_t result;
int i, icg = cg;
u_int i, icg = cg;
mtx_assert(UFS_MTX(ip->i_ump), MA_OWNED);
#ifdef INVARIANTS
@ -1333,7 +1336,7 @@ ffs_hashalloc(ip, cg, pref, size, allocator)
static ufs2_daddr_t
ffs_fragextend(ip, cg, bprev, osize, nsize)
struct inode *ip;
int cg;
u_int cg;
ufs2_daddr_t bprev;
int osize, nsize;
{
@ -1416,7 +1419,7 @@ ffs_fragextend(ip, cg, bprev, osize, nsize)
static ufs2_daddr_t
ffs_alloccg(ip, cg, bpref, size)
struct inode *ip;
int cg;
u_int cg;
ufs2_daddr_t bpref;
int size;
{
@ -1586,7 +1589,7 @@ ffs_alloccgblk(ip, bp, bpref)
static ufs2_daddr_t
ffs_clusteralloc(ip, cg, bpref, len)
struct inode *ip;
int cg;
u_int cg;
ufs2_daddr_t bpref;
int len;
{
@ -1710,7 +1713,7 @@ ffs_clusteralloc(ip, cg, bpref, len)
static ufs2_daddr_t
ffs_nodealloccg(ip, cg, ipref, mode)
struct inode *ip;
int cg;
u_int cg;
ufs2_daddr_t ipref;
int mode;
{
@ -1811,7 +1814,7 @@ ffs_nodealloccg(ip, cg, ipref, mode)
bdwrite(bp);
if (ibp != NULL)
bawrite(ibp);
return (cg * fs->fs_ipg + ipref);
return ((ino_t)(cg * fs->fs_ipg + ipref));
}
/*
@ -1856,7 +1859,8 @@ ffs_blkfree(ump, fs, devvp, bno, size, inum)
struct buf *bp;
ufs1_daddr_t fragno, cgbno;
ufs2_daddr_t cgblkno;
int i, cg, blk, frags, bbase;
int i, blk, frags, bbase;
u_int cg;
u_int8_t *blksfree;
struct cdev *dev;
@ -2054,7 +2058,8 @@ ffs_freefile(ump, fs, devvp, ino, mode)
struct cg *cgp;
struct buf *bp;
ufs2_daddr_t cgbno;
int error, cg;
int error;
u_int cg;
u_int8_t *inosused;
struct cdev *dev;
@ -2068,7 +2073,7 @@ ffs_freefile(ump, fs, devvp, ino, mode)
dev = devvp->v_rdev;
cgbno = fsbtodb(fs, cgtod(fs, cg));
}
if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg)
if (ino >= fs->fs_ipg * fs->fs_ncg)
panic("ffs_freefile: range: dev = %s, ino = %lu, fs = %s",
devtoname(dev), (u_long)ino, fs->fs_fsmnt);
if ((error = bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp))) {
@ -2085,8 +2090,8 @@ ffs_freefile(ump, fs, devvp, ino, mode)
inosused = cg_inosused(cgp);
ino %= fs->fs_ipg;
if (isclr(inosused, ino)) {
printf("dev = %s, ino = %lu, fs = %s\n", devtoname(dev),
(u_long)ino + cg * fs->fs_ipg, fs->fs_fsmnt);
printf("dev = %s, ino = %u, fs = %s\n", devtoname(dev),
ino + cg * fs->fs_ipg, fs->fs_fsmnt);
if (fs->fs_ronly == 0)
panic("ffs_freefile: freeing free inode");
}
@ -2121,7 +2126,8 @@ ffs_checkfreefile(fs, devvp, ino)
struct cg *cgp;
struct buf *bp;
ufs2_daddr_t cgbno;
int ret, cg;
int ret;
u_int cg;
u_int8_t *inosused;
cg = ino_to_cg(fs, ino);
@ -2132,7 +2138,7 @@ ffs_checkfreefile(fs, devvp, ino)
/* devvp is a normal disk device */
cgbno = fsbtodb(fs, cgtod(fs, cg));
}
if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg)
if (ino >= fs->fs_ipg * fs->fs_ncg)
return (1);
if (bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp)) {
brelse(bp);

View File

@ -264,7 +264,7 @@ struct fs {
int32_t fs_old_time; /* last time written */
int32_t fs_old_size; /* number of blocks in fs */
int32_t fs_old_dsize; /* number of data blocks in fs */
int32_t fs_ncg; /* number of cylinder groups */
u_int32_t fs_ncg; /* number of cylinder groups */
int32_t fs_bsize; /* size of basic blocks in fs */
int32_t fs_fsize; /* size of frag blocks in fs */
int32_t fs_frag; /* number of frags in a block in fs */
@ -304,7 +304,7 @@ struct fs {
int32_t fs_old_spc; /* sectors per cylinder */
int32_t fs_old_ncyl; /* cylinders in filesystem */
int32_t fs_old_cpg; /* cylinders per group */
int32_t fs_ipg; /* inodes per group */
u_int32_t fs_ipg; /* inodes per group */
int32_t fs_fpg; /* blocks per group * fs_frag */
/* this data must be re-computed after crashes */
struct csum fs_old_cstotal; /* cylinder summary information */
@ -335,10 +335,10 @@ struct fs {
int64_t fs_dsize; /* number of data blocks in fs */
ufs2_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */
int64_t fs_pendingblocks; /* (u) blocks being freed */
int32_t fs_pendinginodes; /* (u) inodes being freed */
int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
int32_t fs_avgfilesize; /* expected average file size */
int32_t fs_avgfpdir; /* expected # of files per directory */
u_int32_t fs_pendinginodes; /* (u) inodes being freed */
ino_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
u_int32_t fs_avgfilesize; /* expected average file size */
u_int32_t fs_avgfpdir; /* expected # of files per directory */
int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */
int32_t fs_sparecon32[26]; /* reserved for future constants */
int32_t fs_flags; /* see FS_ flags below */
@ -463,26 +463,26 @@ struct cg {
int32_t cg_firstfield; /* historic cyl groups linked list */
int32_t cg_magic; /* magic number */
int32_t cg_old_time; /* time last written */
int32_t cg_cgx; /* we are the cgx'th cylinder group */
u_int32_t cg_cgx; /* we are the cgx'th cylinder group */
int16_t cg_old_ncyl; /* number of cyl's this cg */
int16_t cg_old_niblk; /* number of inode blocks this cg */
int32_t cg_ndblk; /* number of data blocks this cg */
struct csum cg_cs; /* cylinder summary information */
int32_t cg_rotor; /* position of last used block */
int32_t cg_frotor; /* position of last used frag */
int32_t cg_irotor; /* position of last used inode */
int32_t cg_frsum[MAXFRAG]; /* counts of available frags */
u_int32_t cg_ndblk; /* number of data blocks this cg */
struct csum cg_cs; /* cylinder summary information */
u_int32_t cg_rotor; /* position of last used block */
u_int32_t cg_frotor; /* position of last used frag */
u_int32_t cg_irotor; /* position of last used inode */
u_int32_t cg_frsum[MAXFRAG]; /* counts of available frags */
int32_t cg_old_btotoff; /* (int32) block totals per cylinder */
int32_t cg_old_boff; /* (u_int16) free block positions */
int32_t cg_iusedoff; /* (u_int8) used inode map */
int32_t cg_freeoff; /* (u_int8) free block map */
int32_t cg_nextfreeoff; /* (u_int8) next available space */
int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */
int32_t cg_clusteroff; /* (u_int8) free cluster map */
int32_t cg_nclusterblks; /* number of clusters this cg */
int32_t cg_niblk; /* number of inode blocks this cg */
int32_t cg_initediblk; /* last initialized inode */
int32_t cg_unrefs; /* number of unreferenced inodes */
u_int32_t cg_iusedoff; /* (u_int8) used inode map */
u_int32_t cg_freeoff; /* (u_int8) free block map */
u_int32_t cg_nextfreeoff; /* (u_int8) next available space */
u_int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */
u_int32_t cg_clusteroff; /* (u_int8) free cluster map */
u_int32_t cg_nclusterblks; /* number of clusters this cg */
u_int32_t cg_niblk; /* number of inode blocks this cg */
u_int32_t cg_initediblk; /* last initialized inode */
u_int32_t cg_unrefs; /* number of unreferenced inodes */
int32_t cg_sparecon32[2]; /* reserved for future use */
ufs_time_t cg_time; /* time last written */
int64_t cg_sparecon64[3]; /* reserved for future use */
@ -529,11 +529,11 @@ struct cg {
* inode number to cylinder group number.
* inode number to filesystem block address.
*/
#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg)
#define ino_to_cg(fs, x) (((ino_t)(x)) / (fs)->fs_ipg)
#define ino_to_fsba(fs, x) \
((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \
(blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
#define ino_to_fsbo(fs, x) ((x) % INOPB(fs))
((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, (ino_t)(x))) + \
(blkstofrags((fs), ((((ino_t)(x)) % (fs)->fs_ipg) / INOPB(fs))))))
#define ino_to_fsbo(fs, x) (((ino_t)(x)) % INOPB(fs))
/*
* Give cylinder group number for a filesystem block.