void walk_internal_page(int device, uint64 block, uint32 length, int64 *total_nblocks, int32 flag) { int rc; xtpage_t xtree_page; int32 lastindex, index; uint64 first_block, cur_block, last_block; uint32 cur_length; int32 leafbad; /* * Read the internal page */ rc = ujfs_rw_diskblocks( device, block << sb.s_l2bsize, length << sb.s_l2bsize, &xtree_page, GET ); /* * Mark the blocks for the page; if internal page walk down page */ leafbad = (xtree_page.header.flag & BT_LEAF) ? flag : 0; lastindex = xtree_page.header.nextindex; for( index = XTENTRYSTART; index < lastindex; index++ ) { /* * This is actual data of the inode, mark these blocks */ first_block = addressXAD( &(xtree_page.xad[index]) ); cur_length = lengthXAD( &(xtree_page.xad[index]) ); *total_nblocks += cur_length; last_block = first_block + cur_length; for( cur_block = first_block; cur_block < last_block; cur_block++ ) { markit( cur_block, leafbad ); } if( xtree_page.header.flag & BT_INTERNAL ) { /* * This is an internal page of the b-tree. Walk the page. */ walk_internal_page(device, first_block, cur_length, total_nblocks, flag); } } }
void walk_internal_iag( int device, xad_t *top_page, boolean_t is_primary, dinomap_t *control_page, dinomap_t *disk_cp, struct list_item **top_iagfree, struct list_item **top_inofree, struct list_item **top_extfree, int32 inostamp ) { int32 rc, index, lastindex; uint64 block; uint32 length; xtpage_t xtree_page; block = addressXAD(top_page); length = lengthXAD(top_page); rc = ujfs_rw_diskblocks( device, block << sb.s_l2bsize, length << sb.s_l2bsize, &xtree_page, GET ); /* * Walk the IAG page unless this is another internal page, then we need to * walk it as an internal page again. */ lastindex = xtree_page.header.nextindex; for( index = XTENTRYSTART; index < lastindex; index++ ) { if( xtree_page.header.flag & BT_LEAF ) { walk_iag_extent( device, &(xtree_page.xad[index]), is_primary, control_page, disk_cp, top_iagfree, top_inofree, top_extfree, inostamp ); } else { walk_internal_iag( device, &(xtree_page.xad[index]), is_primary, control_page, disk_cp, top_iagfree, top_inofree, top_extfree, inostamp ); } } }
void walk_inode_tree(int device, xtpage_t *inode_root, int64 *total_nblocks, int32 flag) { int32 index, lastindex; uint64 first_block, cur_block, last_block; uint32 length; int32 leafbad; /* * Have root of inode btree. Walk tree marking all blocks allocated. */ leafbad = (inode_root->header.flag & BT_LEAF) ? flag : 0; lastindex = inode_root->header.nextindex; for( index = XTENTRYSTART; index < lastindex; index++ ) { /* * This is actual data of the inode, mark these blocks */ first_block = addressXAD( &(inode_root->xad[index]) ); length = lengthXAD( &(inode_root->xad[index]) ); *total_nblocks += length; last_block = first_block + length; for( cur_block = first_block; cur_block < last_block; cur_block++ ) { markit( cur_block, leafbad ); } if( inode_root->header.flag & BT_INTERNAL ) { /* * This is an internal page of the b-tree. Walk the page. */ walk_internal_page(device, first_block, length, total_nblocks, flag); } } }
int jfs_get_block(struct inode *ip, sector_t lblock, struct buffer_head *bh_result, int create) { s64 lblock64 = lblock; int rc = 0; xad_t xad; s64 xaddr; int xflag; s32 xlen = bh_result->b_size >> ip->i_blkbits; /* * Take appropriate lock on inode */ if (create) IWRITE_LOCK(ip, RDWRLOCK_NORMAL); else IREAD_LOCK(ip, RDWRLOCK_NORMAL); if (((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size) && (!xtLookup(ip, lblock64, xlen, &xflag, &xaddr, &xlen, 0)) && xaddr) { if (xflag & XAD_NOTRECORDED) { if (!create) /* * Allocated but not recorded, read treats * this as a hole */ goto unlock; #ifdef _JFS_4K XADoffset(&xad, lblock64); XADlength(&xad, xlen); XADaddress(&xad, xaddr); #else /* _JFS_4K */ /* * As long as block size = 4K, this isn't a problem. * We should mark the whole page not ABNR, but how * will we know to mark the other blocks BH_New? */ BUG(); #endif /* _JFS_4K */ rc = extRecord(ip, &xad); if (rc) goto unlock; set_buffer_new(bh_result); } map_bh(bh_result, ip->i_sb, xaddr); bh_result->b_size = xlen << ip->i_blkbits; goto unlock; } if (!create) goto unlock; /* * Allocate a new block */ #ifdef _JFS_4K if ((rc = extHint(ip, lblock64 << ip->i_sb->s_blocksize_bits, &xad))) goto unlock; rc = extAlloc(ip, xlen, lblock64, &xad, false); if (rc) goto unlock; set_buffer_new(bh_result); map_bh(bh_result, ip->i_sb, addressXAD(&xad)); bh_result->b_size = lengthXAD(&xad) << ip->i_blkbits; #else /* _JFS_4K */ /* * We need to do whatever it takes to keep all but the last buffers * in 4K pages - see jfs_write.c */ BUG(); #endif /* _JFS_4K */ unlock: /* * Release lock on inode */ if (create) IWRITE_UNLOCK(ip); else IREAD_UNLOCK(ip); return rc; }
static int jfs_get_blocks(struct inode *ip, sector_t lblock, unsigned long max_blocks, struct buffer_head *bh_result, int create) { s64 lblock64 = lblock; int no_size_check = 0; int rc = 0; int take_locks; xad_t xad; s64 xaddr; int xflag; s32 xlen; /* * If this is a special inode (imap, dmap) or directory, * the lock should already be taken */ take_locks = ((JFS_IP(ip)->fileset != AGGREGATE_I) && !S_ISDIR(ip->i_mode)); /* * Take appropriate lock on inode */ if (take_locks) { if (create) IWRITE_LOCK(ip); else IREAD_LOCK(ip); } /* * A directory's "data" is the inode index table, but i_size is the * size of the d-tree, so don't check the offset against i_size */ if (S_ISDIR(ip->i_mode)) no_size_check = 1; if ((no_size_check || ((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size)) && (xtLookup(ip, lblock64, max_blocks, &xflag, &xaddr, &xlen, no_size_check) == 0) && xlen) { if (xflag & XAD_NOTRECORDED) { if (!create) /* * Allocated but not recorded, read treats * this as a hole */ goto unlock; #ifdef _JFS_4K XADoffset(&xad, lblock64); XADlength(&xad, xlen); XADaddress(&xad, xaddr); #else /* _JFS_4K */ /* * As long as block size = 4K, this isn't a problem. * We should mark the whole page not ABNR, but how * will we know to mark the other blocks BH_New? */ BUG(); #endif /* _JFS_4K */ rc = extRecord(ip, &xad); if (rc) goto unlock; set_buffer_new(bh_result); } map_bh(bh_result, ip->i_sb, xaddr); bh_result->b_size = xlen << ip->i_blkbits; goto unlock; } if (!create) goto unlock; /* * Allocate a new block */ #ifdef _JFS_4K if ((rc = extHint(ip, lblock64 << ip->i_sb->s_blocksize_bits, &xad))) goto unlock; rc = extAlloc(ip, max_blocks, lblock64, &xad, FALSE); if (rc) goto unlock; set_buffer_new(bh_result); map_bh(bh_result, ip->i_sb, addressXAD(&xad)); bh_result->b_size = lengthXAD(&xad) << ip->i_blkbits; #else /* _JFS_4K */ /* * We need to do whatever it takes to keep all but the last buffers * in 4K pages - see jfs_write.c */ BUG(); #endif /* _JFS_4K */ unlock: /* * Release lock on inode */ if (take_locks) { if (create) IWRITE_UNLOCK(ip); else IREAD_UNLOCK(ip); } return rc; }
/**************************************************************************** * NAME: process_Inode_Xtree * * FUNCTION: Traverse the xtree of the given inode looking for * allocated extents containing bad blocks. * * PARAMETERS: * dip ptr to the owning disk inode in a buffer * * doRelocate 0 => this is not the JFS Bad Block inode * !0 => this is the JFS Bad Block inode * * NOTES: * * RETURNS: * success: 0 * failure: something else */ int32 process_Inode_Xtree( dinode_t *dip, int8 doRelocate ) { int32 pix_rc = 0; int32 relocate_rc; xtpage_t *p; int32 xlen, i; int64 xaddr, xoff, xlastblk; int8 didRelocate = 0; int32 xtype; cbbl_bdblk_recptr bdblk_recptr = NULL; int32 pList; ULONG pListLen = 0; clrbblks_t pData; ULONG pDataLen = 0; int64 lmxaddr; /* address of left-most child */ xtpage_t next_xtpg; /* next xtpage to work on for the inode */ xtpage_t *pnext_xtpg; int32 nxtpg_inx; /* the next index in next_xtpg to work on */ /* * we start with the root */ pnext_xtpg = p = (xtpage_t *)&dip->di_btroot; if (p->header.flag & BT_LEAF) { xtype = DATAEXT; } else { xtype = XTPAGE; p->header.next = 0; /* * save leftmost child xtpage xaddr */ lmxaddr = addressXAD(&p->xad[XTENTRYSTART]); } nxtpg_inx = XTENTRYSTART; /* * scan each level of xtree */ while(1) { /* * scan each xtpage of current level of xtree */ while(1) { /* * scan each xad in current xtpage */ for (i = nxtpg_inx; i < p->header.nextindex; i++) { /* * does the extent contain at least 1 * bad block? */ xoff = offsetXAD(&p->xad[i]); xaddr = addressXAD(&p->xad[i]) ; xlen = lengthXAD(&p->xad[i]) ; pix_rc = baltree_search( xaddr, &bdblk_recptr ); if( pix_rc != 0 ) { /* something fatal on search */ return( pix_rc ); } else if( bdblk_recptr == NULL ) { /* hit end of tree w/o match */ continue; } /* end hit end of tree w/o match */ xlastblk = xaddr + xlen - 1; if( bdblk_recptr->fs_blkno <= xlastblk ) { /* * the extent contains at least 1 bad block */ #ifdef _JFS_DEBUG printf("bad block 0x0%llx found in xtree for inode %d\n", bdblk_recptr->fs_blkno, dip->di_number ); #endif if( !doRelocate ) { /* relocation not requested */ pix_rc = we_DidntTryTo_Relocate( xaddr, xlastblk, bdblk_recptr ); } /* end relocation not requested */ else { /* relocation is requested */ pDataLen = sizeof(clrbblks_t); pData.flag = CLRBBLKS_RELOCATE | IFREG | xtype; //PS24072004 pData.dev = lvMount->LVNumber; pData.dev = LVNumber; pData.fileset = dip->di_fileset; pData.inostamp = dip->di_inostamp; pData.ino = dip->di_number; pData.gen = dip->di_gen; pData.xoff = xoff; /* offset within the file */ pData.old_xaddr = xaddr; pData.new_xaddr = 0; pData.xlen = xlen; pData.agg_blksize = agg_recptr->fs_blksize; /* * attempt to relocate the extent */ didRelocate = 0; relocate_rc = fscntl( JFSCTL_CLRBBLKS, (void *)&pList, &pListLen, (void *)&pData, &pDataLen ); if( (relocate_rc == 0) && (pData.new_xaddr != 0) ) { /* * extent has been relocated */ didRelocate = -1; } /* end extent has been relocated */ /* * Now handle the individual bad block(s) * in the extent */ if( didRelocate ) { /* * actually did relocate */ pix_rc = we_Did_Relocate( xaddr, xlastblk, bdblk_recptr ); } /* end actually did relocate */ else { /* tried but failed to relocate */ pix_rc = we_Couldnt_Relocate( xaddr, xlastblk, bdblk_recptr, relocate_rc ); } /* end else tried but failed to relocate */ } /* end else relocation is requested */ } /* end the extent contains at least 1 bad block */ } /* end for current xtpage scan */ /* * read in next/right sibling xtpage */ if (p->header.next != 0) { xaddr = p->header.next; pix_rc = pRead(fsMount, xaddr, fsMount->nbperpage, &next_xtpg); if ( pix_rc != 0 ) { return CBBL_CANTREADNEXTXTPG; /* i/o error */ } pnext_xtpg = p = &next_xtpg; nxtpg_inx = XTENTRYSTART; } else break; } /* end while current level scan */ /* * descend: read leftmost xtpage of next * lower level of xtree */ if (xtype == XTPAGE) { /* * get the leftmost child page */ pix_rc = pRead(fsMount, lmxaddr, fsMount->nbperpage, &next_xtpg); if ( pix_rc != 0 ) { return CBBL_CANTREADLMXTCHILD; /* i/o error */ } pnext_xtpg = p = &next_xtpg; nxtpg_inx = XTENTRYSTART; if (p->header.flag & BT_LEAF) { xtype = DATAEXT; } else { xtype = XTPAGE; /* * save leftmost child xtpage xaddr */ lmxaddr = addressXAD(&p->xad[XTENTRYSTART]); } } /* end xtype == XTPAGE */ else break; } /* end while level scan */ /* * this inode is done: reset variables */ pnext_xtpg = NULL; return 0; } /* end process_Inode_Xtree() */
/* * Read the specified extent as an extent of IAG's * If its offset is 0 skip the first page since this is a control page. * For all other IAGs need to mark blocks: * - mark the blocks for any allocated extents for the IAG * - read the extent and mark blocks for any allocated inodes * Note: the blocks owned by the table itself will be marked when the inode for * the table is seen. */ void walk_iag_extent( int device, xad_t *extent, boolean_t is_primary, dinomap_t *control_page, dinomap_t *disk_cp, struct list_item **top_iagfree, struct list_item **top_inofree, struct list_item **top_extfree, int32 inostamp ) { uint64 offset, address, count, end; uint32 length, page_length; iag_t iag_buffer; int32 index, rc, extdx; pxd_t *inoext_ptr; uint32 map, found_map; uint32 agno; ino_t start_inum; uint32 mymap[EXTSPERIAG]; int16 seen_extent = 0, free_inodes = 0; offset = offsetXAD( extent ); address = addressXAD( extent ); length = lengthXAD( extent ); page_length = PSIZE >> sb.s_l2bsize; if( offset == 0 ) { /* * Read in the disk control page now. We will compare it after all the * other pages of the map have been processed. */ rc = ujfs_rw_diskblocks( device, address << sb.s_l2bsize, sizeof(dinomap_t), disk_cp, GET ); if( rc != 0 ) exit(rc); address += page_length; length -= page_length; } while( length > 0 ) { /* * Clear map to use for tracking inodes seen */ memset( mymap, 0, EXTSPERIAG * sizeof(uint32)); /* * Read next IAG */ rc = ujfs_rw_diskblocks( device, address << sb.s_l2bsize, PSIZE, &iag_buffer, GET ); if( rc != 0 ) exit(rc); length -= page_length; address += page_length; control_page->in_nextiag = iag_buffer.iagnum + 1; if( iag_buffer.iagfree != -1 ) { /* * We have an item on the iagfree list following this one. */ rc = search_and_add(top_iagfree, iag_buffer.iagfree, DISK_LIST); if( rc != 0 ) { printf("Bad iagfree item on-disk: %d\n", iag_buffer.iagfree); } } agno = iag_buffer.agstart / sb.s_agsize; if( iag_buffer.extfreefwd != -1 ) { /* * We have an item on the extfree list following this one. */ rc = search_and_add(&(top_extfree[agno]), iag_buffer.extfreefwd, DISK_LIST); if( rc != 0 ) { printf("Bad extfree[%d] item on-disk: %d\n", agno, iag_buffer.extfreefwd); } } if( iag_buffer.inofreefwd != -1 ) { /* * We have an item on the inofree list following this one. */ rc = search_and_add(&(top_inofree[agno]), iag_buffer.inofreefwd, DISK_LIST); if( rc != 0 ) { printf("Bad inofree[%d] item on-disk: %d\n", agno, iag_buffer.inofreefwd); } } /* * Mark blocks for any allocated inode extents */ for( index = 0; index < SMAPSZ; index++ ) { map = iag_buffer.extsmap[index]; inoext_ptr = iag_buffer.inoext + (index * EXTSPERSUM); for( extdx = 0; extdx < EXTSPERSUM, map != 0; extdx++, map <<= 1) { if( (map & HIGHORDER) != 0 ) { seen_extent++; /* * Count inodes for allocated inode extents */ control_page->in_numinos += NUM_INODE_PER_EXTENT; control_page->in_agctl[agno].numinos += NUM_INODE_PER_EXTENT; address = count = addressPXD(inoext_ptr + extdx); end = count + inoext_ptr[extdx].len; for( ; count < end; count++) { markit( count, 0 ); } if( is_primary == TRUE ) { /* * Now need to read inodes and mark blocks for them * Only do this for the primary inode table */ start_inum = (iag_buffer.iagnum << L2INOSPERIAG) + (index << (L2EXTSPERSUM + L2INOSPEREXT)) + (extdx << L2INOSPEREXT); walk_inoext( device, address, inoext_ptr[extdx].len, iag_buffer.wmap[(index * EXTSPERSUM) + extdx], control_page, agno, start_inum, &found_map, inostamp ); mymap[(index * EXTSPERSUM) + extdx] = found_map; if( ~found_map != 0 ) free_inodes = 1; } } } } if( seen_extent == 0 ) { /* * No extents for this IAG, add it to iagfree list */ rc = search_and_add(top_iagfree, iag_buffer.iagnum, FOUND_LIST); if( rc != 0 ) { printf("Bad iagfree item found: %d\n", iag_buffer.iagnum); } } else if( seen_extent != EXTSPERIAG ) { /* * Have free extents in this IAG, add to AG free extent list */ rc = search_and_add(&(top_extfree[agno]), iag_buffer.iagnum, FOUND_LIST); if( rc != 0 ) { printf("Bad extfree[%d] item found: %d\n", agno, iag_buffer.iagnum); } } if( free_inodes != 0 ) { /* * We have some free inodes in the extent */ rc = search_and_add(&(top_inofree[agno]), iag_buffer.iagnum, FOUND_LIST); if( rc != 0 ) { printf("Bad inofree[%d] item found: %d\n", agno, iag_buffer.iagnum); } } if( is_primary ) { /* * Compare map found by walking extents to the on-disk version */ rc = memcmp( mymap, iag_buffer.wmap, EXTSPERIAG * sizeof(uint32)); if( rc != 0 ) { error++; printf("Miscompare of inode wmap of IAG %d.\n", iag_buffer.iagnum); print_uint_array ("Found map:", mymap, EXTSPERIAG); print_uint_array ("Disk wmap:", iag_buffer.wmap, EXTSPERIAG); } rc = memcmp( mymap, iag_buffer.pmap, EXTSPERIAG * sizeof(uint32)); if( rc != 0 ) { error++; printf("Miscompare of inode pmap of IAG %d.\n", iag_buffer.iagnum); print_uint_array ("Found map:", mymap, EXTSPERIAG); print_uint_array ("Disk pmap:", iag_buffer.pmap, EXTSPERIAG); } } } }