/* read the page of fixed disk inode (AIT) in raw mode */
mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1); if (mp == NULL) {
jfs_err("diWriteSpecial: failed to read aggregate inode extent!"); return;
}
/* get the pointer to the disk inode of interest */
dp = (struct dinode *) (mp->data);
dp += inum % 8; /* 8 inodes per 4K page */
/* get the inode number and extent number of the inode within *theiagandtheinodenumberwithintheextent.
*/
ino = inum & (INOSPERIAG - 1);
extno = ino >> L2INOSPEREXT;
bitno = ino & (INOSPEREXT - 1);
mask = HIGHORDER >> bitno;
/* compute the bitmap for the extent reflecting the freed inode.
*/
bitmap = le32_to_cpu(iagp->wmap[extno]) & ~mask;
if (imap->im_agctl[agno].numfree > imap->im_agctl[agno].numinos) {
release_metapage(mp);
IREAD_UNLOCK(ipimap);
AG_UNLOCK(imap, agno);
jfs_error(ip->i_sb, "numfree > numinos\n"); return -EIO;
} /* *inodeextentstillhassomeinodesorbelowlowwatermark: *keeptheinodeextent;
*/ if (bitmap ||
imap->im_agctl[agno].numfree < 96 ||
(imap->im_agctl[agno].numfree < 288 &&
(((imap->im_agctl[agno].numfree * 100) /
imap->im_agctl[agno].numinos) <= 25))) { /* if the iag currently has no free inodes (i.e., *theinodebeingfreedisthefirstfreeinodeofiag), *inserttheiagatheadoftheinodefreelistfortheag.
*/ if (iagp->nfreeinos == 0) { /* check if there are any iags on the ag inode *freelist.ifso,readthefirstonesothat *wecanlinkthecurrentiagontothelistat *thehead.
*/ if ((fwd = imap->im_agctl[agno].inofree) >= 0) { /* read the iag that currently is the head *ofthelist.
*/ if ((rc = diIAGRead(imap, fwd, &))) {
IREAD_UNLOCK(ipimap);
AG_UNLOCK(imap, agno);
release_metapage(mp); return (rc);
}
aiagp = (struct iag *) amp->data;
/* make current head point back to the iag.
*/
aiagp->inofreeback = cpu_to_le32(iagno);
write_metapage(amp);
}
/* iag points forward to current head and iag *becomesthenewheadofthelist.
*/
iagp->inofreefwd =
cpu_to_le32(imap->im_agctl[agno].inofree);
iagp->inofreeback = cpu_to_le32(-1);
imap->im_agctl[agno].inofree = iagno;
}
IREAD_UNLOCK(ipimap);
/* update the free inode summary map for the extent if *freeingtheinodemeanstheextentwillnowhavefree *inodes(i.e.,theinodebeingfreedisthefirstfree *inodeofextent),
*/ if (iagp->wmap[extno] == cpu_to_le32(ONES)) {
sword = extno >> L2EXTSPERSUM;
bitno = extno & (EXTSPERSUM - 1);
iagp->inosmap[sword] &=
cpu_to_le32(~(HIGHORDER >> bitno));
}
/* update the bitmap.
*/
iagp->wmap[extno] = cpu_to_le32(bitmap);
/* update the free inode counts at the iag, ag and *maplevel.
*/
le32_add_cpu(&iagp->nfreeinos, 1);
imap->im_agctl[agno].numfree += 1;
atomic_inc(&imap->im_numfree);
/* release the AG inode map lock
*/
AG_UNLOCK(imap, agno);
/* check if the iag currently has no free extents. if so, *itwillbeplacedontheheadoftheagextentfreelist.
*/ if (iagp->nfreeexts == 0) { /* check if the ag extent free list has any iags. *ifso,readtheiagattheheadofthelistnow. *this(head)iagwillbeupdatedlatertoreflect *theadditionofthecurrentiagattheheadof *thelist.
*/ if ((fwd = imap->im_agctl[agno].extfree) >= 0) { if ((rc = diIAGRead(imap, fwd, &))) goto error_out;
aiagp = (struct iag *) amp->data;
}
} else { /* iag has free extents. check if the addition of a free *extentwillcauseallextentstobefreewithinthis *iag.ifso,theiagwillberemovedfromtheagextent *freelistandplacedontheinodemap'sfreeiaglist.
*/ if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG - 1)) { /* in preparation for removing the iag from the *agextentfreelist,readtheiagspreceding *andfollowingtheiagontheagextentfree *list.
*/ if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) { if ((rc = diIAGRead(imap, fwd, &))) goto error_out;
aiagp = (struct iag *) amp->data;
}
/* remove the iag from the ag inode free list if freeing *thisextentcausetheiagtohavenofreeinodes.
*/ if (iagp->nfreeinos == cpu_to_le32(INOSPEREXT - 1)) { int inofreeback = le32_to_cpu(iagp->inofreeback); int inofreefwd = le32_to_cpu(iagp->inofreefwd);
/* in preparation for removing the iag from the *aginodefreelist,readtheiagspreceding *andfollowingtheiagontheaginodefree *list.beforereadingtheseiags,wemustmake *surethatwealreadydon'thavetheminhand *fromupabove,sincere-readinganiag(buffer) *wearecurrentlyholdingwouldcauseadeadlock.
*/ if (inofreefwd >= 0) {
/* *updateiaglist(s)(carefulupdatestep2)
*/ /* add the iag to the ag extent free list if this is the *firstfreeextentfortheiag.
*/ if (iagp->nfreeexts == 0) { if (fwd >= 0)
aiagp->extfreeback = cpu_to_le32(iagno);
iagp->extfreefwd =
cpu_to_le32(imap->im_agctl[agno].extfree);
iagp->extfreeback = cpu_to_le32(-1);
imap->im_agctl[agno].extfree = iagno;
} else { /* remove the iag from the ag extent list if all extents *arenowfreeandplaceitontheinodemapiagfreelist.
*/ if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG - 1)) { if (fwd >= 0)
aiagp->extfreeback = iagp->extfreeback;
/* remove the iag from the ag inode free list if freeing *thisextentcausestheiagtohavenofreeinodes.
*/ if (iagp->nfreeinos == cpu_to_le32(INOSPEREXT - 1)) { if ((int) le32_to_cpu(iagp->inofreefwd) >= 0)
ciagp->inofreeback = iagp->inofreeback;
/* update the inode extent address and working map *toreflectthefreeextent. *thepermanentmapshouldhavebeenupdatedalready *fortheinodebeingfreed.
*/ if (iagp->pmap[extno] != 0) {
jfs_error(ip->i_sb, "the pmap does not show inode free\n");
}
iagp->wmap[extno] = 0;
PXDlength(&iagp->inoext[extno], 0);
PXDaddress(&iagp->inoext[extno], 0);
/* update the number of free inodes and number of free extents *fortheiag.
*/
le32_add_cpu(&iagp->nfreeinos, -(INOSPEREXT - 1));
le32_add_cpu(&iagp->nfreeexts, 1);
/* update the number of free inodes and backed inodes *attheagandinodemaplevel.
*/
imap->im_agctl[agno].numfree -= (INOSPEREXT - 1);
imap->im_agctl[agno].numinos -= INOSPEREXT;
atomic_sub(INOSPEREXT - 1, &imap->im_numfree);
atomic_sub(INOSPEREXT, &imap->im_numinos);
if (amp)
write_metapage(amp); if (bmp)
write_metapage(bmp); if (cmp)
write_metapage(cmp); if (dmp)
write_metapage(dmp);
/* get the pointers to the inode map inode and the *correspondingimapcontrolstructure.
*/
ipimap = JFS_SBI(pip->i_sb)->ipimap;
imap = JFS_IP(ipimap)->i_imap;
JFS_IP(ip)->ipimap = ipimap;
JFS_IP(ip)->fileset = FILESYSTEM_I;
/* for a directory, the allocation policy is to start *attheaglevelusingthepreferredag.
*/ if (dir) {
agno = dbNextAG(JFS_SBI(pip->i_sb)->ipbmap);
AG_LOCK(imap, agno); goto tryag;
}
/* for files, the policy starts off by trying to allocate from *thesameiagcontainingtheparentdiskinode: *trytoallocatethenewdiskinodeclosetotheparentdisk *inode,usingparentdiskinodenumber+1astheallocation *hint.(weusealeft-to-rightpolicytoattempttoavoid *movingbackwardonthedisk.)computethehintwithinthe *filesystemandtheiag.
*/
/* get the ag number of this iag */
agno = BLKTOAG(JFS_IP(pip)->agstart, JFS_SBI(pip->i_sb));
dn_numag = JFS_SBI(pip->i_sb)->bmap->db_numag; if (agno < 0 || agno > dn_numag || agno >= MAXAG) return -EIO;
/* back off the hint if it is outside of the iag */ if (ino == 0)
inum = pip->i_ino;
/* lock the AG inode map information */
AG_LOCK(imap, agno);
/* Get read lock on imap inode */
IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
/* get the iag number and read the iag */
iagno = INOTOIAG(inum); if ((rc = diIAGRead(imap, iagno, &mp))) {
IREAD_UNLOCK(ipimap);
AG_UNLOCK(imap, agno); return (rc);
}
iagp = (struct iag *) mp->data;
/* determine if new inode extent is allowed to be added to the iag. *newinodeextentcanbeaddedtotheiagiftheag *haslessthan32freediskinodesandtheiaghasfreeextents.
*/
addext = (imap->im_agctl[agno].numfree < 32 && iagp->nfreeexts);
/* *trytoallocatefromtheIAG
*/ /* check if the inode may be allocated from the iag *(i.e.theinodehasfreeinodesornewextentcanbeadded).
*/ if (iagp->nfreeinos || addext) { /* determine the extent number of the hint.
*/
extno = ino >> L2INOSPEREXT;
/* check if the extent containing the hint has backed *inodes.ifso,trytoallocatewithinthisextent.
*/ if (addressPXD(&iagp->inoext[extno])) {
bitno = ino & (INOSPEREXT - 1); if ((bitno =
diFindFree(le32_to_cpu(iagp->wmap[extno]),
bitno))
< INOSPEREXT) {
ino = (extno << L2INOSPEREXT) + bitno;
/* a free inode (bit) was found within this *extent,soallocateit.
*/
rc = diAllocBit(imap, iagp, ino);
IREAD_UNLOCK(ipimap); if (rc) {
assert(rc == -EIO);
} else { /* set the results of the allocation *andwritetheiag.
*/
diInitInode(ip, iagno, ino, extno,
iagp);
mark_metapage_dirty(mp);
}
release_metapage(mp);
/* free the AG lock and return.
*/
AG_UNLOCK(imap, agno); return (rc);
}
/* mask any prior bits for the starting words of the *summarymap.
*/
mask = (bitno == 0) ? 0 : (ONES << (EXTSPERSUM - bitno));
inosmap = le32_to_cpu(iagp->inosmap[sword]) | mask;
extsmap = le32_to_cpu(iagp->extsmap[sword]) | mask;
/* scan the free inode and free extent summary maps for *freeresources.
*/ for (i = 0; i < nwords; i++) { /* check if this word of the free inode summary *mapdescribesanextentwithfreeinodes.
*/ if (~inosmap) { /* an extent with free inodes has been *found.determinetheextentnumber *andtheinodenumberwithintheextent.
*/
rem = diFindFree(inosmap, 0);
extno = (sword << L2EXTSPERSUM) + rem;
rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), 0); if (rem >= INOSPEREXT) {
IREAD_UNLOCK(ipimap);
release_metapage(mp);
AG_UNLOCK(imap, agno);
jfs_error(ip->i_sb, "can't find free bit in wmap\n"); return -EIO;
}
/* determine the inode number within the *iagandallocatetheinodefromthe *map.
*/
ino = (extno << L2INOSPEREXT) + rem;
rc = diAllocBit(imap, iagp, ino);
IREAD_UNLOCK(ipimap); if (rc)
assert(rc == -EIO); else { /* set the results of the allocation *andwritetheiag.
*/
diInitInode(ip, iagno, ino, extno,
iagp);
mark_metapage_dirty(mp);
}
release_metapage(mp);
/* free the AG lock and return.
*/
AG_UNLOCK(imap, agno); return (rc);
}
/* check if we may allocate an extent of free *inodesandwhetherthiswordofthefree *extentssummarymapdescribesafreeextent.
*/ if (addext && ~extsmap) { /* a free extent has been found. determine *theextentnumber.
*/
rem = diFindFree(extsmap, 0);
extno = (sword << L2EXTSPERSUM) + rem;
/* allocate an extent of free inodes.
*/ if ((rc = diNewExt(imap, iagp, extno))) { /* if there is no disk space for a *newextent,trytoallocatethe *diskinodefromsomewhereelse.
*/ if (rc == -ENOSPC) break;
assert(rc == -EIO);
} else { /* set the results of the allocation *andwritetheiag.
*/
diInitInode(ip, iagno,
extno << L2INOSPEREXT,
extno, iagp);
mark_metapage_dirty(mp);
}
release_metapage(mp); /* free the imap inode & the AG lock & return.
*/
IREAD_UNLOCK(ipimap);
AG_UNLOCK(imap, agno); return (rc);
}
/* move on to the next set of summary map words.
*/
sword = (sword == SMAPSZ - 1) ? 0 : sword + 1;
inosmap = le32_to_cpu(iagp->inosmap[sword]);
extsmap = le32_to_cpu(iagp->extsmap[sword]);
}
} /* unlock imap inode */
IREAD_UNLOCK(ipimap);
/* nothing doing in this iag, so release it. */
release_metapage(mp);
/* get the number of free and the number of backed disk *inodescurrentlywithintheag.
*/
numfree = imap->im_agctl[agno].numfree;
numinos = imap->im_agctl[agno].numinos;
/* determine if we should allocate a new extent of free inodes *withintheag:fordirectoryinodes,addanewextent *ifthereareasmallnumberoffreeinodesornumberoffree *inodesisasmallpercentageofthenumberofbackedinodes.
*/ if (dir)
addext = (numfree < 64 ||
(numfree < 256
&& ((numfree * 100) / numinos) <= 20)); else
addext = (numfree == 0);
/* *trytoallocateanewextentoffreeinodes.
*/ if (addext) { /* if free space is not available for this new extent, try *belowtoallocateafreeandexisting(alreadybacked) *inodefromtheag.
*/ if ((rc = diAllocExt(imap, agno, ip)) != -ENOSPC) return (rc);
}
/* check if there are iags on the ag's free inode list.
*/ if ((iagno = imap->im_agctl[agno].inofree) < 0) return -ENOSPC;
/* obtain read lock on imap inode */
IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP);
/* read the iag at the head of the list.
*/ if ((rc = diIAGRead(imap, iagno, &mp))) {
IREAD_UNLOCK(imap->im_ipimap); return (rc);
}
iagp = (struct iag *) mp->data;
/* better be free inodes in this iag if it is on the *list.
*/ if (!iagp->nfreeinos) {
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
jfs_error(ip->i_sb, "nfreeinos = 0, but iag on freelist\n"); return -EIO;
}
/* scan the free inode summary map to find an extent *withfreeinodes.
*/ for (sword = 0;; sword++) { if (sword >= SMAPSZ) {
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
jfs_error(ip->i_sb, "free inode not found in summary map\n"); return -EIO;
}
if (~iagp->inosmap[sword]) break;
}
/* found a extent with free inodes. determine *theextentnumber.
*/
rem = diFindFree(le32_to_cpu(iagp->inosmap[sword]), 0); if (rem >= EXTSPERSUM) {
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
jfs_error(ip->i_sb, "no free extent found\n"); return -EIO;
}
extno = (sword << L2EXTSPERSUM) + rem;
/* find the first free inode in the extent.
*/
rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), 0); if (rem >= INOSPEREXT) {
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
jfs_error(ip->i_sb, "free inode not found\n"); return -EIO;
}
/* compute the inode number within the iag.
*/
ino = (extno << L2INOSPEREXT) + rem;
/* allocate the inode.
*/
rc = diAllocBit(imap, iagp, ino);
IREAD_UNLOCK(imap->im_ipimap); if (rc) {
release_metapage(mp); return (rc);
}
/* set the results of the allocation and write the iag.
*/
diInitInode(ip, iagno, ino, extno, iagp);
write_metapage(mp);
/* check if the ag has any iags with free extents. if not, *allocateanewiagfortheag.
*/ if ((iagno = imap->im_agctl[agno].extfree) < 0) { /* If successful, diNewIAG will obtain the read lock on the *imapinode.
*/ if ((rc = diNewIAG(imap, &iagno, agno, &mp))) { return (rc);
}
iagp = (struct iag *) mp->data;
/* set the ag number if this a brand new iag
*/
iagp->agstart =
cpu_to_le64(AGTOBLK(agno, imap->im_ipimap));
} else { /* read the iag.
*/
IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP); if ((rc = diIAGRead(imap, iagno, &mp))) {
IREAD_UNLOCK(imap->im_ipimap);
jfs_error(ip->i_sb, "error reading iag\n"); return rc;
}
iagp = (struct iag *) mp->data;
}
/* using the free extent summary map, find a free extent.
*/ for (sword = 0;; sword++) { if (sword >= SMAPSZ) {
release_metapage(mp);
IREAD_UNLOCK(imap->im_ipimap);
jfs_error(ip->i_sb, "free ext summary map not found\n"); return -EIO;
} if (~iagp->extsmap[sword]) break;
}
/* determine the extent number of the free extent.
*/
rem = diFindFree(le32_to_cpu(iagp->extsmap[sword]), 0); if (rem >= EXTSPERSUM) {
release_metapage(mp);
IREAD_UNLOCK(imap->im_ipimap);
jfs_error(ip->i_sb, "free extent not found\n"); return -EIO;
}
extno = (sword << L2EXTSPERSUM) + rem;
/* initialize the new extent.
*/
rc = diNewExt(imap, iagp, extno);
IREAD_UNLOCK(imap->im_ipimap); if (rc) { /* something bad happened. if a new iag was allocated, *placeitbackontheinodemap'siagfreelist,and *cleartheagnumberinformation.
*/ if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
IAGFREE_LOCK(imap);
iagp->iagfree = cpu_to_le32(imap->im_freeiag);
imap->im_freeiag = iagno;
IAGFREE_UNLOCK(imap);
}
write_metapage(mp); return (rc);
}
/* set the results of the allocation and write the iag.
*/
diInitInode(ip, iagno, extno << L2INOSPEREXT, extno, iagp);
/* check if this is the last free inode within the iag. *ifso,itwillhavetoberemovedfromtheagfree *inodelist,sogettheiagsprecedingandfollowing *itonthelist.
*/ if (iagp->nfreeinos == cpu_to_le32(1)) { if ((int) le32_to_cpu(iagp->inofreefwd) >= 0) { if ((rc =
diIAGRead(imap, le32_to_cpu(iagp->inofreefwd),
&))) return (rc);
aiagp = (struct iag *) amp->data;
}
if ((int) le32_to_cpu(iagp->inofreeback) >= 0) { if ((rc =
diIAGRead(imap,
le32_to_cpu(iagp->inofreeback),
&bmp))) { if (amp)
release_metapage(amp); return (rc);
}
biagp = (struct iag *) bmp->data;
}
}
/* get the ag number, extent number, inode number within *theextent.
*/
agno = BLKTOAG(le64_to_cpu(iagp->agstart), JFS_SBI(imap->im_ipimap->i_sb));
extno = ino >> L2INOSPEREXT;
bitno = ino & (INOSPEREXT - 1);
/* compute the mask for setting the map.
*/
mask = HIGHORDER >> bitno;
/* the inode should be free and backed.
*/ if (((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) ||
((le32_to_cpu(iagp->wmap[extno]) & mask) != 0) ||
(addressPXD(&iagp->inoext[extno]) == 0)) { if (amp)
release_metapage(amp); if (bmp)
release_metapage(bmp);
/* mark the inode as allocated in the working map.
*/
iagp->wmap[extno] |= cpu_to_le32(mask);
/* check if all inodes within the extent are now *allocated.ifso,updatethefreeinodesummary *maptoreflectthis.
*/ if (iagp->wmap[extno] == cpu_to_le32(ONES)) {
sword = extno >> L2EXTSPERSUM;
bitno = extno & (EXTSPERSUM - 1);
iagp->inosmap[sword] |= cpu_to_le32(HIGHORDER >> bitno);
}
/* if this was the last free inode in the iag, remove the *iagfromtheagfreeinodelist.
*/ if (iagp->nfreeinos == cpu_to_le32(1)) { if (amp) {
aiagp->inofreeback = iagp->inofreeback;
write_metapage(amp);
}
/* better have free extents.
*/ if (!iagp->nfreeexts) {
jfs_error(imap->im_ipimap->i_sb, "no free extents\n"); return -EIO;
}
/* get the inode map inode.
*/
ipimap = imap->im_ipimap;
sbi = JFS_SBI(ipimap->i_sb);
amp = bmp = cmp = NULL;
/* get the ag and iag numbers for this iag.
*/
agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi); if (agno >= MAXAG || agno < 0) return -EIO;
iagno = le32_to_cpu(iagp->iagnum);
/* check if this is the last free extent within the *iag.ifso,theiagmustberemovedfromtheag *freeextentlist,sogettheiagsprecedingand *followingtheiagonthislist.
*/ if (iagp->nfreeexts == cpu_to_le32(1)) { if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) { if ((rc = diIAGRead(imap, fwd, &))) return (rc);
aiagp = (struct iag *) amp->data;
}
if ((back = le32_to_cpu(iagp->extfreeback)) >= 0) { if ((rc = diIAGRead(imap, back, &bmp))) goto error_out;
biagp = (struct iag *) bmp->data;
}
} else { /* the iag has free extents. if all extents are free *(asisthecaseforanewlyallocatediag),theiag *mustbeaddedtotheagfreeextentlist,soget *theiagattheheadofthelistinpreparationfor *addingthisiagtothislist.
*/
fwd = back = -1; if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) { if ((fwd = imap->im_agctl[agno].extfree) >= 0) { if ((rc = diIAGRead(imap, fwd, &))) goto error_out;
aiagp = (struct iag *) amp->data;
}
}
}
/* check if the iag has no free inodes. if so, the iag *willhavetobeaddedtotheagfreeinodelist,soget *theiagattheheadofthelistinpreparationfor *addingthisiagtothislist.indoingthis,wemust *checkifwealreadyhavetheiagattheheadof *thelistinhand.
*/ if (iagp->nfreeinos == 0) {
freei = imap->im_agctl[agno].inofree;
/* allocate disk space for the inode extent.
*/ if ((extno == 0) || (addressPXD(&iagp->inoext[extno - 1]) == 0))
hint = ((s64) agno << sbi->bmap->db_agl2size) - 1; else
hint = addressPXD(&iagp->inoext[extno - 1]) +
lengthPXD(&iagp->inoext[extno - 1]) - 1;
if ((rc = dbAlloc(ipimap, hint, (s64) imap->im_nbperiext, &blkno))) goto error_out;
/* compute the inode number of the first inode within the *extent.
*/
ino = (iagno << L2INOSPERIAG) + (extno << L2INOSPEREXT);
/* initialize the inodes within the newly allocated extent a *pageatatime.
*/ for (i = 0; i < imap->im_nbperiext; i += sbi->nbperpage) { /* get a buffer for this page of disk inodes.
*/
dmp = get_metapage(ipimap, blkno + i, PSIZE, 1); if (dmp == NULL) {
rc = -EIO; goto error_out;
}
dp = (struct dinode *) dmp->data;
/* if this is the last free extent within the iag, remove the *iagfromtheagfreeextentlist.
*/ if (iagp->nfreeexts == cpu_to_le32(1)) { if (fwd >= 0)
aiagp->extfreeback = iagp->extfreeback;
/* if the iag has no free inodes, add the iag to the *agfreeinodelist.
*/ if (iagp->nfreeinos == 0) { if (freei >= 0)
ciagp->inofreeback = cpu_to_le32(iagno);
/* initialize the extent descriptor of the extent. */
PXDlength(&iagp->inoext[extno], imap->im_nbperiext);
PXDaddress(&iagp->inoext[extno], blkno);
/* initialize the working and persistent map of the extent. *theworkingmapwillbeinitializedsuchthat *itindicatesthefirstinodeoftheextentisallocated.
*/
iagp->wmap[extno] = cpu_to_le32(HIGHORDER);
iagp->pmap[extno] = 0;
/* update the free inode and free extent counts for the *iag.
*/
le32_add_cpu(&iagp->nfreeinos, (INOSPEREXT - 1));
le32_add_cpu(&iagp->nfreeexts, -1);
/* update the free and backed inode counts for the ag.
*/
imap->im_agctl[agno].numfree += (INOSPEREXT - 1);
imap->im_agctl[agno].numinos += INOSPEREXT;
/* update the free and backed inode counts for the inode map.
*/
atomic_add(INOSPEREXT - 1, &imap->im_numfree);
atomic_add(INOSPEREXT, &imap->im_numinos);
/* write the iags.
*/ if (amp)
write_metapage(amp); if (bmp)
write_metapage(bmp); if (cmp)
write_metapage(cmp);
return (0);
error_out:
/* release the iags.
*/ if (amp)
release_metapage(amp); if (bmp)
release_metapage(bmp); if (cmp)
release_metapage(cmp);
/* pick up pointers to the inode map and mount inodes */
ipimap = imap->im_ipimap;
sb = ipimap->i_sb;
sbi = JFS_SBI(sb);
/* acquire the free iag lock */
IAGFREE_LOCK(imap);
/* if there are any iags on the inode map free iag list, *allocatetheiagfromtheheadofthelist.
*/ if (imap->im_freeiag >= 0) { /* pick up the iag number at the head of the list */
iagno = imap->im_freeiag;
/* determine the logical block number of the iag */
blkno = IAGTOLBLK(iagno, sbi->l2nbperpage);
} else { /* no free iags. the inode map will have to be extented *toincludeanewiag.
*/
if (ipimap->i_size >> L2PSIZE != imap->im_nextiag + 1) {
IWRITE_UNLOCK(ipimap);
IAGFREE_UNLOCK(imap);
jfs_error(imap->im_ipimap->i_sb, "ipimap->i_size is wrong\n"); return -EIO;
}
/* get the next available iag number */
iagno = imap->im_nextiag;
/* make sure that we have not exceeded the maximum inode *numberlimit.
*/ if (iagno > (MAXIAGS - 1)) { /* release the inode map lock */
IWRITE_UNLOCK(ipimap);
rc = -ENOSPC; goto out;
}
/* *synchronouslyappendnewiagpage.
*/ /* determine the logical address of iag page to append */
blkno = IAGTOLBLK(iagno, sbi->l2nbperpage);
/* Allocate extent for new iag page */
xlen = sbi->nbperpage; if ((rc = dbAlloc(ipimap, 0, (s64) xlen, &xaddr))) { /* release the inode map lock */
IWRITE_UNLOCK(ipimap);
goto out;
}
/* *starttransactionofupdateoftheinodemap *addressingstructurepointingtothenewiagpage;
*/
tid = txBegin(sb, COMMIT_FORCE);
mutex_lock(&JFS_IP(ipimap)->commit_mutex);
/* update the inode map addressing structure to point to it */ if ((rc =
xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
txEnd(tid);
mutex_unlock(&JFS_IP(ipimap)->commit_mutex); /* Free the blocks allocated for the iag since it was *notsuccessfullyaddedtotheinodemap
*/
dbFree(ipimap, xaddr, (s64) xlen);
/* release the inode map lock */
IWRITE_UNLOCK(ipimap);
goto out;
}
/* update the inode map's inode to reflect the extension */
ipimap->i_size += PSIZE;
inode_add_bytes(ipimap, PSIZE);
/* assign a buffer for the page */
mp = get_metapage(ipimap, blkno, PSIZE, 0); if (!mp) { /* *Thisisveryunlikelysincewejustcreatedthe *extent,butlet'strytohandleitcorrectly
*/
xtTruncate(tid, ipimap, ipimap->i_size - PSIZE,
COMMIT_PWMAP);
/* compute the logical block number of the iag. */
blkno = IAGTOLBLK(iagno, JFS_SBI(ipimap->i_sb)->l2nbperpage);
/* read the iag. */
*mpp = read_metapage(ipimap, blkno, PSIZE, 0); if (*mpp == NULL) { return -EIO;
}
return (0);
}
/* *NAME:diFindFree() * *FUNCTION:findthefirstfreebitinawordstartingat *thespecifiedbitposition. * *PARAMETERS: *word-wordtobeexamined. *start-startingbitposition. * *RETURNVALUES: *bitpositionoffirstfreebitinthewordor32if *nofreebitswerefound.
*/ staticint diFindFree(u32 word, int start)
{ int bitno;
assert(start < 32); /* scan the word for the first free bit. */ for (word <<= start, bitno = start; bitno < 32;
bitno++, word <<= 1) { if ((word & HIGHORDER) == 0) break;
} return (bitno);
}
imap = JFS_IP(ipimap)->i_imap; /* get the iag number containing the inode */
iagno = INOTOIAG(inum); /* make sure that the iag is contained within the map */ if (iagno >= imap->im_nextiag) {
jfs_error(ipimap->i_sb, "the iag is outside the map\n"); return -EIO;
} /* read the iag */
IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
rc = diIAGRead(imap, iagno, &mp);
IREAD_UNLOCK(ipimap); if (rc) return (rc);
metapage_wait_for_io(mp);
iagp = (struct iag *) mp->data; /* get the inode number and extent number of the inode within *theiagandtheinodenumberwithintheextent.
*/
ino = inum & (INOSPERIAG - 1);
extno = ino >> L2INOSPEREXT;
bitno = ino & (INOSPEREXT - 1);
mask = HIGHORDER >> bitno; /* *marktheinodefreeinpersistentmap:
*/ if (is_free) { /* The inode should have been allocated both in working *mapandinpersistentmap; *theinodewillbefreedfromworkingmapattherelease *oflastreferencerelease;
*/ if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
jfs_error(ipimap->i_sb, "inode %ld not marked as allocated in wmap!\n",
inum);
} if (!(le32_to_cpu(iagp->pmap[extno]) & mask)) {
jfs_error(ipimap->i_sb, "inode %ld not marked as allocated in pmap!\n",
inum);
} /* update the bitmap for the extent of the freed inode */
iagp->pmap[extno] &= cpu_to_le32(~mask);
} /* *marktheinodeallocatedinpersistentmap:
*/ else { /* The inode should be already allocated in the working map *andshouldbefreeinpersistentmap;
*/ if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
release_metapage(mp);
jfs_error(ipimap->i_sb, "the inode is not allocated in the working map\n"); return -EIO;
} if ((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) {
release_metapage(mp);
jfs_error(ipimap->i_sb, "the inode is not free in the persistent map\n"); return -EIO;
} /* update the bitmap for the extent of the allocated inode */
iagp->pmap[extno] |= cpu_to_le32(mask);
} /* *updateiaglsn
*/
lsn = tblk->lsn;
log = JFS_SBI(tblk->sb)->log;
LOGSYNC_LOCK(log, flags); if (mp->lsn != 0) { /* inherit older/smaller lsn */
logdiff(difft, lsn, log);
logdiff(diffp, mp->lsn, log); if (difft < diffp) {
mp->lsn = lsn; /* move mp after tblock in logsync list */
list_move(&mp->synclist, &tblk->synclist);
} /* inherit younger/larger clsn */
assert(mp->clsn);
logdiff(difft, tblk->clsn, log);
logdiff(diffp, mp->clsn, log); if (difft > diffp)
mp->clsn = tblk->clsn;
} else {
mp->log = log;
mp->lsn = lsn; /* insert mp after tblock in logsync list */
log->count++;
list_add(&mp->synclist, &tblk->synclist);
mp->clsn = tblk->clsn;
}
LOGSYNC_UNLOCK(log, flags);
write_metapage(mp); return (0);
}
/* *diExtendFS() * *function:updateimapforextendfs(); * *note:AGsizehasbeenincreaseds.t.eachkoldcontiguousAGsare *coalescedintoanewAG;
*/ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
{ int rc, rcx = 0; struct inomap *imap = JFS_IP(ipimap)->i_imap; struct iag *iagp = NULL, *hiagp = NULL; struct bmap *mp = JFS_SBI(ipbmap->i_sb)->bmap; struct metapage *bp, *hbp; int i, n, head; int numinos, xnuminos = 0, xnumfree = 0;
s64 agstart;
/* init per AG control information im_agctl[] */ for (i = 0; i < MAXAG; i++) {
imap->im_agctl[i].inofree = -1;
imap->im_agctl[i].extfree = -1;
imap->im_agctl[i].numinos = 0; /* number of backed inodes */
imap->im_agctl[i].numfree = 0; /* number of free backed inodes */
}
/* *processeachiagpageofthemap. * *rebuildAGFreeInodeList,AGFreeInodeExtentList;
*/ for (i = 0; i < imap->im_nextiag; i++) { if ((rc = diIAGRead(imap, i, &bp))) {
rcx = rc; continue;
}
iagp = (struct iag *) bp->data; if (le32_to_cpu(iagp->iagnum) != i) {
release_metapage(bp);
jfs_error(ipimap->i_sb, "unexpected value of iagnum\n"); return -EIO;
}
/* leave free iag in the free iag list */ if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
release_metapage(bp); continue;
}
/* if AIT2 ipmap2 is bad, do not try to update it */ if (JFS_SBI(sb)->mntflag & JFS_BAD_SAIT) /* s_flag */ return;
ip = diReadSpecial(sb, FILESYSTEM_I, 1); if (ip == NULL) {
JFS_SBI(sb)->mntflag |= JFS_BAD_SAIT; if (readSuper(sb, &bh)) return;
j_sb = (struct jfs_superblock *)bh->b_data;
j_sb->s_flag |= cpu_to_le32(JFS_BAD_SAIT);
switch (fileset) { case AGGR_RESERVED_I: case AGGREGATE_I: case BMAP_I: case LOG_I: case BADBLOCK_I: case FILESYSTEM_I: break; default: return -EINVAL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.