/**************************************************************************** * NAME: read_cbblfsck_record * * FUNCTION: Copies stats from the clrbblks aggregate record into * the communication area buffer, then writes the buffer * to the device. * * PARAMETERS: none * * NOTES: * * RETURNS: * success: 0 * failure: something else */ int32 read_cbblfsck_record( ) { int32 rcr_rc = 0; rcr_rc = ujfs_rw_diskblocks(LVHandle, cbblfsck_area_byteoff, cbblfsck_area_size, (void *)cbblfsck_recptr, GET); return( rcr_rc ); } /* end read_cbblfsck_record() */
/**************************************************************************** * NAME: write_cbblfsck_record * * FUNCTION: Copies stats from the clrbblks aggregate record into * the communication area buffer, then writes the buffer * to the device. * * PARAMETERS: none * * NOTES: * * RETURNS: * success: 0 * failure: something else */ int32 write_cbblfsck_record( ) { int32 wcr_rc = 0; wcr_rc = ujfs_rw_diskblocks(LVHandle, cbblfsck_area_byteoff, cbblfsck_area_size, (void *)cbblfsck_recptr, PUT); return( wcr_rc ); } /* end write_cbblfsck_record() */
/* * NAME: getLogpage(pno) * * FUNCTION: if the specified log page is in buffer pool, return its * index. Otherwise read log page into buffer pool. * * PARAMETERS: pno - log page number to look for. * * RETURNS: 0 - 3 - index of the buffer pool the page located * REFORMAT_ERROR(-3) - I/O error, reformat the log * MAJOR_ERROR(-2) - other major errors other than EIO. */ int32 getLogpage( int pno) /* page of log */ { int32 k, rc; uint32 actual; /* * is it in buffer pool ? */ for (k = 0; k <= 3; k++) if (logptr[k] == pno) return(k); /* * read page into buffer pool into next slot * don't have to use llseek() here. log dev will never be > 2 gig */ nextrep = (nextrep + 1) % 4; if ( loglocation == INLINELOG ) rc = ujfs_rw_diskblocks( logfd, (uint64)(vopen[logminor].logxaddr+LOGPNTOB(pno)), (unsigned)LOGPSIZE, (char *)&logp[nextrep], GET); else rc = ujfs_rw_diskblocks( logfd, (uint64)LOGPNTOB(pno), (unsigned)LOGPSIZE, (char *)&logp[nextrep], GET); if (rc != 0 ) { return(JLOG_READERROR1); } logptr[nextrep] = pno; return(nextrep); }
/* * NAME: ujfs_put_superblk * * FUNCTION: Write primary or secondary aggregate superblock * * PRE CONDITIONS: * * POST CONDITIONS: * * PARAMETERS: * fd - open port for device to write superblock to * sb - pointer to struct superblock to be written * is_primary - 0 value means we are putting the secondary superblock; * non-zero value means we are putting the primary * superblock. * * NOTES: The sizeof(struct superblock) is less than the amount of disk space * being allowed for the superblock (SIZE_OF_SUPER). This function will * write 0's to the space following the actual superblock structure to fill * the entire allocated disk space. * * RECOVERY OPERATION: * * DATA STRUCTURES: * * RETURNS: * success: 0 * failure: any other value */ int32 ujfs_put_superblk( HFILE fd, struct superblock *sb, int16 is_primary ) { char buf[SIZE_OF_SUPER]; int32 rc; memset( buf, 0, SIZE_OF_SUPER ); memcpy( buf, sb, sizeof(*sb) ); rc = ujfs_rw_diskblocks( fd, (is_primary ? SUPER1_OFF : SUPER2_OFF), SIZE_OF_SUPER, buf, PUT ); return rc; }
void walk_dtree( int device, uint64 block, uint32 length, int64 *total_nblocks) { int rc; dtpage_t dtree_buffer; uint8 *stbl; idtentry_t *cur_entry; uint64 first_block, cur_block, last_block; uint32 cur_length; int32 lastindex, index; int32 thisindex; /* * Read the page from disk */ rc = ujfs_rw_diskblocks( device, block << sb.s_l2bsize, length << sb.s_l2bsize, &dtree_buffer, GET ); if( dtree_buffer.header.flag & BT_LEAF ) { /* * Nothing to do, since the data here is not pointing to blocks */ return; } /* * Mark blocks for each entry and visit that page */ lastindex = dtree_buffer.header.nextindex; stbl = (uint8 *)&(dtree_buffer.slot[dtree_buffer.header.stblindex]); for( index = 0; index < lastindex; index++ ) { /* * This is an internal page of the d-tree. Mark these blocks and * then walk that page */ thisindex = stbl[index]; cur_entry = (idtentry_t *)&(dtree_buffer.slot[thisindex]); first_block = addressPXD( &(cur_entry->xd) ); cur_length = lengthPXD( &(cur_entry->xd) ); *total_nblocks += cur_length; last_block = first_block + cur_length; for( cur_block = first_block; cur_block < last_block; cur_block++ ) { markit( cur_block, 0 ); } walk_dtree( device, first_block, cur_length, total_nblocks); } }
/* * NAME: ujfs_get_superblk * * FUNCTION: read either the primary or secondary superblock from the specified * device * * PRE CONDITIONS: * * POST CONDITIONS: * * PARAMETERS: * fd - open port for device to read superblock from * sb - pointer to struct superblock to be filled in on return * is_primary - 0 indicates to retrieve secondary superblock, * otherwise retrieve primary superblock * * NOTES: * * RECOVERY OPERATION: * * DATA STRUCTURES: * * RETURNS: * success: 0 * failure: any other value */ int32 ujfs_get_superblk( HFILE fd, struct superblock *sb, int32 is_primary) { int32 rc; char buf[SIZE_OF_SUPER]; struct superblock *sblk = (struct superblock *)buf; rc = ujfs_rw_diskblocks( fd, (is_primary ? SUPER1_OFF : SUPER2_OFF), SIZE_OF_SUPER, sblk, GET ); if( rc != 0 ) return rc; memcpy( sb, sblk, sizeof(*sb) ); return 0; }
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 alter() { int64 address; int64 block; uint8 *buffer; uint8 byte; char cmdline[512]; char *hexstring; uint32 hex_length; uint32 length; uint32 offset; char *ptr; char *token; token = strtok(0, " "); if (token == 0) { fputs("alter: Please enter: block offset hex-digits> ", stdout); gets(cmdline); token = strtok(cmdline, " "); if (token == 0) return; } errno = 0; block = strtoull(token, 0, 0); if (block == 0 && errno) { fputs("alter: invalid block\n\n", stderr); return; } address = block << l2bsize; token = strtok(0, " "); if (!token) { fputs("alter: Not enought arguments!\n", stderr); return; } offset = strtoul(token, 0, 16); if (offset == 0 && errno) { fputs("alter: invalid offset\n", stderr); return; } hexstring = strtok(0, " "); if (!hexstring) { fputs("alter: Not enough arguments!\n", stderr); return; } if (strtok(0, " ")) { fputs("alter: Too many arguments!\n", stderr); return; } hex_length = strlen(hexstring); if (hex_length & 1) { /* odd number of hex digits */ fputs("alter: hex string must have even number of digits!\n", stderr); return; } /* Round length of data up to next full physical block */ length = ( offset + hex_length + bsize - 1 ) & ~(bsize - 1); buffer = (char *)malloc(length); if (!buffer) { fputs("alter: malloc failure!\n", stderr); return; } if (ujfs_rw_diskblocks(fd, address, length, buffer, GET)) { fputs("alter: failed reading disk data!\n", stderr); free(buffer); return; } for (ptr = hexstring; *ptr; ptr++) { if (*ptr >= '0' && *ptr <= '9') byte = *ptr - '0'; else if (*ptr >='a' && *ptr <= 'f') byte = *ptr - 'a' + 10; else if (*ptr >='A' && *ptr <= 'F') byte = *ptr - 'A' + 10; else { fputs("alter: invalid hex digit!\n", stderr); free(buffer); return; } ptr++; byte <<= 4; if (*ptr >= '0' && *ptr <= '9') byte += *ptr - '0'; else if (*ptr >='a' && *ptr <= 'f') byte += *ptr - 'a' + 10; else if (*ptr >='A' && *ptr <= 'F') byte += *ptr - 'A' + 10; else { fputs("alter: invalid hex digit!\n", stderr); free(buffer); return; } buffer[offset++] = byte; } if (ujfs_rw_diskblocks(fd, address, length, buffer, PUT)) fputs("alter: failed writing disk data!\n", stderr); free (buffer); return; }
/* * NAME: setLogpage(pno, eor, pmax, buf) * * FUNCTION: Forms consistent log page and returns eor and pmax values. * * During the first release the following conditions are * assumed: * 1) No corrupted write during power failure * 2) No split write * 3) No out-of-order sector write * * If the header and trailer in the page are not equal, a * system crash happened during this page write. It * is reconciled as follows: * * 1) if h.page != t.page, the smaller value is taken and * the eor fields set to LOGPHDSIZE. * reason: This can happen when a old page is over-written * by a new page and the system crashed. So this page * should be considered not written. * 2) if h.eor != t.eor, the smaller value is taken. * reason: The last log page was rewritten for each * commit record. A system crash happened during the * page rewriting. Since we assume that no corrupted write * no split write and out-of-order sector write, the * previous successfuly writing is still good * 3) if no record ends on the page (eor = 8), still return it. * Let the caller determine whether a) a good long log record * ends on the next log page. or b) it is the first page of the * last long log record and system was crashed when its second * page is written. * * * RETURNS: 0 - ok * REFORMAT_ERROR(-3) - I/O error, reformat log * MAJOR_ERROR(-2) - other major error */ setLogpage(int32 pno, /* page number of log */ int32 *eor, /* log header eor to return */ int32 *pmax, /* log header page number to return */ int32 buf) /* logp[] index number for page */ { int32 diff1, diff2, rc; unsigned long actual; /* check that header and trailer are the same */ if ((diff1 = (logp[buf].h.page - logp[buf].t.page)) != 0) { if (diff1 > 0) logp[buf].h.page = logp[buf].t.page; else logp[buf].t.page = logp[buf].h.page; logp[buf].h.eor = logp[buf].t.eor = LOGPHDRSIZE; /* empty page */ } if ((diff2 = (logp[buf].h.eor - logp[buf].t.eor)) != 0) { if (diff2 > 0) logp[buf].h.eor = logp[buf].t.eor; else logp[buf].t.eor = logp[buf].h.eor; } /* if any difference write the page out */ if (diff1 || diff2) { rc = ujfs_rw_diskblocks(logfd, (uint64)(vopen[logminor].logxaddr+LOGPNTOB(pno)), (unsigned long)LOGPSIZE, (char *)&logp[buf], PUT); if ( rc != 0 ) { sprintf( message_parm_0, "(d) %d", pno ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; sprintf( message_parm_1, "(d) %d", rc ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( lrdo_SLPWRITEFAIL, 0, 2 ); return(JLOG_WRITEERROR1); } } /* * At this point, it is still possible that logp[buf].h.eor * is LOGPHDRSIZE, but we return it anyway. The caller will make * decision. */ *eor = logp[buf].h.eor; *pmax = logp[buf].h.page; return (0); }
/* * NAME: jfs_logform * FUNCTION: format file system log * * RETURN: 0 - successful * -1 - error occur * */ int32 jfs_logform( int32 fd, /* for inline log, this is a file descriptor * for an opened device to write log. * for outline log, it is -1 */ int32 aggr_blk_size, /* aggregate block size in bytes */ int32 s_l2bsize, /* log2 of aggregate block size in bytes */ uint32 s_flag, /* fs superblock s_flag is passed in */ int64 log_start, /* offset of the start of inline log in * number of aggr. blocks. for outline log * it is set as zero */ int32 log_len, /* inline log length in number of aggr. blks * for outline log, it is zero */ char * dev_name, /* logical volume of the outline log device * for inline log, it is NULL */ int32 nblks /* size of the outline log in 512 byte blocks * for inline log, it is zero */ ) { ULONG Action; int64 log_len_in_bytes; char parms = 0; unsigned long parmlen = sizeof(parms); ULONG actual; struct DPB dev; unsigned long devlen = sizeof(dev); int32 oflag,logfd,npages,rc,k,dblks,total_blks; char logpages[4 * LOGPSIZE]; logpage_t *logp; /* array of 4 log pages */ static logsuper_t log_sup; struct lrd *lrd_ptr; int64 log_begin; /* the location of the beginning of the log inside * of the file system. ( in bytes ) */ int64 log_contwt; char answer; int16 inlinelog = (s_flag & JFS_INLINELOG ); int Working_counter; char *Working[5]; #define LOGBUFSIZE 4 * LOGPSIZE logp = (logpage_t *) &logpages; Working[0] = " |\r"; Working[1] = " /\r"; Working[2] = " -\r"; Working[3] = " \\\r"; /* * check to see whether standard out has been redirected, and * set the flag accordingly. */ if( (ujfs_stdout_redirected()) != 0 ) { stdout_redirected = 1; } else { stdout_redirected = 0; } /* * if it is an outline log, do device check and open device */ if (!inlinelog ) { /* open the device */ if (DosOpen(dev_name, (unsigned long *)&logfd, &Action, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, 0)) goto errout; fd = logfd; /* * Lock the drive */ rc = DosDevIOCtl(fd, IOCTL_DISK, DSK_LOCKDRIVE, &parms, sizeof(parms), &parmlen, &parms, sizeof(parms), &parmlen); /* * validate/determine device size. * for bringup allow ioctl to fail or to report zero size. */ rc = DosDevIOCtl(fd, IOCTL_DISK, DSK_GETDEVICEPARAMS, &parms, sizeof(parms), &parmlen, &dev, sizeof(dev), &devlen); if (rc == NO_ERROR) { total_blks = dev.dev_bpb.total_sectors + dev.dev_bpb.large_total_sectors; if (total_blks > 0) { dblks = (nblks == 0) ? total_blks : MIN(nblks,total_blks); } } if ((npages = dblks/(LOGPSIZE/512)) == 0) { printf("ioctl failed \n"); printf("try again but specify number of blocks \n"); return -1; } /* before we destroy anything in the log, try to * confirm with the user */ while(TRUE) { printf("logform: destroy %s (y)?",dev_name); fflush(stdout); answer = getchar(); if(answer == 'n' || answer == 'N') exit(1); else if(answer == 'y' || answer == 'Y' || answer == '\n') break; while((answer = getchar()) != '\n'); } rc = write_bootsec(fd, &(dev.dev_bpb), "jfslog", 1); } /***************************************************************************/ else { /* the fs has an inlinelog */ log_len_in_bytes = ((int64) log_len) << s_l2bsize; npages = log_len_in_bytes / LOGPSIZE; } /* * init log superblock: log page 1 */ log_sup.magic = LOGMAGIC; log_sup.version = LOGVERSION; log_sup.state = LOGREDONE; log_sup.flag = s_flag; /* assign fs s_flag to log superblock. * currently s_flag carries the inlinelog * info and commit option ( i.e. group commit * or lazy commit, etc.. ) */ log_sup.size = npages; log_sup.bsize = aggr_blk_size; log_sup.l2bsize = s_l2bsize; log_sup.end = 2*LOGPSIZE + LOGPHDRSIZE + LOGRDSIZE; /* find the log superblock location */ log_begin = log_start << s_l2bsize; rc = ujfs_rw_diskblocks(fd, (log_begin+LOGPSIZE), (unsigned)LOGPSIZE, (char *)&log_sup, PUT); if ( rc != 0 ) goto errout; /* * init device pages 2 to npages-1 as log data pages: * * log page sequence number (lpsn) initialization: * the N (= npages-2) data pages of the log is maintained as * a circular file for the log records; * lpsn grows by 1 monotonically as each log page is written * to the circular file of the log; * Since the AIX DUMMY log record is dropped for this XJFS, * and setLogpage() will not reset the page number even if * the eor is equal to LOGPHDRSIZE. In order for binary search * still work in find log end process, we have to simulate the * log wrap situation at the log format time. * The 1st log page written will have the highest lpsn. Then * the succeeding log pages will have ascending order of * the lspn starting from 0, ... (N-2) */ /* initialize 1st 2 log pages to be written: lpsn = N-1, 0 and also a SYNCPT log record is written to the N-1 page Since the log is always an even number of meg, if we write 2 pages before entering the loop, we are assured that the log will end after a 4 page buffer. */ logp[0].h.eor = logp[0].t.eor = LOGPHDRSIZE + LOGRDSIZE; logp[0].h.page = logp[0].t.page = npages - 3; lrd_ptr = (struct lrd *)&logp[0].data; lrd_ptr->logtid = 0; lrd_ptr->backchain = 0; lrd_ptr->type = LOG_SYNCPT; lrd_ptr->length = 0; lrd_ptr->log.syncpt.sync = 0; logp[1].h.eor = logp[1].t.eor = LOGPHDRSIZE; logp[1].h.page = logp[1].t.page = 0; lrd_ptr = (struct lrd *)&logp[1].data; lrd_ptr->logtid = 0; lrd_ptr->backchain = 0; lrd_ptr->type = LOG_SYNCPT; lrd_ptr->length = 0; lrd_ptr->log.syncpt.sync = 0; rc = ujfs_rw_diskblocks(fd, (log_begin+2*LOGPSIZE), (unsigned) 2*LOGPSIZE, (char *)&(logp[0]), PUT); if ( rc != 0 ) { printf("Error RW 2\n"); goto errout; } /* initialize buffer to write 4 pages at a time */ logp[0].h.eor = logp[0].t.eor = LOGPHDRSIZE; logp[2].h.eor = logp[2].t.eor = LOGPHDRSIZE; lrd_ptr = (struct lrd *)&logp[2].data; lrd_ptr->logtid = 0; lrd_ptr->backchain = 0; lrd_ptr->type = LOG_SYNCPT; lrd_ptr->length = 0; lrd_ptr->log.syncpt.sync = 0; logp[3].h.eor = logp[3].t.eor = LOGPHDRSIZE; lrd_ptr = (struct lrd *)&logp[3].data; lrd_ptr->logtid = 0; lrd_ptr->backchain = 0; lrd_ptr->type = LOG_SYNCPT; lrd_ptr->length = 0; lrd_ptr->log.syncpt.sync = 0; /* initialize succeeding log pages: lpsn = 1, 2, ..., (N-2) */ Working_counter = 0; log_contwt = log_begin + LOGBUFSIZE; for ( k = 1; k < npages - 4; k+=4 ) { logp[0].h.page = logp[0].t.page = k; logp[1].h.page = logp[1].t.page = k + 1; logp[2].h.page = logp[2].t.page = k + 2; logp[3].h.page = logp[3].t.page = k + 3; rc = ujfs_rw_diskblocks(fd, log_contwt, (unsigned) LOGBUFSIZE, (char *)&(logp[0]), PUT); if (rc != 0 ) { printf("Error RW 3\n"); goto errout; } log_contwt += LOGBUFSIZE; if( !stdout_redirected ) { Working_counter++; switch( Working_counter ) { case( 100 ): DosPutMessage( 1, strlen(Working[0]), Working[0] ); fflush( stdout ); break; case( 200 ): DosPutMessage( 1, strlen(Working[1]), Working[1] ); fflush( stdout ); break; case( 300 ): DosPutMessage( 1, strlen(Working[2]), Working[2] ); fflush( stdout ); break; case( 400 ): DosPutMessage( 1, strlen(Working[3]), Working[3] ); fflush( stdout ); Working_counter = 0; break; default: break; } } } if (!inlinelog) { rc = DosDevIOCtl(fd, IOCTL_DISK, DSK_UNLOCKDRIVE, &parms, sizeof(parms), &parmlen, &parms, sizeof(parms), &parmlen); rc = DosClose(fd); } return(0); errout: if (rc == ERROR_WRITE_PROTECT) message_user(ERROR_WRITE_PROTECT, NULL, 0, STDOUT_CODE, NO_RESPONSE, OSO_MSG); return(-1); }
int32 validfs( HFILE device ) { uint64 num_log_blocks; int32 rc; uint64 first_block, last_block; uint32 length, inode_address; uint64 index; struct dinode inode_buffer; int64 total_nblocks; /* * Initialize internal block map */ num_log_blocks = sb.s_size >> sb.s_l2bfactor; rc = calc_map_size( num_log_blocks, sb.s_bsize, sb.s_agsize ); if( rc != 0 ) { printf("Failure creating internal block map.\n"); } /* * Mark fixed items allocated; these are only the items which aren't mapped * by one of the inode tables. */ /* * Reserved blocks */ length = AGGR_RSVD_BYTES >> sb.s_l2bsize; first_block = 0; last_block = first_block + length; for( index = first_block; index < last_block; index++ ) { markit( index, 0 ); } /* * Primary superblock */ length = SIZE_OF_SUPER >> sb.s_l2bsize; first_block = SUPER1_OFF >> sb.s_l2bsize; last_block = first_block + length; for( index = first_block; index < last_block; index++ ) { markit( index, 0 ); } /* * Secondary superblock */ first_block = SUPER2_OFF >> sb.s_l2bsize; last_block = first_block + length; for( index = first_block; index < last_block; index++ ) { markit( index, 0 ); } /* * Walk aggregate inode table; marking blocks seen */ rc = ujfs_rwinode( device, &inode_buffer, AGGREGATE_I, GET, sb.s_bsize, AGGREGATE_I ); if( rc != 0 ) return(rc); rc = walk_ait( device, &inode_buffer, TRUE ); if( rc != 0 ) { printf( "Failed walking aggregate inode table, or difference in inode maps.\n"); } /* * Walk secondary aggregate inode table; marking blocks seen */ inode_address = (AGGREGATE_I * sizeof(struct dinode)) + ( addressPXD(&(sb.s_ait2)) << sb.s_l2bsize ); rc = ujfs_rw_diskblocks( device, inode_address, sizeof(struct dinode), &inode_buffer, GET ); if( rc != 0 ) return(rc); rc = walk_ait( device, &inode_buffer, FALSE ); if( rc != 0 ) { printf( "Failed walking secondary inode table, or difference in inode maps.\n"); } /* * Since we don't walk the inodes of the secondary inode table we need to * be sure and mark the blocks for the map's addressing structure */ total_nblocks = 0; walk_inode_tree(device, (xtpage_t *)&inode_buffer.di_btroot, &total_nblocks, 0); if( inode_buffer.di_nblocks != total_nblocks ) { error++; printf( "Secondary AIT Inode %d (fileset: %d) nblocks bad, disk: %lld, actual: %lld\n", inode_buffer.di_number, inode_buffer.di_fileset, inode_buffer.di_nblocks, total_nblocks); } /* * Now the bitmaps are marked, fill in the rest of the maps and compare * with the maps on disk */ rc = compare_maps( device, num_log_blocks, sb.s_bsize ); return(rc); }
/* * 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); } } } }
void walk_inoext( int device, uint64 address, uint32 length, uint32 wmap, dinomap_t *control_page, uint32 agno, ino_t start_inum, uint32 *found_map, int32 inostamp ) { dinode_t *next_inode; uint32 left_to_read = length << sb.s_l2bsize; uint64 cur_address = address << sb.s_l2bsize; int32 index, rc; uint32 map = wmap; char page_buffer[PSIZE]; ino_t cur_inum = start_inum; uint32 mask = HIGHORDER; uint64 first_block, cur_block, last_block; uint32 num_blocks; int64 total_nblocks; *found_map = 0; while( (left_to_read > 0) ) { /* * Read next page of inodes for this extent */ rc = ujfs_rw_diskblocks( device, cur_address, PSIZE, page_buffer, GET ); cur_address += PSIZE; left_to_read -= PSIZE; next_inode = (dinode_t *)page_buffer; for( index = 0; index < INOSPERPAGE; index++, next_inode++, cur_inum++, map <<= 1, mask >>= 1 ) { /* * Initialize count for this inode's number of blocks */ total_nblocks = 0; /* * If this inode is allocated, mark blocks for its b-tree */ if( (map & HIGHORDER) != 0 ) { if( next_inode->di_nlink <= 0 ) { error++; printf("Inode %d (fileset: %d) link count bad: %d\n", next_inode->di_number, next_inode->di_fileset, next_inode->di_nlink); } else { *found_map |= mask; } /* * Account for any blocks used by EA for this inode */ if( next_inode->di_ea.flag & DXD_EXTENT ) { first_block = addressDXD(&(next_inode->di_ea)); num_blocks = lengthDXD(&(next_inode->di_ea)); total_nblocks += num_blocks; last_block = first_block + num_blocks; for( cur_block = first_block; cur_block < last_block; cur_block++ ) { markit( cur_block, 0 ); } } if( (next_inode->di_fileset == AGGREGATE_I) && (next_inode->di_number == FILESYSTEM_I) ) { /* * Need to account for inode map's blocks */ walk_inode_tree(device, (xtpage_t *)&next_inode->di_btroot, &total_nblocks, 0); /* * Need to walk this tree of inodes */ rc = walk_ait( device, next_inode, TRUE ); if( rc != 0 ) { error++; printf("Problem with Fileset Inode Allocation Map.\n"); } } else if( (next_inode->di_fileset == AGGREGATE_I) && (next_inode->di_number == BADBLOCK_I) ) { walk_inode_tree(device, (xtpage_t *)&next_inode->di_btroot, &total_nblocks, BADBLOCK); } else if( next_inode->di_mode & IFDIR ) { /* * Need to walk the extents as directory extents */ walk_dir( device, (dtroot_t *)&(next_inode->di_btroot), &total_nblocks); } else { walk_inode_tree(device, (xtpage_t *)&next_inode->di_btroot, &total_nblocks, 0); } /* * Now total_nblocks contains the total number of blocks * actually allocated for this inode. Compare this to the * on-disk information. */ if( next_inode->di_nblocks != total_nblocks ) { error++; printf( "Inode %d (fileset: %d) nblocks bad, disk: %lld, actual: %lld\n", next_inode->di_number, next_inode->di_fileset, next_inode->di_nblocks, total_nblocks); } } else { if( next_inode->di_number == cur_inum && next_inode->di_inostamp == inostamp && addressPXD(&(next_inode->di_ixpxd)) == address && lengthPXD(&(next_inode->di_ixpxd)) == length && next_inode->di_nlink > 0 ) { error++; printf("Inode %d (fileset: %d) link count bad: %d\n", next_inode->di_number, next_inode->di_fileset, next_inode->di_nlink); *found_map |= mask; } control_page->in_numfree++; control_page->in_agctl[agno].numfree++; } } } }