Properly handle UFS2 sparsely allocated inodes. Fix bug that caused

the error "quotacheck: bad inode number 1 to nextinode".

Sponsored by:   DARPA & NAI Labs.
Reported-by:	Franky <franky@jasna.tarnow.pl> and Matthew Kolb <muk@msu.edu>
This commit is contained in:
Kirk McKusick 2002-11-20 02:13:32 +00:00
parent fa8b708706
commit a5a82fa863
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=107094

View File

@ -77,8 +77,13 @@ char *quotagroup = QUOTAGROUP;
union { union {
struct fs sblk; struct fs sblk;
char dummy[MAXBSIZE]; char dummy[MAXBSIZE];
} un; } sb_un;
#define sblock un.sblk #define sblock sb_un.sblk
union {
struct cg cgblk;
char dummy[MAXBSIZE];
} cg_un;
#define cgblk cg_un.cgblk
long dev_bsize = 1; long dev_bsize = 1;
ino_t maxino; ino_t maxino;
@ -119,7 +124,7 @@ u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */
struct fileusage * struct fileusage *
addid(u_long, int, char *); addid(u_long, int, char *);
char *blockcheck(char *); char *blockcheck(char *);
void bread(daddr_t, char *, long); void bread(ufs2_daddr_t, char *, long);
extern int checkfstab(int, int, void * (*)(struct fstab *), extern int checkfstab(int, int, void * (*)(struct fstab *),
int (*)(char *, char *, struct quotaname *)); int (*)(char *, char *, struct quotaname *));
int chkquota(char *, char *, struct quotaname *); int chkquota(char *, char *, struct quotaname *);
@ -132,7 +137,7 @@ struct fileusage *
lookup(u_long, int); lookup(u_long, int);
void *needchk(struct fstab *); void *needchk(struct fstab *);
int oneof(char *, char*[], int); int oneof(char *, char*[], int);
void resetinodebuf(void); void setinodebuf(ino_t);
int update(char *, char *, int); int update(char *, char *, int);
void usage(void); void usage(void);
@ -264,7 +269,8 @@ chkquota(fsname, mntpt, qnp)
struct fileusage *fup; struct fileusage *fup;
union dinode *dp; union dinode *dp;
int cg, i, mode, errs = 0; int cg, i, mode, errs = 0;
ino_t ino; ino_t ino, inosused;
char *cp;
if ((fi = open(fsname, O_RDONLY, 0)) < 0) { if ((fi = open(fsname, O_RDONLY, 0)) < 0) {
warn("%s", fsname); warn("%s", fsname);
@ -297,14 +303,42 @@ chkquota(fsname, mntpt, qnp)
} }
dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
maxino = sblock.fs_ncg * sblock.fs_ipg; maxino = sblock.fs_ncg * sblock.fs_ipg;
resetinodebuf(); for (cg = 0; cg < sblock.fs_ncg; cg++) {
for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) { ino = cg * sblock.fs_ipg;
for (i = 0; i < sblock.fs_ipg; i++, ino++) { setinodebuf(ino);
if (ino < ROOTINO) bread(fsbtodb(&sblock, cgtod(&sblock, cg)), (char *)(&cgblk),
sblock.fs_cgsize);
if (sblock.fs_magic == FS_UFS2_MAGIC)
inosused = cgblk.cg_initediblk;
else
inosused = sblock.fs_ipg;
/*
* If we are using soft updates, then we can trust the
* cylinder group inode allocation maps to tell us which
* inodes are allocated. We will scan the used inode map
* to find the inodes that are really in use, and then
* read only those inodes in from disk.
*/
if (sblock.fs_flags & FS_DOSOFTDEP) {
if (!cg_chkmagic(&cgblk))
errx(1, "CG %d: BAD MAGIC NUMBER\n", cg);
cp = &cg_inosused(&cgblk)[(inosused - 1) / CHAR_BIT];
for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) {
if (*cp == 0)
continue; continue;
if ((dp = getnextinode(ino)) == NULL) for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) {
if (*cp & i)
break;
inosused--;
}
break;
}
if (inosused <= 0)
continue; continue;
if ((mode = DIP(dp, di_mode) & IFMT) == 0) }
for (i = 0; i < inosused; i++, ino++) {
if ((dp = getnextinode(ino)) == NULL || ino < ROOTINO ||
(mode = DIP(dp, di_mode) & IFMT) == 0)
continue; continue;
if (qnp->flags & HASGRP) { if (qnp->flags & HASGRP) {
fup = addid((u_long)DIP(dp, di_gid), GRPQUOTA, fup = addid((u_long)DIP(dp, di_gid), GRPQUOTA,
@ -568,8 +602,7 @@ static caddr_t inodebuf;
#define INOBUFSIZE 56*1024 /* size of buffer to read inodes */ #define INOBUFSIZE 56*1024 /* size of buffer to read inodes */
union dinode * union dinode *
getnextinode(inumber) getnextinode(ino_t inumber)
ino_t inumber;
{ {
long size; long size;
ufs2_daddr_t dblk; ufs2_daddr_t dblk;
@ -607,12 +640,17 @@ getnextinode(inumber)
* Prepare to scan a set of inodes. * Prepare to scan a set of inodes.
*/ */
void void
resetinodebuf() setinodebuf(ino_t inum)
{ {
nextino = 0; if (inum % sblock.fs_ipg != 0)
lastinum = 0; errx(1, "bad inode number %d to setinodebuf", inum);
lastvalidinum = inum + sblock.fs_ipg - 1;
nextino = inum;
lastinum = inum;
readcnt = 0; readcnt = 0;
if (inodebuf != NULL)
return;
inobufsize = blkroundup(&sblock, INOBUFSIZE); inobufsize = blkroundup(&sblock, INOBUFSIZE);
fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ? fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ?
sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode)); sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
@ -626,11 +664,8 @@ resetinodebuf()
partialcnt = fullcnt; partialcnt = fullcnt;
partialsize = inobufsize; partialsize = inobufsize;
} }
if (inodebuf == NULL && if ((inodebuf = malloc((unsigned)inobufsize)) == NULL)
(inodebuf = malloc((u_int)inobufsize)) == NULL) errx(1, "cannot allocate space for inode buffer");
errx(1, "malloc failed");
while (nextino < ROOTINO)
getnextinode(nextino);
} }
/* /*
@ -650,12 +685,12 @@ freeinodebuf()
*/ */
void void
bread(bno, buf, cnt) bread(bno, buf, cnt)
daddr_t bno; ufs2_daddr_t bno;
char *buf; char *buf;
long cnt; long cnt;
{ {
if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0 || if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0 ||
read(fi, buf, cnt) != cnt) read(fi, buf, cnt) != cnt)
errx(1, "block %ld", (long)bno); errx(1, "bread failed on block %ld", (long)bno);
} }