#include <sys/param.h>
#include <sys/diskslice.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <paths.h>
#include <ctype.h>
#include <err.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <vfs/ufs/dinode.h>
#include <vfs/ufs/fs.h>
#include "debug.h"
#ifdef FS_DEBUG
int _dbg_lvl_ = (DL_INFO);
#endif
static union {
struct fs fs;
char pad[SBSIZE];
} fsun1, fsun2;
#define sblock fsun1.fs
#define osblock fsun2.fs
static union {
struct cg cg;
char pad[MAXBSIZE];
} cgun1, cgun2;
#define acg cgun1.cg
#define aocg cgun2.cg
static char ablk[MAXBSIZE];
static char i1blk[MAXBSIZE];
static char i2blk[MAXBSIZE];
static char i3blk[MAXBSIZE];
static daddr_t in_src, i1_src, i2_src, i3_src;
enum pointer_source {
GFS_PS_INODE,
GFS_PS_IND_BLK_LVL1,
GFS_PS_IND_BLK_LVL2,
GFS_PS_IND_BLK_LVL3
};
static struct csum *fscs;
static struct ufs1_dinode zino[MAXBSIZE/sizeof(struct ufs1_dinode)];
struct gfs_bpp {
daddr_t old;
daddr_t new;
#define GFS_FL_FIRST 1
#define GFS_FL_LAST 2
unsigned int flags;
int found;
};
static void growfs(int, int, unsigned int);
static void rdfs(daddr_t, size_t, void *, int);
static void wtfs(daddr_t, size_t, void *, int, unsigned int);
static daddr_t alloc(void);
static int charsperline(void);
static void usage(void);
static int isblock(struct fs *, unsigned char *, int);
static void clrblock(struct fs *, unsigned char *, int);
static void setblock(struct fs *, unsigned char *, int);
static void initcg(int, time_t, int, unsigned int);
static void updjcg(int, time_t, int, int, unsigned int);
static void updcsloc(time_t, int, int, unsigned int);
static struct ufs1_dinode *ginode(ino_t, int, int);
static void frag_adjust(daddr_t, int);
static void cond_bl_upd(ufs_daddr_t *, struct gfs_bpp *,
enum pointer_source, int, unsigned int);
static void updclst(int);
static void updrefs(int, ino_t, struct gfs_bpp *, int, int, unsigned int);
static void
growfs(int fsi, int fso, unsigned int Nflag)
{
int i;
int cylno, j;
time_t utime;
int width;
char tmpbuf[100];
#ifdef FSIRAND
static int randinit=0;
DBG_ENTER;
if (!randinit) {
randinit = 1;
srandomdev();
}
#else
DBG_ENTER;
#endif
time(&utime);
fscs = (struct csum *)calloc((size_t)1, (size_t)sblock.fs_cssize);
if(fscs == NULL) {
errx(1, "calloc failed");
}
for (i = 0; i < osblock.fs_cssize; i += osblock.fs_bsize) {
rdfs(fsbtodb(&osblock, osblock.fs_csaddr +
numfrags(&osblock, i)), (size_t)MIN(osblock.fs_cssize - i,
osblock.fs_bsize), (void *)(((char *)fscs)+i), fsi);
}
#ifdef FS_DEBUG
{
struct csum *dbg_csp;
int dbg_csc;
char dbg_line[80];
dbg_csp=fscs;
for(dbg_csc=0; dbg_csc<osblock.fs_ncg; dbg_csc++) {
snprintf(dbg_line, sizeof(dbg_line),
"%d. old csum in old location", dbg_csc);
DBG_DUMP_CSUM(&osblock,
dbg_line,
dbg_csp++);
}
}
#endif
DBG_PRINT0("fscs read\n");
updjcg(osblock.fs_ncg-1, utime, fsi, fso, Nflag);
printf("growfs:\t%d sectors in %d %s of %d tracks, %d sectors\n",
sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl,
"cylinders", sblock.fs_ntrak, sblock.fs_nsect);
#define B2MBFACTOR (1 / (1024.0 * 1024.0))
printf("\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)\n",
(float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR,
sblock.fs_ncg, sblock.fs_cpg,
(float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR,
sblock.fs_ipg);
#undef B2MBFACTOR
printf("super-block backups (for fsck -b #) at:\n");
i = 0;
width = charsperline();
for (cylno = osblock.fs_ncg; cylno < sblock.fs_ncg; cylno++) {
initcg(cylno, utime, fso, Nflag);
j = sprintf(tmpbuf, " %d%s",
(int)fsbtodb(&sblock, cgsblock(&sblock, cylno)),
cylno < (sblock.fs_ncg-1) ? "," : "" );
if (i + j >= width) {
printf("\n");
i = 0;
}
i += j;
printf("%s", tmpbuf);
fflush(stdout);
}
printf("\n");
updcsloc(utime, fsi, fso, Nflag);
for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) {
wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)),
(size_t)MIN(sblock.fs_cssize - i, sblock.fs_bsize),
(void *)(((char *)fscs) + i), fso, Nflag);
}
DBG_PRINT0("fscs written\n");
#ifdef FS_DEBUG
{
struct csum *dbg_csp;
int dbg_csc;
char dbg_line[80];
dbg_csp=fscs;
for(dbg_csc=0; dbg_csc<sblock.fs_ncg; dbg_csc++) {
snprintf(dbg_line, sizeof(dbg_line),
"%d. new csum in new location", dbg_csc);
DBG_DUMP_CSUM(&sblock,
dbg_line,
dbg_csp++);
}
}
#endif
sblock.fs_time = utime;
wtfs((daddr_t)(SBOFF / DEV_BSIZE), (size_t)SBSIZE, &sblock,
fso, Nflag);
DBG_PRINT0("sblock written\n");
DBG_DUMP_FS(&sblock,
"new initial sblock");
sblock.fs_fmod = 0;
sblock.fs_clean = 1;
sblock.fs_ronly = 0;
sblock.fs_cgrotor = 0;
sblock.fs_state = 0;
memset((void *)&sblock.fs_fsmnt, 0, sizeof(sblock.fs_fsmnt));
sblock.fs_flags &= FS_DOSOFTDEP;
for (cylno = 0; cylno < sblock.fs_ncg; cylno++) {
wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)),
(size_t)SBSIZE, &sblock, fso, Nflag);
}
DBG_PRINT0("sblock copies written\n");
DBG_DUMP_FS(&sblock,
"new other sblocks");
DBG_LEAVE;
return;
}
static void
initcg(int cylno, time_t utime, int fso, unsigned int Nflag)
{
daddr_t cbase, d, dlower, dupper, dmax, blkno;
int i;
struct csum *cs;
#ifdef FSIRAND
int j;
#endif
DBG_ENTER;
cbase = cgbase(&sblock, cylno);
dmax = cbase + sblock.fs_fpg;
if (dmax > sblock.fs_size) {
dmax = sblock.fs_size;
}
dlower = cgsblock(&sblock, cylno) - cbase;
dupper = cgdmin(&sblock, cylno) - cbase;
if (cylno == 0) {
dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
}
cs = fscs + cylno;
memset(&acg, 0, (size_t)sblock.fs_cgsize);
acg.cg_time = utime;
acg.cg_magic = CG_MAGIC;
acg.cg_cgx = cylno;
if (cylno == sblock.fs_ncg - 1) {
acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
} else {
acg.cg_ncyl = sblock.fs_cpg;
}
acg.cg_niblk = sblock.fs_ipg;
acg.cg_ndblk = dmax - cbase;
if (sblock.fs_contigsumsize > 0) {
acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag;
}
acg.cg_btotoff = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield);
acg.cg_boff = acg.cg_btotoff + sblock.fs_cpg * sizeof(int32_t);
acg.cg_iusedoff = acg.cg_boff +
sblock.fs_cpg * sblock.fs_nrpos * sizeof(u_int16_t);
acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY);
if (sblock.fs_contigsumsize <= 0) {
acg.cg_nextfreeoff = acg.cg_freeoff +
howmany(sblock.fs_cpg* sblock.fs_spc/ NSPF(&sblock), NBBY);
} else {
acg.cg_clustersumoff = acg.cg_freeoff + howmany
(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY) -
sizeof(u_int32_t);
acg.cg_clustersumoff =
roundup(acg.cg_clustersumoff, sizeof(u_int32_t));
acg.cg_clusteroff = acg.cg_clustersumoff +
(sblock.fs_contigsumsize + 1) * sizeof(u_int32_t);
acg.cg_nextfreeoff = acg.cg_clusteroff + howmany
(sblock.fs_cpg * sblock.fs_spc / NSPB(&sblock), NBBY);
}
if (acg.cg_nextfreeoff-(intptr_t)(&acg.cg_firstfield) > sblock.fs_cgsize) {
errx(37, "panic: cylinder group too big");
}
acg.cg_cs.cs_nifree += sblock.fs_ipg;
if (cylno == 0)
for (i = 0; (size_t)i < UFS_ROOTINO; i++) {
setbit(cg_inosused(&acg), i);
acg.cg_cs.cs_nifree--;
}
for (i = 0; i < sblock.fs_ipg / INOPF(&sblock); i += sblock.fs_frag) {
#ifdef FSIRAND
for (j = 0; j < sblock.fs_bsize / sizeof(struct ufs1_dinode); j++) {
zino[j].di_gen = random();
}
#endif
wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i),
(size_t)sblock.fs_bsize, (void *)zino, fso, Nflag);
}
for (d = 0; d < dlower; d += sblock.fs_frag) {
blkno = d / sblock.fs_frag;
setblock(&sblock, cg_blksfree(&acg), blkno);
if (sblock.fs_contigsumsize > 0) {
setbit(cg_clustersfree(&acg), blkno);
}
acg.cg_cs.cs_nbfree++;
cg_blktot(&acg)[cbtocylno(&sblock, d)]++;
cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
[cbtorpos(&sblock, d)]++;
}
sblock.fs_dsize += dlower;
sblock.fs_dsize += acg.cg_ndblk - dupper;
if ((i = dupper % sblock.fs_frag)) {
acg.cg_frsum[sblock.fs_frag - i]++;
for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
setbit(cg_blksfree(&acg), dupper);
acg.cg_cs.cs_nffree++;
}
}
for (d = dupper; d + sblock.fs_frag <= dmax - cbase; ) {
blkno = d / sblock.fs_frag;
setblock(&sblock, cg_blksfree(&acg), blkno);
if (sblock.fs_contigsumsize > 0) {
setbit(cg_clustersfree(&acg), blkno);
}
acg.cg_cs.cs_nbfree++;
cg_blktot(&acg)[cbtocylno(&sblock, d)]++;
cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
[cbtorpos(&sblock, d)]++;
d += sblock.fs_frag;
}
if (d < dmax - cbase) {
acg.cg_frsum[dmax - cbase - d]++;
for (; d < dmax - cbase; d++) {
setbit(cg_blksfree(&acg), d);
acg.cg_cs.cs_nffree++;
}
}
if (sblock.fs_contigsumsize > 0) {
int32_t *sump = cg_clustersum(&acg);
u_char *mapp = cg_clustersfree(&acg);
int map = *mapp++;
int bit = 1;
int run = 0;
for (i = 0; i < acg.cg_nclusterblks; i++) {
if ((map & bit) != 0) {
run++;
} else if (run != 0) {
if (run > sblock.fs_contigsumsize) {
run = sblock.fs_contigsumsize;
}
sump[run]++;
run = 0;
}
if ((i & (NBBY - 1)) != (NBBY - 1)) {
bit <<= 1;
} else {
map = *mapp++;
bit = 1;
}
}
if (run != 0) {
if (run > sblock.fs_contigsumsize) {
run = sblock.fs_contigsumsize;
}
sump[run]++;
}
}
sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir;
sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree;
sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree;
sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree;
*cs = acg.cg_cs;
wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)),
(size_t)sblock.fs_bsize, &acg, fso, Nflag);
DBG_DUMP_CG(&sblock,
"new cg",
&acg);
DBG_LEAVE;
return;
}
static void
frag_adjust(daddr_t frag, int sign)
{
int fragsize;
int f;
DBG_ENTER;
fragsize=0;
for(f=rounddown(frag, sblock.fs_frag);
f<roundup(frag+1, sblock.fs_frag);
f++) {
if(isset(cg_blksfree(&acg), f)) {
fragsize++;
} else {
if(fragsize && fragsize<sblock.fs_frag) {
acg.cg_frsum[fragsize]+=sign;
DBG_PRINT2("frag_adjust [%d]+=%d\n",
fragsize,
sign);
}
fragsize=0;
}
}
if(fragsize && fragsize<sblock.fs_frag) {
acg.cg_frsum[fragsize]+=sign;
DBG_PRINT2("frag_adjust [%d]+=%d\n",
fragsize,
sign);
}
DBG_PRINT2("frag_adjust [[%d]]+=%d\n",
fragsize,
sign);
DBG_LEAVE;
return;
}
static void
cond_bl_upd(ufs_daddr_t *block, struct gfs_bpp *field,
enum pointer_source source, int fso, unsigned int Nflag)
{
struct gfs_bpp *f;
char *src;
daddr_t dst=0;
DBG_ENTER;
f=field;
while(f->old) {
if(*block/sblock.fs_frag == f->old) {
*block=(f->new*sblock.fs_frag+(*block%sblock.fs_frag));
f->found++;
DBG_PRINT3("scg (%d->%d)[%d] reference updated\n",
f->old,
f->new,
*block%sblock.fs_frag);
switch (source) {
case GFS_PS_INODE:
src=ablk;
dst=in_src;
break;
case GFS_PS_IND_BLK_LVL1:
src=i1blk;
dst=i1_src;
break;
case GFS_PS_IND_BLK_LVL2:
src=i2blk;
dst=i2_src;
break;
case GFS_PS_IND_BLK_LVL3:
src=i3blk;
dst=i3_src;
break;
default:
src=NULL;
break;
}
if(src) {
wtfs(dst, (size_t)sblock.fs_bsize, src,
fso, Nflag);
}
break;
}
f++;
}
DBG_LEAVE;
return;
}
static void
updjcg(int cylno, time_t utime, int fsi, int fso, unsigned int Nflag)
{
daddr_t cbase, dmax;
struct csum *cs;
int i,k;
int j=0;
DBG_ENTER;
rdfs(fsbtodb(&osblock, cgtod(&osblock, cylno)),
(size_t)osblock.fs_cgsize, &aocg, fsi);
DBG_PRINT0("jcg read\n");
DBG_DUMP_CG(&sblock,
"old joining cg",
&aocg);
memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2));
if(cgbase(&osblock, cylno+1) == osblock.fs_size) {
acg.cg_ncyl=sblock.fs_cpg;
wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)),
(size_t)sblock.fs_cgsize, &acg, fso, Nflag);
DBG_PRINT0("jcg written\n");
DBG_DUMP_CG(&sblock,
"new joining cg",
&acg);
DBG_LEAVE;
return;
}
cbase = cgbase(&sblock, cylno);
dmax = cbase + sblock.fs_fpg;
if (dmax > sblock.fs_size)
dmax = sblock.fs_size;
cs = fscs + cylno;
acg.cg_time = utime;
if (cylno == sblock.fs_ncg - 1) {
acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
} else {
acg.cg_ncyl = sblock.fs_cpg;
}
DBG_PRINT4("jcg dbg: %d %u %d %u\n",
cylno,
sblock.fs_ncg,
acg.cg_ncyl,
sblock.fs_cpg);
acg.cg_ndblk = dmax - cbase;
sblock.fs_dsize += acg.cg_ndblk-aocg.cg_ndblk;
if (sblock.fs_contigsumsize > 0) {
acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag;
}
if(osblock.fs_size % sblock.fs_frag) {
if(roundup(osblock.fs_size, sblock.fs_frag)<=sblock.fs_size) {
j=0;
for(i=roundup(osblock.fs_size-cbase, sblock.fs_frag)-1;
i>=osblock.fs_size-cbase;
i--) {
setbit(cg_blksfree(&acg), i);
acg.cg_cs.cs_nffree++;
j++;
}
if(isblock(&sblock, cg_blksfree(&acg),
((osblock.fs_size - cgbase(&sblock, cylno))/
sblock.fs_frag))) {
DBG_PRINT0("block was\n");
acg.cg_frsum[osblock.fs_size%sblock.fs_frag]--;
acg.cg_cs.cs_nbfree++;
acg.cg_cs.cs_nffree-=sblock.fs_frag;
k=rounddown(osblock.fs_size-cbase,
sblock.fs_frag);
cg_blktot(&acg)[cbtocylno(&sblock, k)]++;
cg_blks(&sblock, &acg, cbtocylno(&sblock, k))
[cbtorpos(&sblock, k)]++;
updclst((osblock.fs_size-cbase)/sblock.fs_frag);
} else {
k=0;
while(isset(cg_blksfree(&acg), i) &&
(i>=rounddown(osblock.fs_size-cbase,
sblock.fs_frag))) {
i--;
k++;
}
if(k) {
acg.cg_frsum[k]--;
}
acg.cg_frsum[k+j]++;
}
} else {
for(i=sblock.fs_size-cbase-1;
i>=osblock.fs_size-cbase;
i--) {
setbit(cg_blksfree(&acg), i);
acg.cg_cs.cs_nffree++;
j++;
}
k=0;
while(isset(cg_blksfree(&acg), i) &&
(i>=rounddown(osblock.fs_size-cbase,
sblock.fs_frag))) {
i--;
k++;
}
if(k) {
acg.cg_frsum[k]--;
}
acg.cg_frsum[k+j]++;
}
}
for(i=roundup(osblock.fs_size-cbase, sblock.fs_frag);
i+sblock.fs_frag<=dmax-cbase;
i+=sblock.fs_frag) {
j = i / sblock.fs_frag;
setblock(&sblock, cg_blksfree(&acg), j);
updclst(j);
acg.cg_cs.cs_nbfree++;
cg_blktot(&acg)[cbtocylno(&sblock, i)]++;
cg_blks(&sblock, &acg, cbtocylno(&sblock, i))
[cbtorpos(&sblock, i)]++;
}
if (i < (dmax - cbase)) {
acg.cg_frsum[dmax - cbase - i]++;
for (; i < dmax - cbase; i++) {
setbit(cg_blksfree(&acg), i);
acg.cg_cs.cs_nffree++;
}
}
sblock.fs_cstotal.cs_nffree +=
(acg.cg_cs.cs_nffree - aocg.cg_cs.cs_nffree);
sblock.fs_cstotal.cs_nbfree +=
(acg.cg_cs.cs_nbfree - aocg.cg_cs.cs_nbfree);
*cs = acg.cg_cs;
wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)), (size_t)sblock.fs_cgsize,
&acg, fso, Nflag);
DBG_PRINT0("jcg written\n");
DBG_DUMP_CG(&sblock,
"new joining cg",
&acg);
DBG_LEAVE;
return;
}
static void
updcsloc(time_t utime, int fsi, int fso, unsigned int Nflag)
{
struct csum *cs;
int ocscg, ncscg;
int blocks;
daddr_t cbase, dupper, odupper, d, f, g;
int ind;
int cylno, inc;
struct gfs_bpp *bp;
int i, l;
int lcs=0;
int block;
DBG_ENTER;
if(howmany(sblock.fs_cssize, sblock.fs_fsize) ==
howmany(osblock.fs_cssize, osblock.fs_fsize)) {
DBG_LEAVE;
return;
}
ocscg=dtog(&osblock, osblock.fs_csaddr);
cs=fscs+ocscg;
blocks = 1+howmany(sblock.fs_cssize, sblock.fs_bsize)-
howmany(osblock.fs_cssize, osblock.fs_bsize);
rdfs(fsbtodb(&osblock, cgtod(&osblock, ocscg)),
(size_t)osblock.fs_cgsize, &aocg, fsi);
DBG_PRINT0("oscg read\n");
DBG_DUMP_CG(&sblock,
"old summary cg",
&aocg);
memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2));
acg.cg_time = utime;
if( cs->cs_nbfree < blocks) {
DBG_TRC;
if(sblock.fs_ncg-osblock.fs_ncg < 2) {
errx(2, "panic: not enough space");
}
d=osblock.fs_csaddr+(osblock.fs_cssize/osblock.fs_fsize);
if(sblock.fs_contigsumsize > 0) {
for(block=howmany(d%sblock.fs_fpg, sblock.fs_frag),
lcs=0; lcs<sblock.fs_contigsumsize;
block++, lcs++) {
if(isclr(cg_clustersfree(&acg), block)){
break;
}
}
}
d--;
DBG_PRINT1("d=%d\n",
d);
if((d+1)%sblock.fs_frag) {
DBG_TRC;
frag_adjust(d%sblock.fs_fpg, -1);
for(; (d+1)%sblock.fs_frag; d--) {
DBG_PRINT1("d=%d\n",
d);
setbit(cg_blksfree(&acg), d%sblock.fs_fpg);
acg.cg_cs.cs_nffree++;
sblock.fs_cstotal.cs_nffree++;
}
d++;
frag_adjust(d%sblock.fs_fpg, 1);
if(isblock(&sblock, cg_blksfree(&acg),
(d%sblock.fs_fpg)/sblock.fs_frag)) {
DBG_PRINT1("d=%d\n",
d);
acg.cg_cs.cs_nffree-=sblock.fs_frag;
acg.cg_cs.cs_nbfree++;
sblock.fs_cstotal.cs_nffree-=sblock.fs_frag;
sblock.fs_cstotal.cs_nbfree++;
cg_blktot(&acg)[cbtocylno(&sblock,
d%sblock.fs_fpg)]++;
cg_blks(&sblock, &acg, cbtocylno(&sblock,
d%sblock.fs_fpg))[cbtorpos(&sblock,
d%sblock.fs_fpg)]++;
if(sblock.fs_contigsumsize > 0) {
setbit(cg_clustersfree(&acg),
(d%sblock.fs_fpg)/sblock.fs_frag);
if(lcs < sblock.fs_contigsumsize) {
if(lcs) {
cg_clustersum(&acg)
[lcs]--;
}
lcs++;
cg_clustersum(&acg)[lcs]++;
}
}
}
d--;
}
DBG_PRINT1("d=%d\n",
d);
for(d=rounddown(d, sblock.fs_frag); d >= osblock.fs_csaddr;
d-=sblock.fs_frag) {
DBG_TRC;
DBG_PRINT1("d=%d\n",
d);
setblock(&sblock, cg_blksfree(&acg),
(d%sblock.fs_fpg)/sblock.fs_frag);
acg.cg_cs.cs_nbfree++;
sblock.fs_cstotal.cs_nbfree++;
cg_blktot(&acg)[cbtocylno(&sblock, d%sblock.fs_fpg)]++;
cg_blks(&sblock, &acg, cbtocylno(&sblock,
d%sblock.fs_fpg))[cbtorpos(&sblock,
d%sblock.fs_fpg)]++;
if(sblock.fs_contigsumsize > 0) {
setbit(cg_clustersfree(&acg),
(d%sblock.fs_fpg)/sblock.fs_frag);
if(lcs < sblock.fs_contigsumsize) {
if(lcs) {
cg_clustersum(&acg)[lcs]--;
}
lcs++;
cg_clustersum(&acg)[lcs]++;
}
}
}
*cs = acg.cg_cs;
wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg)),
(size_t)sblock.fs_cgsize, &acg, fso, Nflag);
DBG_PRINT0("oscg written\n");
DBG_DUMP_CG(&sblock,
"old summary cg",
&acg);
sblock.fs_csaddr=cgdmin(&sblock, osblock.fs_ncg);
ncscg=dtog(&sblock, sblock.fs_csaddr);
cs=fscs+ncscg;
if(Nflag) {
DBG_PRINT0("nscg update skipped\n");
DBG_LEAVE;
return;
}
rdfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)),
(size_t)sblock.fs_cgsize, &aocg, fsi);
DBG_PRINT0("nscg read\n");
DBG_DUMP_CG(&sblock,
"new summary cg",
&aocg);
memcpy((void *)&cgun1, (void *)&cgun2, sizeof(cgun2));
for(d=sblock.fs_csaddr; d+sblock.fs_frag <=
sblock.fs_csaddr+(sblock.fs_cssize/sblock.fs_fsize);
d+=sblock.fs_frag) {
clrblock(&sblock, cg_blksfree(&acg),
(d%sblock.fs_fpg)/sblock.fs_frag);
acg.cg_cs.cs_nbfree--;
sblock.fs_cstotal.cs_nbfree--;
cg_blktot(&acg)[cbtocylno(&sblock, d%sblock.fs_fpg)]--;
cg_blks(&sblock, &acg, cbtocylno(&sblock,
d%sblock.fs_fpg))[cbtorpos(&sblock,
d%sblock.fs_fpg)]--;
if(sblock.fs_contigsumsize > 0) {
clrbit(cg_clustersfree(&acg),
(d%sblock.fs_fpg)/sblock.fs_frag);
}
}
if(d<sblock.fs_csaddr+(sblock.fs_cssize/sblock.fs_fsize)) {
for(; d-sblock.fs_csaddr<
sblock.fs_cssize/sblock.fs_fsize;
d++) {
clrbit(cg_blksfree(&acg), d%sblock.fs_fpg);
acg.cg_cs.cs_nffree--;
sblock.fs_cstotal.cs_nffree--;
}
acg.cg_cs.cs_nbfree--;
acg.cg_cs.cs_nffree+=sblock.fs_frag;
sblock.fs_cstotal.cs_nbfree--;
sblock.fs_cstotal.cs_nffree+=sblock.fs_frag;
cg_blktot(&acg)[cbtocylno(&sblock, d%sblock.fs_fpg)]--;
cg_blks(&sblock, &acg, cbtocylno(&sblock,
d%sblock.fs_fpg))[cbtorpos(&sblock,
d%sblock.fs_fpg)]--;
if(sblock.fs_contigsumsize > 0) {
clrbit(cg_clustersfree(&acg),
(d%sblock.fs_fpg)/sblock.fs_frag);
}
frag_adjust(d%sblock.fs_fpg, +1);
}
*cs = acg.cg_cs;
wtfs(fsbtodb(&sblock, cgtod(&sblock, ncscg)),
(size_t)sblock.fs_cgsize, &acg, fso, Nflag);
DBG_PRINT0("nscg written\n");
DBG_DUMP_CG(&sblock,
"new summary cg",
&acg);
DBG_LEAVE;
return;
}
DBG_TRC;
cbase = cgbase(&osblock, ocscg);
dupper = sblock.fs_csaddr - cbase +
howmany(sblock.fs_cssize, sblock.fs_fsize);
odupper = osblock.fs_csaddr - cbase +
howmany(osblock.fs_cssize, osblock.fs_fsize);
sblock.fs_dsize -= dupper-odupper;
bp=(struct gfs_bpp *)malloc(((dupper-odupper)/sblock.fs_frag+2)*
sizeof(struct gfs_bpp));
if(bp == NULL) {
errx(1, "malloc failed");
}
memset((char *)bp, 0, ((dupper-odupper)/sblock.fs_frag+2)*
sizeof(struct gfs_bpp));
ind=0;
frag_adjust(odupper, -1);
for(d=odupper; ((d<dupper)&&(d%sblock.fs_frag)); d++) {
DBG_PRINT1("scg first frag check loop d=%d\n",
d);
if(isclr(cg_blksfree(&acg), d)) {
if (!ind) {
bp[ind].old=d/sblock.fs_frag;
bp[ind].flags|=GFS_FL_FIRST;
if(roundup(d, sblock.fs_frag) >= dupper) {
bp[ind].flags|=GFS_FL_LAST;
}
ind++;
}
} else {
clrbit(cg_blksfree(&acg), d);
acg.cg_cs.cs_nffree--;
sblock.fs_cstotal.cs_nffree--;
}
}
frag_adjust(odupper, 1);
for(; d+sblock.fs_frag<=dupper; d+=sblock.fs_frag) {
DBG_PRINT1("scg block check loop d=%d\n",
d);
if(!isblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag)) {
for(f=d; f<d+sblock.fs_frag; f++) {
if(isset(cg_blksfree(&aocg), f)) {
acg.cg_cs.cs_nffree--;
sblock.fs_cstotal.cs_nffree--;
}
}
clrblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag);
bp[ind].old=d/sblock.fs_frag;
ind++;
} else {
clrblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag);
acg.cg_cs.cs_nbfree--;
sblock.fs_cstotal.cs_nbfree--;
cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
[cbtorpos(&sblock, d)]--;
if(sblock.fs_contigsumsize > 0) {
clrbit(cg_clustersfree(&acg), d/sblock.fs_frag);
for(lcs=0, l=(d/sblock.fs_frag)+1;
lcs<sblock.fs_contigsumsize;
l++, lcs++ ) {
if(isclr(cg_clustersfree(&acg),l)){
break;
}
}
if(lcs < sblock.fs_contigsumsize) {
cg_clustersum(&acg)[lcs+1]--;
if(lcs) {
cg_clustersum(&acg)[lcs]++;
}
}
}
}
}
if(d<dupper) {
frag_adjust(dupper-1, -1);
if(isblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag)) {
acg.cg_cs.cs_nbfree--;
sblock.fs_cstotal.cs_nbfree--;
acg.cg_cs.cs_nffree+=sblock.fs_frag;
sblock.fs_cstotal.cs_nffree+=sblock.fs_frag;
cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
[cbtorpos(&sblock, d)]--;
if(sblock.fs_contigsumsize > 0) {
clrbit(cg_clustersfree(&acg), d/sblock.fs_frag);
for(lcs=0, l=(d/sblock.fs_frag)+1;
lcs<sblock.fs_contigsumsize;
l++, lcs++ ) {
if(isclr(cg_clustersfree(&acg),l)){
break;
}
}
if(lcs < sblock.fs_contigsumsize) {
cg_clustersum(&acg)[lcs+1]--;
if(lcs) {
cg_clustersum(&acg)[lcs]++;
}
}
}
}
for(; d<dupper; d++) {
DBG_PRINT1("scg second frag check loop d=%d\n",
d);
if(isclr(cg_blksfree(&acg), d)) {
bp[ind].old=d/sblock.fs_frag;
bp[ind].flags|=GFS_FL_LAST;
} else {
clrbit(cg_blksfree(&acg), d);
acg.cg_cs.cs_nffree--;
sblock.fs_cstotal.cs_nffree--;
}
}
if(bp[ind].flags & GFS_FL_LAST) {
ind++;
}
frag_adjust(dupper-1, 1);
}
if(ind) {
for(i=0; i<ind; i++) {
if(!bp[i].old) {
break;
}
bp[i].new=alloc()/sblock.fs_frag;
for(f=bp[i].old*sblock.fs_frag,
g=bp[i].new*sblock.fs_frag;
f<(bp[i].old+1)*sblock.fs_frag;
f++, g++) {
if(isset(cg_blksfree(&aocg), f)) {
setbit(cg_blksfree(&acg), g);
acg.cg_cs.cs_nffree++;
sblock.fs_cstotal.cs_nffree++;
}
}
if(bp[i].flags & GFS_FL_FIRST) {
for(f=bp[i].old*sblock.fs_frag,
g=bp[i].new*sblock.fs_frag;
f<odupper;
f++, g++) {
setbit(cg_blksfree(&acg), g);
acg.cg_cs.cs_nffree++;
sblock.fs_cstotal.cs_nffree++;
}
if(!(bp[i].flags & GFS_FL_LAST)) {
frag_adjust(bp[i].new*sblock.fs_frag,1);
}
}
if(bp[i].flags & GFS_FL_LAST) {
frag_adjust(bp[i].new*sblock.fs_frag, 1);
frag_adjust(bp[i].old*sblock.fs_frag, -1);
for(f=dupper;
f<roundup(dupper, sblock.fs_frag);
f++) {
if(isclr(cg_blksfree(&acg), f)) {
setbit(cg_blksfree(&acg), f);
acg.cg_cs.cs_nffree++;
sblock.fs_cstotal.cs_nffree++;
}
}
frag_adjust(bp[i].old*sblock.fs_frag, 1);
}
bp[i].old+=cbase/sblock.fs_frag;
bp[i].new+=cbase/sblock.fs_frag;
rdfs(fsbtodb(&sblock, bp[i].old*sblock.fs_frag),
(size_t)sblock.fs_bsize, &ablk, fsi);
wtfs(fsbtodb(&sblock, bp[i].new*sblock.fs_frag),
(size_t)sblock.fs_bsize, &ablk, fso, Nflag);
DBG_DUMP_HEX(&sblock,
"copied full block",
(unsigned char *)&ablk);
DBG_PRINT2("scg (%d->%d) block relocated\n",
bp[i].old,
bp[i].new);
}
for(cylno=0; cylno<osblock.fs_ncg; cylno++) {
DBG_PRINT1("scg doing cg (%d)\n",
cylno);
for(inc=osblock.fs_ipg-1 ; inc>=0 ; inc--) {
updrefs(cylno, (ino_t)inc, bp, fsi, fso, Nflag);
}
}
for(i=0; i<ind; i++) {
if(!bp[i].found || (bp[i].found>sblock.fs_frag)) {
warnx("error: %d refs found for block %d.",
bp[i].found, bp[i].old);
}
}
}
*cs = acg.cg_cs;
wtfs(fsbtodb(&sblock, cgtod(&sblock, ocscg)), (size_t)sblock.fs_cgsize,
&acg, fso, Nflag);
DBG_PRINT0("scg written\n");
DBG_DUMP_CG(&sblock,
"new summary cg",
&acg);
DBG_LEAVE;
return;
}
static void
rdfs(daddr_t bno, size_t size, void *bf, int fsi)
{
ssize_t n;
DBG_ENTER;
if (lseek(fsi, (off_t)bno * DEV_BSIZE, 0) < 0) {
err(33, "rdfs: seek error: %ld", (long)bno);
}
n = read(fsi, bf, size);
if (n != (ssize_t)size) {
err(34, "rdfs: read error: %ld", (long)bno);
}
DBG_LEAVE;
return;
}
static void
wtfs(daddr_t bno, size_t size, void *bf, int fso, unsigned int Nflag)
{
ssize_t n;
DBG_ENTER;
if (Nflag) {
DBG_LEAVE;
return;
}
if (lseek(fso, (off_t)bno * DEV_BSIZE, SEEK_SET) < 0) {
err(35, "wtfs: seek error: %ld", (long)bno);
}
n = write(fso, bf, size);
if (n != (ssize_t)size) {
err(36, "wtfs: write error: %ld", (long)bno);
}
DBG_LEAVE;
return;
}
static daddr_t
alloc(void)
{
daddr_t d, blkno;
int lcs1, lcs2;
int l;
int csmin, csmax;
int dlower, dupper, dmax;
DBG_ENTER;
if (acg.cg_magic != CG_MAGIC) {
warnx("acg: bad magic number");
DBG_LEAVE;
return (0);
}
if (acg.cg_cs.cs_nbfree == 0) {
warnx("error: cylinder group ran out of space");
DBG_LEAVE;
return (0);
}
blkno=-1;
dlower=cgsblock(&sblock, acg.cg_cgx)-cgbase(&sblock, acg.cg_cgx);
dupper=cgdmin(&sblock, acg.cg_cgx)-cgbase(&sblock, acg.cg_cgx);
dmax=cgbase(&sblock, acg.cg_cgx)+sblock.fs_fpg;
if (dmax > sblock.fs_size) {
dmax = sblock.fs_size;
}
dmax-=cgbase(&sblock, acg.cg_cgx);
csmin=sblock.fs_csaddr-cgbase(&sblock, acg.cg_cgx);
csmax=csmin+howmany(sblock.fs_cssize, sblock.fs_fsize);
DBG_PRINT3("seek range: dl=%d, du=%d, dm=%d\n",
dlower,
dupper,
dmax);
DBG_PRINT2("range cont: csmin=%d, csmax=%d\n",
csmin,
csmax);
for(d=0; (d<dlower && blkno==-1); d+=sblock.fs_frag) {
if(d>=csmin && d<=csmax) {
continue;
}
if(isblock(&sblock, cg_blksfree(&acg), fragstoblks(&sblock,
d))) {
blkno = fragstoblks(&sblock, d);
break;
}
}
for(d=dupper; (d<dmax && blkno==-1); d+=sblock.fs_frag) {
if(d>=csmin && d<=csmax) {
continue;
}
if(isblock(&sblock, cg_blksfree(&acg), fragstoblks(&sblock,
d))) {
blkno = fragstoblks(&sblock, d);
break;
}
}
if(blkno==-1) {
warnx("internal error: couldn't find promised block in cg");
DBG_LEAVE;
return (0);
}
d=blkstofrags(&sblock, blkno);
clrblock(&sblock, cg_blksfree(&acg), blkno);
if (sblock.fs_contigsumsize > 0) {
clrbit(cg_clustersfree(&acg), blkno);
for(lcs1=0, l=blkno-1; lcs1<sblock.fs_contigsumsize;
l--, lcs1++ ) {
if(isclr(cg_clustersfree(&acg),l)){
break;
}
}
for(lcs2=0, l=blkno+1; lcs2<sblock.fs_contigsumsize;
l++, lcs2++ ) {
if(isclr(cg_clustersfree(&acg),l)){
break;
}
}
cg_clustersum(&acg)[MIN(lcs1+lcs2+1,sblock.fs_contigsumsize)]--;
if(lcs1) {
cg_clustersum(&acg)[lcs1]++;
}
if(lcs2) {
cg_clustersum(&acg)[lcs2]++;
}
}
acg.cg_cs.cs_nbfree--;
sblock.fs_cstotal.cs_nbfree--;
cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--;
DBG_LEAVE;
return (d);
}
static int
isblock(struct fs *fs, unsigned char *cp, int h)
{
unsigned char mask;
DBG_ENTER;
switch (fs->fs_frag) {
case 8:
DBG_LEAVE;
return (cp[h] == 0xff);
case 4:
mask = 0x0f << ((h & 0x1) << 2);
DBG_LEAVE;
return ((cp[h >> 1] & mask) == mask);
case 2:
mask = 0x03 << ((h & 0x3) << 1);
DBG_LEAVE;
return ((cp[h >> 2] & mask) == mask);
case 1:
mask = 0x01 << (h & 0x7);
DBG_LEAVE;
return ((cp[h >> 3] & mask) == mask);
default:
fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
DBG_LEAVE;
return (0);
}
}
static void
clrblock(struct fs *fs, unsigned char *cp, int h)
{
DBG_ENTER;
switch ((fs)->fs_frag) {
case 8:
cp[h] = 0;
break;
case 4:
cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
break;
case 2:
cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
break;
case 1:
cp[h >> 3] &= ~(0x01 << (h & 0x7));
break;
default:
warnx("clrblock bad fs_frag %d", fs->fs_frag);
break;
}
DBG_LEAVE;
return;
}
static void
setblock(struct fs *fs, unsigned char *cp, int h)
{
DBG_ENTER;
switch (fs->fs_frag) {
case 8:
cp[h] = 0xff;
break;
case 4:
cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
break;
case 2:
cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
break;
case 1:
cp[h >> 3] |= (0x01 << (h & 0x7));
break;
default:
warnx("setblock bad fs_frag %d", fs->fs_frag);
break;
}
DBG_LEAVE;
return;
}
static struct ufs1_dinode *
ginode(ino_t inumber, int fsi, int cg)
{
ufs_daddr_t iblk;
static ino_t startinum=0;
struct ufs1_dinode *pi;
DBG_ENTER;
pi=(struct ufs1_dinode *)(void *)ablk;
inumber+=(cg * sblock.fs_ipg);
if (startinum == 0 || inumber < startinum ||
inumber >= startinum + INOPB(&sblock)) {
iblk = ino_to_fsba(&sblock, inumber);
in_src=fsbtodb(&sblock, iblk);
rdfs(in_src, (size_t)sblock.fs_bsize, &ablk, fsi);
startinum = rounddown(inumber, INOPB(&sblock));
}
DBG_LEAVE;
return (&(pi[inumber % INOPB(&sblock)]));
}
static int
charsperline(void)
{
int columns;
char *cp;
struct winsize ws;
DBG_ENTER;
columns = 0;
if (ioctl(0, TIOCGWINSZ, &ws) != -1) {
columns = ws.ws_col;
}
if (columns == 0 && (cp = getenv("COLUMNS"))) {
columns = atoi(cp);
}
if (columns == 0) {
columns = 80;
}
DBG_LEAVE;
return columns;
}
int
main(int argc, char **argv)
{
struct partinfo pinfo;
char *device, *special;
char ch;
unsigned int size=0;
size_t len;
unsigned int Nflag=0;
int ExpertFlag=0;
struct stat st;
int fsi,fso;
char reply[5];
#ifdef FSMAXSNAP
int j;
#endif
DBG_ENTER;
while((ch=getopt(argc, argv, "Ns:vy")) != -1) {
switch(ch) {
case 'N':
Nflag=1;
break;
case 's':
size=(size_t)atol(optarg);
if(size<1) {
usage();
}
break;
case 'v':
break;
case 'y':
ExpertFlag=1;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if(argc != 1) {
usage();
}
device=*argv;
if (0 == strrchr(device, '/')) {
len=strlen(device)+strlen(_PATH_DEV)+2+strlen("vinum/");
special=(char *)malloc(len);
if(special == NULL) {
errx(1, "malloc failed");
}
snprintf(special, len, "%sr%s", _PATH_DEV, device);
if (stat(special, &st) == -1) {
snprintf(special, len, "%s%s", _PATH_DEV, device);
if (stat(special, &st) == -1) {
snprintf(special, len, "%svinum/r%s",
_PATH_DEV, device);
if (stat(special, &st) == -1) {
snprintf(special, len, "%svinum/%s",
_PATH_DEV, device);
}
}
}
device = special;
}
if (Nflag) {
fso = -1;
} else {
fso = open(device, O_WRONLY);
if (fso < 0) {
err(1, "%s", device);
}
}
fsi = open(device, O_RDONLY);
if (fsi < 0) {
err(1, "%s", device);
}
if (ioctl(fsi, DIOCGPART, &pinfo) < 0) {
if (fstat(fsi, &st) < 0)
err(1, "unable to figure out the partition size");
pinfo.media_blocks = st.st_size / DEV_BSIZE;
pinfo.media_blksize = DEV_BSIZE;
}
if (pinfo.media_blocks < 1) {
errx(1, "partition is unavailable");
}
rdfs((daddr_t)(SBOFF/DEV_BSIZE), (size_t)SBSIZE, &osblock, fsi);
if (osblock.fs_magic != FS_MAGIC) {
errx(1, "superblock not recognized");
}
memcpy((void *)&fsun1, (void *)&fsun2, sizeof(fsun2));
DBG_OPEN("/tmp/growfs.debug");
DBG_DUMP_FS(&sblock,
"old sblock");
sblock.fs_size = dbtofsb(&osblock, pinfo.media_blocks);
if (size != 0) {
if (size > pinfo.media_blocks){
errx(1, "There is not enough space (%ju < %d)",
(intmax_t)pinfo.media_blocks, size);
}
sblock.fs_size = dbtofsb(&osblock, size);
}
if(osblock.fs_size >= sblock.fs_size) {
errx(1, "we are not growing (%d->%d)", osblock.fs_size,
sblock.fs_size);
}
#ifdef FSMAXSNAP
if(ExpertFlag == 0) {
for(j=0; j<FSMAXSNAP; j++) {
if(sblock.fs_snapinum[j]) {
errx(1, "active snapshot found in filesystem\n"
" please remove all snapshots before "
"using growfs\n");
}
if(!sblock.fs_snapinum[j]) {
break;
}
}
}
#endif
if (ExpertFlag == 0 && Nflag == 0) {
printf("We strongly recommend you to make a backup "
"before growing the Filesystem\n\n"
" Did you backup your data (Yes/No) ? ");
fgets(reply, (int)sizeof(reply), stdin);
if (strcmp(reply, "Yes\n")){
printf("\n Nothing done \n");
exit (0);
}
}
printf("new filesystemsize is: %d frags\n", sblock.fs_size);
wtfs((daddr_t)pinfo.media_blocks-1, (size_t)DEV_BSIZE, &sblock, fso,
Nflag);
sblock.fs_ncyl = sblock.fs_size * NSPF(&sblock) / sblock.fs_spc;
if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) {
sblock.fs_ncyl++;
}
sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg;
if (sblock.fs_ncyl % sblock.fs_cpg) {
sblock.fs_ncg++;
}
if ((sblock.fs_size - (sblock.fs_ncg-1) * sblock.fs_fpg) <
sblock.fs_fpg && cgdmin(&sblock, (sblock.fs_ncg-1))-
cgbase(&sblock, (sblock.fs_ncg-1)) > (sblock.fs_size -
(sblock.fs_ncg-1) * sblock.fs_fpg )) {
sblock.fs_ncg--;
#if 1
sblock.fs_ncyl = sblock.fs_ncg * sblock.fs_cpg;
#else
sblock.fs_ncyl -= sblock.fs_ncyl % sblock.fs_cpg;
#endif
sblock.fs_ncyl -= sblock.fs_ncyl % sblock.fs_cpg;
printf( "Warning: %d sector(s) cannot be allocated.\n",
(sblock.fs_size-(sblock.fs_ncg)*sblock.fs_fpg) *
NSPF(&sblock));
sblock.fs_size = sblock.fs_ncyl * sblock.fs_spc / NSPF(&sblock);
}
sblock.fs_cssize =
fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
if(osblock.fs_size >= sblock.fs_size) {
errx(1, "not enough new space");
}
DBG_PRINT0("sblock calculated\n");
growfs(fsi, fso, Nflag);
close(fsi);
if(fso>-1) close(fso);
DBG_CLOSE;
DBG_LEAVE;
return 0;
}
static void
usage(void)
{
DBG_ENTER;
fprintf(stderr, "usage: growfs [-Ny] [-s size] special\n");
DBG_LEAVE;
exit(1);
}
static void
updclst(int block)
{
static int lcs=0;
DBG_ENTER;
if(sblock.fs_contigsumsize < 1) {
return;
}
setbit(cg_clustersfree(&acg), block);
if(!lcs) {
for(block--; lcs<sblock.fs_contigsumsize; block--, lcs++ ) {
if(isclr(cg_clustersfree(&acg), block)){
break;
}
}
}
if(lcs < sblock.fs_contigsumsize) {
if(lcs) {
cg_clustersum(&acg)[lcs]--;
}
lcs++;
cg_clustersum(&acg)[lcs]++;
}
DBG_LEAVE;
return;
}
static void
updrefs(int cg, ino_t in, struct gfs_bpp *bp, int fsi, int fso, unsigned int
Nflag)
{
unsigned int ictr, ind2ctr, ind3ctr;
ufs_daddr_t *iptr, *ind2ptr, *ind3ptr;
struct ufs1_dinode *ino;
int remaining_blocks;
DBG_ENTER;
ino=ginode(in, fsi, cg);
if(!((ino->di_mode & IFMT)==IFDIR || (ino->di_mode & IFMT)==IFREG ||
(ino->di_mode & IFMT)==IFLNK)) {
DBG_LEAVE;
return;
}
if(((ino->di_mode & IFMT)==IFLNK) && (ino->di_size<UFS1_MAXSYMLINKLEN)) {
DBG_LEAVE;
return;
}
if(!ino->di_size) {
DBG_LEAVE;
return;
}
if(!ino->di_blocks) {
DBG_LEAVE;
return;
}
DBG_PRINT2("scg checking inode (%ju in %d)\n",
(uintmax_t)in,
cg);
remaining_blocks=howmany(ino->di_size, sblock.fs_bsize);
for(ictr=0; ictr < MIN(UFS_NDADDR, (unsigned int)remaining_blocks);
ictr++) {
iptr=&(ino->di_db[ictr]);
if(*iptr) {
cond_bl_upd(iptr, bp, GFS_PS_INODE, fso, Nflag);
}
}
DBG_PRINT0("~~scg direct blocks checked\n");
remaining_blocks-=UFS_NDADDR;
if(remaining_blocks<0) {
DBG_LEAVE;
return;
}
if(ino->di_ib[0]) {
cond_bl_upd(&(ino->di_ib[0]), bp, GFS_PS_INODE, fso, Nflag);
i1_src=fsbtodb(&sblock, ino->di_ib[0]);
rdfs(i1_src, (size_t)sblock.fs_bsize, &i1blk, fsi);
for(ictr=0; ictr < MIN(howmany(sblock.fs_bsize,
sizeof(ufs_daddr_t)), (unsigned int)remaining_blocks);
ictr++) {
iptr=&((ufs_daddr_t *)(void *)&i1blk)[ictr];
if(*iptr) {
cond_bl_upd(iptr, bp, GFS_PS_IND_BLK_LVL1,
fso, Nflag);
}
}
}
DBG_PRINT0("scg indirect_1 blocks checked\n");
remaining_blocks-= howmany(sblock.fs_bsize, sizeof(ufs_daddr_t));
if(remaining_blocks<0) {
DBG_LEAVE;
return;
}
if(ino->di_ib[1]) {
cond_bl_upd(&(ino->di_ib[1]), bp, GFS_PS_INODE, fso, Nflag);
i2_src=fsbtodb(&sblock, ino->di_ib[1]);
rdfs(i2_src, (size_t)sblock.fs_bsize, &i2blk, fsi);
for(ind2ctr=0; ind2ctr < howmany(sblock.fs_bsize,
sizeof(ufs_daddr_t)); ind2ctr++) {
ind2ptr=&((ufs_daddr_t *)(void *)&i2blk)[ind2ctr];
if(!*ind2ptr) {
continue;
}
cond_bl_upd(ind2ptr, bp, GFS_PS_IND_BLK_LVL2, fso,
Nflag);
i1_src=fsbtodb(&sblock, *ind2ptr);
rdfs(i1_src, (size_t)sblock.fs_bsize, &i1blk,
fsi);
for(ictr=0; ictr<MIN(howmany((unsigned int)
sblock.fs_bsize, sizeof(ufs_daddr_t)),
(unsigned int)remaining_blocks); ictr++) {
iptr=&((ufs_daddr_t *)(void *)&i1blk)[ictr];
if(*iptr) {
cond_bl_upd(iptr, bp,
GFS_PS_IND_BLK_LVL1, fso, Nflag);
}
}
}
}
DBG_PRINT0("scg indirect_2 blocks checked\n");
#define SQUARE(a) ((a)*(a))
remaining_blocks-=SQUARE(howmany(sblock.fs_bsize, sizeof(ufs_daddr_t)));
#undef SQUARE
if(remaining_blocks<0) {
DBG_LEAVE;
return;
}
if(ino->di_ib[2]) {
cond_bl_upd(&(ino->di_ib[2]), bp, GFS_PS_INODE, fso, Nflag);
i3_src=fsbtodb(&sblock, ino->di_ib[2]);
rdfs(i3_src, (size_t)sblock.fs_bsize, &i3blk, fsi);
for(ind3ctr=0; ind3ctr < howmany(sblock.fs_bsize,
sizeof(ufs_daddr_t)); ind3ctr ++) {
ind3ptr=&((ufs_daddr_t *)(void *)&i3blk)[ind3ctr];
if(!*ind3ptr) {
continue;
}
cond_bl_upd(ind3ptr, bp, GFS_PS_IND_BLK_LVL3, fso,
Nflag);
i2_src=fsbtodb(&sblock, *ind3ptr);
rdfs(i2_src, (size_t)sblock.fs_bsize, &i2blk,
fsi);
for(ind2ctr=0; ind2ctr < howmany(sblock.fs_bsize,
sizeof(ufs_daddr_t)); ind2ctr ++) {
ind2ptr=&((ufs_daddr_t *)(void *)&i2blk)
[ind2ctr];
if(!*ind2ptr) {
continue;
}
cond_bl_upd(ind2ptr, bp, GFS_PS_IND_BLK_LVL2,
fso, Nflag);
i1_src=fsbtodb(&sblock, *ind2ptr);
rdfs(i1_src, (size_t)sblock.fs_bsize,
&i1blk, fsi);
for(ictr=0; ictr < MIN(howmany(sblock.fs_bsize,
sizeof(ufs_daddr_t)),
(unsigned int)remaining_blocks); ictr++) {
iptr=&((ufs_daddr_t *)(void *)&i1blk)
[ictr];
if(*iptr) {
cond_bl_upd(iptr, bp,
GFS_PS_IND_BLK_LVL1, fso,
Nflag);
}
}
}
}
}
DBG_PRINT0("scg indirect_3 blocks checked\n");
DBG_LEAVE;
return;
}