aboutsummaryrefslogtreecommitdiff
path: root/sbin/quotacheck/quotacheck.c
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2002-11-20 02:13:32 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2002-11-20 02:13:32 +0000
commita5a82fa863a9963cf653c5b68492320036de217a (patch)
tree9be1bbf6fbb4e194c1f916d29d5d7ab375fb2b9c /sbin/quotacheck/quotacheck.c
parentfa8b7087062f0d75bfe06a983acd34e2db2e8177 (diff)
downloadsrc-a5a82fa863a9963cf653c5b68492320036de217a.tar.gz
src-a5a82fa863a9963cf653c5b68492320036de217a.zip
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>
Notes
Notes: svn path=/head/; revision=107094
Diffstat (limited to 'sbin/quotacheck/quotacheck.c')
-rw-r--r--sbin/quotacheck/quotacheck.c83
1 files changed, 59 insertions, 24 deletions
diff --git a/sbin/quotacheck/quotacheck.c b/sbin/quotacheck/quotacheck.c
index d66f42d5d57b..4c2aa23fc538 100644
--- a/sbin/quotacheck/quotacheck.c
+++ b/sbin/quotacheck/quotacheck.c
@@ -77,8 +77,13 @@ char *quotagroup = QUOTAGROUP;
union {
struct fs sblk;
char dummy[MAXBSIZE];
-} un;
-#define sblock un.sblk
+} sb_un;
+#define sblock sb_un.sblk
+union {
+ struct cg cgblk;
+ char dummy[MAXBSIZE];
+} cg_un;
+#define cgblk cg_un.cgblk
long dev_bsize = 1;
ino_t maxino;
@@ -119,7 +124,7 @@ u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */
struct fileusage *
addid(u_long, int, 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 *),
int (*)(char *, char *, struct quotaname *));
int chkquota(char *, char *, struct quotaname *);
@@ -132,7 +137,7 @@ struct fileusage *
lookup(u_long, int);
void *needchk(struct fstab *);
int oneof(char *, char*[], int);
-void resetinodebuf(void);
+void setinodebuf(ino_t);
int update(char *, char *, int);
void usage(void);
@@ -264,7 +269,8 @@ chkquota(fsname, mntpt, qnp)
struct fileusage *fup;
union dinode *dp;
int cg, i, mode, errs = 0;
- ino_t ino;
+ ino_t ino, inosused;
+ char *cp;
if ((fi = open(fsname, O_RDONLY, 0)) < 0) {
warn("%s", fsname);
@@ -297,14 +303,42 @@ chkquota(fsname, mntpt, qnp)
}
dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
maxino = sblock.fs_ncg * sblock.fs_ipg;
- resetinodebuf();
- for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) {
- for (i = 0; i < sblock.fs_ipg; i++, ino++) {
- if (ino < ROOTINO)
- continue;
- if ((dp = getnextinode(ino)) == NULL)
+ for (cg = 0; cg < sblock.fs_ncg; cg++) {
+ ino = cg * sblock.fs_ipg;
+ setinodebuf(ino);
+ 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;
- 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;
if (qnp->flags & HASGRP) {
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 */
union dinode *
-getnextinode(inumber)
- ino_t inumber;
+getnextinode(ino_t inumber)
{
long size;
ufs2_daddr_t dblk;
@@ -607,12 +640,17 @@ getnextinode(inumber)
* Prepare to scan a set of inodes.
*/
void
-resetinodebuf()
+setinodebuf(ino_t inum)
{
- nextino = 0;
- lastinum = 0;
+ if (inum % sblock.fs_ipg != 0)
+ errx(1, "bad inode number %d to setinodebuf", inum);
+ lastvalidinum = inum + sblock.fs_ipg - 1;
+ nextino = inum;
+ lastinum = inum;
readcnt = 0;
+ if (inodebuf != NULL)
+ return;
inobufsize = blkroundup(&sblock, INOBUFSIZE);
fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ?
sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
@@ -626,11 +664,8 @@ resetinodebuf()
partialcnt = fullcnt;
partialsize = inobufsize;
}
- if (inodebuf == NULL &&
- (inodebuf = malloc((u_int)inobufsize)) == NULL)
- errx(1, "malloc failed");
- while (nextino < ROOTINO)
- getnextinode(nextino);
+ if ((inodebuf = malloc((unsigned)inobufsize)) == NULL)
+ errx(1, "cannot allocate space for inode buffer");
}
/*
@@ -650,12 +685,12 @@ freeinodebuf()
*/
void
bread(bno, buf, cnt)
- daddr_t bno;
+ ufs2_daddr_t bno;
char *buf;
long cnt;
{
if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0 ||
read(fi, buf, cnt) != cnt)
- errx(1, "block %ld", (long)bno);
+ errx(1, "bread failed on block %ld", (long)bno);
}