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:
parent
fa8b708706
commit
a5a82fa863
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=107094
@ -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;
|
||||||
|
for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) {
|
||||||
|
if (*cp & i)
|
||||||
|
break;
|
||||||
|
inosused--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (inosused <= 0)
|
||||||
continue;
|
continue;
|
||||||
if ((dp = getnextinode(ino)) == NULL)
|
}
|
||||||
continue;
|
for (i = 0; i < inosused; i++, ino++) {
|
||||||
if ((mode = DIP(dp, di_mode) & IFMT) == 0)
|
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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user